Search code examples
macoshidiokit

IOHIDManagerOpen returns error code -536870201


I am new to USB usage in my application on Mac. When I log the result of IOHIDManagerOpen(x,y) function call on my application I get error code -536870201. I have found in the following post (Keystrokes are not blocked when using kIOHIDOptionsTypeSeizeDevice and are still passed to the OS) that -536870207 is translated to kIOReturnNotPrivileged. How can I translate my error code and understand the cause of an error?

Code that I am running:

  manager = std::make_unique<CoreFoundationReference<IOHIDManagerRef>>(
      IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone));

  IOHIDManagerSetDeviceMatching(manager->Get(), nullptr);
  IOHIDManagerRegisterDeviceMatchingCallback(
      manager->Get(), &MacHidDeviceManager::OnDeviceMatched, this);
  IOHIDManagerRegisterDeviceRemovalCallback(
      manager->Get(), &MacHidDeviceManager::OnDeviceRemoved, this);
  IOHIDManagerScheduleWithRunLoop(
      manager->Get(), CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);

  auto ioResult = IOHIDManagerOpen(manager->Get(), kIOHIDOptionsTypeNone);
  if (ioResult != kIOReturnSuccess) {
    throw UsbInterfaceException("DeviceManager::DeviceManager", "Cannot open IO device manager, error: {}", ioResult);
  }

Solution

  • For IOKit return values (IOReturn) it's typically much more helpful to print them as hexadecimal, ("0x%x") as that's how the constants are defined in <IOKit/IOReturn.h>.

    So for example, -536870201 is represented in hexadecimal as 0xE00002C7. The 0xE0000000 part means it's an IOKit constant, the last few digits of 2C7 identify it as kIOReturnUnsupported.

    You haven't posted any code or other details about the run-up or arguments to your IOHIDManagerOpen() call, so I can't really say why it should return kIOReturnUnsupported without more details.

    Based on the code you added to your question, I tried to come up with the minimum reproducible sample:

    #include <IOKit/hid/IOHIDManager.h>
    
    struct MacHidDeviceManager
    {
        static void OnDeviceMatched(void *context, IOReturn result, void *sender, IOHIDDeviceRef device) {}
        static void OnDeviceRemoved(void *context, IOReturn result, void *sender, IOHIDDeviceRef device) {}
        void Start()
        {
            IOHIDManagerRef manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
            IOHIDManagerSetDeviceMatching(manager, nullptr);
            IOHIDManagerRegisterDeviceMatchingCallback(
                manager, &MacHidDeviceManager::OnDeviceMatched, this);
            IOHIDManagerRegisterDeviceRemovalCallback(
                manager, &MacHidDeviceManager::OnDeviceRemoved, this);
            IOHIDManagerScheduleWithRunLoop(
                manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
    
            auto ioResult = IOHIDManagerOpen(manager, kIOHIDOptionsTypeNone);
            if (ioResult != kIOReturnSuccess) {
                fprintf(stderr, "MacHidDeviceManager -> 0x%x\n", ioResult);
            }
        }
    };
    
    int main()
    {
        MacHidDeviceManager m;
        m.Start();
    }
    

    This initially fails (0xe00002e2, kIOReturnNotPermitted) due to missing consent from Security & Privacy, but succeeds once I've granted that permission in System Preferences. I've tested this on macOS 11 and 13 with the same result. I suspect some of the code you haven't posted (CoreFoundationReference?) might be where the problem lies. Or perhaps some sandboxing issue?

    Incidentally, I maintain a small library of IOKit helper utilities, and one of those things is a function djt_ioreturn_string which converts IOReturn values into string representations of those constants. (You just need to include the ioreturn_strings.cpp and ioreturn_strings.h files in your project, the ioreturn_strings.h can be #include/#imported from pure C or Objective-C, just the .cpp uses C++.)