2011-08-25 23 views
7

Tôi đang cố gắng sử dụng IOHIDManager để nhận các sự kiện phím bổ trợ vì các cờ ca caoCác sự kiện thay đổi bị thiếu (khó phân biệt giữa bấm/thả, trái/phải nếu cả hai đều bị ngừng, v.v.) mã nơi tôi tạo người quản lý và đăng ký cuộc gọi lại.Sử dụng IOHIDManager để nhận các sự kiện phím bổ trợ

IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault, 
     kIOHIDOptionsTypeNone); 
if (CFGetTypeID(hidManager) != IOHIDManagerGetTypeID()) 
    return 1; 

CFMutableDictionaryRef capsLock = 
    myCreateDeviceMatchingDictionary(0x07, 0x39); 
CFMutableDictionaryRef lctrl = 
    myCreateDeviceMatchingDictionary(0x07, 0xE0); 
CFMutableDictionaryRef lshift = 
    myCreateDeviceMatchingDictionary(0x07, 0xE1); 
CFMutableDictionaryRef lalt = 
    myCreateDeviceMatchingDictionary(0x07, 0xE2); 
CFMutableDictionaryRef lsuper = 
    myCreateDeviceMatchingDictionary(0x07, 0xE3); 
CFMutableDictionaryRef rctrl = 
    myCreateDeviceMatchingDictionary(0x07, 0xE4); 
CFMutableDictionaryRef rshift = 
    myCreateDeviceMatchingDictionary(0x07, 0xE5); 
CFMutableDictionaryRef ralt = 
    myCreateDeviceMatchingDictionary(0x07, 0xE6); 
CFMutableDictionaryRef rsuper = 
    myCreateDeviceMatchingDictionary(0x07, 0xE7); 

CFMutableDictionaryRef matchesList[] = { 
    capsLock, 
    lctrl, 
    lshift, 
    lalt, 
    lsuper, 
    rctrl, 
    rshift, 
    ralt, 
    rsuper 
}; 
CFArrayRef matches = CFArrayCreate(kCFAllocatorDefault, 
     (const void **)matchesList, 9, NULL); 
IOHIDManagerSetDeviceMatchingMultiple(hidManager, matches); 

IOHIDManagerRegisterInputValueCallback(hidManager, 
     myHandleModifiersCallback, NULL); 

IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetMain(), 
     kCFRunLoopDefaultMode); 

IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone); 

Tuy nhiên, gọi lại không bao giờ được chạy. Tôi có thiếu gì không?

Tôi không hiểu đầy đủ các trang sử dụng HID, vì vậy tôi không biết có sử dụng Generic Desktop Page (0x01) với ID sử dụng bàn phím (06) hoặc Bàn phím/Trang bàn phím (0x07) hay không ID cho các khóa riêng lẻ. Có thể là có cái gì đó để làm với nó?

Trả lời

9

Tôi đã tìm ra. Cách để làm điều đó là sử dụng bàn phím chung (0x01) bàn phím (06) (và bàn phím (07) để hoàn thành) để sử dụng với IOHIDManagerSetDeviceMatchingMultiple, và sau đó gọi lại giá trị đầu vào được bàn phím/bàn phím sử dụng trang (0x07) thứ.

Ví dụ, để thiết lập một một HIDManager cho tất cả bàn phím/bàn phím, người ta có thể làm điều gì đó như:

IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault, 
     kIOHIDOptionsTypeNone); 

CFMutableDictionaryRef keyboard = 
    myCreateDeviceMatchingDictionary(0x01, 6); 
CFMutableDictionaryRef keypad = 
    myCreateDeviceMatchingDictionary(0x01, 7); 

CFMutableDictionaryRef matchesList[] = { 
    keyboard, 
    keypad, 
}; 
CFArrayRef matches = CFArrayCreate(kCFAllocatorDefault, 
     (const void **)matchesList, 2, NULL); 
IOHIDManagerSetDeviceMatchingMultiple(hidManager, matches); 

IOHIDManagerRegisterInputValueCallback(hidManager, 
     myHIDKeyboardCallback, NULL); 

IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetMain(), 
     kCFRunLoopDefaultMode); 

IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone); 

đâu myCreateDeviceMatchingDictionary là một cái gì đó như:

CFMutableDictionaryRef myCreateDeviceMatchingDictionary(UInt32 usagePage, 
     UInt32 usage) { 
    CFMutableDictionaryRef ret = CFDictionaryCreateMutable(kCFAllocatorDefault, 
      0, &kCFTypeDictionaryKeyCallBacks, 
      &kCFTypeDictionaryValueCallBacks); 
    if (!ret) 
     return NULL; 

    CFNumberRef pageNumberRef = CFNumberCreate(kCFAllocatorDefault, 
      kCFNumberIntType, &usagePage); 
    if (!pageNumberRef) { 
     CFRelease(ret); 
     return NULL; 
    } 

    CFDictionarySetValue(ret, CFSTR(kIOHIDDeviceUsagePageKey), pageNumberRef); 
    CFRelease(pageNumberRef); 

    CFNumberRef usageNumberRef = CFNumberCreate(kCFAllocatorDefault, 
      kCFNumberIntType, &usage); 
    if (!usageNumberRef) { 
     CFRelease(ret); 
     return NULL; 
    } 

    CFDictionarySetValue(ret, CFSTR(kIOHIDDeviceUsageKey), usageNumberRef); 
    CFRelease(usageNumberRef); 

    return ret; 
} 

Và myHIDKeyboardCallback là một cái gì đó như:

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); 
    // ... Do something ... 
} 

Lưu ý rằng cuộc gọi lại dường như được gọi nhiều lần cho mỗi lần nhấn hoặc thả nhưng với ID sử dụng ngoài phạm vi bình thường, đó là những gì "if (scancode < 4 || scancode> 231)" là cho.

+0

Bạn đã tìm thông tin về cách phân tích cú pháp 'giá trị' trong hàm gọi lại của bạn ở đâu, để có được những thứ như scancode? Bạn có một số (có thể đọc) tham khảo về điều đó, hoặc làm thế nào bạn tìm ra nó? – jalf

4

thx cho việc cung cấp câu trả lời cho câu hỏi của bạn.

thay cho if-tuyên bố trong myHIDKeyboardCallback, trong đó kiểm tra scancode < 4 hoặc scancode> 231 bạn có thể sử dụng IOHIDManagerSetInputValueMatching.

// before IOHIDManagerOpen 
int usageMin = 4; 
CFNumberRef minNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usageMin); 
CFDictionarySetValue(inputValueFilter, CFSTR(kIOHIDElementUsageMinKey), minNumberRef); 
CFRelease(minNumberRef); 

int usageMax = 231; 
CFNumberRef maxNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usageMax); 
CFDictionarySetValue(inputValueFilter, CFSTR(kIOHIDElementUsageMaxKey), maxNumberRef); 
CFRelease(maxNumberRef); 

IOHIDManagerSetInputValueMatching(hidManager, inputValueFilter); 

nó là nhiều LỘC sau đó một đơn giản nếu-tuyên bố, nhưng bạn kết thúc với một callback sạch hơn.

+0

Điều cần biết. Tôi tưởng tượng bạn cũng có thể giới hạn các trang sử dụng phần tử thành 0x07 bằng kIOHIDElementUsagePageKey. Điều này có cần thiết không? Các thiết bị bàn phím/bàn phím có bao giờ tạo ra các phần tử không phải là 0x07 không? Tôi tưởng tượng nó có thể nếu, nói, bạn có một bàn phím bên ngoài với trackpad hoặc phím điều khiển được xây dựng trong hoặc một cái gì đó. – dostende

+0

không, không bao giờ có một cái không phải 0x07 :) – Yevgeniy

+0

Tôi chưa bao giờ sử dụng bàn phím như thế này (tức là với cần điều khiển hoặc tương tự), nhưng tôi mong đợi thiết bị thứ hai và bàn phím để các sự kiện của chúng được tách ra. nhưng tôi không thể chắc chắn. – Yevgeniy