IOHIDUserKeyboardTest.c [plain text]
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDUserDevice.h>
#include <pthread.h>
#include <AssertMacros.h>
#include <stdio.h>
typedef struct GenericLEDKeyboardDescriptor {
UInt8 devUsagePageOp;
UInt8 devUsagePageNum;
UInt8 devUsageOp;
UInt8 devUsageNum;
UInt8 appCollectionOp;
UInt8 appCollectionNum;
UInt8 modUsagePageOp;
UInt8 modUsagePageNum;
UInt8 modUsageMinOp;
UInt8 modUsageMinNum;
UInt8 modUsageMaxOp;
UInt8 modUsageMaxNum;
UInt8 modLogMinOp;
UInt8 modLogMinNum;
UInt8 modLogMaxOp;
UInt8 modLogMaxNum;
UInt8 modRptCountOp;
UInt8 modRptCountNum;
UInt8 modRptSizeOp;
UInt8 modRptSizeNum;
UInt8 modInputOp;
UInt8 modInputNum;
UInt8 rsrvCountOp;
UInt8 rsrvCountNum;
UInt8 rsrvSizeOp;
UInt8 rsrvSizeNum;
UInt8 rsrvInputOp;
UInt8 rsrvInputNum;
UInt8 ledRptCountOp;
UInt8 ledRptCountNum;
UInt8 ledRptSizeOp;
UInt8 ledRptSizeNum;
UInt8 ledUsagePageOp;
UInt8 ledUsagePageNum;
UInt8 ledUsageMinOp;
UInt8 ledUsageMinNum;
UInt8 ledUsageMaxOp;
UInt8 ledUsageMaxNum;
UInt8 ledInputOp;
UInt8 ledInputNum;
UInt8 fillRptCountOp;
UInt8 fillRptCountNum;
UInt8 fillRptSizeOp;
UInt8 fillRptSizeNum;
UInt8 fillInputOp;
UInt8 fillInputNum;
UInt8 keyRptCountOp;
UInt8 keyRptCountNum;
UInt8 keyRptSizeOp;
UInt8 keyRptSizeNum;
UInt8 keyLogMinOp;
UInt8 keyLogMinNum;
UInt8 keyLogMaxOp;
UInt16 keyLogMaxNum;
UInt8 keyUsagePageOp;
UInt8 keyUsagePageNum;
UInt8 keyUsageMinOp;
UInt8 keyUsageMinNum;
UInt8 keyUsageMaxOp;
UInt8 keyUsageMaxNum;
UInt8 keyInputOp;
UInt8 keyInputNum;
UInt8 appCollectionEnd;
} GenericLEDKeyboardDescriptor;
typedef struct GenericKeyboardRpt {
UInt8 modifiers;
UInt8 reserved;
UInt8 keys[6];
} GenericKeyboardRpt;
static UInt8 gGenLEDKeyboardDesc[] = {
0x05, 0x01,
0x09, 0x06,
0xA1, 0x01,
0x05, 0x07,
0x19, 0xe0,
0x29, 0xe7,
0x15, 0x00,
0x25, 0x01,
0x75, 0x01,
0x95, 0x08,
0x81, 0x02,
0x95, 0x01,
0x75, 0x08,
0x81, 0x01,
0x95, 0x02,
0x75, 0x01,
0x05, 0x08,
0x19, 0x01,
0x29, 0x02,
0x91, 0x02,
0x95, 0x01,
0x75, 0x06,
0x91, 0x01,
0x95, 0x06,
0x75, 0x08,
0x15, 0x00,
0x26, 0xff, 0x00,
0x05, 0x07,
0x19, 0x00,
0x29, 0xff,
0x81, 0x00,
0xC0
};
static IOHIDUserDeviceRef gKeyboard = NULL;
static pthread_mutex_t gMuxtex = PTHREAD_MUTEX_INITIALIZER;
static void printReport(uint8_t * report, CFIndex reportLength, bool rcv)
{
int index;
printf("%s report: reportLength=%d: ", rcv ? "Received" : "Dispatching", reportLength);
for (index=0; index<reportLength; index++)
printf("%02x ", report[index]);
printf("\n");
}
static void dispatchKeyboardEvent(char c)
{
GenericKeyboardRpt report;
IOReturn ret;
bzero(&report, sizeof(report));
if ( c < 'a' || c > 'z' )
return;
printf("dispatching keyboard event for '%c'\n", c);
pthread_mutex_lock(&gMuxtex);
report.keys[0] = 4 + c - 97;
printReport((uint8_t*)&report, sizeof(report), 0);
ret = IOHIDUserDeviceHandleReport(gKeyboard, (uint8_t*)&report, sizeof(report));
report.keys[0] = 0;
printReport((uint8_t*)&report, sizeof(report), 0);
ret = IOHIDUserDeviceHandleReport(gKeyboard, (uint8_t*)&report, sizeof(report));
pthread_mutex_unlock(&gMuxtex);
}
static void * getcThread(void *arg)
{
printf("This virtual keyboard supports dispatching typed characters within the range of 'a' - 'z'\n");
while (1) {
dispatchKeyboardEvent(getchar());
}
return arg;
}
static IOReturn setReportCallback(void * refcon, IOHIDReportType type, uint32_t reportID, uint8_t * report, CFIndex reportLength)
{
printReport(report, reportLength, 1);
return kIOReturnSuccess;
}
int main (int argc, const char * argv[])
{
CFDataRef descriptor = NULL;
CFStringRef key = CFSTR(kIOHIDReportDescriptorKey);
CFDictionaryRef properties = NULL;
descriptor = CFDataCreate(kCFAllocatorDefault, gGenLEDKeyboardDesc, sizeof(gGenLEDKeyboardDesc));
require(descriptor, finish);
properties = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&key, (const void **)&descriptor, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
require(properties, finish);
gKeyboard = IOHIDUserDeviceCreate(kCFAllocatorDefault, properties);
require(gKeyboard, finish);
IOHIDUserDeviceScheduleWithRunLoop(gKeyboard, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
IOHIDUserDeviceRegisterSetReportCallback(gKeyboard, setReportCallback, NULL);
pthread_t tid;
pthread_attr_t attr;
assert(!pthread_attr_init(&attr));
assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
assert(!pthread_create( &tid, &attr, getcThread, NULL));
assert(!pthread_attr_destroy(&attr));
CFRunLoopRun();
finish:
if ( gKeyboard )
CFRelease(gKeyboard);
if ( properties )
CFRelease(properties);
if ( descriptor )
CFRelease(descriptor);
return 0;
}