diff --git a/CMakeLists.txt b/CMakeLists.txt index 719d48bb..b01216f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,6 @@ -cmake_minimum_required(VERSION 2.8) -cmake_policy(SET CMP0048 OLD) -project(hidapi) - -set(VERSION_MAJOR "0") -set(VERSION_MINOR "7") -set(VERSION_PATCH "1") -set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") +cmake_minimum_required(VERSION 3.0) +project(hidapi VERSION 0.7.1) option(HID_DEBUG_PARSER "verbose parser debugging output" OFF) @@ -16,7 +10,7 @@ option(HID_DEBUG_PARSER "verbose parser debugging output" OFF) option(HID_EXAMPLE_TEST "build test example" OFF) option(HID_EXAMPLE_OSC "build osc example" OFF) -option(HID_INSTALL_HUT "install hid usage tables" OFF) +option(HID_INSTALL_HUT "install hid usage tables" ON) if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(HIDAPI "default" CACHE STRING "HID API to use (one of {default,hidraw,libusb})") @@ -96,17 +90,38 @@ if( HID_EXAMPLE_TEST ) if(APPLE) add_subdirectory(hidtestosx) endif() + if(WIN32) + add_subdirectory(hidtestwindows) + endif() endif() if( HID_EXAMPLE_OSC ) add_subdirectory(hidapi2osc) endif() -if( HID_DEBUG_PARSER ) - set(HID_HUT_PATH ${CMAKE_INSTALL_PREFIX}/share/hidapi CACHE STRING "Installation path for the HID usage tables") - +if( HID_DEBUG_PARSER OR HID_INSTALL_HUT ) + # provisional to avoid having to commit to sc master while the HID submodule + # is not final/added to master + # the sc-settings for cmake_install_prefix and scappauxresourcesdir are not + # visible in this scope + if(APPLE) + if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + SET(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/Install") + endif() + # this will break if scappbundlename is reassigned in SC + # similar problem in editors/sc-ide/CMakeLists.txt 284 + set(scappbundlename "SuperCollider") + set(scappauxresourcesdir "${scappbundlename}/${scappbundlename}.app/Contents/Resources") + set(HID_HUT_PATH "${CMAKE_INSTALL_PREFIX}/${scappauxresourcesdir}/HID_Support") + elseif(WIN32) + set(auxresourcesdir "SuperCollider" CACHE STRING "Resources directory") + set(HID_HUT_PATH "${CMAKE_INSTALL_PREFIX}/${auxresourcesdir}/HID_Support") + else() + set(auxresourcesdir "share/SuperCollider" CACHE STRING "Resources directory") + set(HID_HUT_PATH "${CMAKE_INSTALL_PREFIX}/${auxresourcesdir}/HID_Support") + endif(APPLE) install(DIRECTORY hut - DESTINATION ${HID_HUT_PATH} - FILES_MATCHING PATTERN "*.yaml" + DESTINATION ${HID_HUT_PATH} + FILES_MATCHING PATTERN "*.yaml" ) endif() diff --git a/cmake_modules/Findlibusb-1.0.cmake b/cmake_modules/Findlibusb-1.0.cmake index 405ed516..1ae933dd 100644 --- a/cmake_modules/Findlibusb-1.0.cmake +++ b/cmake_modules/Findlibusb-1.0.cmake @@ -43,13 +43,25 @@ # +if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + # Remove prefix "1" as FreeBSD has its own implementation + # of libusb compatible with libusb1. + set(LIBUSB_1_HEADER_NAME "libusb.h") + set(LIBUSB_1_LIBRARY_NAME "usb") +else(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + # Just preserve values before my intrusion. 10.04.2017 Vasily + # Can it be just "libusb.h" for Linux also? + set(LIBUSB_1_HEADER_NAME "libusb-1.0/libusb.h") + set(LIBUSB_1_LIBRARY_NAME "usb-1.0") +endif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + if (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) # in cache already set(LIBUSB_FOUND TRUE) else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) find_path(LIBUSB_1_INCLUDE_DIR NAMES - libusb-1.0/libusb.h + ${LIBUSB_1_HEADER_NAME} PATHS /usr/include /usr/local/include @@ -61,7 +73,7 @@ else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) find_library(LIBUSB_1_LIBRARY NAMES - usb-1.0 + ${LIBUSB_1_LIBRARY_NAME} PATHS /usr/lib /usr/local/lib diff --git a/hidapi/hidapi.h b/hidapi/hidapi.h index 950cc64f..5e70cf3c 100644 --- a/hidapi/hidapi.h +++ b/hidapi/hidapi.h @@ -429,6 +429,10 @@ extern "C" { int HID_API_EXPORT HID_API_CALL hid_dump_element_info(hid_device *dev); IOHIDDeviceRef HID_API_EXPORT HID_API_CALL get_device_handle( hid_device *dev ); #endif +#ifdef WIN32 + #include + HANDLE HID_API_EXPORT HID_API_CALL get_device_handle(hid_device *dev); +#endif #ifdef __cplusplus } diff --git a/hidapi_parser/hidapi_parser.c b/hidapi_parser/hidapi_parser.c index 3f94cb50..32f9ca12 100644 --- a/hidapi_parser/hidapi_parser.c +++ b/hidapi_parser/hidapi_parser.c @@ -1,12 +1,12 @@ -/* hidapi_parser $ +/* hidapi_parser $ * * Copyright (C) 2013, Marije Baalman * This work was funded by a crowd-funding initiative for SuperCollider's [1] HID implementation * including a substantial donation from BEK, Bergen Center for Electronic Arts, Norway - * + * * [1] http://supercollider.sourceforge.net * [2] http://www.bek.no - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or @@ -27,8 +27,18 @@ #include #include +#ifdef _WIN32 +#include +// for MinGW < 5.3 include locally provided "../windows hidsdi.h" rather +// than #include : +// #include "../windows/hidsdi.h" +#include +#endif + #include "hidapi_parser.h" + + // SET IN CMAKE // #define DEBUG_PARSER @@ -136,7 +146,7 @@ // struct hid_device_descriptor * descriptor; // descriptor = (struct hid_device_descriptor *) malloc( sizeof( struct hid_device_descriptor) ); // // hid_descriptor_init( descriptor ); -// +// // descriptor->first = NULL; // hid_set_descriptor_callback(descriptor, NULL, NULL); // hid_set_element_callback(descriptor, NULL, NULL); @@ -146,8 +156,10 @@ struct hid_device_element * hid_new_element(){ struct hid_device_element * element = (struct hid_device_element *) malloc( sizeof( struct hid_device_element ) ); element->next = NULL; + element->parent_collection = NULL; + element->index = -1; element->repeat = 0; - + element->usage_min = 0; element->usage_max = 0; element->logical_min = 0; @@ -157,7 +169,7 @@ struct hid_device_element * hid_new_element(){ element->report_id = 0; element->unit = 0; element->unit_exponent = 0; - + element->rawvalue = 0; return element; @@ -215,7 +227,7 @@ void hid_set_element_callback( struct hid_dev_desc * devd, hid_element_callback } void hid_set_from_making_element( struct hid_device_element * making, struct hid_device_element * new_element ){ - + new_element->type = making->type; new_element->isrelative = (making->type & HID_ITEM_RELATIVE ) > 0; new_element->isarray = ( (making->type & HID_ITEM_VARIABLE ) == 0 ); @@ -229,14 +241,14 @@ void hid_set_from_making_element( struct hid_device_element * making, struct hid if ( (making->phys_min == 0) && (making->phys_max == 0) ){ new_element->phys_min = making->logical_min; new_element->phys_max = making->logical_max; - + } else { new_element->phys_min = making->phys_min; new_element->phys_max = making->phys_max; } new_element->unit = making->unit; new_element->unit_exponent = making->unit_exponent; - + new_element->report_size = making->report_size; new_element->report_id = making->report_id; } @@ -244,7 +256,7 @@ void hid_set_from_making_element( struct hid_device_element * making, struct hid int hid_element_get_signed_value( int inputvalue, int bytesize ){ int outputvalue; int bitSignIndex = bytesize*8 - 1; - int signBit = 0x1 << bitSignIndex; + int signBit = 0x1 << bitSignIndex; if ( signBit & inputvalue ){ unsigned int bitMask = BITMASK1( bytesize*8 ); unsigned int uvalue = (unsigned int) inputvalue; @@ -262,36 +274,36 @@ int hid_element_get_signed_value( int inputvalue, int bytesize ){ int hid_parse_report_descriptor( unsigned char* descr_buf, int size, struct hid_dev_desc * device_desc ){ struct hid_device_collection * device_collection = hid_new_collection(); device_desc->device_collection = device_collection; - + struct hid_device_collection * parent_collection = device_desc->device_collection; struct hid_device_collection * prev_collection = 0; struct hid_device_element * prev_element = 0; - + struct hid_device_element * making_element = hid_new_element(); - + int current_usages[256]; int current_usage_index = 0; int current_report_size; int current_usage_min = -1; int current_usage_max = -1; - + int current_report_count = 0; // unsigned char current_input; // unsigned char current_output; int collection_nesting = 0; - + int next_byte_tag = -1; int next_byte_size = 0; int next_byte_type = 0; int next_val = 0; - + unsigned char toadd = 0; int byte_count = 0; - + int i,j; - + int numreports = 1; int report_lengths[256]; int report_ids[256]; @@ -300,7 +312,7 @@ int hid_parse_report_descriptor( unsigned char* descr_buf, int size, struct hid_ int k; int index; - + device_collection->num_collections = 0; device_collection->num_elements = 0; #ifdef DEBUG_PARSER @@ -488,7 +500,7 @@ int hid_parse_report_descriptor( unsigned char* descr_buf, int size, struct hid_ new_element->usage = current_usage_min + j; } new_element->report_index = j; - + new_element->value = 0; new_element->array_value = 0; if ( parent_collection->num_elements == 0 ){ @@ -523,7 +535,7 @@ int hid_parse_report_descriptor( unsigned char* descr_buf, int size, struct hid_ #endif making_element->type = next_val; // add the elements for this report - for ( j=0; jio_type = 2; @@ -536,7 +548,7 @@ int hid_parse_report_descriptor( unsigned char* descr_buf, int size, struct hid_ new_element->usage = current_usage_min + j; } new_element->report_index = j; - + index = 0; for ( k=0; kreport_id == report_ids[k] ){ @@ -545,7 +557,7 @@ int hid_parse_report_descriptor( unsigned char* descr_buf, int size, struct hid_ } } report_lengths[index] += making_element->report_size; - + new_element->value = 0; new_element->array_value = 0; if ( parent_collection->num_elements == 0 ){ @@ -581,7 +593,7 @@ int hid_parse_report_descriptor( unsigned char* descr_buf, int size, struct hid_ making_element->type = next_val; // add the elements for this report for ( j=0; jio_type = 3; new_element->index = device_collection->num_elements; new_element->parent_collection = parent_collection; @@ -592,7 +604,7 @@ int hid_parse_report_descriptor( unsigned char* descr_buf, int size, struct hid_ new_element->usage = current_usage_min + j; } new_element->report_index = j; - + new_element->value = 0; new_element->array_value = 0; if ( parent_collection->num_elements == 0 ){ @@ -615,7 +627,7 @@ int hid_parse_report_descriptor( unsigned char* descr_buf, int size, struct hid_ } current_usage_index = 0; current_usage_min = -1; - current_usage_max = -1; + current_usage_max = -1; making_element->usage_min = -1; making_element->usage_max = -1; making_element->usage = 0; @@ -647,7 +659,7 @@ int hid_parse_report_descriptor( unsigned char* descr_buf, int size, struct hid_ making_element->usage_max = -1; current_usage_index = 0; current_usage_min = -1; - current_usage_max = -1; + current_usage_max = -1; collection_nesting--; #ifdef DEBUG_PARSER printf("\n\tend collection: %i, %i\n", collection_nesting, descr_buf[i] ); @@ -679,50 +691,54 @@ int hid_parse_report_descriptor( unsigned char* descr_buf, int size, struct hid_ device_desc->report_lengths[j] = report_lengths[j]; device_desc->report_ids[j] = report_ids[j]; } - + #ifdef DEBUG_PARSER printf("----------- end setting report ids --------------\n " ); #endif - + return 0; } void hid_element_set_value_from_input( struct hid_device_element * element, int value ){ - element->rawvalue = value; - if ( element->logical_min < 0 ){ - // value should be interpreted as signed value - // so: check report size, test the highest bit, if one, invert and add one, otherwise keep value - int bitSignIndex = element->report_size - 1; - int signBit = 0x1 << bitSignIndex; - if ( signBit & value ){ - unsigned int bitMask = BITMASK1( element->report_size ); - unsigned int uvalue = (unsigned int) value; - unsigned int negvalue = ~(uvalue); - negvalue = ~(uvalue) & bitMask; - negvalue = negvalue + 1; - element->value = -1 * negvalue; - } else { - element->value = value; - } - } else { - // value should be interpreted as unsigned value - // so: keep value as is - if ( element->isarray ){ // array elements should be parsed differently - if ( value == 0 ){ // previous key was pressed, so keep previous usage - element->value = 0; - element->array_value = 0; - } else { // new key, so value + usage min is the current usage - element->usage = element->usage_min + value; - element->value = 1; - element->array_value = value; - } - } else { - element->value = value; + element->rawvalue = value; + if (element->logical_min < 0){ + // value should be interpreted as signed value + // so: check report size, test the highest bit, if one, invert and add one, otherwise keep value + int bitSignIndex = element->report_size - 1; + int signBit = 0x1 << bitSignIndex; + if (signBit & value){ + unsigned int bitMask = BITMASK1(element->report_size); + unsigned int uvalue = (unsigned int)value; + unsigned int negvalue = ~(uvalue); + negvalue = ~(uvalue)& bitMask; + negvalue = negvalue + 1; + element->value = -1 * negvalue; + } + else { + element->value = value; + } + } + else { + // value should be interpreted as unsigned value + // so: keep value as is + if (element->isarray){ // array elements should be parsed differently + if (value == 0){ // previous key was pressed, so keep previous usage + element->value = 0; + element->array_value = 0; + } + else { // new key, so value + usage min is the current usage + element->usage = element->usage_min + value; + element->value = 1; + element->array_value = value; + } + } + else { + element->value = value; + } } - } } -float hid_element_map_logical( struct hid_device_element * element ){ +float hid_element_map_logical( struct hid_device_element * element ){ float result; if ( element->isarray ){ result = (float) element->value; @@ -852,7 +868,7 @@ int hid_parse_single_byte( unsigned char current_byte, struct hid_parsing_byte * nextVal = ( current_byte << pbyte->bitIndex ); pbyte->bitIndex += pbyte->remainingBits; pbyte->remainingBits = 0; - } else { + } else { // use a partial byte: bitMask = BITMASK1( currentBitsize ); nextVal = bitMask & current_byte; @@ -874,16 +890,16 @@ int hid_parse_single_byte( unsigned char current_byte, struct hid_parsing_byte * return -1; } -int hid_parse_input_report( unsigned char* buf, int size, struct hid_dev_desc * devdesc ){ +int hid_parse_input_report( unsigned char* buf, int size, struct hid_dev_desc * devdesc ){ -#ifdef APPLE +#ifdef APPLE return hid_parse_input_elements_values( buf, devdesc ); #endif #ifdef WIN32 - return hid_parse_input_elements_values( buf, devdesc ); + return hid_parse_input_elements_values( buf, size, devdesc ); #endif #ifdef LINUX_FREEBSD - struct hid_parsing_byte pbyte; + struct hid_parsing_byte pbyte; pbyte.nextVal = 0; pbyte.currentSize = 10; pbyte.bitIndex = 0; @@ -893,10 +909,10 @@ int hid_parse_input_report( unsigned char* buf, int size, struct hid_dev_desc * struct hid_device_collection * device_collection = devdesc->device_collection; struct hid_device_element * cur_element = device_collection->first_element; int newvalue; - int i; + int i = 0; int starti = 0; int reportid = 0; - + if ( devdesc->number_of_reports > 1 ){ reportid = (int) buf[i]; starti = 1; @@ -944,11 +960,11 @@ int hid_send_output_report( struct hid_dev_desc * devd, int reportid ){ break; } } - + size_t buflength = devd->report_lengths[ index ] / 8; #ifdef DEBUG_PARSER printf("report id %i, buflength %i\t", reportid, buflength ); -#endif +#endif // if ( reportid != 0 ){ buflength++; // one more byte if report id is not 0 @@ -956,17 +972,17 @@ int hid_send_output_report( struct hid_dev_desc * devd, int reportid ){ buf = (char *) malloc( sizeof( char ) * buflength ); memset(buf, 0x0, sizeof(char) * buflength); - + // iterate over elements, find which ones are output elements with the right report id, // and set their output values to the buffer - + struct hid_device_collection * device_collection = devd->device_collection; struct hid_device_element * cur_element = device_collection->first_element; if ( cur_element->io_type != 2 || ( cur_element->report_id != reportid ) ){ cur_element = hid_get_next_output_element_with_reportid(cur_element, reportid); } - + #ifdef DEBUG_PARSER printf("-----------------------\n"); #endif @@ -975,7 +991,7 @@ int hid_send_output_report( struct hid_dev_desc * devd, int reportid ){ int byte_index = 1; int bit_offset = 0; int next_val = 0; - + while ( cur_element != NULL && (byte_index < buflength) ){ int current_output = 0; @@ -1010,7 +1026,7 @@ int hid_send_output_report( struct hid_dev_desc * devd, int reportid ){ #ifdef DEBUG_PARSER printf("-----------------------\n"); #endif - + int res = hid_write(devd->device, (const unsigned char*)buf, buflength); @@ -1029,11 +1045,11 @@ int hid_send_output_report_old( struct hid_dev_desc * devd, int reportid ){ break; } } - + size_t buflength = devd->report_lengths[ index ] / 8; #ifdef DEBUG_PARSER printf("report id %i, buflength %i\t", reportid, buflength ); -#endif +#endif if ( reportid != 0 ){ buflength++; // one more byte if report id is not 0 @@ -1043,7 +1059,7 @@ int hid_send_output_report_old( struct hid_dev_desc * devd, int reportid ){ // iterate over elements, find which ones are output elements with the right report id, // and set their output values to the buffer - + int next_byte_size; int next_mod_bit_size; int byte_count = 0; @@ -1058,8 +1074,8 @@ int hid_send_output_report_old( struct hid_dev_desc * devd, int reportid ){ #ifdef DEBUG_PARSER printf("report_size %i, bytesize %i, bitsize %i \t", cur_element->report_size, next_byte_size, next_mod_bit_size ); -#endif - +#endif + #ifdef DEBUG_PARSER printf("-----------------------\n"); #endif @@ -1070,16 +1086,16 @@ int hid_send_output_report_old( struct hid_dev_desc * devd, int reportid ){ curbyte = (unsigned char) cur_element->value; #ifdef DEBUG_PARSER printf("element page %i, usage %i, index %i, value %i, report_size %i, curbyte %i\n", cur_element->usage_page, cur_element->usage, cur_element->index, cur_element->value, cur_element->report_size, curbyte ); -#endif +#endif cur_element = hid_get_next_output_element_with_reportid( cur_element, reportid ); - next_byte_size = cur_element->report_size/8; + next_byte_size = cur_element->report_size/8; } else if ( cur_element->report_size == 16 ){ int shift = byte_count*8; curbyte = (unsigned char) (cur_element->value >> shift); byte_count++; #ifdef DEBUG_PARSER printf("element page %i, usage %i, index %i, value %i, report_size %i, curbyte %i\n", cur_element->usage_page, cur_element->usage, cur_element->index, cur_element->value, cur_element->report_size, curbyte ); -#endif +#endif if ( byte_count == next_byte_size ){ cur_element = hid_get_next_output_element_with_reportid( cur_element, reportid ); next_byte_size = cur_element->report_size/8; @@ -1095,17 +1111,17 @@ int hid_send_output_report_old( struct hid_dev_desc * devd, int reportid ){ bitindex += cur_element->report_size; #ifdef DEBUG_PARSER printf("element page %i, usage %i, index %i, value %i, report_size %i, curbyte %i\n", cur_element->usage_page, cur_element->usage, cur_element->index, cur_element->value, cur_element->report_size, curbyte ); -#endif +#endif cur_element = hid_get_next_output_element_with_reportid( cur_element, reportid ); next_byte_size = cur_element->report_size/8; - } + } } buf[ i ] = curbyte; } #ifdef DEBUG_PARSER printf("-----------------------\n"); #endif - + int res = hid_write(devd->device, (const unsigned char*)buf, buflength); @@ -1149,14 +1165,14 @@ struct hid_dev_desc * hid_open_device_path( const char *path, unsigned short ven hid_device * handle = hid_open_path( path ); if (!handle){ return NULL; - } + } struct hid_dev_desc * newdesc = hid_read_descriptor( handle ); if ( newdesc == NULL ){ hid_close( handle ); return NULL; } struct hid_device_info * newinfo = hid_enumerate(vendor,product); - //newdesc->device = handle; + //newdesc->device = handle; int havenotfound = strcmp(path, newinfo->path) != 0; while (havenotfound && (newinfo != NULL) ){ newinfo = newinfo->next; @@ -1164,7 +1180,7 @@ struct hid_dev_desc * hid_open_device_path( const char *path, unsigned short ven } if ( newinfo == NULL ){ hid_close( handle ); - return NULL; + return NULL; } newdesc->info = newinfo; @@ -1180,7 +1196,7 @@ struct hid_dev_desc * hid_open_device( unsigned short vendor, unsigned short pr hid_device * handle = hid_open( vendor, product, serial_number ); if (!handle){ return NULL; - } + } struct hid_dev_desc * newdesc = hid_read_descriptor( handle ); if ( newdesc == NULL ){ hid_close( handle ); @@ -1192,11 +1208,11 @@ struct hid_dev_desc * hid_open_device( unsigned short vendor, unsigned short pr // int havenotfound = wcscmp(serial_number, newinfo->serial_number) == 0; // while (havenotfound && (newinfo != NULL) ){ // newinfo = newinfo->next; -// havenotfound = wcscmp(serial_number, newinfo->serial_number) == 0; +// havenotfound = wcscmp(serial_number, newinfo->serial_number) == 0; // } if ( newinfo == NULL ){ hid_close( handle ); - return NULL; + return NULL; } newdesc->info = newinfo; @@ -1212,14 +1228,14 @@ void hid_close_device( struct hid_dev_desc * devdesc ){ hid_free_enumeration( devdesc->info ); hid_free_collection( devdesc->device_collection ); free( devdesc->report_ids ); - free( devdesc->report_lengths ); + free( devdesc->report_lengths ); // hid_free_descriptor( devdesc->descriptor ); - //TODO: more memory freeing? + //TODO: more memory freeing? } void hid_element_set_output_value( struct hid_dev_desc * devdesc, struct hid_device_element * element, int value ){ element->value = value; -#ifdef APPLE +#ifdef APPLE hid_send_element_output( devdesc, element ); #endif #ifdef WIN32 @@ -1232,14 +1248,482 @@ void hid_element_set_output_value( struct hid_dev_desc * devdesc, struct hid_dev #ifdef WIN32 -int hid_send_element_output( struct hid_dev_desc * devdesc, struct hid_device_element * element ){ +void debug_element(struct hid_device_element *element) +{ + printf("index: %d\n", element->index); + printf("parent_collection: %p\n", element->parent_collection); + printf("io_type: %d\n", element->io_type); + printf("usage_page: %d\n", element->usage_page); + printf("usage_min: %d\n", element->usage_min); + printf("usage_max: %d\n", element->usage_max); + printf("usage: %d\n", element->usage); + printf("type: %d\n", element->type); + printf("isarray: %d\n", element->isarray); + printf("isrelative: %d\n", element->isrelative); + printf("isvariable: %d\n", element->isvariable); + printf("logical_min: %d\n", element->logical_min); + printf("logical_max: %d\n", element->logical_max); + printf("phys_min: %d\n", element->phys_min); + printf("phys_max: %d\n", element->phys_max); + printf("unit: %d\n", element->unit); + printf("unit_exponent: %d\n", element->unit_exponent); + printf("report_id: %d\n", element->report_id); + printf("report_size: %d\n", element->report_size); + printf("report_index: %d\n", element->report_index); + printf("\n\n"); + fflush(stdout); +} + +void debug_collection(struct hid_device_collection *collection, int col_index) +{ + printf("COLLECTION[%d] @%p:\n", col_index, collection); + printf("index: %d\n", collection->index); + printf("type: %d\n", collection->type); + printf("usage_page: %d\n", collection->usage_page); + printf("usage_index: %d\n", collection->usage_index); + printf("parent: %p\n", collection->parent_collection); + printf("children collections: %d\n", collection->num_collections); + if (collection->first_collection) + printf("first_collection: %p\n", collection->first_collection); + if (collection->next_collection) + printf("next_collection: %p\n", collection->next_collection); + printf("children elements: %d\n", collection->num_elements); + if (collection->first_element) + printf("first_element: %p\n", collection->first_element); + printf("\n\n"); + fflush(stdout); } -int hid_parse_input_elements_values( unsigned char* buf, struct hid_dev_desc * devdesc ){ +static void add_element_to_collection(struct hid_device_collection *collection, struct hid_device_element *element) +{ + if (!collection->first_element){ + collection->first_element = element; + } + collection->num_elements++; + element->parent_collection = collection; +} + + +static struct hid_device_element *duplicate_element_with_new_usage(struct hid_device_element *source_element, int new_usage, struct hid_device_collection *device_collection, int *index) +{ + struct hid_device_element *new_element = hid_new_element(); + memcpy(new_element, source_element, sizeof(struct hid_device_element)); + new_element->index = (*index)++; + device_collection->num_elements++; + // Update the collection + add_element_to_collection(source_element->parent_collection, new_element); + new_element->usage = new_usage; + return new_element; +} + + +static void fill_element_from_button_caps(PHIDP_BUTTON_CAPS pCaps, struct hid_device_element *element) +{ + USHORT bitField = pCaps->BitField; + element->usage_page = pCaps->UsagePage; + element->type = bitField & 0xf; + element->logical_min = 0; + element->logical_max = 1; + element->isarray = ((bitField & HID_ITEM_VARIABLE) == 0); + element->isrelative = pCaps->IsAbsolute ? 0 : 1; + element->isvariable = ((bitField & HID_ITEM_CONSTANT) == 0); + element->report_id = pCaps->ReportID; + element->report_size = pCaps->Range.UsageMax - pCaps->Range.UsageMin + 1; + element->report_index = 1; // TODO: not sure about this one. The API does not seem to provide this. Perhaps set to 1? + +} + + +static void fill_element_from_value_caps(PHIDP_VALUE_CAPS pCaps, struct hid_device_element *element) +{ + USHORT bitField = pCaps->BitField; + element->usage_page = pCaps->UsagePage; + element->type = bitField & 0xf; + element->isarray = ((bitField & HID_ITEM_VARIABLE) == 0); + element->isrelative = pCaps->IsAbsolute ? 0 : 1; + element->isvariable = ((bitField & HID_ITEM_CONSTANT) == 0); + element->logical_min = pCaps->LogicalMin; + element->logical_max = pCaps->LogicalMax; + element->phys_min = pCaps->PhysicalMin; + element->phys_max = pCaps->PhysicalMax; + element->unit = pCaps->Units; + element->unit_exponent = pCaps->UnitsExp; + element->report_id = pCaps->ReportID; + element->report_size = pCaps->BitSize; + element->report_index = pCaps->ReportCount; +} + +static int hid_parse_caps(struct hid_device_element **pplast_element, struct hid_device_collection **ppcollections, struct hid_device_collection *pdevice_collection, + const PHIDP_PREPARSED_DATA pp_data, const PHIDP_CAPS caps, int report_type, BOOL is_button, int *index) +{ + int i, j; + USHORT numCaps; + enum _HIDP_REPORT_TYPE api_report_type; + struct hid_device_element *plast_element = *pplast_element; + + if (is_button){ + switch (report_type){ + case HID_REPORT_TYPE_INPUT: numCaps = caps->NumberInputButtonCaps; api_report_type = HidP_Input; break; + case HID_REPORT_TYPE_OUTPUT: numCaps = caps->NumberOutputButtonCaps; api_report_type = HidP_Output; break; + case HID_REPORT_TYPE_FEATURE: numCaps = caps->NumberFeatureButtonCaps; api_report_type = HidP_Feature; break; + } + PHIDP_BUTTON_CAPS pButtonCaps; + pButtonCaps = malloc(numCaps * sizeof(HIDP_BUTTON_CAPS)); + if (HidP_GetButtonCaps(api_report_type, pButtonCaps, &numCaps, pp_data) != HIDP_STATUS_SUCCESS){ + free(pButtonCaps); + return -1; + } + for (i = 0; i < numCaps; i++){ + // Create a new element + struct hid_device_element *new_element = hid_new_element(); + if (plast_element){ + plast_element->next = new_element; + } + // Connect to previous element + plast_element = new_element; + // Add element to collections, and fill element values + PHIDP_BUTTON_CAPS pCaps = &pButtonCaps[i]; + add_element_to_collection(pdevice_collection, new_element); + add_element_to_collection(ppcollections[pCaps->LinkCollection], new_element); + new_element->io_type = report_type; + new_element->index = (*index)++; + fill_element_from_button_caps(pCaps, new_element); + if (pCaps->IsRange){ + // If it is a range, we copy the element, and update the usage. We want to have an element per usage. + new_element->usage = pCaps->Range.UsageMin; +#ifdef DEBUG_PARSER + debug_element(new_element); +#endif + for (j = pCaps->Range.UsageMin + 1; j <= pCaps->Range.UsageMax; j++){ + new_element = duplicate_element_with_new_usage(plast_element, j, pdevice_collection, index); + plast_element->next = new_element; + plast_element = new_element; +#ifdef DEBUG_PARSER + debug_element(new_element); +#endif + } + } + else{ + new_element->usage = pCaps->NotRange.Usage; +#ifdef DEBUG_PARSER + debug_element(new_element); +#endif + } + } + free(pButtonCaps); + } + else { + switch (report_type){ + case HID_REPORT_TYPE_INPUT: numCaps = caps->NumberInputValueCaps; api_report_type = HidP_Input; break; + case HID_REPORT_TYPE_OUTPUT: numCaps = caps->NumberOutputValueCaps; api_report_type = HidP_Output; break; + case HID_REPORT_TYPE_FEATURE: numCaps = caps->NumberFeatureValueCaps; api_report_type = HidP_Feature; break; + } + PHIDP_VALUE_CAPS pValueCaps; + pValueCaps = malloc(numCaps * sizeof(HIDP_VALUE_CAPS)); + if (HidP_GetValueCaps(api_report_type, pValueCaps, &numCaps, pp_data) != HIDP_STATUS_SUCCESS){ + free(pValueCaps); + return -1; + } + for (i = 0; i < numCaps; i++){ + // Create a new element + struct hid_device_element *new_element = hid_new_element(); + if (plast_element){ + plast_element->next = new_element; + } + // Connect to previous element + plast_element = new_element; + // Add element to collections, and fill element values + PHIDP_VALUE_CAPS pCaps = &pValueCaps[i]; + add_element_to_collection(pdevice_collection, new_element); + add_element_to_collection(ppcollections[pCaps->LinkCollection], new_element); + new_element->io_type = report_type; + new_element->index = (*index)++; + fill_element_from_value_caps(pCaps, new_element); + + if (pCaps->IsRange){ + // If it is a range, we copy the element, and update the usage. We want to have an element per usage. + new_element->usage = pCaps->Range.UsageMin; + debug_element(new_element); + for (j = pCaps->Range.UsageMin + 1; j <= pCaps->Range.UsageMax; j++){ + new_element = duplicate_element_with_new_usage(plast_element, j, pdevice_collection, index); + plast_element->next = new_element; + plast_element = new_element; +#ifdef DEBUG_PARSER + debug_element(new_element); +#endif + } + } + else{ + new_element->usage = pCaps->NotRange.Usage; +#ifdef DEBUG_PARSER + debug_element(new_element); +#endif + } + } + free(pValueCaps); + } + + // make sure the last element index is visible outside + *pplast_element = plast_element; + return 0; +} + + + +int hid_send_element_output( struct hid_dev_desc * devdesc, struct hid_device_element * element ){ + return 0; +} +int hid_parse_input_elements_values( unsigned char* buf, int size, struct hid_dev_desc * devdesc ){ + // If there is only one report, there will be no report ID in the report. Otherwise, it is the first byte + int i; + int report_id = 0; + int report_length = 0; + struct hid_device_collection * device_collection = devdesc->device_collection; + struct hid_device_element * cur_element = device_collection->first_element; + NTSTATUS res; + + if (devdesc->number_of_reports != 1){ + report_id = buf[0]; + } + + // I thtink on Windows we do not need to calculate the report size here, and we can just get it from the size parameter that we got from above + for (i = 0; i < devdesc->number_of_reports; i++){ + if (devdesc->report_ids[i] == report_id){ + report_length = size; + } + } + if (report_length == 0){ + // This should not happen, the report was not found + return -1; + } + + if (cur_element->io_type != HID_REPORT_TYPE_INPUT){ + cur_element = hid_get_next_input_element(cur_element); + } + + // The Windows API has a function to get the data of all the buttons that are on, and another to get the value data by component page and usage + // We get all the buttons that are on + HANDLE dev_handle = get_device_handle(devdesc->device); + PHIDP_PREPARSED_DATA pp_data; + if (!HidD_GetPreparsedData(dev_handle, &pp_data)){ + return -1; + } + long usage_and_page_length = HidP_MaxUsageListLength(HidP_Input, 0, pp_data); + PUSAGE_AND_PAGE usage_and_page_list = malloc(usage_and_page_length * sizeof(USAGE_AND_PAGE)); + memset(usage_and_page_list, 0, usage_and_page_length * sizeof(USAGE_AND_PAGE)); + + NTSTATUS ntres = HidP_GetButtonsEx(HidP_Input, 0, usage_and_page_list, &usage_and_page_length, pp_data, buf, report_length); + if ( ntres != HIDP_STATUS_SUCCESS){ + free(usage_and_page_list); + return -1; + } + + while (cur_element != NULL){ + // Check that the element is part of this report + if (cur_element->report_id != report_id){ + cur_element = hid_get_next_input_element(cur_element); + continue; + } + + if (devdesc->_element_callback != NULL){ + // TODO may need to use HidP_GetUsageValueArray, if element->report_index > 1 + unsigned long new_value; + res = HidP_GetUsageValue(HidP_Input, cur_element->usage_page, 0, cur_element->usage, &new_value, pp_data, buf, report_length); + if (res == HIDP_STATUS_SUCCESS){ + if (new_value != cur_element->rawvalue || cur_element->repeat){ +#ifdef DEBUG_PARSER + printf("element page %i, usage %i, index %i, value %i, rawvalue %i, newvalue %i\n", cur_element->usage_page, cur_element->usage, cur_element->index, cur_element->value, cur_element->rawvalue, new_value); +#endif + hid_element_set_value_from_input(cur_element, new_value); + devdesc->_element_callback(cur_element, devdesc->_element_data); + } + } + else if (res == HIDP_STATUS_USAGE_NOT_FOUND){ + // Then see if we can find the element's page and usage in the buttons that are set to on, if not, it is implicitly 0 + new_value = 0; + for (i = 0; i < usage_and_page_length; i++){ + USAGE usage = usage_and_page_list[i].Usage; + if (usage_and_page_list[i].UsagePage = cur_element->usage_page && usage == cur_element->usage){ + new_value = 1; + break; + } + } + if (new_value != cur_element->rawvalue || cur_element->repeat){ + hid_element_set_value_from_input(cur_element, new_value); +#ifdef DEBUG_PARSER + printf("element page %i, usage %i, index %i, value %i, rawvalue %i, newvalue %i\n", cur_element->usage_page, cur_element->usage, cur_element->index, cur_element->value, cur_element->rawvalue, new_value); +#endif + devdesc->_element_callback(cur_element, devdesc->_element_data); + } + } + } + cur_element = hid_get_next_input_element(cur_element); + } + free(usage_and_page_list); + + return 0; } void hid_parse_element_info( struct hid_dev_desc * devdesc ){ + int i, j; + hid_device * dev = devdesc->device; + + struct hid_device_collection * device_collection = hid_new_collection(); + devdesc->device_collection = device_collection; + + struct hid_device_collection * parent_collection = devdesc->device_collection; + + device_collection->num_collections = 0; + device_collection->num_elements = 0; + + int numreports = 1; + int report_lengths[256]; + int report_ids[256]; + report_ids[0] = 0; + report_lengths[0] = 0; + + // To keep track of indices + int new_index = 0; + + int numColls = 0; + + NTSTATUS nt_res; + PHIDP_PREPARSED_DATA pp_data = NULL; + HIDP_CAPS caps; + + /* Open a handle to the device */ + HANDLE dev_handle = get_device_handle(dev); + + /* Check validity of write_handle. */ + if (dev_handle == INVALID_HANDLE_VALUE) { + /* Unable to open the device. */ + //register_error(dev, "CreateFile"); + // TODO: not sure what to do here + return; + } + + /* Get the Usage Page and Usage for this device. */ + BOOLEAN res = HidD_GetPreparsedData(dev_handle, &pp_data); + if (!res){ + // TODO: what should we do here? + return; + } + + nt_res = HidP_GetCaps(pp_data, &caps); + if (nt_res != HIDP_STATUS_SUCCESS) { + // TODO: what should we do here + return; + } + numColls = caps.NumberLinkCollectionNodes; + + device_collection->num_collections = numColls; + device_collection->usage_page = caps.UsagePage; + device_collection->usage_index = caps.Usage; + + device_collection->index = new_index++; + device_collection->num_elements = 0; + + PHIDP_LINK_COLLECTION_NODE linkCollectionNodes; + linkCollectionNodes = malloc(numColls * sizeof(HIDP_LINK_COLLECTION_NODE)); + struct hid_device_collection **collections = malloc(numColls * sizeof(struct hid_device_collection *)); + nt_res = HidP_GetLinkCollectionNodes( linkCollectionNodes, &numColls, pp_data ); + if (nt_res != HIDP_STATUS_SUCCESS){ + // TODO: what to do here? + return; + } + + // Create the N collections, and put them in an array, so that we can efficiently construct the pointers to each other using the Windows API + for (i = 0; i < numColls; i++){ + collections[i] = hid_new_collection(); + } + + // And now fill the data and create the collection links + for (i = 0; i < numColls; i++){ + PHIDP_LINK_COLLECTION_NODE p_collection = &linkCollectionNodes[i]; + // Documentation says that if parent is 0, then there is no parent, but then how do you indicate that the parent is at index 0??? + // I think that is wrong, and 0 indicates that the parent is the collection at index + // I will assume that the collection at index 0 is always the outermost one + if (i == 0){ + device_collection->first_collection = collections[i]; + collections[i]->parent_collection = device_collection; + } + else{ + collections[i]->parent_collection = collections[p_collection->Parent]; + } + if (p_collection->NextSibling) + collections[i]->next_collection = collections[p_collection->NextSibling]; + + if (p_collection->FirstChild) + collections[i]->first_collection = collections[p_collection->FirstChild]; + + collections[i]->num_collections = p_collection->NumberOfChildren; + collections[i]->type = p_collection->CollectionType; + collections[i]->usage_page = p_collection->LinkUsagePage; + collections[i]->usage_index = p_collection->LinkUsage; + collections[i]->index = new_index++; // TODO not sure about this one +#ifdef DEBUG_PARSER + debug_collection(collections[i], i); +#endif + } +#ifdef DEBUG_PARSER + debug_collection(device_collection, 100); +#endif + + /* Now, create the elements, parsing the (input, output, feature) x (button, values) capabilities */ + int index_element = 0; + new_index = 0; + struct hid_device_element *last_element = NULL; + hid_parse_caps(&last_element, collections, device_collection, pp_data, &caps, HID_REPORT_TYPE_INPUT, FALSE, &new_index); + hid_parse_caps(&last_element, collections, device_collection, pp_data, &caps, HID_REPORT_TYPE_INPUT, TRUE, &new_index); + hid_parse_caps(&last_element, collections, device_collection, pp_data, &caps, HID_REPORT_TYPE_OUTPUT, FALSE, &new_index); + hid_parse_caps(&last_element, collections, device_collection, pp_data, &caps, HID_REPORT_TYPE_OUTPUT, TRUE, &new_index); + hid_parse_caps(&last_element, collections, device_collection, pp_data, &caps, HID_REPORT_TYPE_FEATURE, FALSE, &new_index); + hid_parse_caps(&last_element, collections, device_collection, pp_data, &caps, HID_REPORT_TYPE_FEATURE, TRUE, &new_index); + + /* Reports */ + // Perhaps look at this (from MSDN): The XxxReportByteLength members of a HID collection's HIDP_CAPS structure specify the required size of input, output, and feature reports + // On Windows it is not clear that knowing the report size is important at this point, since we get it implicitly on the read size. It's quite likely that the calculation done here + // is not right, but it does not affect (should revisit later) + struct hid_device_element *element = device_collection->first_element; + while (element != NULL){ + int report_id = element->report_id; + int report_size = element->report_size; + int report_count = element->report_index; // TODO: report_count is not used???? + + int reportexists = 0; + for (j = 0; j < numreports; j++){ + reportexists = (report_ids[j] == report_id); + } + if (!reportexists){ + report_ids[numreports] = report_id; + report_lengths[numreports] = 0; + numreports++; + } + int k = 0; + int index = 0; + for (k = 0; knext; + } + + devdesc->number_of_reports = numreports; + devdesc->report_lengths = (int*)malloc(sizeof(int) * numreports); + devdesc->report_ids = (int*)malloc(sizeof(int) * numreports); + for (j = 0; jreport_lengths[j] = report_lengths[j]; + devdesc->report_ids[j] = report_ids[j]; + } + + /* And clean up the temp structures */ + free(collections); + free(linkCollectionNodes); + HidD_FreePreparsedData(pp_data); } #endif @@ -1259,16 +1743,16 @@ int hid_send_element_output( struct hid_dev_desc * devdesc, struct hid_device_el // get the logical mix/max for this LED element CFIndex minCFIndex = IOHIDElementGetLogicalMin( tIOHIDElementRef ); - CFIndex maxCFIndex = IOHIDElementGetLogicalMax( tIOHIDElementRef ); + CFIndex maxCFIndex = IOHIDElementGetLogicalMax( tIOHIDElementRef ); // calculate the range CFIndex modCFIndex = maxCFIndex - minCFIndex + 1; // compute the value for this LED element CFIndex tCFIndex = minCFIndex + ( element->value % modCFIndex ); uint64_t timestamp = 0; // create the IO HID Value to be sent - + IOHIDValueRef tIOHIDValueRef = IOHIDValueCreateWithIntegerValue( kCFAllocatorDefault, tIOHIDElementRef, timestamp, tCFIndex ); - + if ( tIOHIDValueRef ) { tIOReturn = IOHIDDeviceSetValue( device_handle, tIOHIDElementRef, tIOHIDValueRef ); CFRelease( tIOHIDValueRef ); @@ -1279,23 +1763,23 @@ int hid_send_element_output( struct hid_dev_desc * devdesc, struct hid_device_el return -1; } -// int hid_parse_input_report( unsigned char* buf, int size, struct hid_dev_desc * devdesc ){ +// int hid_parse_input_report( unsigned char* buf, int size, struct hid_dev_desc * devdesc ){ int hid_parse_input_elements_values( unsigned char* buf, struct hid_dev_desc * devdesc ){ struct hid_device_collection * device_collection = devdesc->device_collection; struct hid_device_element * cur_element = device_collection->first_element; int i=0; int newvalue; int reportid = 0; - + IOHIDDeviceRef device_handle = get_device_handle( devdesc->device ); IOHIDValueRef newValueRef; IOReturn tIOReturn; - + /* if ( devdesc->number_of_reports > 1 ){ reportid = (int) buf[i]; } - + if ( cur_element->io_type != 1 || ( cur_element->report_id != reportid ) ){ cur_element = hid_get_next_input_element_with_reportid(cur_element, reportid ); } @@ -1326,7 +1810,7 @@ int hid_parse_input_elements_values( unsigned char* buf, struct hid_dev_desc * d // printf( "cur_element %i\n", cur_element ); } // printf( "======== end of report\n"); - return 0; + return 0; } /* @@ -1369,7 +1853,7 @@ void hid_parse_element_info( struct hid_dev_desc * devdesc ) IOHIDElementType tIOHIDElementType = IOHIDElementGetType(tIOHIDElementRef); uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef); uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef); - + if ( tIOHIDElementType == kIOHIDElementTypeCollection ){ //TODO: COULD ALSO READ WHICH KIND OF COLLECTION struct hid_device_collection * new_collection = hid_new_collection(); @@ -1414,7 +1898,7 @@ void hid_parse_element_info( struct hid_dev_desc * devdesc ) Boolean hasPreferredState = IOHIDElementHasPreferredState(tIOHIDElementRef); // ["NoNullPosition", "NullState"], Boolean hasNullState = IOHIDElementHasNullState(tIOHIDElementRef); - int type = 0; + int type = 0; new_element->type = 0; type = (int) isVirtual; new_element->isvariable = (int) !isVirtual; diff --git a/hidapi_parser/hidapi_parser.h b/hidapi_parser/hidapi_parser.h index 4756ea3e..e6056447 100644 --- a/hidapi_parser/hidapi_parser.h +++ b/hidapi_parser/hidapi_parser.h @@ -32,7 +32,7 @@ extern "C" { #endif -#include +#include "hidapi.h" struct hid_device_element; struct hid_device_collection; @@ -184,7 +184,7 @@ void hid_parse_element_info( struct hid_dev_desc * devdesc ); #ifdef WIN32 int hid_send_element_output( struct hid_dev_desc * devdesc, struct hid_device_element * element ); -int hid_parse_input_elements_values( unsigned char* buf, struct hid_dev_desc * devdesc ); +int hid_parse_input_elements_values( unsigned char* buf, int size, struct hid_dev_desc * devdesc ); void hid_parse_element_info( struct hid_dev_desc * devdesc ); #endif diff --git a/hidtest/hidtest.cpp b/hidtest/hidtest.cpp index 7682afa5..8ff3ea80 100644 --- a/hidtest/hidtest.cpp +++ b/hidtest/hidtest.cpp @@ -224,7 +224,8 @@ int main(int argc, char* argv[]) return -1; devs = hid_enumerate(0x0, 0x0); - cur_dev = devs; + cur_dev = devs; + printf( "curdev %ls\n", cur_dev ); while (cur_dev) { printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number); printf("\n"); @@ -250,7 +251,9 @@ int main(int argc, char* argv[]) // mouse: // handle = hid_open(0x1241, 0x1166, NULL); // run'n'drive - handle = hid_open(0x044f, 0xd003, NULL); +// handle = hid_open(0x044f, 0xd003, NULL); + // impakt + handle = hid_open(0x07b5, 0x0312, NULL); if (!handle) { printf("unable to open device\n"); return 1; @@ -285,7 +288,7 @@ int main(int argc, char* argv[]) printf("Unable to read indexed string 1\n"); printf("Indexed String 1: %ls\n", wstr); - +/* //// PARSING THE DESCRIPTOR res = hid_get_report_descriptor( handle, descr_buf, MAX_DESCRIPTOR ); if (res < 0) @@ -560,7 +563,7 @@ int main(int argc, char* argv[]) } printf("\n"); printf("number of elements, %i\n", descriptor->num_elements ); - +*/ // Set the hid_read() function to be non-blocking. hid_set_nonblocking(handle, 1); // @@ -620,6 +623,7 @@ int main(int argc, char* argv[]) // printf("bitmask test, %i, %i, %02hhx\n", i, BITMASK1(i), BITMASK1(i) ); // } +/* // Read requested state. hid_read() has been set to be // non-blocking by the call to hid_set_nonblocking() above. // This loop demonstrates the non-blocking nature of hid_read(). @@ -661,7 +665,7 @@ int main(int argc, char* argv[]) usleep(500*100); #endif } - +*/ hid_close(handle); diff --git a/hidtestwindows/CMakeLists.txt b/hidtestwindows/CMakeLists.txt new file mode 100644 index 00000000..19a0fb38 --- /dev/null +++ b/hidtestwindows/CMakeLists.txt @@ -0,0 +1,18 @@ +message( "===hidtestwindows cmakelists===" ) + +include_directories( + ${CMAKE_BINARY_DIR} + ${hidapi_SOURCE_DIR}/hidapi/ + ${hidapi_SOURCE_DIR}/hidapi_parser/ +) + + +set(hidtest_SRCS + hidtestwindows.cpp +) + +add_executable( hidtestwindows ${hidtest_SRCS} ) + +target_link_libraries(hidtestwindows hidapi hidapi_parser ${EXTRA_LIBS}) + +install(TARGETS hidtestwindows DESTINATION bin) diff --git a/hidtestwindows/hidtestwindows.cpp b/hidtestwindows/hidtestwindows.cpp new file mode 100644 index 00000000..7ee18203 --- /dev/null +++ b/hidtestwindows/hidtestwindows.cpp @@ -0,0 +1,311 @@ +/* hidapi_parser $ + * + * Copyright (C) 2013, Marije Baalman + * This work was funded by a crowd-funding initiative for SuperCollider's [1] HID implementation + * including a substantial donation from BEK, Bergen Center for Electronic Arts, Norway + * + * [1] http://supercollider.sourceforge.net + * [2] http://www.bek.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/******************************************************* + Windows HID simplification + + Alan Ott + Signal 11 Software + + 8/22/2009 + + Copyright 2009 + + This contents of this file may be used by anyone + for any reason without any conditions and may be + used as a starting point for your own applications + which use HIDAPI. +********************************************************/ + +//TODO: add copyright notice + +#include +#include +#include +#include +#include "hidapi.h" + +// Headers needed for sleeping. +#ifdef _WIN32 + #include +#else + #include +#endif + + +//// ---------- HID descriptor parser + +#define MAX_DESCRIPTOR 4096 + + +// main items +#define HID_INPUT 0x80 +#define HID_OUTPUT 0x90 +#define HID_COLLECTION 0xA0 +#define HID_FEATURE 0xB0 +// #define HID_COLLECTION 0xa1 +#define HID_END_COLLECTION 0xC0 + +// HID Report Items from HID 1.11 Section 6.2.2 +#define HID_USAGE_PAGE 0x04 +// #define HID_USAGE_PAGE 0x05 +// #define HID_USAGE_PAGE_EXT 0x06 + +#define HID_USAGE 0x08 +// #define HID_USAGE 0x09 +// #define HID_USAGE_EXT 0x0a + +#define HID_USAGE_MIN 0x18 +// #define HID_USAGE_MIN 0x19 +#define HID_USAGE_MAX 0x28 +// #define HID_USAGE_MAX 0x29 + +#define HID_DESIGNATOR_INDEX 0x38 +#define HID_DESIGNATOR_MIN 0x48 +#define HID_DESIGNATOR_MAX 0x58 + +#define HID_STRING_INDEX 0x78 +#define HID_STRING_MIN 0x88 +#define HID_STRING_MAX 0x98 + +#define HID_DELIMITER 0xA8 + +#define HID_LOGICAL_MIN 0x14 +// #define HID_LOGICAL_MIN 0x15 +// #define HID_LOGICAL_MIN_2 0x16 +#define HID_LOGICAL_MAX 0x24 +// #define HID_LOGICAL_MAX 0x25 +// #define HID_LOGICAL_MAX_2 0x26 + +#define HID_PHYSICAL_MIN 0x34 +// #define HID_PHYSICAL_MIN 0x35 +// #define HID_PHYSICAL_MIN_2 0x36 +// #define HID_PHYSICAL_MIN_3 0x37 +#define HID_PHYSICAL_MAX 0x44 +// #define HID_PHYSICAL_MAX 0x45 +// #define HID_PHYSICAL_MAX_2 0x46 + +#define HID_UNIT_EXPONENT 0x54 +// #define HID_UNIT 0x55 +#define HID_UNIT 0x64 +// #define HID_UNIT 0x65 + +#define HID_REPORT_SIZE 0x74 +// #define HID_REPORT_SIZE 0x75 +#define HID_REPORT_ID 0x84 + +#define HID_REPORT_COUNT 0x94 +// #define HID_REPORT_COUNT 0x95 + +#define HID_PUSH 0xA4 +#define HID_POP 0xB4 + +#define HID_RESERVED 0xC4 // above this it is all reserved + + +// HID Report Usage Pages from HID Usage Tables 1.12 Section 3, Table 1 +#define HID_USAGE_PAGE_GENERICDESKTOP 0x01 +#define HID_USAGE_PAGE_KEY_CODES 0x07 +#define HID_USAGE_PAGE_LEDS 0x08 +#define HID_USAGE_PAGE_BUTTONS 0x09 + +// HID Report Usages from HID Usage Tables 1.12 Section 4, Table 6 +#define HID_USAGE_POINTER 0x01 +#define HID_USAGE_MOUSE 0x02 +#define HID_USAGE_JOYSTICK 0x04 +#define HID_USAGE_KEYBOARD 0x06 +#define HID_USAGE_X 0x30 +#define HID_USAGE_Y 0x31 +#define HID_USAGE_Z 0x32 +#define HID_USAGE_RX 0x33 +#define HID_USAGE_RY 0x34 +#define HID_USAGE_RZ 0x35 +#define HID_USAGE_SLIDER 0x36 +#define HID_USAGE_DIAL 0x37 +#define HID_USAGE_WHEEL 0x38 + + +// HID Report Collection Types from HID 1.12 6.2.2.6 +#define HID_COLLECTION_PHYSICAL 0 +#define HID_COLLECTION_APPLICATION 1 + +// HID Input/Output/Feature Item Data (attributes) from HID 1.11 6.2.2.5 +/// more like flags +#define HID_ITEM_CONSTANT 0x1 +#define HID_ITEM_VARIABLE 0x2 +#define HID_ITEM_RELATIVE 0x4 +#define HID_ITEM_WRAP 0x8 +#define HID_ITEM_LINEAR 0x10 +#define HID_ITEM_PREFERRED 0x20 +#define HID_ITEM_NULL 0x40 +#define HID_ITEM_BITFIELD 0x80 + +// Report Types from HID 1.11 Section 7.2.1 +#define HID_REPORT_TYPE_INPUT 1 +#define HID_REPORT_TYPE_OUTPUT 2 +#define HID_REPORT_TYPE_FEATURE 3 + +struct hid_device_descriptor { + int num_elements; +// int usage_page; +// int usage; + /** Pointer to the first element */ + struct hid_device_element *first; +}; + +struct hid_device_element { + int index; + + int type; // button/axis + int vartype; // abs/relative + int usage_page; // usage page + int usage; // some kind of index (as from descriptor) + + int logical_min; + int logical_max; + + int phys_min; + int phys_max; + + int resolution; // in bits + + int value; + + /** Pointer to the next element */ + struct hid_device_element *next; +}; + +struct hid_device_descriptor *descriptor; + +#define BITMASK1(n) ((1ULL << (n)) - 1ULL) + +int main(int argc, char* argv[]) +{ + int res; + unsigned char buf[256]; + unsigned char descr_buf[MAX_DESCRIPTOR]; + #define MAX_STR 255 + wchar_t wstr[MAX_STR]; + hid_device *handle; + int i; + + descriptor = (struct hid_device_descriptor *) malloc( sizeof( struct hid_device_descriptor) ); + descriptor->num_elements = 0; + +#ifdef WIN32 + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); +#endif + + struct hid_device_info *devs, *cur_dev; + + if (hid_init()) + return -1; + + devs = hid_enumerate(0x0, 0x0); + cur_dev = devs; + printf( "curdev %ls\n", cur_dev ); + while (cur_dev) { + printf("Device Found\n (vendor,product): %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number); + printf("\n"); + printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string); + printf(" Product: %ls\n", cur_dev->product_string); + printf(" Release: %hx\n", cur_dev->release_number); + printf(" Interface: %d\n", cur_dev->interface_number); + printf("\n"); + cur_dev = cur_dev->next; + } + hid_free_enumeration(devs); + + // Set up the command buffer. + memset(buf,0x00,sizeof(buf)); + buf[0] = 0x01; + buf[1] = 0x81; + + + // Open the device using the VID, PID, + // and optionally the Serial number. + ////handle = hid_open(0x4d8, 0x3f, L"12345"); +// handle = hid_open(0x4d8, 0x3f, NULL); + // mouse: +// handle = hid_open(0x1241, 0x1166, NULL); + // run'n'drive +// handle = hid_open(0x044f, 0xd003, NULL); + // impakt + handle = hid_open(0x07b5, 0x0312, NULL); + if (!handle) { + printf("unable to open device\n"); + return 1; + } + + // Read the Manufacturer String + wstr[0] = 0x0000; + res = hid_get_manufacturer_string(handle, wstr, MAX_STR); + if (res < 0) + printf("Unable to read manufacturer string\n"); + printf("Manufacturer String: %ls\n", wstr); + + // Read the Product String + wstr[0] = 0x0000; + res = hid_get_product_string(handle, wstr, MAX_STR); + if (res < 0) + printf("Unable to read product string\n"); + printf("Product String: %ls\n", wstr); + + // Read the Serial Number String + wstr[0] = 0x0000; + res = hid_get_serial_number_string(handle, wstr, MAX_STR); + if (res < 0) + printf("Unable to read serial number string\n"); + printf("Serial Number String: (%d) %ls", wstr[0], wstr); + printf("\n"); + + // Read Indexed String 1 + wstr[0] = 0x0000; + res = hid_get_indexed_string(handle, 1, wstr, MAX_STR); + if (res < 0) + printf("Unable to read indexed string 1\n"); + printf("Indexed String 1: %ls\n", wstr); + + + // Set the hid_read() function to be non-blocking. + hid_set_nonblocking(handle, 1); + +// // Try to read from the device. There shoud be no +// // data here, but execution should not block. + res = hid_read(handle, buf, 17); + + printf( "res of read %i\n", res ); + + hid_close(handle); + + /* Free static HIDAPI objects. */ + hid_exit(); + +#ifdef WIN32 + system("pause"); +#endif + + return 0; +} diff --git a/mac/hid.c b/mac/hid.c index 8240f223..439337cd 100644 --- a/mac/hid.c +++ b/mac/hid.c @@ -411,13 +411,6 @@ int HID_API_EXPORT hid_exit(void) return 0; } -static void process_pending_events(void) { - SInt32 res; - do { - res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, FALSE); - } while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut); -} - struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) { struct hid_device_info *root = NULL; /* return object */ @@ -429,9 +422,6 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, if (hid_init() < 0) return NULL; - /* give the IOHIDManager a chance to update itself */ - process_pending_events(); - /* Get a list of the Devices */ IOHIDManagerSetDeviceMatching(hid_mgr, NULL); CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr); @@ -707,9 +697,6 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path) if (hid_init() < 0) return NULL; - /* give the IOHIDManager a chance to update itself */ - process_pending_events(); - CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr); num_devices = CFSetGetCount(device_set); diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index 9d551598..5129ea97 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -2,4 +2,4 @@ message(STATUS " Windows" ) include_directories( ${hidapi_SOURCE_DIR}/hidapi/ ) add_library( hidapi STATIC hid.c ) -target_link_libraries( hidapi setupapi.lib ) +target_link_libraries( hidapi setupapi ) diff --git a/windows/hid.c b/windows/hid.c index 0671f128..fef1fc83 100755 --- a/windows/hid.c +++ b/windows/hid.c @@ -8,7 +8,7 @@ 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 @@ -21,6 +21,10 @@ ********************************************************/ #include +// for MinGW < 5.3 include locally provided "../windows hidsdi.h" rather +// than #include : +// #include "./hidsdi.h" +#include #ifndef _NTDEF_ typedef LONG NTSTATUS; @@ -29,6 +33,7 @@ typedef LONG NTSTATUS; #ifdef __MINGW32__ #include #include +#include #endif #ifdef __CYGWIN__ @@ -36,16 +41,11 @@ typedef LONG NTSTATUS; #define _wcsdup wcsdup #endif -/*#define HIDAPI_USE_DDK*/ - #ifdef __cplusplus extern "C" { #endif #include #include - #ifdef HIDAPI_USE_DDK - #include - #endif /* Copied from inc/ddk/hidclass.h, part of the Windows DDK. */ #define HID_OUT_CTL_CODE(id) \ @@ -62,6 +62,7 @@ extern "C" { #include "hidapi.h" + #ifdef _MSC_VER /* Thanks Microsoft, but I know how to use strncpy(). */ #pragma warning(disable:4996) @@ -71,59 +72,6 @@ extern "C" { 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 SDK, we have to define all this - stuff here. In lookup_functions(), the function pointers - defined below are set. */ - typedef struct _HIDD_ATTRIBUTES{ - ULONG Size; - USHORT VendorID; - USHORT ProductID; - USHORT VersionNumber; - } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; - - typedef USHORT USAGE; - typedef struct _HIDP_CAPS { - USAGE Usage; - USAGE UsagePage; - USHORT InputReportByteLength; - USHORT OutputReportByteLength; - USHORT FeatureReportByteLength; - USHORT Reserved[17]; - USHORT fields_not_used_by_hidapi[10]; - } HIDP_CAPS, *PHIDP_CAPS; - typedef void* PHIDP_PREPARSED_DATA; - #define HIDP_STATUS_SUCCESS 0x110000 - - typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib); - typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len); - typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); - typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); - typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length); - typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length); - typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len); - typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data); - typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data); - typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps); - typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers); - - 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_GetIndexedString_ HidD_GetIndexedString; - static HidD_GetPreparsedData_ HidD_GetPreparsedData; - static HidD_FreePreparsedData_ HidD_FreePreparsedData; - static HidP_GetCaps_ HidP_GetCaps; - static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers; - - static HMODULE lib_handle = NULL; - static BOOLEAN initialized = FALSE; -#endif /* HIDAPI_USE_DDK */ - struct hid_device_ { HANDLE device_handle; BOOL blocking; @@ -174,7 +122,7 @@ static void register_error(hid_device *device, const char *op) MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPVOID)&msg, 0/*sz*/, NULL); - + /* Get rid of the CR and LF that FormatMessage() sticks at the end of the message. Thanks Microsoft! */ ptr = msg; @@ -192,32 +140,6 @@ static void register_error(hid_device *device, const char *op) device->last_error_str = msg; } -#ifndef HIDAPI_USE_DDK -static int lookup_functions() -{ - lib_handle = LoadLibraryA("hid.dll"); - if (lib_handle) { -#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1; - RESOLVE(HidD_GetAttributes); - RESOLVE(HidD_GetSerialNumberString); - RESOLVE(HidD_GetManufacturerString); - RESOLVE(HidD_GetProductString); - RESOLVE(HidD_SetFeature); - RESOLVE(HidD_GetFeature); - RESOLVE(HidD_GetIndexedString); - RESOLVE(HidD_GetPreparsedData); - RESOLVE(HidD_FreePreparsedData); - RESOLVE(HidP_GetCaps); - RESOLVE(HidD_SetNumInputBuffers); -#undef RESOLVE - } - else - return -1; - - return 0; -} -#endif - static HANDLE open_device(const char *path, BOOL enumerate) { HANDLE handle; @@ -239,26 +161,11 @@ static HANDLE open_device(const char *path, BOOL enumerate) int HID_API_EXPORT hid_init(void) { -#ifndef HIDAPI_USE_DDK - if (!initialized) { - if (lookup_functions() < 0) { - hid_exit(); - return -1; - } - initialized = TRUE; - } -#endif return 0; } int HID_API_EXPORT hid_exit(void) { -#ifndef HIDAPI_USE_DDK - if (lib_handle) - FreeLibrary(lib_handle); - lib_handle = NULL; - initialized = FALSE; -#endif return 0; } @@ -269,7 +176,8 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor 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} }; + GUID InterfaceClassGuid; + HidD_GetHidGuid(&InterfaceClassGuid); SP_DEVINFO_DATA devinfo_data; SP_DEVICE_INTERFACE_DATA device_interface_data; SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL; @@ -287,9 +195,9 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor /* 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; @@ -300,7 +208,7 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor &InterfaceClassGuid, device_index, &device_interface_data); - + if (!res) { /* A return of FALSE from this function means that there are no more devices. */ @@ -372,7 +280,7 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor /* Unable to open the device. */ //register_error(dev, "CreateFile"); goto cont_close; - } + } /* Get the Vendor ID and Product ID for this device. */ @@ -416,7 +324,7 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor HidD_FreePreparsedData(pp_data); } - + /* Fill out the record */ cur_dev->next = NULL; str = device_interface_detail_data->DevicePath; @@ -516,7 +424,7 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsi 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) { @@ -542,7 +450,7 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsi } hid_free_enumeration(devs); - + return handle; } @@ -583,9 +491,10 @@ HID_API_EXPORT hid_device* HID_API_CALL hid_open_path(const char *path) 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"); + register_error(dev, "HidP_GetCaps"); goto err_pp_data; } dev->output_report_length = caps.OutputReportByteLength; @@ -598,7 +507,7 @@ HID_API_EXPORT hid_device* HID_API_CALL hid_open_path(const char *path) err_pp_data: HidD_FreePreparsedData(pp_data); -err: +err: free_hid_device(dev); return NULL; } @@ -637,7 +546,7 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char * } res = WriteFile(dev->device_handle, buf, length, NULL, &ol); - + if (!res) { if (GetLastError() != ERROR_IO_PENDING) { /* WriteFile() failed. Return error. */ @@ -680,16 +589,17 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char memset(dev->read_buf, 0, dev->input_report_length); ResetEvent(ev); res = ReadFile(dev->device_handle, dev->read_buf, 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; - } - } + + if (!res) { + DWORD er = GetLastError(); + 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; + } + } } if (milliseconds >= 0) { @@ -706,33 +616,22 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char we are in non-blocking mode. Get the number of bytes read. The actual data has been copied to the data[] array which was passed to ReadFile(). */ res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*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); - } + /* 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 copy_len; } @@ -879,11 +778,15 @@ HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) return (wchar_t*)dev->last_error_str; } +HANDLE HID_API_EXPORT get_device_handle(hid_device *dev){ + return dev->device_handle; +} + /*#define PICPGM*/ /*#define S11*/ #define P32 -#ifdef S11 +#ifdef S11 unsigned short VendorID = 0xa0a0; unsigned short ProductID = 0x0001; #endif @@ -913,7 +816,7 @@ int __cdecl main(int argc, char* argv[]) memset(buf,0x00,sizeof(buf)); buf[0] = 0; buf[1] = 0x81; - + /* Open the device. */ int handle = open(VendorID, ProductID, L"12345"); diff --git a/windows/hidsdi.h b/windows/hidsdi.h new file mode 100644 index 00000000..1ccf5492 --- /dev/null +++ b/windows/hidsdi.h @@ -0,0 +1,88 @@ +/* + * hidsdi.h + * + * [extended MinGW header with definitions for hidapi in SuperCollider 3.8 MinGW build + * source: https://sourceforge.net/p/mingw-w64/mailman/mingw-w64-public/thread/87mxjs7l5a.fsf@latte.josefsson.org/ + * tested with MinGW 4.8.2 as provided with Qt 5.5: + * version : MinGW-W64-builds-4.2.0 + * user : niXman] + * + * Public interface for USB HID user space functions. + * + * Contributors: + * Created by Simon Josefsson + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __HIDSDI_H +#define __HIDSDI_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* http://msdn.microsoft.com/en-us/library/ff538876%28v=VS.85%29.aspx */ +HIDAPI BOOLEAN NTAPI HidD_FlushQueue(HANDLE HidDeviceObject); + +/* http://msdn.microsoft.com/en-us/library/ff538900%28v=VS.85%29.aspx */ +HIDAPI BOOLEAN NTAPI HidD_GetAttributes(HANDLE HidDeviceObject, PHIDD_ATTRIBUTES Attributes); + +/* http://msdn.microsoft.com/en-us/library/ff538945%28v=VS.85%29.aspx */ +HIDAPI BOOLEAN NTAPI HidD_GetInputReport(HANDLE HidDeviceObject, PVOID ReportBuffer, ULONG ReportBufferLength); + +/* http://msdn.microsoft.com/en-us/library/ff539677%28v=VS.85%29.aspx */ +HIDAPI BOOLEAN NTAPI HidD_GetPhysicalDescriptor(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength); + +/* http://msdn.microsoft.com/en-us/library/ff538959%28v=VS.85%29.aspx */ +HIDAPI BOOLEAN NTAPI HidD_GetManufacturerString(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength); + +/* http://msdn.microsoft.com/en-us/library/windows/hardware/ff539681(v=vs.85).aspx */ +HIDAPI BOOLEAN NTAPI HidD_GetProductString (HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength); + +/* http://msdn.microsoft.com/en-us/library/ff539683%28v=VS.85%29.aspx */ +HIDAPI BOOLEAN NTAPI HidD_GetSerialNumberString(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength); + +/* http://msdn.microsoft.com/en-us/library/ff538910%28v=VS.85%29.aspx */ +HIDAPI BOOLEAN NTAPI HidD_GetFeature(HANDLE HidDeviceObject, PVOID ReportBuffer, ULONG ReportBufferLength); + + /* http://msdn.microsoft.com/en-us/library/ff539684%28v=VS.85%29.aspx */ +HIDAPI BOOLEAN NTAPI HidD_SetFeature(HANDLE HidDeviceObject, PVOID ReportBuffer, ULONG ReportBufferLength); + +/* http://msdn.microsoft.com/en-us/library/ff538924(v=vs.85).aspx */ +HIDAPI VOID NTAPI HidD_GetHidGuid(LPGUID HidGuid); + +/* http://msdn.microsoft.com/en-us/library/windows/hardware/ff539675(v=vs.85).aspx */ +HIDAPI BOOLEAN NTAPI HidD_GetNumInputBuffers (HANDLE HidDeviceObject, PULONG NumberBuffers); + +/* http://msdn.microsoft.com/en-us/library/windows/hardware/ff539686(v=vs.85).aspx */ +HIDAPI BOOLEAN NTAPI HidD_SetNumInputBuffers (HANDLE HidDeviceObject, ULONG NumberBuffers); + +/* http://msdn.microsoft.com/en-us/library/ff538893%28v=VS.85%29.aspx */ +HIDAPI BOOLEAN NTAPI HidD_FreePreparsedData(PHIDP_PREPARSED_DATA PreparsedData); + +/*http://msdn.microsoft.com/en-us/library/ff539679%28v=VS.85%29.aspx*/ +HIDAPI BOOLEAN NTAPI HidD_GetPreparsedData(HANDLE HidDeviceObject, PHIDP_PREPARSED_DATA *PreparsedData); + +/* http://msdn.microsoft.com/en-us/library/ff538927%28v=VS.85%29.aspx */ +HIDAPI BOOLEAN NTAPI HidD_GetIndexedString(HANDLE HidDeviceObject, ULONG StringIndex, PVOID Buffer, ULONG BufferLength); + +/* http://msdn.microsoft.com/en-us/library/ff539690%28v=VS.85%29.aspx */ +HIDAPI BOOLEAN NTAPI HidD_SetOutputReport(HANDLE HidDeviceObject, PVOID ReportBuffer, ULONG ReportBufferLength); + +#ifdef __cplusplus +} +#endif + +#endif /* __HIDSDI_H */