1# This is based on previous support for libhidapi which was dropped in 2# upstream commit f5d2eba. 3import ctypes as _C 4from struct import pack as _pack 5 6_native = _C.CDLL("libhidapi.so") 7 8class _NativeDeviceInfo(_C.Structure): 9 pass 10_NativeDeviceInfo._fields_ = [ 11 ('path', _C.c_char_p), 12 ('vendor_id', _C.c_ushort), 13 ('product_id', _C.c_ushort), 14 ('serial', _C.c_wchar_p), 15 ('release', _C.c_ushort), 16 ('manufacturer', _C.c_wchar_p), 17 ('product', _C.c_wchar_p), 18 ('usage_page', _C.c_ushort), 19 ('usage', _C.c_ushort), 20 ('interface', _C.c_int), 21 ('next_device', _C.POINTER(_NativeDeviceInfo)) 22] 23 24from collections import namedtuple 25DeviceInfo = namedtuple('DeviceInfo', [ 26 'path', 27 'vendor_id', 28 'product_id', 29 'serial', 30 'release', 31 'manufacturer', 32 'product', 33 'interface', 34 'driver', 35]) 36del namedtuple 37 38def _makeDeviceInfo(native_device_info): 39 return DeviceInfo( 40 path=native_device_info.path.decode('ascii'), 41 vendor_id=hex(native_device_info.vendor_id)[2:].zfill(4), 42 product_id=hex(native_device_info.product_id)[2:].zfill(4), 43 serial=native_device_info.serial if native_device_info.serial else None, 44 release=hex(native_device_info.release)[2:], 45 manufacturer=native_device_info.manufacturer, 46 product=native_device_info.product, 47 interface=native_device_info.interface, 48 driver=None) 49 50_native.hid_init.argtypes = None 51_native.hid_init.restype = _C.c_int 52 53_native.hid_exit.argtypes = None 54_native.hid_exit.restype = _C.c_int 55 56_native.hid_enumerate.argtypes = [_C.c_ushort, _C.c_ushort] 57_native.hid_enumerate.restype = _C.POINTER(_NativeDeviceInfo) 58 59_native.hid_free_enumeration.argtypes = [_C.POINTER(_NativeDeviceInfo)] 60_native.hid_free_enumeration.restype = None 61 62_native.hid_open.argtypes = [_C.c_ushort, _C.c_ushort, _C.c_wchar_p] 63_native.hid_open.restype = _C.c_void_p 64 65_native.hid_open_path.argtypes = [_C.c_char_p] 66_native.hid_open_path.restype = _C.c_void_p 67 68_native.hid_close.argtypes = [_C.c_void_p] 69_native.hid_close.restype = None 70 71_native.hid_write.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t] 72_native.hid_write.restype = _C.c_int 73 74_native.hid_read.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t] 75_native.hid_read.restype = _C.c_int 76 77_native.hid_read_timeout.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t, _C.c_int] 78_native.hid_read_timeout.restype = _C.c_int 79 80_native.hid_set_nonblocking.argtypes = [_C.c_void_p, _C.c_int] 81_native.hid_set_nonblocking.restype = _C.c_int 82 83_native.hid_send_feature_report.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t] 84_native.hid_send_feature_report.restype = _C.c_int 85 86_native.hid_get_feature_report.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t] 87_native.hid_get_feature_report.restype = _C.c_int 88 89_native.hid_get_manufacturer_string.argtypes = [_C.c_void_p, _C.c_wchar_p, _C.c_size_t] 90_native.hid_get_manufacturer_string.restype = _C.c_int 91 92_native.hid_get_product_string.argtypes = [_C.c_void_p, _C.c_wchar_p, _C.c_size_t] 93_native.hid_get_product_string.restype = _C.c_int 94 95_native.hid_get_serial_number_string.argtypes = [_C.c_void_p, _C.c_wchar_p, _C.c_size_t] 96_native.hid_get_serial_number_string.restype = _C.c_int 97 98_native.hid_get_indexed_string.argtypes = [_C.c_void_p, _C.c_int, _C.c_wchar_p, _C.c_size_t] 99_native.hid_get_indexed_string.restype = _C.c_int 100 101_native.hid_error.argtypes = [_C.c_void_p] 102_native.hid_error.restype = _C.c_wchar_p 103 104def init(): 105 return _native.hid_init() == 0 106 107def exit(): 108 return _native.hid_exit() == 0 109 110def monitor_glib(callback, *device_filters): 111 pass 112 113def enumerate(vendor_id=None, product_id=None, interface_number=None, hid_driver=None): 114 devices = _native.hid_enumerate(vendor_id, product_id) 115 d = devices 116 while d: 117 if interface_number is None or interface_number == d.contents.interface: 118 yield _makeDeviceInfo(d.contents) 119 d = d.contents.next_device 120 121 if devices: 122 _native.hid_free_enumeration(devices) 123 124def open(vendor_id, product_id, serial=None): 125 return _native.hid_open(vendor_id, product_id, serial) or None 126 127def open_path(device_path): 128 if type(device_path) == str: 129 device_path = device_path.encode('ascii') 130 return _native.hid_open_path(device_path) or None 131 132def close(device_handle): 133 _native.hid_close(device_handle) 134 135def write(device_handle, data): 136 bytes_written = _native.hid_write(device_handle, _C.c_char_p(data), len(data)) 137 if bytes_written != len(data): 138 raise IOError(_errno.EIO, 'written %d bytes out of expected %d' % (bytes_written, len(data))) 139 140def read(device_handle, bytes_count, timeout_ms=-1): 141 out_buffer = _C.create_string_buffer(b'\x00' * (bytes_count + 1)) 142 bytes_read = _native.hid_read_timeout(device_handle, out_buffer, bytes_count, timeout_ms) 143 if bytes_read == -1: 144 return None 145 if bytes_read == 0: 146 return b'' 147 return out_buffer[:bytes_read] 148 149def send_feature_report(device_handle, data, report_number=None): 150 if report_number is not None: 151 data = _pack(b'!B', report_number) + data 152 bytes_written = _native.hid_send_feature_report(device_handle, _C.c_char_p(data), len(data)) 153 return bytes_written > -1 154 155def get_feature_report(device_handle, bytes_count, report_number=None): 156 out_buffer = _C.create_string_buffer('\x00' * (bytes_count + 2)) 157 if report_number is not None: 158 out_buffer[0] = _pack(b'!B', report_number) 159 bytes_read = _native.hid_get_feature_report(device_handle, out_buffer, bytes_count) 160 if bytes_read > -1: 161 return out_buffer[:bytes_read] 162 163def _read_wchar(func, device_handle, index=None): 164 _BUFFER_SIZE = 64 165 buf = _C.create_unicode_buffer('\x00' * _BUFFER_SIZE) 166 if index is None: 167 ok = func(device_handle, buf, _BUFFER_SIZE) 168 else: 169 ok = func(device_handle, index, buf, _BUFFER_SIZE) 170 if ok == 0: 171 return buf.value 172 173def get_manufacturer(device_handle): 174 return _read_wchar(_native.hid_get_manufacturer_string, device_handle) 175 176def get_product(device_handle): 177 return _read_wchar(_native.hid_get_product_string, device_handle) 178 179def get_serial(device_handle): 180 serial = _read_wchar(_native.hid_get_serial_number_string, device_handle) 181 if serial is not None: 182 return ''.join(hex(ord(c)) for c in serial) 183 184def get_indexed_string(device_handle, index): 185 return _read_wchar(_native.hid_get_indexed_string, device_handle, index) 186