Is there a way to determine if a Mac has more than one mouse attached? - macos

I'm looking for a way to determine if the Mac running my game has more than one mouse attached. The typical real world example is a MacBook (with built in trackpad) with an external mouse connected.
My game has different control set ups for common configurations like keyboard+mouse, just keyboard (e.g., a MacBook with just the trackpad, no mouse) and gamepad. Ideally I'll be able to detect this in the game and set the controls accordingly.
I'm planning to support Mac OS 10.7+.
Is there a Cocoa (or non-Cocoa) API I can use to get this information?
For reference, I've ask (and got an answer) for a similar question for Windows-based computers.

you should deal with IOKit... the following sample enumerates all the USB devices connected to the system, you can use that to see if there's a pointing device attached:
#include <IOKit/IOKitLib.h>
#include <IOKit/usb/IOUSBLib.h>
int main(int argc, const char *argv[])
{
CFMutableDictionaryRef matchingDict;
io_iterator_t iter;
kern_return_t kr;
io_service device;
/* set up a matching dictionary for the class */
matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
if (matchingDict == NULL)
{
return -1; // fail
}
/* Now we have a dictionary, get an iterator.*/
kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
if (kr != KERN_SUCCESS)
{
return -1;
}
/* iterate */
while ((device = IOIteratorNext(iter)))
{
/* do something with device, eg. check properties */
/* ... */
/* And free the reference taken before continuing to the next item */
IOObjectRelease(device);
}
/* Done, release the iterator */
IOObjectRelase(iter);
return 0;
}
The internal trackpad should be seen as an attached USB device but I'm not sure about that...

I ended up using ManyMouse, a cross-platform library for detecting the number of mice attached to a computer. On OSX it uses HIDManager to detect mice. Once it's built getting the number of mice attached to the system is a one-liner:
const int available_mice = ManyMouse_Init();

Related

Get address family from socket OS X

Getting address family can be done with getsockopt() with option SO_DOMAIN (see socket options) on linux.
(read Get address family from socket. Linux)
How do I do the same thing on OS X ?
When using the code that worked on linux on OS X I get
error: use of undeclared identifier 'SO_DOMAIN'
int err = getsockopt(sock, SOL_SOCKET, SO_DOMAIN, &addr_family, &len);
^
so not SO_DOMAIN ?
You can find this out by calling proc_pidfdinfo() on your own PID, and requesting PROC_PIDFDSOCKETINFO:
#include <libproc.h>
#include <stdbool.h>
#include <unistd.h>
bool socketDomainGet(int socket, int *domain) {
struct socket_fdinfo info;
int rc = proc_pidfdinfo(getpid(), socket, PROC_PIDFDSOCKETINFO, &info, sizeof info);
if (rc <= 0) return false;
*domain = info.psi.soi_family;
return true;
}
Unlike getsockname(), this works even if the socket hasn't been bound yet. Note as well as the domain (psi.soi_family), it also can tell you the type (psi.soi_type) and the protocol (psi.soi_protocol).
Keep in mind though this warning Apple gives in the libproc.h header:
/*
* This header file contains private interfaces to obtain process information.
* These interfaces are subject to change in future releases.
*/
They probably aren't going to break this, but the risk is higher than for more official APIs.
use SO_TYPE instead of SO_DOMAIN
in OS X man GETSOCKOPT(2) says
SO_TYPE get the type of the socket (get only)

Can I use SetupDiEnumDeviceInterfaces to get a DevicePath from SetupDiGetDeviceInterfaceDetail when no InterfaceClassGUID is known?

