2015-05-21 22 views
5

bây giờ tôi đã khám phá ra làm thế nào để treo/sự kiện tap bàn phím trên OS X ở mức thấp: How to tap (hook) F7 through F12 and Power/Eject on a MacBook keyboardLàm thế nào để khai thác/móc sự kiện bàn phím trong OSX và ghi lại mà bàn phím cháy mỗi sự kiện

In ra mã từ đó 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 
} 

Làm cách nào để (có thể điều chỉnh mã đó) xác định bàn phím nào chịu trách nhiệm cho một sự kiện cụ thể?

Trường hợp sử dụng là tôi đang lên kế hoạch sử dụng bàn phím ngoài sẽ được ánh xạ lại, nhưng đồng thời giữ lại ánh xạ ban đầu cho bàn phím MacBook sẵn có của tôi.

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

Trả lời

1

Nếu bạn đăng ký gọi lại trên mỗi thiết bị hấp dẫn riêng với IOHIDDeviceRegisterInputValueCallback sau đó lập luận sender sẽ là một IOHIDDeviceRef cho biết thiết bị. (thay vì sử dụng IOHIDManagerRegisterInputValueCallback nơi người gửi sẽ là tài liệu tham khảo về trình quản lý HID)

Nhược điểm duy nhất cho điều này là bạn cần phải đăng ký và xử lý thông báo về sự kiện hotplugging cho các thiết bị phù hợp. (đăng ký bất cứ khi nào thiết bị mới xuất hiện và hủy đăng ký khi thiết bị biến mất)

Bạn có thể nhận tham chiếu thiết bị HID bằng cách sử dụng IOHIDDeviceCreate() - điều này có một tham số io_service_t. Điều này có nghĩa là bạn cần sử dụng các hàm kết hợp IOKit IOService tiêu chuẩn để có được và xem danh sách thiết bị của bạn, nhưng bạn thực sự nhận được một danh sách rõ ràng các thiết bị riêng lẻ, bạn có thể truy vấn tên để hiển thị cho người dùng, v.v. chức năng chính cho điều này là IOServiceAddMatchingNotification.

+0

Cảm ơn bạn đã chọn. Tôi nên nghĩ đến việc đăng nhập 'người gửi'. Chỉ cần thử nó với ví dụ mã của tôi, và nó thực sự cung cấp cho một giá trị khác nhau tùy thuộc vào bàn phím tôi đang sử dụng (1800442080 inbuilt, 1800440000 không dây). Tôi có thể liệt kê bàn ​​phím của mình theo cách mà tôi có thể lấy ID được liên kết cho bàn phím sẵn có không? –

+0

Lưu ý rằng bạn đang sử dụng 'IOHIDManagerRegisterInputValueCallback', trong khi tôi đề xuất [' IOHIDDeviceRegisterInputValueCallback'] (https://developer.apple.com/library/mac/documentation/IOKit/Reference/IOHIDDevice_iokit_header_reference/index.html#// apple_ref/c/func/IOHIDDeviceCopyMatchingElements) - sự khác biệt tinh tế nhưng quan trọng. Tôi sẽ cập nhật câu trả lời với một số chi tiết hơn về liệt kê thiết bị HID. – pmdj

+0

Bạn nói rằng với hiện tại của tôi ('IOHIDManagerRegisterInputValueCallback') thiết lập rằng' người gửi' sẽ là tài liệu tham khảo quản lý HID. Nhưng nó thực sự báo cáo khác nhau cho mỗi bàn phím, mà dường như đề nghị khác, vì chỉ có một người quản lý. Điều này làm cho tôi tự hỏi nếu nó thực sự là cần thiết để thiết lập gọi lại cho một thiết bị cụ thể. –

2

Tôi đang nghiên cứu vấn đề này và cuối cùng đã có giải pháp. đang OP là đúng, nếu bạn muốn sản phẩm ID của bàn phím/pad, thêm đường vào myHIDKeyboardCallback() chức năng:

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); 
} 

Như @pmdj nói rằng bạn có thể sử dụng IOHIDDeviceRegisterInputValueCallback(), tôi đã gặp rắc rối với điều này, và thấy rằng đối số sender cung cấp id sản phẩm bàn phím anyways.

Các vấn đề liên quan