2015-05-21 7 views
5

मैं अब कैसे एक निम्न स्तर पर हुक करने/ओएस एक्स पर टैप कीबोर्ड की घटनाओं की खोज की है: How to tap (hook) F7 through F12 and Power/Eject on a MacBook keyboardकैसे OSX में/हुक कुंजीपटल घटनाओं और रिकॉर्ड है जो कुंजीपटल आग दोहन करने के लिए प्रत्येक घटना

मुद्रण कि से कोड बाहर का जवाब:

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

मैं कैसे (शायद कि कोड अनुकूल करने के लिए) की पहचान जो कुंजीपटल एक विशेष घटना के लिए जिम्मेदार है सकते हैं?

उपयोग का मामला यह है कि मैं एक बाहरी कीबोर्ड का उपयोग करने की योजना बना रहा हूं जिसे रीमेप किया जाएगा, लेकिन साथ ही मेरे इनबिल्ट मैकबुक कीबोर्ड के लिए मूल मानचित्रण को बनाए रखा जाएगा।

संपादित करें:
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

उत्तर

1

आप IOHIDDeviceRegisterInputValueCallback साथ व्यक्तिगत रूप से ब्याज की प्रत्येक डिवाइस पर कॉलबैक रजिस्टर तो sender तर्क एकहो जाएगाडिवाइस को इंगित करता है। (IOHIDManagerRegisterInputValueCallback का उपयोग करने के बजाय जहां प्रेषक छिपा प्रबंधक संदर्भ होगा)

इसका एकमात्र नकारात्मक पक्ष यह है कि आपको मिलान करने वाले उपकरणों के लिए हॉटप्लगिंग ईवेंट की अधिसूचना के लिए पंजीकरण करने और संभालने की आवश्यकता होगी। (जब भी कोई नया डिवाइस प्रकट होता है, रजिस्टर करें और डिवाइस गायब होने पर पंजीकरण करें)

आप IOHIDDeviceCreate() का उपयोग करके डिवाइस डिवाइस संदर्भ प्राप्त कर सकते हैं - यह io_service_t को तर्क के रूप में लेता है। बदले में इसका मतलब है कि आपको डिवाइस की अपनी सूची प्राप्त करने और देखने के लिए मानक IOKit IOService मिलान फ़ंक्शंस का उपयोग करने की आवश्यकता है, लेकिन आपको वास्तव में अलग-अलग डिवाइसों की स्पष्ट सूची मिलती है, जिन्हें आप उपयोगकर्ता को दिखाने के लिए नामों के लिए पूछ सकते हैं। इसके लिए महत्वपूर्ण कार्य IOServiceAddMatchingNotification है।

+0

उठा लेने के लिए धन्यवाद। मुझे 'प्रेषक' लॉगिंग करने का विचार करना चाहिए था। बस मेरे कोड उदाहरण के साथ कोशिश की, और यह वास्तव में एक अलग मूल्य देता है कि मैं किस कीबोर्ड का उपयोग कर रहा हूं (1800442080 इनबिल्ट, 1800440000 वायरलेस)। क्या मैं अपने कीबोर्ड को इस तरह से समझा सकता हूं कि मैं इनबिल्ट कीबोर्ड के लिए संबंधित आईडी प्राप्त कर सकता हूं? –

+0

ध्यान दें कि आप 'IOHIDManagerRegisterInputValueCallback' का उपयोग कर रहे हैं, जबकि मैं सुझाव दे रहा हूं [' IOHIDDeviceRegisterInputValueCallback'] (https://developer.apple.com/library/mac/documentation/IOKit/Reference/IOHIDDevice_iokit_header_reference/index.html#// apple_ref/c/func/IOHIDDeviceCopyMatchingElements) - सूक्ष्म लेकिन महत्वपूर्ण अंतर। मैं एचआईडी डिवाइस गणना पर कुछ और विवरण के साथ जवाब अपडेट कर दूंगा। – pmdj

+0

आप कहते हैं कि मेरे वर्तमान ('IOHIDManagerRegisterInputValueCallback') के साथ स्थापित किया गया है कि 'प्रेषक' छुपा प्रबंधक संदर्भ होगा। लेकिन यह वास्तव में प्रत्येक कीबोर्ड के लिए अलग-अलग रिपोर्ट करता है, जो अन्यथा सुझाव देता है, क्योंकि केवल एक प्रबंधक है। इससे मुझे आश्चर्य होता है कि किसी विशेष डिवाइस के लिए कॉलबैक सेट करना वास्तव में आवश्यक है। –

2

मैं इस समस्या पर काम कर रहा था, और अंत में समाधान मिला। ओपी के कोड सही है, अगर तुम, कीबोर्ड/पैड की उत्पाद ID चाहते हैं 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 तर्क ने कीबोर्ड उत्पाद आईडी को वैसे भी प्रदान किया है।

संबंधित मुद्दे