1

I'm building a MacOS app using IOKit.

I'm encountering an issue where if Karabiner is running before I run my app, opening a HIDManager fails with kIOReturnExclusiveAccess.

If I close Karabiner and run my app, the HIDManager opens successfully. I can then reopen karabiner and both apps function as normal.

This is a snippet of where in my code this is occurring.

let noreturn = IOHIDManagerOpen(manager, IOOptionBits(kIOHIDOptionsTypeNone));
if(noreturn == kIOReturnExclusiveAccess) {
   print("FAILED");
}

I have originally posted this as an issue to the developer, but I'm not sure if it's me or them. Also, I saw that this previous issue went unacknowledged, so thought best to ask here also.

I am new to using IOKit with MacOS, and don't yet understand why this could occur.

Is anybody able to give me an understanding whether I should be doing something to work around this on my side? It seems tricky to deal with if another application is able to "hog" the HID interface.

Any help would be much appreciated.

Update

The developer answered my question on the GitHub issue I raised.

Karabiner-Elements open IOHIDDevice with kIOHIDOptionsTypeSeizeDevice in order to avoid hidd receives unmodified input events. It causes kIOReturnExclusiveAccess if other apps will open the devices.

As per the Apple documentation for kIOHIDOptionsTypeSeizeDevice

Used to open exclusive communication with the device. This will prevent the system and other clients from receiving events from the device.

Karabiner does this so that the system doesn't receive HID events before Karabiner has a chance to modify them.

If any one like myself needs a bit more of a primer on this, I found the technical notes for the HID Manager APIs super helpful.

At this point, I'm still figuring out best options around this.

Chris
  • 7,996
  • 11
  • 66
  • 98

1 Answers1

0

Are you actually trying to use the device that Karabiner has open (I guess that’s the mouse)? If not, you should be able to avoid this by using the HID Manager differently.

The HID Manager is poorly documented and confusing, particularly how IOHIDManagerOpen works. IOHIDManagerOpen opens every matching device connected to the system (and if you haven’t set a matching dictionary yet, it’ll open every connected device). This is likely the problem, trying to open every device when you only need a specific one.

You should either:

  • set the matching dictionary before you call IOHIDManagerOpen
  • or, don’t call IOHIDManagerOpen at all. You don’t need to! You can use IOHIDManagerCopyDevices or IOHIDManagerRegisterDeviceMatchingCallback to discover devices, then use IOHIDDeviceOpen to open them.
Brendan Shanks
  • 3,141
  • 14
  • 13
  • Thanks Brendan. This is helpful. I have already got matching on the correct usage and usage page. I need to listen to events from any keyboard attached to the system. But I'm now only exploring the concept of handling individual devices. In regards to the difference between the hid manager and hid devices -- Does opening the HID manager basically allow you to listen to devices of a given usage / usage page all at once, where opening a device allows you to open individual devices of interest simultaneously? (thus providing more granularity/control if needed?) – Chris Dec 29 '20 at 07:36
  • I've taken the approach of discovering devices, then opening them selectively. In the case of the Apple Trackpad/Keyboard (yes I need HID access to this and any other keyboard), I still can't open the device due to the aforementioned seizure. If I close karabiner, I can open the device as expected and receive reports. – Chris Dec 29 '20 at 08:54