2015-05-21 10 views
5

Ora ho scoperto come collegare/eventi della tastiera tap su OS X ad un livello basso: How to tap (hook) F7 through F12 and Power/Eject on a MacBook keyboardCome toccare/gancio eventi della tastiera in OSX e segnare i tastiera incendi ogni evento

stampa il codice da quel RISPOSTA:

// 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 
} 

Come posso (forse adattarsi quel codice a) identificare quale tastiera è responsabile di un evento particolare?

Il caso di utilizzo è che sto pensando di utilizzare una tastiera esterna che verrà rimappata, ma allo stesso tempo mantenendo la mappatura originale per la tastiera del mio MacBook incorporato.

EDIT:
OSX HID Filter for Secondary 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

risposta

1

Se si registra la richiamata su ogni dispositivo di interesse individualmente con IOHIDDeviceRegisterInputValueCallback allora l'argomento sender sarà un IOHIDDeviceRef indicando il dispositivo. (invece di utilizzare IOHIDManagerRegisterInputValueCallback dove il mittente sarà il riferimento gestore HID)

L'unico svantaggio di questo è che è necessario registrarsi e gestire la notifica degli eventi hotplugging per i dispositivi corrispondenti. (registrarsi ogni volta che appare un nuovo dispositivo e annullare la registrazione quando un dispositivo scompare)

È possibile ottenere riferimenti dispositivo HID utilizzando IOHIDDeviceCreate() - questo accetta un argomento io_service_t come argomento. Ciò a sua volta significa che è necessario utilizzare le funzioni di corrispondenza IOService standard IOKit per ottenere e visualizzare il proprio elenco di dispositivi, ma in effetti si ottiene un elenco esplicito di singoli dispositivi, che è possibile interrogare affinché i nomi vengano mostrati all'utente, ecc. la funzione chiave è IOServiceAddMatchingNotification.

+0

Grazie per il ritiro. Avrei dovuto pensare alla registrazione di "mittente". Ho appena provato con il mio esempio di codice, e in effetti dà un valore diverso a seconda della tastiera che sto usando (1800442080 integrato, 1800440000 wireless). Posso enumerare le mie tastiere in modo tale da ottenere l'ID associato per la tastiera incorporata? –

+0

Si noti che si sta utilizzando 'IOHIDManagerRegisterInputValueCallback', mentre sto suggerendo [' IOHIDDeviceRegisterInputValueCallback'] (https://developer.apple.com/library/mac/documentation/IOKit/Reference/IOHIDDevice_iokit_header_reference/index.html#// apple_ref/c/func/IOHIDDeviceCopyMatchingElements) - differenza sottile ma importante. Aggiornerò la risposta con ulteriori dettagli sull'enumerazione dei dispositivi HID. – pmdj

+0

Si dice che con il mio attuale ('IOHIDManagerRegisterInputValueCallback') si imposta che' sender' sarà il riferimento al gestore HID. Ma in realtà segnala in modo diverso per ogni tastiera, che sembra suggerire il contrario, in quanto esiste un solo gestore. Questo mi fa chiedere se sia davvero necessario impostare la callback per un particolare dispositivo. –

2

Stavo lavorando a questo problema e finalmente ho trovato la soluzione. il codice di OP è corretto, se vuoi l'ID prodotto della tastiera/pad, aggiungere linee alla funzione 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); 
} 

Come @pmdj detto è possibile utilizzare IOHIDDeviceRegisterInputValueCallback(), ho avuto problemi con questo, e trovato che l'argomento sender ha fornito comunque l'id prodotto della tastiera.

Problemi correlati