Overview...
I have read How to get device interface GUID for a device? and How to open a handle to a device using its Device Instance ID?, but I'm still confused about how I am to (or whether I should even) use SetupDiEnumDeviceInterfaces paired with SetupDiGetDeviceInterfaceDetail to get a DevicePath that can be opened with CreateFile to access the device when no device interface class GUID is known. My question is based on the MSDN article here and here which rely on these functions.
More details...
The high level of my problem is I've got an audio USB device I need to send control transfer commands. To do so, I want to use WinUSB's API, and to do that I need to get a handle to the device via CreateFile. Unfortunately, there is no .inf file associated with the device and so there is no known device interface class GUID. If one plugs the device in, Windows associates with it usbaudio.sys as the driver. To start talking over WinUSB, I use libwdi to install WinUSB as the device driver so that I can communicate with it via the WinUSB API. To accomplish the install of WinUSB, libwdi dynamically creates a self-signed .cat and .inf file pair, which unfortunately has no device interface class defined. In fact, the INF file has the following in it:
[NoDeviceInterfaceGUID]
; Avoids adding a DeviceInterfaceGUID for generic driver
So, despite the fact I now have swapped out usbaudio.sys for winusb.sys, I'm unable to communicate with the device.
At first I thought maybe I should try using GUID_DEVINTERFACE_USB_DEVICE, reasoning that this is WinUSB and therefore seen as a generic USB device. But, if I invoke
SetupDiEnumDeviceInterfaces(_deviceList,
&devInfo,
&GUID_DEVINTERFACE_USB_DEVICE,
0,
&usbInterface)
it fails and GetLastError returns 259, or ERROR_NO_MORE_ITEMS immediately. I'm assuming this means it doesn't implement the interface?
So, in general, when no interface class guid is known, am I able to use the aforementioned functions in any form to get the full device path?
Thanks in advance for your time.
Yes, first you need to get a device information set for devices that implement the interface via SetupDiGetClassDevs, then pick one of the devices and read its device interface data, and use that to get the device interface detail that contains the device path.
Example:
#include <windows.h>
#include <setupapi.h>
#include <initguid.h>
#include <usbioctl.h>
#include <stdio.h>
BOOL DevicePath(_In_ LPCGUID interfaceGuid, DWORD instance)
{
BOOL result = FALSE;
PSP_DEVICE_INTERFACE_DETAIL_DATA_W devInterfaceDetailData = NULL;
HDEVINFO hDevInfo = SetupDiGetClassDevsW(interfaceGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(hDevInfo == INVALID_HANDLE_VALUE)
goto cleanup;
SP_DEVICE_INTERFACE_DATA devInterfaceData;
devInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if(!SetupDiEnumDeviceInterfaces(hDevInfo, NULL, interfaceGuid, instance, &devInterfaceData))
goto cleanup;
// Call this with an empty buffer to the required size of the structure.
ULONG requiredSize;
SetupDiGetDeviceInterfaceDetailW(hDevInfo, &devInterfaceData, NULL, 0, &requiredSize, NULL);
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto cleanup;
devInterfaceDetailData = malloc(requiredSize);
if(!devInterfaceDetailData)
goto cleanup;
devInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if(!SetupDiGetDeviceInterfaceDetailW(hDevInfo, &devInterfaceData, devInterfaceDetailData, requiredSize, &requiredSize, NULL))
goto cleanup;
wprintf(L"%s\n", devInterfaceDetailData->DevicePath);
result = TRUE;
cleanup:
if(hDevInfo != INVALID_HANDLE_VALUE)
SetupDiDestroyDeviceInfoList(hDevInfo);
free(devInterfaceDetailData);
return result;
}
int main()
{
for(DWORD i = 0; DevicePath(&GUID_DEVINTERFACE_USB_DEVICE, i); ++i)
;
}

WINAPI USB DEVICE LIST C LIBUSB not any good

I hope someone can help me with this issue. I made an application to read some data from a smartphone and display in an application. It worked fine at my house, so I took it to my friend's house to show him and it didn't work. So after the panic, I realized that the address had changed slightly due to being connected to a new PC not a problem there must be a simple solution on winapi.
\\?\usb#vid_045e&pid_0040#6&ff454f2&0&3#{a5dcbf10-6530-11d2-901f-00c04fb951ed}\
I have only found code for C++ and my app is in C so it's no use. I also found libusb on google, however this doesn't return the full paths like in my example above.
Is there a simple fix like search by GUID? Hope you can help.
BR
This was the LIBUSB I used
#include <stdio.h>
#include <sys/types.h>
#include <windows.h>
#include <libusb.h>
static void print_devs(libusb_device **devs)
{
libusb_device *dev;
int i = 0;
while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
fprintf(stderr, "failed to get device descriptor");
return;
}
printf("%04x:%04x (bus %d, device %d)\n",
desc.idVendor, desc.idProduct,
libusb_get_bus_number(dev), libusb_get_device_address(dev));
}
}
int main(void)
{
libusb_device **devs;
int r;
ssize_t cnt;
r = libusb_init(NULL);
if (r < 0)
return r;
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0)
return (int) cnt;
print_devs(devs);
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
system("pause");
return 0;
}
This just returns for example
1033:0194 (bus 1, device 255)
Yes you can get a list of all the device identifiers on your computer, but it's not really all that simple, especially if you need to filter it for a particular kind of device.
You start with SetupDiGetClassDevs. After enumerating the matching devices, use SetupDiGetDeviceInstanceId to get the device path, like the one shown in your question.

