Как нажать / перехватить события клавиатуры в OSX и записать, какая клавиатура запускает каждое событие
Теперь я обнаружил, как перехватывать / касаться событий клавиатуры в OS X на низком уровне: как перебирать F7 через F12 и Power/Eject на клавиатуре MacBook
Распечатка кода из этого ответа:
// 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
}
Как я могу (возможно, адаптировать этот код), чтобы определить, какая клавиатура отвечает за конкретное событие?
Вариант использования: я планирую использовать внешнюю клавиатуру, которая будет переназначена, но в то же время сохраню исходное отображение для моей встроенной клавиатуры MacBook.
РЕДАКТИРОВАТЬ:
OSX HID фильтр для вторичной клавиатуры?
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
2 ответа
Я работал над этой проблемой и, наконец, получил решение. Код OP правильный, если вам нужен идентификатор продукта клавиатуры / планшета, добавьте строки в myHIDKeyboardCallback()
функция:
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);
}
Как сказал @pmdj, вы можете использовать IOHIDDeviceRegisterInputValueCallback()
У меня были проблемы с этим, и обнаружил, что sender
аргумент предоставил идентификатор продукта клавиатуры в любом случае.
Если вы регистрируете обратный вызов на каждом интересующем устройстве индивидуально с IOHIDDeviceRegisterInputValueCallback
тогда sender
аргумент будет IOHIDDeviceRef
с указанием устройства. (Вместо того, чтобы использовать IOHIDManagerRegisterInputValueCallback
где отправителем будет ссылка на HID-менеджер)
Единственным недостатком для этого является то, что вам нужно зарегистрироваться и обрабатывать уведомления о событиях горячего подключения для соответствующих устройств. (зарегистрироваться при появлении нового устройства и отменить регистрацию при исчезновении устройства)
Вы можете получить HID ссылки на устройства, используя IOHIDDeviceCreate()
- это занимает io_service_t
в качестве аргумента. Это, в свою очередь, означает, что вам нужно использовать стандартные функции сопоставления IOKit IOService для получения и просмотра вашего списка устройств, но вы действительно получаете явный список отдельных устройств, который вы можете запросить, чтобы имена отображались пользователю и т. Д. ключевая функция для этого - IOServiceAddMatchingNotification.