34 #include <IOKit/hid/IOHIDManager.h>
35 #include <IOKit/hid/IOHIDKeys.h>
36 #include <CoreFoundation/CoreFoundation.h>
67 if (pthread_mutex_init(&barrier->
mutex, 0) < 0)
71 if (pthread_cond_init(&barrier->
cond, 0) < 0)
73 pthread_mutex_destroy(&barrier->
mutex);
84 pthread_cond_destroy(&barrier->
cond);
85 pthread_mutex_destroy(&barrier->
mutex);
91 pthread_mutex_lock(&barrier->
mutex);
96 pthread_cond_broadcast(&barrier->
cond);
97 pthread_mutex_unlock(&barrier->
mutex);
102 pthread_cond_wait(&barrier->
cond, &(barrier->
mutex));
103 pthread_mutex_unlock(&barrier->
mutex);
108 static int return_data(
hid_device *dev,
unsigned char *data,
size_t length);
132 pthread_mutex_t
mutex;
154 pthread_mutex_init(&dev->
mutex, NULL);
155 pthread_cond_init(&dev->
condition, NULL);
156 pthread_barrier_init(&dev->
barrier, NULL, 2);
188 pthread_barrier_destroy(&dev->
barrier);
190 pthread_mutex_destroy(&dev->
mutex);
196 static IOHIDManagerRef hid_mgr = 0x0;
205 static int32_t get_int_property(IOHIDDeviceRef
device, CFStringRef key)
210 ref = IOHIDDeviceGetProperty(
device, key);
213 if (CFGetTypeID(ref) == CFNumberGetTypeID())
215 CFNumberGetValue((CFNumberRef)ref, kCFNumberSInt32Type, &value);
222 static unsigned short get_vendor_id(IOHIDDeviceRef
device)
224 return get_int_property(
device, CFSTR(kIOHIDVendorIDKey));
227 static unsigned short get_product_id(IOHIDDeviceRef
device)
229 return get_int_property(
device, CFSTR(kIOHIDProductIDKey));
232 static int32_t get_max_report_length(IOHIDDeviceRef
device)
234 return get_int_property(
device, CFSTR(kIOHIDMaxInputReportSizeKey));
237 static int get_string_property(IOHIDDeviceRef
device, CFStringRef prop,
wchar_t *buf,
size_t len)
244 str = IOHIDDeviceGetProperty(
device, prop);
252 CFIndex str_len = CFStringGetLength(str);
255 range.length = (str_len > (long)
len) ?
len : str_len;
256 CFIndex used_buf_len;
257 CFIndex chars_copied;
259 CFStringGetBytes(str, range, kCFStringEncodingUTF32LE, (
char)
'?',
FALSE, (UInt8 *)buf,
len, &used_buf_len);
261 buf[chars_copied] = 0;
268 static int get_string_property_utf8(IOHIDDeviceRef
device, CFStringRef prop,
char *buf,
size_t len)
274 str = IOHIDDeviceGetProperty(
device, prop);
282 CFIndex str_len = CFStringGetLength(str);
285 range.length = (str_len > (long)
len) ?
len : str_len;
286 CFIndex used_buf_len;
287 CFIndex chars_copied;
289 CFStringGetBytes(str, range, kCFStringEncodingUTF8, (
char)
'?',
FALSE, (UInt8 *)buf,
len, &used_buf_len);
291 buf[chars_copied] = 0;
298 static int get_serial_number(IOHIDDeviceRef
device,
wchar_t *buf,
size_t len)
300 return get_string_property(
device, CFSTR(kIOHIDSerialNumberKey), buf,
len);
303 static int get_manufacturer_string(IOHIDDeviceRef
device,
wchar_t *buf,
size_t len)
305 return get_string_property(
device, CFSTR(kIOHIDManufacturerKey), buf,
len);
308 static int get_product_string(IOHIDDeviceRef
device,
wchar_t *buf,
size_t len)
310 return get_string_property(
device, CFSTR(kIOHIDProductKey), buf,
len);
314 static wchar_t *dup_wcs(
const wchar_t *s)
316 size_t len = wcslen(s);
317 wchar_t *ret = malloc((
len + 1) *
sizeof(
wchar_t));
323 static int make_path(IOHIDDeviceRef
device,
char *buf,
size_t len)
326 unsigned short vid, pid;
331 res = get_string_property_utf8(
device, CFSTR(kIOHIDTransportKey), transport,
sizeof(transport));
336 vid = get_vendor_id(
device);
337 pid = get_product_id(
device);
339 res = snprintf(buf,
len,
"%s_%04hx_%04hx_%p", transport, vid, pid,
device);
346 static int init_hid_manager(
void)
349 hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
352 IOHIDManagerSetDeviceMatching(hid_mgr, NULL);
353 IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
367 return init_hid_manager();
379 IOHIDManagerClose(hid_mgr, kIOHIDOptionsTypeNone);
387 static void process_pending_events(
void)
392 res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001,
FALSE);
393 }
while (res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut);
408 process_pending_events();
411 CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
414 num_devices = CFSetGetCount(device_set);
415 IOHIDDeviceRef *device_array = calloc(num_devices,
sizeof(IOHIDDeviceRef));
416 CFSetGetValues(device_set, (
const void **)device_array);
419 for (i = 0; i < num_devices; i++)
421 unsigned short dev_vid;
422 unsigned short dev_pid;
427 IOHIDDeviceRef dev = device_array[i];
433 dev_vid = get_vendor_id(dev);
434 dev_pid = get_product_id(dev);
454 cur_dev->
usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey));
455 cur_dev->
usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey));
458 cur_dev->
next = NULL;
459 make_path(dev, cbuf,
sizeof(cbuf));
460 cur_dev->
path = strdup(cbuf);
463 get_serial_number(dev, buf,
BUF_LEN);
467 get_manufacturer_string(dev, buf,
BUF_LEN);
469 get_product_string(dev, buf,
BUF_LEN);
477 cur_dev->
release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey));
485 CFRelease(device_set);
510 const char *path_to_open = NULL;
523 path_to_open = cur_dev->
path;
529 path_to_open = cur_dev->
path;
533 cur_dev = cur_dev->
next;
547 static void hid_device_removal_callback(
void *context, IOReturn result,
void *sender)
561 static void hid_report_callback(
void *context, IOReturn result,
void *sender, IOHIDReportType report_type,
562 uint32_t report_id, uint8_t *report, CFIndex report_length)
573 rpt->
data = calloc(1, report_length);
574 memcpy(rpt->
data, report, report_length);
575 rpt->
len = report_length;
579 pthread_mutex_lock(&dev->
mutex);
592 while (cur->
next != NULL)
604 return_data(dev, NULL, 0);
612 pthread_mutex_unlock(&dev->
mutex);
617 static void perform_signal_callback(
void *context)
623 static void *read_thread(
void *param)
632 CFRunLoopSourceContext ctx;
633 memset(&ctx, 0,
sizeof(ctx));
636 ctx.perform = &perform_signal_callback;
637 dev->
source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0 , &ctx);
642 dev->
run_loop = CFRunLoopGetCurrent();
645 pthread_barrier_wait(&dev->
barrier);
654 if (code == kCFRunLoopRunFinished)
661 if (code != kCFRunLoopRunTimedOut && code != kCFRunLoopRunHandledSource)
676 pthread_mutex_lock(&dev->
mutex);
678 pthread_mutex_unlock(&dev->
mutex);
694 dev = new_hid_device();
701 process_pending_events();
703 CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
705 num_devices = CFSetGetCount(device_set);
706 IOHIDDeviceRef *device_array = calloc(num_devices,
sizeof(IOHIDDeviceRef));
707 CFSetGetValues(device_set, (
const void **)device_array);
708 for (i = 0; i < num_devices; i++)
711 IOHIDDeviceRef os_dev = device_array[i];
713 make_path(os_dev, cbuf,
sizeof(cbuf));
714 if (!strcmp(cbuf, path))
717 IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeNone);
718 if (ret == kIOReturnSuccess)
724 CFRelease(device_set);
733 sprintf(str,
"HIDAPI_%p", os_dev);
734 dev->
run_loop_mode = CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII);
738 &hid_report_callback, dev);
739 IOHIDDeviceRegisterRemovalCallback(dev->
device_handle, hid_device_removal_callback, dev);
742 pthread_create(&dev->
thread, NULL, read_thread, dev);
745 pthread_barrier_wait(&dev->
barrier);
758 CFRelease(device_set);
759 free_hid_device(dev);
763 static int set_report(
hid_device *dev, IOHIDReportType
type,
const unsigned char *
data,
size_t length)
765 const unsigned char *data_to_send;
766 size_t length_to_send;
777 data_to_send =
data + 1;
778 length_to_send = length - 1;
785 length_to_send = length;
791 data_to_send, length_to_send);
793 if (res == kIOReturnSuccess)
806 return set_report(dev, kIOHIDReportTypeOutput,
data, length);
810 static int return_data(
hid_device *dev,
unsigned char *
data,
size_t length)
815 size_t len = (length < rpt->
len) ? length : rpt->
len;
823 static int cond_wait(
const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex)
827 int res = pthread_cond_wait(cond, mutex);
844 static int cond_timedwait(
const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex,
845 const struct timespec *abstime)
849 int res = pthread_cond_timedwait(cond, mutex, abstime);
871 pthread_mutex_lock(&dev->
mutex);
877 bytes_read = return_data(dev,
data, length);
899 if (milliseconds == -1)
905 bytes_read = return_data(dev,
data, length);
912 else if (milliseconds > 0)
918 gettimeofday(&tv, NULL);
919 TIMEVAL_TO_TIMESPEC(&tv, &ts);
920 ts.tv_sec += milliseconds / 1000;
921 ts.tv_nsec += (milliseconds % 1000) * 1000000;
922 if (ts.tv_nsec >= 1000000000L)
925 ts.tv_nsec -= 1000000000L;
930 bytes_read = return_data(dev, data, length);
931 else if (res == ETIMEDOUT)
944 pthread_mutex_unlock(&dev->
mutex);
963 return set_report(dev, kIOHIDReportTypeFeature, data, length);
968 CFIndex len = length;
975 res = IOHIDDeviceGetReport(dev->
device_handle, kIOHIDReportTypeFeature, data[0],
977 if (res == kIOReturnSuccess)
993 IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, NULL, dev);
995 IOHIDDeviceScheduleWithRunLoop(dev->
device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
1002 CFRunLoopSourceSignal(dev->
source);
1009 pthread_join(dev->
thread, NULL);
1016 IOHIDDeviceClose(dev->
device_handle, kIOHIDOptionsTypeNone);
1020 pthread_mutex_lock(&dev->
mutex);
1023 return_data(dev, NULL, 0);
1025 pthread_mutex_unlock(&dev->
mutex);
1028 free_hid_device(dev);
1033 return get_manufacturer_string(dev->
device_handle,
string, maxlen);
1038 return get_product_string(dev->
device_handle,
string, maxlen);
1043 return get_serial_number(dev->
device_handle,
string, maxlen);
1064 static int32_t get_location_id(IOHIDDeviceRef
device)
1066 return get_int_property(
device, CFSTR(kIOHIDLocationIDKey));
1069 static int32_t get_usage(IOHIDDeviceRef
device)
1072 res = get_int_property(
device, CFSTR(kIOHIDDeviceUsageKey));
1074 res = get_int_property(
device, CFSTR(kIOHIDPrimaryUsageKey));
1078 static int32_t get_usage_page(IOHIDDeviceRef
device)
1081 res = get_int_property(
device, CFSTR(kIOHIDDeviceUsagePageKey));
1083 res = get_int_property(
device, CFSTR(kIOHIDPrimaryUsagePageKey));
1087 static int get_transport(IOHIDDeviceRef
device,
wchar_t * buf,
size_t len)
1089 return get_string_property(
device, CFSTR(kIOHIDTransportKey), buf, len);
1095 IOHIDManagerRef mgr;
1098 mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
1099 IOHIDManagerSetDeviceMatching(mgr, NULL);
1100 IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone);
1102 CFSetRef device_set = IOHIDManagerCopyDevices(mgr);
1104 CFIndex num_devices = CFSetGetCount(device_set);
1105 IOHIDDeviceRef * device_array = calloc(num_devices,
sizeof(IOHIDDeviceRef));
1106 CFSetGetValues(device_set, (
const void **) device_array);
1108 for (i = 0; i < num_devices; i++)
1110 IOHIDDeviceRef dev = device_array[i];
1111 printf(
"Device: %p\n", dev);
1112 printf(
" %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev));
1114 wchar_t serial[256], buf[256];
1116 get_serial_number(dev, serial, 256);
1119 printf(
" Serial: %ls\n", serial);
1120 printf(
" Loc: %ld\n", get_location_id(dev));
1121 get_transport(dev, buf, 256);
1122 printf(
" Trans: %ls\n", buf);
1123 make_path(dev, cbuf, 256);
1124 printf(
" Path: %s\n", cbuf);
int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
Read an Input report from a HID device.
hid_device *HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
Open a HID device using a Vendor ID (VID), Product ID (PID) and optionally a serial number.
int HID_API_EXPORT hid_init(void)
Initialize the HIDAPI library.
void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
Free an enumeration Linked List.
int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
Get a string from a HID device, based on its string index.
int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
Read an Input report from a HID device with timeout.
int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
Write an Output report to a HID device.
int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
Get The Serial Number String from a HID device.
int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
Get a feature report from a HID device.
hid_device *HID_API_EXPORT hid_open_path(const char *path)
Open a HID device by its path name.
int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
Get The Product String from a HID device.
int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
Get The Manufacturer String from a HID device.
void HID_API_EXPORT hid_close(hid_device *dev)
Close a HID device.
int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
Send a Feature report to the device.
HID_API_EXPORT const wchar_t *HID_API_CALL hid_error(hid_device *dev)
Get a string describing the last error which occurred.
int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
Set the device handle to be non-blocking.
int HID_API_EXPORT hid_exit(void)
Finalize the HIDAPI library.
struct hid_device_info HID_API_EXPORT * hid_enumerate(unsigned short vendor_id, unsigned short product_id)
Enumerate the HID Devices.
int pthread_barrierattr_t
struct pthread_barrier pthread_barrier_t
#define HID_API_EXPORT_CALL
@ value
the parser finished reading a JSON value
pthread_barrier_t barrier
CFRunLoopSourceRef source
libusb_device_handle * device_handle
int uses_numbered_reports
pthread_barrier_t shutdown_barrier
CFIndex max_input_report_len
struct input_report * input_reports
uint8_t * input_report_buf
IOHIDDeviceRef device_handle
CFStringRef run_loop_mode
unsigned short product_id
struct hid_device_info * next
wchar_t * manufacturer_string
unsigned short release_number
unsigned short usage_page