| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430 |
- /*******************************************************
- HIDAPI - Multi-Platform library for
- communication with HID devices.
- Alan Ott
- Signal 11 Software
- 8/22/2009
- Copyright 2009, All Rights Reserved.
- At the discretion of the user of this library,
- this software may be licensed under the terms of the
- GNU General Public License v3, a BSD-Style license, or the
- original HIDAPI license as outlined in the LICENSE.txt,
- LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
- files located at the root of the source distribution.
- These files may also be found in the public source
- code repository located at:
- https://github.com/libusb/hidapi .
- ********************************************************/
- #include "SDL_internal.h"
- #include <windows.h>
- #ifndef _WIN32_WINNT_WIN8
- #define _WIN32_WINNT_WIN8 0x0602
- #endif
- #if 0 /* can cause redefinition errors on some toolchains */
- #ifdef __MINGW32__
- #include <ntdef.h>
- #include <winbase.h>
- #endif
- #ifdef __CYGWIN__
- #include <ntdef.h>
- #define _wcsdup wcsdup
- #endif
- #endif /* */
- #ifndef _NTDEF_
- typedef LONG NTSTATUS;
- #endif
- /* The maximum number of characters that can be passed into the
- HidD_Get*String() functions without it failing.*/
- #define MAX_STRING_WCHARS 0xFFF
- /*#define HIDAPI_USE_DDK*/
- /* The timeout in milliseconds for waiting on WriteFile to
- complete in hid_write. The longest observed time to do a output
- report that we've seen is ~200-250ms so let's double that */
- #define HID_WRITE_TIMEOUT_MILLISECONDS 500
- /* We will only enumerate devices that match these usages */
- #define USAGE_PAGE_GENERIC_DESKTOP 0x0001
- #define USAGE_JOYSTICK 0x0004
- #define USAGE_GAMEPAD 0x0005
- #define USAGE_MULTIAXISCONTROLLER 0x0008
- #define USB_VENDOR_VALVE 0x28de
- #ifdef __cplusplus
- extern "C" {
- #endif
- #include <setupapi.h>
- #include <winioctl.h>
- #include <devpropdef.h>
- #include "hidapi_cfgmgr32.h"
- #include "hidapi_hidclass.h"
- #include "hidapi_hidsdi.h"
- #ifdef __cplusplus
- } /* extern "C" */
- #endif
- #include "../hidapi/hidapi.h"
- /*#include <stdio.h>*/
- /*#include <stdlib.h>*/
- /* SDL C runtime functions */
- #define calloc SDL_calloc
- #define free SDL_free
- #define malloc SDL_malloc
- #define memcpy SDL_memcpy
- #define memset SDL_memset
- #define strcmp SDL_strcmp
- #define strlen SDL_strlen
- #define strstr SDL_strstr
- #define strtol SDL_strtol
- #define towupper SDL_toupper
- #define wcscmp SDL_wcscmp
- #define wcslen SDL_wcslen
- #define _wcsdup SDL_wcsdup
- #define wcsstr SDL_wcsstr
- #undef MIN
- #define MIN(x,y) ((x) < (y)? (x): (y))
- #ifdef _MSC_VER
- /* Yes, we have some unreferenced formal parameters */
- #pragma warning(disable:4100)
- #endif
- #ifdef __cplusplus
- extern "C" {
- #endif
- #ifndef HIDAPI_USE_DDK
- /* Since we're not building with the DDK, and the HID header
- files aren't part of the Windows SDK, we define what we need ourselves.
- In lookup_functions(), the function pointers
- defined below are set. */
- static HidD_GetHidGuid_ HidD_GetHidGuid;
- static HidD_GetAttributes_ HidD_GetAttributes;
- static HidD_GetSerialNumberString_ HidD_GetSerialNumberString;
- static HidD_GetManufacturerString_ HidD_GetManufacturerString;
- static HidD_GetProductString_ HidD_GetProductString;
- static HidD_SetFeature_ HidD_SetFeature;
- static HidD_GetFeature_ HidD_GetFeature;
- static HidD_GetInputReport_ HidD_GetInputReport;
- static HidD_GetIndexedString_ HidD_GetIndexedString;
- static HidD_GetPreparsedData_ HidD_GetPreparsedData;
- static HidD_FreePreparsedData_ HidD_FreePreparsedData;
- static HidP_GetCaps_ HidP_GetCaps;
- static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers;
- static HidD_SetOutputReport_ HidD_SetOutputReport;
- static CM_Locate_DevNodeW_ CM_Locate_DevNodeW = NULL;
- static CM_Get_Parent_ CM_Get_Parent = NULL;
- static CM_Get_DevNode_PropertyW_ CM_Get_DevNode_PropertyW = NULL;
- static CM_Get_Device_Interface_PropertyW_ CM_Get_Device_Interface_PropertyW = NULL;
- static CM_Get_Device_Interface_List_SizeW_ CM_Get_Device_Interface_List_SizeW = NULL;
- static CM_Get_Device_Interface_ListW_ CM_Get_Device_Interface_ListW = NULL;
- static HMODULE hid_lib_handle = NULL;
- static HMODULE cfgmgr32_lib_handle = NULL;
- static BOOLEAN hidapi_initialized = FALSE;
- static void free_library_handles(void)
- {
- if (hid_lib_handle)
- FreeLibrary(hid_lib_handle);
- hid_lib_handle = NULL;
- if (cfgmgr32_lib_handle)
- FreeLibrary(cfgmgr32_lib_handle);
- cfgmgr32_lib_handle = NULL;
- }
- #if defined(__GNUC__)
- # pragma GCC diagnostic push
- # pragma GCC diagnostic ignored "-Wcast-function-type"
- #endif
- static int lookup_functions(void)
- {
- hid_lib_handle = LoadLibraryW(L"hid.dll");
- if (hid_lib_handle == NULL) {
- goto err;
- }
- cfgmgr32_lib_handle = LoadLibraryW(L"cfgmgr32.dll");
- if (cfgmgr32_lib_handle == NULL) {
- goto err;
- }
- #define RESOLVE(lib_handle, x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) goto err;
- RESOLVE(hid_lib_handle, HidD_GetHidGuid);
- RESOLVE(hid_lib_handle, HidD_GetAttributes);
- RESOLVE(hid_lib_handle, HidD_GetSerialNumberString);
- RESOLVE(hid_lib_handle, HidD_GetManufacturerString);
- RESOLVE(hid_lib_handle, HidD_GetProductString);
- RESOLVE(hid_lib_handle, HidD_SetFeature);
- RESOLVE(hid_lib_handle, HidD_GetFeature);
- RESOLVE(hid_lib_handle, HidD_GetInputReport);
- RESOLVE(hid_lib_handle, HidD_GetIndexedString);
- RESOLVE(hid_lib_handle, HidD_GetPreparsedData);
- RESOLVE(hid_lib_handle, HidD_FreePreparsedData);
- RESOLVE(hid_lib_handle, HidP_GetCaps);
- RESOLVE(hid_lib_handle, HidD_SetNumInputBuffers);
- RESOLVE(hid_lib_handle, HidD_SetOutputReport);
- RESOLVE(cfgmgr32_lib_handle, CM_Locate_DevNodeW);
- RESOLVE(cfgmgr32_lib_handle, CM_Get_Parent);
- RESOLVE(cfgmgr32_lib_handle, CM_Get_DevNode_PropertyW);
- RESOLVE(cfgmgr32_lib_handle, CM_Get_Device_Interface_PropertyW);
- RESOLVE(cfgmgr32_lib_handle, CM_Get_Device_Interface_List_SizeW);
- RESOLVE(cfgmgr32_lib_handle, CM_Get_Device_Interface_ListW);
- #undef RESOLVE
- return 0;
- err:
- free_library_handles();
- return -1;
- }
- #if defined(__GNUC__)
- # pragma GCC diagnostic pop
- #endif
- #endif /* HIDAPI_USE_DDK */
- struct hid_device_ {
- HANDLE device_handle;
- BOOL blocking;
- USHORT output_report_length;
- size_t input_report_length;
- void *last_error_str;
- DWORD last_error_num;
- BOOL read_pending;
- char *read_buf;
- OVERLAPPED ol;
- OVERLAPPED write_ol;
- BOOL use_hid_write_output_report;
- };
- static BOOL
- IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
- {
- OSVERSIONINFOEXW osvi;
- DWORDLONG const dwlConditionMask = VerSetConditionMask(
- VerSetConditionMask(
- VerSetConditionMask(
- 0, VER_MAJORVERSION, VER_GREATER_EQUAL ),
- VER_MINORVERSION, VER_GREATER_EQUAL ),
- VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL );
- memset(&osvi, 0, sizeof(osvi));
- osvi.dwOSVersionInfoSize = sizeof( osvi );
- osvi.dwMajorVersion = wMajorVersion;
- osvi.dwMinorVersion = wMinorVersion;
- osvi.wServicePackMajor = wServicePackMajor;
- return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
- }
- static hid_device *new_hid_device(void)
- {
- hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
- dev->device_handle = INVALID_HANDLE_VALUE;
- dev->blocking = TRUE;
- dev->output_report_length = 0;
- dev->input_report_length = 0;
- dev->last_error_str = NULL;
- dev->last_error_num = 0;
- dev->read_pending = FALSE;
- dev->read_buf = NULL;
- memset(&dev->ol, 0, sizeof(dev->ol));
- dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
- memset(&dev->write_ol, 0, sizeof(dev->write_ol));
- dev->write_ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
- return dev;
- }
- static void free_hid_device(hid_device *dev)
- {
- CloseHandle(dev->ol.hEvent);
- CloseHandle(dev->write_ol.hEvent);
- CloseHandle(dev->device_handle);
- LocalFree(dev->last_error_str);
- free(dev->read_buf);
- free(dev);
- }
- static void register_error(hid_device *device, const char *op)
- {
- WCHAR *ptr, *msg;
- DWORD count = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPWSTR)&msg, 0/*sz*/,
- NULL);
- if (!count)
- return;
- /* Get rid of the CR and LF that FormatMessage() sticks at the
- end of the message. Thanks Microsoft! */
- ptr = msg;
- while (*ptr) {
- if (*ptr == '\r') {
- *ptr = 0x0000;
- break;
- }
- ptr++;
- }
- /* Store the message off in the Device entry so that
- the hid_error() function can pick it up. */
- LocalFree(device->last_error_str);
- device->last_error_str = msg;
- }
- static HANDLE open_device(const char *path, BOOL enumerate, BOOL bExclusive )
- {
- HANDLE handle;
- // Opening with access 0 causes keyboards to stop responding in some system configurations
- // http://steamcommunity.com/discussions/forum/1/1843493219428923893
- // Thanks to co-wie (Ka-wei Low <kawei@mac.com>) for help narrowing down the problem on his system
- //DWORD desired_access = (enumerate)? 0: (GENERIC_WRITE | GENERIC_READ);
- DWORD desired_access = ( GENERIC_WRITE | GENERIC_READ );
- DWORD share_mode = bExclusive ? 0 : ( FILE_SHARE_READ | FILE_SHARE_WRITE );
- handle = CreateFileA(path,
- desired_access,
- share_mode,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/
- 0);
- return handle;
- }
- int HID_API_EXPORT hid_init(void)
- {
- #ifndef HIDAPI_USE_DDK
- if (!hidapi_initialized) {
- if (lookup_functions() < 0) {
- return -1;
- }
- hidapi_initialized = TRUE;
- }
- #endif
- return 0;
- }
- int HID_API_EXPORT hid_exit(void)
- {
- #ifndef HIDAPI_USE_DDK
- free_library_handles();
- hidapi_initialized = FALSE;
- #endif
- return 0;
- }
- static void* hid_internal_get_devnode_property(DEVINST dev_node, const DEVPROPKEY* property_key, DEVPROPTYPE expected_property_type)
- {
- ULONG len = 0;
- CONFIGRET cr;
- DEVPROPTYPE property_type;
- PBYTE property_value = NULL;
- cr = CM_Get_DevNode_PropertyW(dev_node, property_key, &property_type, NULL, &len, 0);
- if (cr != CR_BUFFER_SMALL || property_type != expected_property_type)
- return NULL;
- property_value = (PBYTE)calloc(len, sizeof(BYTE));
- cr = CM_Get_DevNode_PropertyW(dev_node, property_key, &property_type, property_value, &len, 0);
- if (cr != CR_SUCCESS) {
- free(property_value);
- return NULL;
- }
- return property_value;
- }
- static void* hid_internal_get_device_interface_property(const wchar_t* interface_path, const DEVPROPKEY* property_key, DEVPROPTYPE expected_property_type)
- {
- ULONG len = 0;
- CONFIGRET cr;
- DEVPROPTYPE property_type;
- PBYTE property_value = NULL;
- cr = CM_Get_Device_Interface_PropertyW(interface_path, property_key, &property_type, NULL, &len, 0);
- if (cr != CR_BUFFER_SMALL || property_type != expected_property_type)
- return NULL;
- property_value = (PBYTE)calloc(len, sizeof(BYTE));
- cr = CM_Get_Device_Interface_PropertyW(interface_path, property_key, &property_type, property_value, &len, 0);
- if (cr != CR_SUCCESS) {
- free(property_value);
- return NULL;
- }
- return property_value;
- }
- static void hid_internal_get_ble_info(struct hid_device_info* dev, DEVINST dev_node)
- {
- wchar_t *manufacturer_string, *serial_number, *product_string;
- /* Manufacturer String */
- manufacturer_string = hid_internal_get_devnode_property(dev_node, (const DEVPROPKEY*)&PKEY_DeviceInterface_Bluetooth_Manufacturer, DEVPROP_TYPE_STRING);
- if (manufacturer_string) {
- free(dev->manufacturer_string);
- dev->manufacturer_string = manufacturer_string;
- }
- /* Serial Number String (MAC Address) */
- serial_number = hid_internal_get_devnode_property(dev_node, (const DEVPROPKEY*)&PKEY_DeviceInterface_Bluetooth_DeviceAddress, DEVPROP_TYPE_STRING);
- if (serial_number) {
- free(dev->serial_number);
- dev->serial_number = serial_number;
- }
- /* Get devnode grandparent to reach out Bluetooth LE device node */
- if (CM_Get_Parent(&dev_node, dev_node, 0) != CR_SUCCESS)
- return;
- /* Product String */
- product_string = hid_internal_get_devnode_property(dev_node, &DEVPKEY_NAME, DEVPROP_TYPE_STRING);
- if (product_string) {
- free(dev->product_string);
- dev->product_string = product_string;
- }
- }
- #if 0
- /* USB Device Interface Number.
- It can be parsed out of the Hardware ID if a USB device is has multiple interfaces (composite device).
- See https://docs.microsoft.com/windows-hardware/drivers/hid/hidclass-hardware-ids-for-top-level-collections
- and https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers
- hardware_id is always expected to be uppercase.
- */
- static int hid_internal_get_interface_number(const wchar_t* hardware_id)
- {
- int interface_number;
- wchar_t *startptr, *endptr;
- const wchar_t *interface_token = L"&MI_";
- startptr = wcsstr(hardware_id, interface_token);
- if (!startptr)
- return -1;
- startptr += wcslen(interface_token);
- interface_number = wcstol(startptr, &endptr, 16);
- if (endptr == startptr)
- return -1;
- return interface_number;
- }
- static void hid_internal_get_info(const wchar_t* interface_path, struct hid_device_info* dev)
- {
- wchar_t *device_id = NULL, *compatible_ids = NULL, *hardware_ids = NULL;
- wchar_t *id;
- CONFIGRET cr;
- DEVINST dev_node;
- /* Get the device id from interface path */
- device_id = hid_internal_get_device_interface_property(interface_path, &DEVPKEY_Device_InstanceId, DEVPROP_TYPE_STRING);
- if (!device_id)
- goto end;
- /* Open devnode from device id */
- cr = CM_Locate_DevNodeW(&dev_node, (DEVINSTID_W)device_id, CM_LOCATE_DEVNODE_NORMAL);
- if (cr != CR_SUCCESS)
- goto end;
- /* Get the hardware ids from devnode */
- hardware_ids = hid_internal_get_devnode_property(dev_node, &DEVPKEY_Device_HardwareIds, DEVPROP_TYPE_STRING_LIST);
- if (!hardware_ids)
- goto end;
- /* Search for interface number in hardware ids */
- for (id = hardware_ids; *id; id += wcslen(id) + 1) {
- /* Normalize to upper case */
- wchar_t* p = id;
- for (; *p; ++p) *p = towupper(*p);
- dev->interface_number = hid_internal_get_interface_number(id);
- if (dev->interface_number != -1)
- break;
- }
- /* Get devnode parent */
- cr = CM_Get_Parent(&dev_node, dev_node, 0);
- if (cr != CR_SUCCESS)
- goto end;
- /* Get the compatible ids from parent devnode */
- compatible_ids = hid_internal_get_devnode_property(dev_node, &DEVPKEY_Device_CompatibleIds, DEVPROP_TYPE_STRING_LIST);
- if (!compatible_ids)
- goto end;
- /* Now we can parse parent's compatible IDs to find out the device bus type */
- for (id = compatible_ids; *id; id += wcslen(id) + 1) {
- /* Normalize to upper case */
- wchar_t* p = id;
- for (; *p; ++p) *p = towupper(*p);
- /* USB devices
- https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support
- https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers */
- if (wcsstr(id, L"USB") != NULL) {
- dev->bus_type = HID_API_BUS_USB;
- break;
- }
- /* Bluetooth devices
- https://docs.microsoft.com/windows-hardware/drivers/bluetooth/installing-a-bluetooth-device */
- if (wcsstr(id, L"BTHENUM") != NULL) {
- dev->bus_type = HID_API_BUS_BLUETOOTH;
- break;
- }
- /* Bluetooth LE devices */
- if (wcsstr(id, L"BTHLEDEVICE") != NULL) {
- /* HidD_GetProductString/HidD_GetManufacturerString/HidD_GetSerialNumberString is not working for BLE HID devices
- Request this info via dev node properties instead.
- https://docs.microsoft.com/answers/questions/401236/hidd-getproductstring-with-ble-hid-device.html */
- hid_internal_get_ble_info(dev, dev_node);
- dev->bus_type = HID_API_BUS_BLUETOOTH;
- break;
- }
- /* I2C devices
- https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support-and-power-management */
- if (wcsstr(id, L"PNP0C50") != NULL) {
- dev->bus_type = HID_API_BUS_I2C;
- break;
- }
- /* SPI devices
- https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-for-spi */
- if (wcsstr(id, L"PNP0C51") != NULL) {
- dev->bus_type = HID_API_BUS_SPI;
- break;
- }
- }
- end:
- free(device_id);
- free(hardware_ids);
- free(compatible_ids);
- }
- static char *hid_internal_UTF16toUTF8(const wchar_t *src)
- {
- char *dst = NULL;
- int len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, NULL, 0, NULL, NULL);
- if (len) {
- dst = (char*)calloc(len, sizeof(char));
- if (dst == NULL) {
- return NULL;
- }
- WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, dst, len, NULL, NULL);
- }
- return dst;
- }
- #endif /* 0 */
- static wchar_t *hid_internal_UTF8toUTF16(const char *src)
- {
- wchar_t *dst = NULL;
- int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, NULL, 0);
- if (len) {
- dst = (wchar_t*)calloc(len, sizeof(wchar_t));
- if (dst == NULL) {
- return NULL;
- }
- MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, dst, len);
- }
- return dst;
- }
- static int hid_get_bluetooth_info(const char *path, struct hid_device_info* dev)
- {
- wchar_t *interface_path = NULL, *device_id = NULL, *compatible_ids = NULL;
- wchar_t *id;
- CONFIGRET cr;
- DEVINST dev_node;
- int is_bluetooth = 0;
- /* Get the device id from interface path */
- interface_path = hid_internal_UTF8toUTF16(path);
- device_id = hid_internal_get_device_interface_property(interface_path, &DEVPKEY_Device_InstanceId, DEVPROP_TYPE_STRING);
- if (!device_id)
- goto end;
- /* Open devnode from device id */
- cr = CM_Locate_DevNodeW(&dev_node, (DEVINSTID_W)device_id, CM_LOCATE_DEVNODE_NORMAL);
- if (cr != CR_SUCCESS)
- goto end;
- /* Get devnode parent */
- cr = CM_Get_Parent(&dev_node, dev_node, 0);
- if (cr != CR_SUCCESS)
- goto end;
- /* Get the compatible ids from parent devnode */
- compatible_ids = hid_internal_get_devnode_property(dev_node, &DEVPKEY_Device_CompatibleIds, DEVPROP_TYPE_STRING_LIST);
- if (!compatible_ids)
- goto end;
- /* Now we can parse parent's compatible IDs to find out the device bus type */
- for (id = compatible_ids; *id; id += wcslen(id) + 1) {
- /* Normalize to upper case */
- wchar_t* p = id;
- for (; *p; ++p) *p = towupper(*p);
- /* USB devices
- https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support
- https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers */
- if (wcsstr(id, L"USB") != NULL) {
- /*dev->bus_type = HID_API_BUS_USB;*/
- break;
- }
- /* Bluetooth devices
- https://docs.microsoft.com/windows-hardware/drivers/bluetooth/installing-a-bluetooth-device */
- if (wcsstr(id, L"BTHENUM") != NULL) {
- /*dev->bus_type = HID_API_BUS_BLUETOOTH;*/
- is_bluetooth = 1;
- break;
- }
- /* Bluetooth LE devices */
- if (wcsstr(id, L"BTHLEDEVICE") != NULL) {
- /* HidD_GetProductString/HidD_GetManufacturerString/HidD_GetSerialNumberString is not working for BLE HID devices
- Request this info via dev node properties instead.
- https://docs.microsoft.com/answers/questions/401236/hidd-getproductstring-with-ble-hid-device.html */
- if (dev)
- hid_internal_get_ble_info(dev, dev_node);
- /*dev->bus_type = HID_API_BUS_BLUETOOTH;*/
- is_bluetooth = 1;
- break;
- }
- /* I2C devices
- https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support-and-power-management */
- if (wcsstr(id, L"PNP0C50") != NULL) {
- /*dev->bus_type = HID_API_BUS_I2C;*/
- break;
- }
- /* SPI devices
- https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-for-spi */
- if (wcsstr(id, L"PNP0C51") != NULL) {
- /*dev->bus_type = HID_API_BUS_SPI;*/
- break;
- }
- }
- end:
- free(interface_path);
- free(device_id);
- free(compatible_ids);
- return is_bluetooth;
- }
- static int hid_blacklist(unsigned short vendor_id, unsigned short product_id)
- {
- size_t i;
- static const struct { unsigned short vid; unsigned short pid; } known_bad[] = {
- /* Causes deadlock when asking for device details... */
- { 0x1B1C, 0x1B3D }, /* Corsair Gaming keyboard */
- { 0x1532, 0x0109 }, /* Razer Lycosa Gaming keyboard */
- { 0x1532, 0x010B }, /* Razer Arctosa Gaming keyboard */
- { 0x045E, 0x0822 }, /* Microsoft Precision Mouse */
- { 0x0D8C, 0x0014 }, /* Sharkoon Skiller SGH2 headset */
- { 0x1CCF, 0x0000 }, /* All Konami Amusement Devices */
- /* Turns into an Android controller when enumerated... */
- { 0x0738, 0x2217 } /* SPEEDLINK COMPETITION PRO */
- };
- for (i = 0; i < (sizeof(known_bad)/sizeof(known_bad[0])); i++) {
- if ((vendor_id == known_bad[i].vid) && (product_id == known_bad[i].pid || known_bad[i].pid == 0x0000)) {
- return 1;
- }
- }
- return 0;
- }
- struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
- {
- BOOL res;
- struct hid_device_info *root = NULL; /* return object */
- struct hid_device_info *cur_dev = NULL;
- /* Windows objects for interacting with the driver. */
- GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} };
- SP_DEVINFO_DATA devinfo_data;
- SP_DEVICE_INTERFACE_DATA device_interface_data;
- SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;
- HDEVINFO device_info_set = INVALID_HANDLE_VALUE;
- int device_index = 0;
- const char *hint = SDL_GetHint(SDL_HINT_HIDAPI_IGNORE_DEVICES);
- if (hid_init() < 0)
- return NULL;
- /* Initialize the Windows objects. */
- memset(&devinfo_data, 0x0, sizeof(devinfo_data));
- devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
- device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- /* Get information for all the devices belonging to the HID class. */
- device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
- /* Iterate over each device in the HID class, looking for the right one. */
- for (;;) {
- HANDLE write_handle = INVALID_HANDLE_VALUE;
- DWORD required_size = 0;
- HIDD_ATTRIBUTES attrib;
- res = SetupDiEnumDeviceInterfaces(device_info_set,
- NULL,
- &InterfaceClassGuid,
- device_index,
- &device_interface_data);
- if (!res) {
- /* A return of FALSE from this function means that
- there are no more devices. */
- break;
- }
- /* Call with 0-sized detail size, and let the function
- tell us how long the detail struct needs to be. The
- size is put in &required_size. */
- res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
- &device_interface_data,
- NULL,
- 0,
- &required_size,
- NULL);
- /* Allocate a long enough structure for device_interface_detail_data. */
- device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size);
- device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
- /* Get the detailed data for this device. The detail data gives us
- the device path for this device, which is then passed into
- CreateFile() to get a handle to the device. */
- res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
- &device_interface_data,
- device_interface_detail_data,
- required_size,
- NULL,
- NULL);
- if (!res) {
- /* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");
- Continue to the next device. */
- goto cont;
- }
- /* XInput devices don't get real HID reports and are better handled by the raw input driver */
- if (strstr(device_interface_detail_data->DevicePath, "&ig_") != NULL) {
- goto cont;
- }
- /* Make sure this device is of Setup Class "HIDClass" and has a
- driver bound to it. */
- /* In the main HIDAPI tree this is a loop which will erroneously open
- devices that aren't HID class. Please preserve this delta if we ever
- update to take new changes */
- {
- char driver_name[256];
- /* Populate devinfo_data. This function will return failure
- when there are no more interfaces left. */
- res = SetupDiEnumDeviceInfo(device_info_set, device_index, &devinfo_data);
- if (!res)
- goto cont;
- res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
- SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
- if (!res)
- goto cont;
- if (strcmp(driver_name, "HIDClass") == 0) {
- /* See if there's a driver bound. */
- res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
- SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
- if (!res)
- goto cont;
- }
- else
- {
- goto cont;
- }
- }
- //wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);
- /* Open a handle to the device */
- write_handle = open_device(device_interface_detail_data->DevicePath, TRUE, FALSE);
- /* Check validity of write_handle. */
- if (write_handle == INVALID_HANDLE_VALUE) {
- /* Unable to open the device. */
- //register_error(dev, "CreateFile");
- goto cont;
- }
- /* Get the Vendor ID and Product ID for this device. */
- attrib.Size = sizeof(HIDD_ATTRIBUTES);
- HidD_GetAttributes(write_handle, &attrib);
- //wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);
- /* See if there are any devices we should skip in enumeration */
- if (hint) {
- char vendor_match[16], product_match[16];
- SDL_snprintf(vendor_match, sizeof(vendor_match), "0x%.4x/0x0000", attrib.VendorID);
- SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", attrib.VendorID, attrib.ProductID);
- if (SDL_strcasestr(hint, vendor_match) || SDL_strcasestr(hint, product_match)) {
- continue;
- }
- }
- /* Check the VID/PID to see if we should add this
- device to the enumeration list. */
- if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
- (product_id == 0x0 || attrib.ProductID == product_id) &&
- !hid_blacklist(attrib.VendorID, attrib.ProductID)) {
- #define WSTR_LEN 512
- const char *str;
- struct hid_device_info *tmp;
- PHIDP_PREPARSED_DATA pp_data = NULL;
- HIDP_CAPS caps;
- BOOLEAN hidp_res;
- NTSTATUS nt_res;
- wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */
- size_t len;
- /* Get the Usage Page and Usage for this device. */
- hidp_res = HidD_GetPreparsedData(write_handle, &pp_data);
- if (hidp_res) {
- nt_res = HidP_GetCaps(pp_data, &caps);
- HidD_FreePreparsedData(pp_data);
- if (nt_res != HIDP_STATUS_SUCCESS) {
- goto cont_close;
- }
- }
- else {
- goto cont_close;
- }
- /* SDL Modification: Ignore the device if it's not a gamepad. This limits compatibility
- risk from devices that may respond poorly to our string queries below. */
- if (attrib.VendorID != USB_VENDOR_VALVE) {
- if (caps.UsagePage != USAGE_PAGE_GENERIC_DESKTOP) {
- goto cont_close;
- }
- if (caps.Usage != USAGE_JOYSTICK && caps.Usage != USAGE_GAMEPAD && caps.Usage != USAGE_MULTIAXISCONTROLLER) {
- goto cont_close;
- }
- }
- /* VID/PID match. Create the record. */
- tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
- if (cur_dev) {
- cur_dev->next = tmp;
- }
- else {
- root = tmp;
- }
- cur_dev = tmp;
- /* Fill out the record */
- cur_dev->usage_page = caps.UsagePage;
- cur_dev->usage = caps.Usage;
- cur_dev->next = NULL;
- str = device_interface_detail_data->DevicePath;
- if (str) {
- len = strlen(str);
- cur_dev->path = (char*) calloc(len+1, sizeof(char));
- memcpy(cur_dev->path, str, len+1);
- }
- else
- cur_dev->path = NULL;
- /* Serial Number */
- hidp_res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr));
- wstr[WSTR_LEN-1] = 0x0000;
- if (hidp_res) {
- cur_dev->serial_number = _wcsdup(wstr);
- }
- /* Manufacturer String */
- hidp_res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr));
- wstr[WSTR_LEN-1] = 0x0000;
- if (hidp_res) {
- cur_dev->manufacturer_string = _wcsdup(wstr);
- }
- /* Product String */
- hidp_res = HidD_GetProductString(write_handle, wstr, sizeof(wstr));
- wstr[WSTR_LEN-1] = 0x0000;
- if (hidp_res) {
- cur_dev->product_string = _wcsdup(wstr);
- }
- /* VID/PID */
- cur_dev->vendor_id = attrib.VendorID;
- cur_dev->product_id = attrib.ProductID;
- /* Release Number */
- cur_dev->release_number = attrib.VersionNumber;
- /* Interface Number. It can sometimes be parsed out of the path
- on Windows if a device has multiple interfaces. See
- http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or
- search for "Hardware IDs for HID Devices" at MSDN. If it's not
- in the path, it's set to -1. */
- cur_dev->interface_number = -1;
- if (cur_dev->path) {
- char *interface_component = strstr(cur_dev->path, "&mi_");
- if (interface_component) {
- char *hex_str = interface_component + 4;
- char *endptr = NULL;
- cur_dev->interface_number = strtol(hex_str, &endptr, 16);
- if (endptr == hex_str) {
- /* The parsing failed. Set interface_number to -1. */
- cur_dev->interface_number = -1;
- }
- }
- }
- /* Get the Bluetooth device info */
- hid_get_bluetooth_info(cur_dev->path, cur_dev);
- }
- cont_close:
- CloseHandle(write_handle);
- cont:
- /* We no longer need the detail data. It can be freed */
- free(device_interface_detail_data);
- device_index++;
- }
- /* Close the device information handle. */
- SetupDiDestroyDeviceInfoList(device_info_set);
- return root;
- }
- void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
- {
- /* TODO: Merge this with the Linux version. This function is platform-independent. */
- struct hid_device_info *d = devs;
- while (d) {
- struct hid_device_info *next = d->next;
- free(d->path);
- free(d->serial_number);
- free(d->manufacturer_string);
- free(d->product_string);
- free(d);
- d = next;
- }
- }
- HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
- {
- /* TODO: Merge this functions with the Linux version. This function should be platform independent. */
- struct hid_device_info *devs, *cur_dev;
- const char *path_to_open = NULL;
- hid_device *handle = NULL;
- devs = hid_enumerate(vendor_id, product_id);
- cur_dev = devs;
- while (cur_dev) {
- if (cur_dev->vendor_id == vendor_id &&
- cur_dev->product_id == product_id) {
- if (serial_number) {
- if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
- path_to_open = cur_dev->path;
- break;
- }
- }
- else {
- path_to_open = cur_dev->path;
- break;
- }
- }
- cur_dev = cur_dev->next;
- }
- if (path_to_open) {
- /* Open the device */
- handle = hid_open_path(path_to_open, 0);
- }
- hid_free_enumeration(devs);
- return handle;
- }
- HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path, int bExclusive)
- {
- hid_device *dev;
- HIDP_CAPS caps;
- PHIDP_PREPARSED_DATA pp_data = NULL;
- BOOLEAN res;
- NTSTATUS nt_res;
- if (hid_init() < 0) {
- return NULL;
- }
- dev = new_hid_device();
- /* Open a handle to the device */
- dev->device_handle = open_device(path, FALSE, bExclusive);
- /* Check validity of write_handle. */
- if (dev->device_handle == INVALID_HANDLE_VALUE) {
- /* Unable to open the device. */
- register_error(dev, "CreateFile");
- goto err;
- }
- /* Set the Input Report buffer size to 64 reports. */
- res = HidD_SetNumInputBuffers(dev->device_handle, 64);
- if (!res) {
- register_error(dev, "HidD_SetNumInputBuffers");
- goto err;
- }
- /* Get the Input Report length for the device. */
- res = HidD_GetPreparsedData(dev->device_handle, &pp_data);
- if (!res) {
- register_error(dev, "HidD_GetPreparsedData");
- goto err;
- }
- nt_res = HidP_GetCaps(pp_data, &caps);
- if (nt_res != HIDP_STATUS_SUCCESS) {
- register_error(dev, "HidP_GetCaps");
- goto err_pp_data;
- }
- dev->output_report_length = caps.OutputReportByteLength;
- dev->input_report_length = caps.InputReportByteLength;
- HidD_FreePreparsedData(pp_data);
- /* On Windows 7, we need to use hid_write_output_report() over Bluetooth */
- if (dev->output_report_length > 512) {
- dev->use_hid_write_output_report = !IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN8 ), LOBYTE( _WIN32_WINNT_WIN8 ), 0 );
- }
- dev->read_buf = (char*) malloc(dev->input_report_length);
- return dev;
- err_pp_data:
- HidD_FreePreparsedData(pp_data);
- err:
- free_hid_device(dev);
- return NULL;
- }
- int HID_API_EXPORT HID_API_CALL hid_write_output_report(hid_device *dev, const unsigned char *data, size_t length)
- {
- BOOL res;
- res = HidD_SetOutputReport(dev->device_handle, (void *)data, (ULONG)length);
- if (res)
- return (int)length;
- else
- return -1;
- }
- static int hid_write_timeout(hid_device *dev, const unsigned char *data, size_t length, int milliseconds)
- {
- DWORD bytes_written;
- BOOL res;
- unsigned char *buf;
- if (dev->use_hid_write_output_report) {
- return hid_write_output_report(dev, data, length);
- }
- /* Make sure the right number of bytes are passed to WriteFile. Windows
- expects the number of bytes which are in the _longest_ report (plus
- one for the report number) bytes even if the data is a report
- which is shorter than that. Windows gives us this value in
- caps.OutputReportByteLength. If a user passes in fewer bytes than this,
- create a temporary buffer which is the proper size. */
- if (length >= dev->output_report_length) {
- /* The user passed the right number of bytes. Use the buffer as-is. */
- buf = (unsigned char *) data;
- } else {
- /* Create a temporary buffer and copy the user's data
- into it, padding the rest with zeros. */
- buf = (unsigned char *) malloc(dev->output_report_length);
- memcpy(buf, data, length);
- memset(buf + length, 0, dev->output_report_length - length);
- length = dev->output_report_length;
- }
- res = WriteFile( dev->device_handle, buf, ( DWORD ) length, NULL, &dev->write_ol );
- if (!res) {
- if (GetLastError() != ERROR_IO_PENDING) {
- /* WriteFile() failed. Return error. */
- register_error(dev, "WriteFile");
- bytes_written = (DWORD) -1;
- goto end_of_function;
- }
- }
- /* Wait here until the write is done. This makes hid_write() synchronous. */
- res = WaitForSingleObject(dev->write_ol.hEvent, milliseconds);
- if (res != WAIT_OBJECT_0)
- {
- // There was a Timeout.
- bytes_written = (DWORD) -1;
- register_error(dev, "WriteFile/WaitForSingleObject Timeout");
- goto end_of_function;
- }
- res = GetOverlappedResult(dev->device_handle, &dev->write_ol, &bytes_written, FALSE/*F=don't_wait*/);
- if (!res) {
- /* The Write operation failed. */
- register_error(dev, "WriteFile");
- bytes_written = (DWORD) -1;
- goto end_of_function;
- }
- end_of_function:
- if (buf != data)
- free(buf);
- return bytes_written;
- }
- int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
- {
- return hid_write_timeout(dev, data, length, HID_WRITE_TIMEOUT_MILLISECONDS);
- }
- int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
- {
- DWORD bytes_read = 0;
- size_t copy_len = 0;
- BOOL res;
- /* Copy the handle for convenience. */
- HANDLE ev = dev->ol.hEvent;
- if (!dev->read_pending) {
- /* Start an Overlapped I/O read. */
- dev->read_pending = TRUE;
- memset(dev->read_buf, 0, dev->input_report_length);
- ResetEvent(ev);
- res = ReadFile(dev->device_handle, dev->read_buf, (DWORD)dev->input_report_length, &bytes_read, &dev->ol);
- if (!res) {
- if (GetLastError() != ERROR_IO_PENDING) {
- /* ReadFile() has failed.
- Clean up and return error. */
- CancelIo(dev->device_handle);
- dev->read_pending = FALSE;
- goto end_of_function;
- }
- }
- }
- /* See if there is any data yet. */
- res = WaitForSingleObject(ev, milliseconds >= 0 ? milliseconds : INFINITE);
- if (res != WAIT_OBJECT_0) {
- /* There was no data this time. Return zero bytes available,
- but leave the Overlapped I/O running. */
- return 0;
- }
- /* Get the number of bytes read. The actual data has been copied to the data[]
- array which was passed to ReadFile(). We must not wait here because we've
- already waited on our event above, and since it's auto-reset, it will have
- been reset back to unsignalled by now. */
- res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, FALSE/*don't wait*/);
- /* Set pending back to false, even if GetOverlappedResult() returned error. */
- dev->read_pending = FALSE;
- if (res && bytes_read > 0) {
- if (dev->read_buf[0] == 0x0) {
- /* If report numbers aren't being used, but Windows sticks a report
- number (0x0) on the beginning of the report anyway. To make this
- work like the other platforms, and to make it work more like the
- HID spec, we'll skip over this byte. */
- bytes_read--;
- copy_len = length > bytes_read ? bytes_read : length;
- memcpy(data, dev->read_buf+1, copy_len);
- }
- else {
- /* Copy the whole buffer, report number and all. */
- copy_len = length > bytes_read ? bytes_read : length;
- memcpy(data, dev->read_buf, copy_len);
- }
- }
- end_of_function:
- if (!res) {
- register_error(dev, "GetOverlappedResult");
- return -1;
- }
- return (int)copy_len;
- }
- int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)
- {
- return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
- }
- int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock)
- {
- dev->blocking = !nonblock;
- return 0; /* Success */
- }
- int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
- {
- BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, (ULONG)length);
- if (!res) {
- register_error(dev, "HidD_SetFeature");
- return -1;
- }
- return (int)length;
- }
- int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
- {
- BOOL res;
- #if 0
- res = HidD_GetFeature(dev->device_handle, (PVOID)data, (ULONG)length);
- if (!res) {
- register_error(dev, "HidD_GetFeature");
- return -1;
- }
- return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */
- #else
- DWORD bytes_returned;
- OVERLAPPED ol;
- memset(&ol, 0, sizeof(ol));
- res = DeviceIoControl(dev->device_handle,
- IOCTL_HID_GET_FEATURE,
- data, (DWORD)length,
- data, (DWORD)length,
- &bytes_returned, &ol);
- if (!res) {
- if (GetLastError() != ERROR_IO_PENDING) {
- /* DeviceIoControl() failed. Return error. */
- register_error(dev, "Send Feature Report DeviceIoControl");
- return -1;
- }
- }
- /* Wait here until the write is done. This makes
- hid_get_feature_report() synchronous. */
- res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
- if (!res) {
- /* The operation failed. */
- register_error(dev, "Send Feature Report GetOverLappedResult");
- return -1;
- }
- return bytes_returned;
- #endif
- }
- void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
- {
- typedef BOOL (WINAPI *CancelIoEx_t)(HANDLE hFile, LPOVERLAPPED lpOverlapped);
- CancelIoEx_t CancelIoExFunc = (CancelIoEx_t)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "CancelIoEx");
- if (!dev)
- return;
- if (CancelIoExFunc) {
- CancelIoExFunc(dev->device_handle, NULL);
- } else {
- /* Windows XP, this will only cancel I/O on the current thread */
- CancelIo(dev->device_handle);
- }
- if (dev->read_pending) {
- DWORD bytes_read = 0;
- GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
- }
- free_hid_device(dev);
- }
- int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
- {
- BOOL res;
- res = HidD_GetManufacturerString(dev->device_handle, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
- if (!res) {
- register_error(dev, "HidD_GetManufacturerString");
- return -1;
- }
- return 0;
- }
- int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
- {
- BOOL res;
- res = HidD_GetProductString(dev->device_handle, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
- if (!res) {
- register_error(dev, "HidD_GetProductString");
- return -1;
- }
- return 0;
- }
- int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
- {
- BOOL res;
- res = HidD_GetSerialNumberString(dev->device_handle, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
- if (!res) {
- register_error(dev, "HidD_GetSerialNumberString");
- return -1;
- }
- return 0;
- }
- int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
- {
- BOOL res;
- res = HidD_GetIndexedString(dev->device_handle, string_index, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
- if (!res) {
- register_error(dev, "HidD_GetIndexedString");
- return -1;
- }
- return 0;
- }
- HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
- {
- return (wchar_t*)dev->last_error_str;
- }
- #if 0
- /*#define PICPGM*/
- /*#define S11*/
- #define P32
- #ifdef S11
- unsigned short VendorID = 0xa0a0;
- unsigned short ProductID = 0x0001;
- #endif
- #ifdef P32
- unsigned short VendorID = 0x04d8;
- unsigned short ProductID = 0x3f;
- #endif
- #ifdef PICPGM
- unsigned short VendorID = 0x04d8;
- unsigned short ProductID = 0x0033;
- #endif
- int __cdecl main(int argc, char* argv[])
- {
- int i, res;
- unsigned char buf[65];
- UNREFERENCED_PARAMETER(argc);
- UNREFERENCED_PARAMETER(argv);
- /* Set up the command buffer. */
- memset(buf,0x00,sizeof(buf));
- buf[0] = 0;
- buf[1] = 0x81;
- /* Open the device. */
- int handle = open(VendorID, ProductID, L"12345");
- if (handle < 0)
- printf("unable to open device\n");
- /* Toggle LED (cmd 0x80) */
- buf[1] = 0x80;
- res = write(handle, buf, 65);
- if (res < 0)
- printf("Unable to write()\n");
- /* Request state (cmd 0x81) */
- buf[1] = 0x81;
- write(handle, buf, 65);
- if (res < 0)
- printf("Unable to write() (2)\n");
- /* Read requested state */
- read(handle, buf, 65);
- if (res < 0)
- printf("Unable to read()\n");
- /* Print out the returned buffer. */
- for (i = 0; i < 4; i++)
- printf("buf[%d]: %d\n", i, buf[i]);
- return 0;
- }
- #endif
- #ifdef __cplusplus
- } /* extern "C" */
- #endif
|