How to connect / connect keyboard events in OSX and record which keyboard fires each event

Now I learned how to connect / delete keyboard events on OS X at a low level: How to connect F7 via F12 and Power / Eject on a MacBook keyboard

Print the code from this answer:

// compile and run from the commandline with: // clang -framework coreFoundation -framework IOKit ./HID.c -o hid // sudo ./hid // This code works with the IOHID library to get notified of keys. // Still haven't figured out how to truly intercept with // substitution. #include <IOKit/hid/IOHIDValue.h> #include <IOKit/hid/IOHIDManager.h> void myHIDKeyboardCallback( void* context, IOReturn result, void* sender, IOHIDValueRef value ) { IOHIDElementRef elem = IOHIDValueGetElement( value ); if (IOHIDElementGetUsagePage(elem) != 0x07) return; uint32_t scancode = IOHIDElementGetUsage( elem ); if (scancode < 4 || scancode > 231) return; long pressed = IOHIDValueGetIntegerValue( value ); printf( "scancode: %d, pressed: %ld\n", scancode, pressed ); } CFMutableDictionaryRef myCreateDeviceMatchingDictionary( UInt32 usagePage, UInt32 usage ) { CFMutableDictionaryRef dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0 , & kCFTypeDictionaryKeyCallBacks , & kCFTypeDictionaryValueCallBacks ); if ( ! dict ) return NULL; CFNumberRef pageNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, & usagePage ); if ( ! pageNumberRef ) { CFRelease( dict ); return NULL; } CFDictionarySetValue( dict, CFSTR(kIOHIDDeviceUsagePageKey), pageNumberRef ); CFRelease( pageNumberRef ); CFNumberRef usageNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, & usage ); if ( ! usageNumberRef ) { CFRelease( dict ); return NULL; } CFDictionarySetValue( dict, CFSTR(kIOHIDDeviceUsageKey), usageNumberRef ); CFRelease( usageNumberRef ); return dict; } int main(void) { IOHIDManagerRef hidManager = IOHIDManagerCreate( kCFAllocatorDefault, kIOHIDOptionsTypeNone ); CFArrayRef matches; { CFMutableDictionaryRef keyboard = myCreateDeviceMatchingDictionary( 0x01, 6 ); CFMutableDictionaryRef keypad = myCreateDeviceMatchingDictionary( 0x01, 7 ); CFMutableDictionaryRef matchesList[] = { keyboard, keypad }; matches = CFArrayCreate( kCFAllocatorDefault, (const void **)matchesList, 2, NULL ); } IOHIDManagerSetDeviceMatchingMultiple( hidManager, matches ); IOHIDManagerRegisterInputValueCallback( hidManager, myHIDKeyboardCallback, NULL ); IOHIDManagerScheduleWithRunLoop( hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode ); IOHIDManagerOpen( hidManager, kIOHIDOptionsTypeNone ); CFRunLoopRun(); // spins } 

How can I (possibly adapt this code) determine which keyboard is responsible for a particular event?

A use case is that I plan to use an external keyboard, which will be reassigned, but at the same time preserving the original mapping for the built-in MacBook keyboard.

EDIT:
OSX HID filter for optional keyboard
https://github.com/candera/khordr/blob/master/src/c/keygrab/hid-scratch.c
http://ianjoker.googlecode.com/svn/trunk/Joker/Joker/hid_test.cpp
http://www.cplusplusdevelop.com/72_17345226/
http://www.cocoabuilder.com/archive/cocoa/229902-which-keyboard-barcode-scanner-did-the-event-come-from.html

+5
source share
2 answers

I worked on this problem and finally got a solution. The OP code is correct, if you want the keyboard / pad product identifier, add lines to the myHIDKeyboardCallback() function:

 void myHIDKeyboardCallback(void* context, IOReturn result, void* sender, IOHIDValueRef value){ IOHIDElementRef elem = IOHIDValueGetElement(value); if (IOHIDElementGetUsagePage(elem) != 0x07) return; IOHIDDeviceRef device = sender; int32_t pid = 1; CFNumberGetValue(IOHIDDeviceGetProperty(device, CFSTR("idProduct")), kCFNumberSInt32Type, &pid); uint32_t scancode = IOHIDElementGetUsage(elem); if (scancode < 4 || scancode > 231) return; long pressed = IOHIDValueGetIntegerValue(value); printf("scancode: %d, pressed: %ld, keyboardId=%d\n", scancode, pressed, pid); } 

As @pmdj said that you can use IOHIDDeviceRegisterInputValueCallback() , I had problems with this and found that the sender argument provided the product keyboard identifier anyway.

+2
source

If you register a callback on each device of interest individually using IOHIDDeviceRegisterInputValueCallback , then the sender argument will contain an IOHIDDeviceRef indicating the device. (instead of using IOHIDManagerRegisterInputValueCallback , where the sender will be the HID manager link)

The only drawback to this is that you will need to register and process notification of hotplugging events for the respective devices. (registered every time a new device appears, and unregisters when the device disappears)

You can get links to HID devices using IOHIDDeviceCreate() - io_service_t is required as an argument. This, in turn, means that you need to use the standard IOKit IOService mapping functions to get and view the list of devices, but you really get an explicit list of individual devices that you can request for the names displayed for the user, etc. The key function for this is the IOServiceAddMatchingNotification .

+1
source

Source: https://habr.com/ru/post/987438/


All Articles