SysInternal's WinObj device listing mechanism

SysInternals's WinObj can list all device objects.
I wonder how it can list the devices.
Is there any open source we can read?(or a code snippet)
What is the most significant function I should know?
WinObj uses the NT system calls NtOpenDirectoryObject and NtQueryDirectoryObject. There is no driver or kernel code needed. You won't see the imports because these NT functions are loaded via LoadLibrary/GetProcAddress.
You don't have to enumerate the entire object namespace. If you're interested in the device objects call NtOpenDirectoryObject with "\Device", then call NtQueryDirectoryObject on the returned handle.
According to SysInternals' web page:
The native NT API provides routines
that allow user-mode programs to
browse the namespace and query the
status of objects located there, but
the interfaces are undocumented.
I've tried looking at WinObj's import table (dumpbin /imports winobj.exe) but there are no obvious suspects :-(
As per the answer from user1575778 you can use NtOpenDirectoryObject and NtQueryDirectoryObject (which from user mode are identical to ZwOpenDirectoryObject and ZwQueryDirectoryObject respectively) to list the objects inside the object manager namespace.
Have a look at objmgr.hpp of NT Objects aka ntobjx, in particular at the class NtObjMgr::Directory (or DirectoryT). It provides the same functionality nicely wrapped into a C++ class. The whole utility is open source under a liberal license (dual-licensed due to WTL-use: MIT and MS-PL), so bits and pieces can be reused however you please, provided you comply with the license terms.
But here's a simple C++ code example catering just your use case:
#include <Windows.h>
#include <tchar.h>
#include <cstdio>
#include <winternl.h>
NTSTATUS (NTAPI* NtOpenDirectoryObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
NTSTATUS (NTAPI* NtQueryDirectoryObject)(HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG);
VOID (NTAPI* RtlInitUnicodeString_)(PUNICODE_STRING, PCWSTR);
NTSTATUS (NTAPI* NtClose_)(HANDLE);
#define DIRECTORY_QUERY (0x0001)
#define DIRECTORY_TRAVERSE (0x0002)
typedef struct _OBJECT_DIRECTORY_INFORMATION {
UNICODE_STRING Name;
UNICODE_STRING TypeName;
} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth
#endif // STATUS_SUCCESS
#ifndef STATUS_MORE_ENTRIES
#define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L)
#endif // STATUS_MORE_ENTRIES
#ifndef STATUS_NO_MORE_ENTRIES
#define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL)
#endif // STATUS_NO_MORE_ENTRIES
int PrintDevices()
{
NTSTATUS ntStatus;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING objname;
HANDLE hDeviceDir = NULL;
RtlInitUnicodeString_(&objname, L"\\Device");
InitializeObjectAttributes(&oa, &objname, 0, NULL, NULL);
ntStatus = NtOpenDirectoryObject(&hDeviceDir, DIRECTORY_QUERY | DIRECTORY_TRAVERSE, &oa);
if(NT_SUCCESS(ntStatus))
{
size_t const bufSize = 0x10000;
BYTE buf[bufSize] = {0};
ULONG start = 0, idx = 0, bytes;
BOOLEAN restart = TRUE;
for(;;)
{
ntStatus = NtQueryDirectoryObject(hDeviceDir, PBYTE(buf), bufSize, FALSE, restart, &idx, &bytes);
if(NT_SUCCESS(ntStatus))
{
POBJECT_DIRECTORY_INFORMATION const pdilist = reinterpret_cast<POBJECT_DIRECTORY_INFORMATION>(PBYTE(buf));
for(ULONG i = 0; i < idx - start; i++)
{
if(0 == wcsncmp(pdilist[i].TypeName.Buffer, L"Device", pdilist[i].TypeName.Length / sizeof(WCHAR)))
{
_tprintf(_T("%s\n"), pdilist[i].Name.Buffer);
}
}
}
if(STATUS_MORE_ENTRIES == ntStatus)
{
start = idx;
restart = FALSE;
continue;
}
if((STATUS_SUCCESS == ntStatus) || (STATUS_NO_MORE_ENTRIES == ntStatus))
{
break;
}
}
(void)NtClose_(hDeviceDir);
return 0;
}
_tprintf(_T("Failed NtOpenDirectoryObject with 0x%08X"), ntStatus);
return 1;
}
int _tmain(int /*argc*/, _TCHAR** /*argv*/)
{
HMODULE hNtDll = ::GetModuleHandle(_T("ntdll.dll"));
*(FARPROC*)&NtOpenDirectoryObject = ::GetProcAddress(hNtDll, "NtOpenDirectoryObject");
*(FARPROC*)&NtQueryDirectoryObject = ::GetProcAddress(hNtDll, "NtQueryDirectoryObject");
*(FARPROC*)&RtlInitUnicodeString_ = ::GetProcAddress(hNtDll, "RtlInitUnicodeString");
*(FARPROC*)&NtClose_ = ::GetProcAddress(hNtDll, "NtClose");
if (!NtOpenDirectoryObject || !NtQueryDirectoryObject || !RtlInitUnicodeString_ || !NtClose_)
{
_tprintf(_T("Failed to retrieve ntdll.dll function pointers\n"));
return 1;
}
return PrintDevices();
}
Some remarks: This will not delve into subdirectories, it will not list any types other than Device and it will not resolve symbolic links, if any. For any of those features, please look at the aforementioned utility's source code and adjust as needed. winternl.h should be available in any recent Windows SDK.
The functions RtlInitUnicodeString_ and NtClose_ have a trailing underscore to avoid clashes with these native API functions, which are declared in winternl.h, but use __declspec(dllimport).
Disclosure: I am the author of ntobjx.
You can use NtOpenDirectoryObject and NtQueryDirectoryObject to enumarate the objects list in a given directory.
To get the details of the object namespace, you must use the Windows NT Undocumented API. That is also used by the WinObj as it is described here that how WinOBj getting the all results..and for those who are saying that we need a driver to do this please, read these lines on given page.
"One obvious way is to use a driver – in kernel mode everything is accessible – so the client app can get the required information by communicating with its own driver. WinObj does not use a driver, however (this is one reason it’s able to execute without admin privileges, although with admin privileges it shows all objects as opposed to partial results)."
You can start with SetupDiCreateDeviceInfoList and use other related functions to enumerate all the devices. This stuff is painful to use.

How to detect the presence of a default recording device in the system?

How do I detect if the system has a default recording device installed?
I bet this can be done through some calls to the Win32 API, anyone has any experience with this?
I'm talking about doing this through code, not by opening the control panel and taking a look under sound options.
Using the DirectX SDK, you can call DirectSoundCaptureEnumerate, which will call your DSEnumCallback function for each DirectSoundCapture device on the system. The first parameter passed to your DSEnumCallback is an LPGUID, which is the "Address of the GUID that identifies the device being enumerated, or NULL for the primary device".
If all you need to do is find out if a recording device is present (I don't think this is good enough if you really need to know the default device), you can use waveInGetNumDevs:
#include <tchar.h>
#include <windows.h>
#include "mmsystem.h"
int _tmain( int argc, wchar_t *argv[] )
{
UINT deviceCount = waveInGetNumDevs();
if ( deviceCount > 0 )
{
for ( int i = 0; i < deviceCount; i++ )
{
WAVEINCAPSW waveInCaps;
waveInGetDevCapsW( i, &waveInCaps, sizeof( WAVEINCAPS ) );
// do some stuff with waveInCaps...
}
}
return 0;
}
There is an Open Source Audio API called PortAudio that has a method you could use. I think the method is called Pa_GetDeviceInfo() or something.
The win32 api has a function called waveInGetNumDevs for it.

Resources