I'm trying to receive input reports for my mouse (wrapped in an IOHIDDeviceRef
), but for the life of me I can't seem to get it working on macOS 10.12. The same code works fine in 10.11 and 10.10, and it works great for all other kinds of HID input devices (Keyboard, Gamepads and Joysticks).
I have tried it multiple ways, but no matter what, I simply don't receive any input events. I have tried:
IOHIDDeviceRegisterInputReportCallback
and IOHIDDeviceRegisterInputValueCallback()
, as they are the most straight forward ways to receive the date. Additionally, I have tried to create a IOHIDQueueRef
with all the IOHIDElement
's of the mouse added to it.
None of these methods do the trick. The code does work for other input devices, as mentioned, so I'm 99.999% sure I set it up correctly. I open the device via IOHIDDeviceOpen(device, kIOHIDOptionsTypeNone)
which returns kIOReturnSuccess
. I schedule the device to the main run loop with kCFRunLoopCommonModes
mode. In the case of the IOHIDQueueRef
I also register that one to the run loop and call IOHIDQueueStart()
. Also worth noting: The code used to work on 10.10 and 10.11, it just simply stopped working for 10.12.
Am I doing something wrong here, or is this just no longer supported on macOS 10.12?
Here is a minimal repro example (I apologize for the boilerplate cod), which will match keyboard and mouse devices and open then. However, it'll only produce input values for the keyboards, the mouse never reports anything on 10.12:
#include <iostream>
#include <IOKit/hid/IOHIDLib.h>
void HIDDeviceValueReceived(__unused void *context, __unused IOReturn result, void *sender, __unused IOHIDValueRef value)
{
std::cout << "Received IOHIDValue from " << sender << std::endl;
}
void HIDDeviceMatched(__unused void *context, __unused IOReturn result, __unused void *sender, IOHIDDeviceRef deviceRef)
{
CFNumberRef usagePageValue = (CFNumberRef)IOHIDDeviceGetProperty(deviceRef, CFSTR(kIOHIDPrimaryUsagePageKey));
CFNumberRef usageValue = (CFNumberRef)IOHIDDeviceGetProperty(deviceRef, CFSTR(kIOHIDPrimaryUsageKey));
if(!usagePageValue || !usageValue)
{
IOHIDDeviceClose(deviceRef, kIOHIDOptionsTypeNone);
return;
}
int32_t usagePage;
int32_t usage;
CFNumberGetValue(usagePageValue, kCFNumberSInt32Type, &usagePage);
CFNumberGetValue(usageValue, kCFNumberSInt32Type, &usage);
switch(usagePage)
{
case kHIDPage_GenericDesktop:
{
switch(usage)
{
case kHIDUsage_GD_Keyboard:
case kHIDUsage_GD_Keypad:
{
std::cout << "Found keyboard device " << (void *)deviceRef << std::endl;
if(IOHIDDeviceOpen(deviceRef, kIOHIDOptionsTypeNone) != kIOReturnSuccess)
std::cerr << "Couldn't open keyboard device";
IOHIDDeviceRegisterInputValueCallback(deviceRef, &HIDDeviceValueReceived, nullptr);
IOHIDDeviceScheduleWithRunLoop(deviceRef, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
break;
}
case kHIDUsage_GD_Mouse:
case kHIDUsage_GD_Pointer:
{
std::cout << "Found mouse device " << (void *)deviceRef << std::endl;
if(IOHIDDeviceOpen(deviceRef, kIOHIDOptionsTypeNone) != kIOReturnSuccess)
std::cerr << "Couldn't open mouse device";
IOHIDDeviceRegisterInputValueCallback(deviceRef, &HIDDeviceValueReceived, nullptr);
IOHIDDeviceScheduleWithRunLoop(deviceRef, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
break;
}
default:
break;
}
break;
}
default:
break;
}
}
int main()
{
// Find all HID Devices
IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
IOHIDManagerSetDeviceMatching(hidManager, nullptr);
IOHIDManagerRegisterDeviceMatchingCallback(hidManager, &HIDDeviceMatched, nullptr);
IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone);
// Run the run loop
CFRunLoopRun();
return 0;
}
Edit: CGEventTaps still work fine, so it can't be a security thing I would think. I guess I'll submit a bug report to Apple about this one.