From: Brendan Shanks Subject: [PATCH] winebus.sys: Open IOHID devices individually to fix macOS Catalina and Big Sur. Message-Id: <20201124004844.8932-1-bshanks@codeweavers.com> Date: Mon, 23 Nov 2020 16:48:44 -0800 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50153 Signed-off-by: Brendan Shanks --- This fixes HID device access on macOS Catalina and Big Sur when "Input Monitoring" permission has not been granted by the user (by design, a fairly inconvenient process). In the future I'd also like to have hidclass.sys defer report processing until a device is opened, not created. Then the IOHIDDeviceOpen() call can be made from the necessary vtbl functions, and the permission dialog should not appear unless an application actually tries to open a privileged HID device. dlls/winebus.sys/bus_iohid.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/dlls/winebus.sys/bus_iohid.c b/dlls/winebus.sys/bus_iohid.c index df578b4b9d6..ee6225bf398 100644 --- a/dlls/winebus.sys/bus_iohid.c +++ b/dlls/winebus.sys/bus_iohid.c @@ -297,6 +297,13 @@ static void handle_DeviceMatchingCallback(void *context, IOReturn result, void * if (str) CFStringToWSTR(str, serial_string, ARRAY_SIZE(serial_string)); uid = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDLocationIDKey))); + if (IOHIDDeviceOpen(IOHIDDevice, 0) != kIOReturnSuccess) + { + ERR("Failed to open HID device %p (vid %04x, pid %04x)\n", IOHIDDevice, vid, pid); + return; + } + IOHIDDeviceScheduleWithRunLoop(IOHIDDevice, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + if (IOHIDDeviceConformsTo(IOHIDDevice, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad) || IOHIDDeviceConformsTo(IOHIDDevice, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick)) { @@ -365,6 +372,8 @@ static void handle_RemovalCallback(void *context, IOReturn result, void *sender, IOHIDDeviceRegisterInputReportCallback(IOHIDDevice, NULL, 0, NULL, NULL); /* Note: Yes, we leak the buffer. But according to research there is no safe way to deallocate that buffer. */ + IOHIDDeviceUnscheduleFromRunLoop(IOHIDDevice, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + IOHIDDeviceClose(IOHIDDevice, 0); device = bus_find_hid_device(&iohid_vtbl, IOHIDDevice); if (device) { @@ -383,13 +392,6 @@ static DWORD CALLBACK runloop_thread(void *args) IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, handle_DeviceMatchingCallback, NULL); IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, handle_RemovalCallback, NULL); IOHIDManagerScheduleWithRunLoop(hid_manager, run_loop, kCFRunLoopDefaultMode); - if (IOHIDManagerOpen( hid_manager, 0 ) != kIOReturnSuccess) - { - ERR("Couldn't open IOHIDManager.\n"); - IOHIDManagerUnscheduleFromRunLoop(hid_manager, run_loop, kCFRunLoopDefaultMode); - CFRelease(hid_manager); - return 0; - } CFRunLoopRun(); TRACE("Run Loop exiting\n"); -- 2.26.2