├── .classpath ├── .hgignore ├── .project ├── AUTHORS.txt ├── LICENSE-bsd.txt ├── LICENSE-gpl3.txt ├── LICENSE-orig.txt ├── LICENSE.txt ├── README.md ├── README.pdf ├── bin └── com │ └── codeminders │ └── hidapi │ └── ClassPathLibraryLoader.class ├── build.xml ├── hidapi ├── .classpath ├── .project └── hidapi.h ├── hidtest └── hidtest.cpp ├── jni-impl ├── HIDDevice.cpp ├── HIDDeviceInfo.cpp ├── HIDManager.cpp ├── hid-java.cpp └── hid-java.h ├── jni-stubs ├── com_codeminders_hidapi_HIDDevice.h ├── com_codeminders_hidapi_HIDDeviceInfo.h └── com_codeminders_hidapi_HIDManager.h ├── lib ├── maven-ant-tasks-2.1.3.jar └── native │ ├── linux │ ├── libhidapi-jni-32.so │ └── libhidapi-jni-64.so │ ├── mac │ ├── libhidapi-jni-32.jnilib │ └── libhidapi-jni-64.jnilib │ └── win │ ├── hidapi-jni-32.dll │ └── hidapi-jni-64.dll ├── linux ├── Makefile ├── README.txt ├── hid-libusb.c └── hid.c ├── mac ├── Makefile └── hid.c ├── pom.xml ├── src └── com │ └── codeminders │ ├── hidapi │ ├── ClassPathLibraryLoader.java │ ├── HIDAPITest.java │ ├── HIDDevice.java │ ├── HIDDeviceInfo.java │ ├── HIDDeviceNotFoundException.java │ └── HIDManager.java │ └── hidapplet │ └── HidApplet.java └── windows ├── Makefile ├── Makefile.mingw ├── ddk_build ├── hidapi.def ├── makefile └── sources ├── hid.c ├── hidapi-jni └── hidapi-jni.vcproj ├── hidapi.sln ├── hidapi.vcproj ├── hidapi.vcxproj ├── hidapi.vcxproj.filters ├── hidtest.vcproj ├── hidtest.vcxproj └── hidtest.vcxproj.filters /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | windows/*.user 3 | windows/*.ncb 4 | windows/*.sdf 5 | windows/*.opensdf 6 | windows/ipch 7 | windows/*.suo 8 | windows/Debug 9 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | javahidapi 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /AUTHORS.txt: -------------------------------------------------------------------------------- 1 | 2 | HIDAPI Authors: 3 | 4 | Alan Ott : 5 | Original Author and Maintainer 6 | Linux, Windows, and Mac implementations 7 | 8 | Ludovic Rousseau : 9 | Formatting for Doxygen documentation 10 | Bug fixes 11 | Correctness fixes 12 | 13 | 14 | For a comprehensive list of contributions, see the commit list at github: 15 | http://github.com/signal11/hidapi/commits/master 16 | 17 | 18 | Java binding Authors: 19 | 20 | Vadim Zaliva 21 | Alex Sova 22 | 23 | developemnt of Java bindings sponsored Codeminders: www.codeminders.com 24 | -------------------------------------------------------------------------------- /LICENSE-bsd.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Alan Ott, Signal 11 Software 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of Signal 11 Software nor the names of its 13 | contributors may be used to endorse or promote products derived from 14 | this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /LICENSE-orig.txt: -------------------------------------------------------------------------------- 1 | HIDAPI - Multi-Platform library for 2 | communication with HID devices. 3 | 4 | Copyright 2009, Alan Ott, Signal 11 Software. 5 | All Rights Reserved. 6 | 7 | This software may be used by anyone for any reason so 8 | long as the copyright notice in the source files 9 | remains intact. 10 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | HIDAPI can be used under one of three licenses. 2 | 3 | 1. The GNU Public License, version 3.0, in LICENSE-gpl3.txt 4 | 2. A BSD-Style License, in LICENSE-bsd.txt. 5 | 3. The more liberal original HIDAPI license. LICENSE-orig.txt 6 | 7 | The license chosen is at the discretion of the user of HIDAPI. For example: 8 | 1. An author of GPL software would likely use HIDAPI under the terms of the 9 | GPL. 10 | 11 | 2. An author of commercial closed-source software would likely use HIDAPI 12 | under the terms of the BSD-style license or the original HIDAPI license. 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is JNI wrapper around [C/C++ HIDAPI library](http://www.signal11.us/oss/hidapi/) providing simple java API to work with devices such as USB gamepads, joysticks, keyboards, mice on Mac, Linux and Windows. 2 | 3 | Please check out sources and see ReadMe for details. 4 | 5 | Developed by [Codeminders](http://www.codeminders.com). Commercial support options available. 6 | 7 | ## Support ## 8 | 9 | If you need a professional support or need to do a custom project based on JavaHIDAPI, 10 | please contact [Codeminders](http://www.codeminders.com/) for a quote. 11 | -------------------------------------------------------------------------------- /README.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeminders/javahidapi/ac7cf8790baf63a51ee53617a5596baeac28942b/README.pdf -------------------------------------------------------------------------------- /bin/com/codeminders/hidapi/ClassPathLibraryLoader.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeminders/javahidapi/ac7cf8790baf63a51ee53617a5596baeac28942b/bin/com/codeminders/hidapi/ClassPathLibraryLoader.class -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /hidapi/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /hidapi/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | hidapi 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /hidapi/hidapi.h: -------------------------------------------------------------------------------- 1 | /******************************************************* 2 | HIDAPI - Multi-Platform library for 3 | communication with HID devices. 4 | 5 | Alan Ott 6 | Signal 11 Software 7 | 8 | 8/22/2009 9 | 10 | Copyright 2009, All Rights Reserved. 11 | 12 | At the discretion of the user of this library, 13 | this software may be licensed under the terms of the 14 | GNU Public License v3, a BSD-Style license, or the 15 | original HIDAPI license as outlined in the LICENSE.txt, 16 | LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt 17 | files located at the root of the source distribution. 18 | These files may also be found in the public source 19 | code repository located at: 20 | http://github.com/signal11/hidapi . 21 | ********************************************************/ 22 | 23 | /** @file 24 | * @defgroup API hidapi API 25 | */ 26 | 27 | #ifndef HIDAPI_H__ 28 | #define HIDAPI_H__ 29 | 30 | #include 31 | 32 | #ifdef _WIN32 33 | #define HID_API_EXPORT __declspec(dllexport) 34 | #define HID_API_CALL 35 | #else 36 | #define HID_API_EXPORT /**< API export macro */ 37 | #define HID_API_CALL /**< API call macro */ 38 | #endif 39 | 40 | #define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/ 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | struct hid_device_; 46 | typedef struct hid_device_ hid_device; /**< opaque hidapi structure */ 47 | 48 | /** hidapi info structure */ 49 | struct hid_device_info { 50 | /** Platform-specific device path */ 51 | char *path; 52 | /** Device Vendor ID */ 53 | unsigned short vendor_id; 54 | /** Device Product ID */ 55 | unsigned short product_id; 56 | /** Serial Number */ 57 | wchar_t *serial_number; 58 | /** Device Release Number in binary-coded decimal, 59 | also known as Device Version Number */ 60 | unsigned short release_number; 61 | /** Manufacturer String */ 62 | wchar_t *manufacturer_string; 63 | /** Product string */ 64 | wchar_t *product_string; 65 | /** Usage Page for this Device/Interface 66 | (Windows/Mac only). */ 67 | unsigned short usage_page; 68 | /** Usage for this Device/Interface 69 | (Windows/Mac only).*/ 70 | unsigned short usage; 71 | /** The USB interface which this logical device 72 | represents. Valid on both Linux implementations 73 | in all cases, and valid on the Windows implementation 74 | only if the device contains more than one interface. */ 75 | int interface_number; 76 | 77 | /** Pointer to the next device */ 78 | struct hid_device_info *next; 79 | }; 80 | 81 | 82 | /** @brief Initialize the HIDAPI library. 83 | 84 | This function initializes the HIDAPI library. Calling it is not 85 | strictly necessary, as it will be called automatically by 86 | hid_enumerate() and any of the hid_open_*() functions if it is 87 | needed. This function should be called at the beginning of 88 | execution however, if there is a chance of HIDAPI handles 89 | being opened by different threads simultaneously. 90 | 91 | @ingroup API 92 | 93 | @returns 94 | This function returns 0 on success and -1 on error. 95 | */ 96 | int HID_API_EXPORT HID_API_CALL hid_init(void); 97 | 98 | /** @brief Finalize the HIDAPI library. 99 | 100 | This function frees all of the static data associated with 101 | HIDAPI. It should be called at the end of execution to avoid 102 | memory leaks. 103 | 104 | @ingroup API 105 | 106 | @returns 107 | This function returns 0 on success and -1 on error. 108 | */ 109 | int HID_API_EXPORT HID_API_CALL hid_exit(void); 110 | 111 | /** @brief Enumerate the HID Devices. 112 | 113 | This function returns a linked list of all the HID devices 114 | attached to the system which match vendor_id and product_id. 115 | If @p vendor_id and @p product_id are both set to 0, then 116 | all HID devices will be returned. 117 | 118 | @ingroup API 119 | @param vendor_id The Vendor ID (VID) of the types of device 120 | to open. 121 | @param product_id The Product ID (PID) of the types of 122 | device to open. 123 | 124 | @returns 125 | This function returns a pointer to a linked list of type 126 | struct #hid_device, containing information about the HID devices 127 | attached to the system, or NULL in the case of failure. Free 128 | this linked list by calling hid_free_enumeration(). 129 | */ 130 | struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id); 131 | 132 | /** @brief Free an enumeration Linked List 133 | 134 | This function frees a linked list created by hid_enumerate(). 135 | 136 | @ingroup API 137 | @param devs Pointer to a list of struct_device returned from 138 | hid_enumerate(). 139 | */ 140 | void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs); 141 | 142 | /** @brief Open a HID device using a Vendor ID (VID), Product ID 143 | (PID) and optionally a serial number. 144 | 145 | If @p serial_number is NULL, the first device with the 146 | specified VID and PID is opened. 147 | 148 | @ingroup API 149 | @param vendor_id The Vendor ID (VID) of the device to open. 150 | @param product_id The Product ID (PID) of the device to open. 151 | @param serial_number The Serial Number of the device to open 152 | (Optionally NULL). 153 | 154 | @returns 155 | This function returns a pointer to a #hid_device object on 156 | success or NULL on failure. 157 | */ 158 | HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number); 159 | 160 | /** @brief Open a HID device by its path name. 161 | 162 | The path name be determined by calling hid_enumerate(), or a 163 | platform-specific path name can be used (eg: /dev/hidraw0 on 164 | Linux). 165 | 166 | @ingroup API 167 | @param path The path name of the device to open 168 | 169 | @returns 170 | This function returns a pointer to a #hid_device object on 171 | success or NULL on failure. 172 | */ 173 | HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path); 174 | 175 | /** @brief Write an Output report to a HID device. 176 | 177 | The first byte of @p data[] must contain the Report ID. For 178 | devices which only support a single report, this must be set 179 | to 0x0. The remaining bytes contain the report data. Since 180 | the Report ID is mandatory, calls to hid_write() will always 181 | contain one more byte than the report contains. For example, 182 | if a hid report is 16 bytes long, 17 bytes must be passed to 183 | hid_write(), the Report ID (or 0x0, for devices with a 184 | single report), followed by the report data (16 bytes). In 185 | this example, the length passed in would be 17. 186 | 187 | hid_write() will send the data on the first OUT endpoint, if 188 | one exists. If it does not, it will send the data through 189 | the Control Endpoint (Endpoint 0). 190 | 191 | @ingroup API 192 | @param device A device handle returned from hid_open(). 193 | @param data The data to send, including the report number as 194 | the first byte. 195 | @param length The length in bytes of the data to send. 196 | 197 | @returns 198 | This function returns the actual number of bytes written and 199 | -1 on error. 200 | */ 201 | int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length); 202 | 203 | /** @brief Read an Input report from a HID device with timeout. 204 | 205 | Input reports are returned 206 | to the host through the INTERRUPT IN endpoint. The first byte will 207 | contain the Report number if the device uses numbered reports. 208 | 209 | @ingroup API 210 | @param device A device handle returned from hid_open(). 211 | @param data A buffer to put the read data into. 212 | @param length The number of bytes to read. For devices with 213 | multiple reports, make sure to read an extra byte for 214 | the report number. 215 | @param milliseconds timeout in milliseconds or -1 for blocking wait. 216 | 217 | @returns 218 | This function returns the actual number of bytes read and 219 | -1 on error. 220 | */ 221 | int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds); 222 | 223 | /** @brief Read an Input report from a HID device. 224 | 225 | Input reports are returned 226 | to the host through the INTERRUPT IN endpoint. The first byte will 227 | contain the Report number if the device uses numbered reports. 228 | 229 | @ingroup API 230 | @param device A device handle returned from hid_open(). 231 | @param data A buffer to put the read data into. 232 | @param length The number of bytes to read. For devices with 233 | multiple reports, make sure to read an extra byte for 234 | the report number. 235 | 236 | @returns 237 | This function returns the actual number of bytes read and 238 | -1 on error. 239 | */ 240 | int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length); 241 | 242 | /** @brief Set the device handle to be non-blocking. 243 | 244 | In non-blocking mode calls to hid_read() will return 245 | immediately with a value of 0 if there is no data to be 246 | read. In blocking mode, hid_read() will wait (block) until 247 | there is data to read before returning. 248 | 249 | Nonblocking can be turned on and off at any time. 250 | 251 | @ingroup API 252 | @param device A device handle returned from hid_open(). 253 | @param nonblock enable or not the nonblocking reads 254 | - 1 to enable nonblocking 255 | - 0 to disable nonblocking. 256 | 257 | @returns 258 | This function returns 0 on success and -1 on error. 259 | */ 260 | int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock); 261 | 262 | /** @brief Send a Feature report to the device. 263 | 264 | Feature reports are sent over the Control endpoint as a 265 | Set_Report transfer. The first byte of @p data[] must 266 | contain the Report ID. For devices which only support a 267 | single report, this must be set to 0x0. The remaining bytes 268 | contain the report data. Since the Report ID is mandatory, 269 | calls to hid_send_feature_report() will always contain one 270 | more byte than the report contains. For example, if a hid 271 | report is 16 bytes long, 17 bytes must be passed to 272 | hid_send_feature_report(): the Report ID (or 0x0, for 273 | devices which do not use numbered reports), followed by the 274 | report data (16 bytes). In this example, the length passed 275 | in would be 17. 276 | 277 | @ingroup API 278 | @param device A device handle returned from hid_open(). 279 | @param data The data to send, including the report number as 280 | the first byte. 281 | @param length The length in bytes of the data to send, including 282 | the report number. 283 | 284 | @returns 285 | This function returns the actual number of bytes written and 286 | -1 on error. 287 | */ 288 | int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length); 289 | 290 | /** @brief Get a feature report from a HID device. 291 | 292 | Make sure to set the first byte of @p data[] to the Report 293 | ID of the report to be read. Make sure to allow space for 294 | this extra byte in @p data[]. 295 | 296 | @ingroup API 297 | @param device A device handle returned from hid_open(). 298 | @param data A buffer to put the read data into, including 299 | the Report ID. Set the first byte of @p data[] to the 300 | Report ID of the report to be read. 301 | @param length The number of bytes to read, including an 302 | extra byte for the report ID. The buffer can be longer 303 | than the actual report. 304 | 305 | @returns 306 | This function returns the number of bytes read and 307 | -1 on error. 308 | */ 309 | int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length); 310 | 311 | /** @brief Close a HID device. 312 | 313 | @ingroup API 314 | @param device A device handle returned from hid_open(). 315 | */ 316 | void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device); 317 | 318 | /** @brief Get The Manufacturer String from a HID device. 319 | 320 | @ingroup API 321 | @param device A device handle returned from hid_open(). 322 | @param string A wide string buffer to put the data into. 323 | @param maxlen The length of the buffer in multiples of wchar_t. 324 | 325 | @returns 326 | This function returns 0 on success and -1 on error. 327 | */ 328 | int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen); 329 | 330 | /** @brief Get The Product String from a HID device. 331 | 332 | @ingroup API 333 | @param device A device handle returned from hid_open(). 334 | @param string A wide string buffer to put the data into. 335 | @param maxlen The length of the buffer in multiples of wchar_t. 336 | 337 | @returns 338 | This function returns 0 on success and -1 on error. 339 | */ 340 | int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen); 341 | 342 | /** @brief Get The Serial Number String from a HID device. 343 | 344 | @ingroup API 345 | @param device A device handle returned from hid_open(). 346 | @param string A wide string buffer to put the data into. 347 | @param maxlen The length of the buffer in multiples of wchar_t. 348 | 349 | @returns 350 | This function returns 0 on success and -1 on error. 351 | */ 352 | int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen); 353 | 354 | /** @brief Get a string from a HID device, based on its string index. 355 | 356 | @ingroup API 357 | @param device A device handle returned from hid_open(). 358 | @param string_index The index of the string to get. 359 | @param string A wide string buffer to put the data into. 360 | @param maxlen The length of the buffer in multiples of wchar_t. 361 | 362 | @returns 363 | This function returns 0 on success and -1 on error. 364 | */ 365 | int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen); 366 | 367 | /** @brief Get a string describing the last error which occurred. 368 | 369 | @ingroup API 370 | @param device A device handle returned from hid_open(). 371 | 372 | @returns 373 | This function returns a string containing the last error 374 | which occurred or NULL if none has occurred. 375 | */ 376 | HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device); 377 | 378 | #ifdef __cplusplus 379 | } 380 | #endif 381 | 382 | #endif 383 | 384 | -------------------------------------------------------------------------------- /hidtest/hidtest.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************* 2 | Windows HID simplification 3 | 4 | Alan Ott 5 | Signal 11 Software 6 | 7 | 8/22/2009 8 | 9 | Copyright 2009, All Rights Reserved. 10 | 11 | This contents of this file may be used by anyone 12 | for any reason without any conditions and may be 13 | used as a starting point for your own applications 14 | which use HIDAPI. 15 | ********************************************************/ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "hidapi.h" 22 | 23 | // Headers needed for sleeping. 24 | #ifdef _WIN32 25 | #include 26 | #else 27 | #include 28 | #endif 29 | 30 | int main(int argc, char* argv[]) 31 | { 32 | int res; 33 | unsigned char buf[256]; 34 | #define MAX_STR 255 35 | wchar_t wstr[MAX_STR]; 36 | hid_device *handle; 37 | int i; 38 | 39 | #ifdef WIN32 40 | UNREFERENCED_PARAMETER(argc); 41 | UNREFERENCED_PARAMETER(argv); 42 | #endif 43 | 44 | struct hid_device_info *devs, *cur_dev; 45 | 46 | devs = hid_enumerate(0x0, 0x0); 47 | cur_dev = devs; 48 | while (cur_dev) { 49 | 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); 50 | printf("\n"); 51 | printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string); 52 | printf(" Product: %ls\n", cur_dev->product_string); 53 | printf(" Release: %hx\n", cur_dev->release_number); 54 | printf(" Interface: %d\n", cur_dev->interface_number); 55 | printf("\n"); 56 | cur_dev = cur_dev->next; 57 | } 58 | hid_free_enumeration(devs); 59 | 60 | // Set up the command buffer. 61 | memset(buf,0x00,sizeof(buf)); 62 | buf[0] = 0x01; 63 | buf[1] = 0x81; 64 | 65 | 66 | // Open the device using the VID, PID, 67 | // and optionally the Serial number. 68 | ////handle = hid_open(0x4d8, 0x3f, L"12345"); 69 | handle = hid_open(0x54c, 0x268, NULL); 70 | if (!handle) { 71 | printf("unable to open device\n"); 72 | return 1; 73 | } 74 | 75 | // Read the Manufacturer String 76 | wstr[0] = 0x0000; 77 | res = hid_get_manufacturer_string(handle, wstr, MAX_STR); 78 | if (res < 0) 79 | printf("Unable to read manufacturer string\n"); 80 | printf("Manufacturer String: %ls\n", wstr); 81 | 82 | // Read the Product String 83 | wstr[0] = 0x0000; 84 | res = hid_get_product_string(handle, wstr, MAX_STR); 85 | if (res < 0) 86 | printf("Unable to read product string\n"); 87 | printf("Product String: %ls\n", wstr); 88 | 89 | // Read the Serial Number String 90 | wstr[0] = 0x0000; 91 | res = hid_get_serial_number_string(handle, wstr, MAX_STR); 92 | if (res < 0) 93 | printf("Unable to read serial number string\n"); 94 | printf("Serial Number String: (%d) %ls", wstr[0], wstr); 95 | printf("\n"); 96 | 97 | // Read Indexed String 1 98 | wstr[0] = 0x0000; 99 | res = hid_get_indexed_string(handle, 1, wstr, MAX_STR); 100 | if (res < 0) 101 | printf("Unable to read indexed string 1\n"); 102 | printf("Indexed String 1: %ls\n", wstr); 103 | 104 | // Set the hid_read() function to be non-blocking. 105 | hid_set_nonblocking(handle, 1); 106 | 107 | memset(buf,0,sizeof(buf)); 108 | 109 | // Read requested state. hid_read() has been set to be 110 | // non-blocking by the call to hid_set_nonblocking() above. 111 | // This loop demonstrates the non-blocking nature of hid_read(). 112 | res = 0; 113 | while (res == 0) { 114 | res = hid_read(handle, buf, sizeof(buf)); 115 | if (res == 0) 116 | printf("waiting...\n"); 117 | if (res < 0) 118 | printf("Unable to read()\n"); 119 | #ifdef WIN32 120 | Sleep(500); 121 | #else 122 | usleep(500*1000); 123 | #endif 124 | } 125 | 126 | printf("Data read:\n "); 127 | // Print out the returned buffer. 128 | for (i = 0; i < res; i++) 129 | printf("%02hhx ", buf[i]); 130 | printf("\n"); 131 | 132 | hid_close(handle); 133 | 134 | /* Free static HIDAPI objects. */ 135 | hid_exit(); 136 | 137 | #ifdef WIN32 138 | system("pause"); 139 | #endif 140 | 141 | return 0; 142 | } 143 | -------------------------------------------------------------------------------- /jni-impl/HIDDevice.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include "hidapi/hidapi.h" 7 | #include "hid-java.h" 8 | 9 | #define MAX_BUFFER_SIZE 2014 10 | 11 | static hid_device* getPeer(JNIEnv *env, jobject self) 12 | { 13 | jclass cls = env->FindClass(DEV_CLASS); 14 | assert(cls!=NULL); 15 | if (cls == NULL) 16 | return NULL; 17 | jfieldID fid = env->GetFieldID(cls, "peer", "J"); 18 | return (hid_device*)(env->GetLongField(self, fid)); 19 | } 20 | 21 | static void setPeer(JNIEnv *env, jobject self, hid_device *peer) 22 | { 23 | jclass cls = env->FindClass(DEV_CLASS); 24 | assert(cls!=NULL); 25 | if (cls == NULL) 26 | return; //TODO: exception will be raised by FindClass 27 | jfieldID fid = env->GetFieldID(cls, "peer", "J"); 28 | jlong peerj = (jlong)peer; 29 | env->SetLongField(self, fid, peerj); 30 | } 31 | 32 | JNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDDevice_close 33 | (JNIEnv *env, jobject self) 34 | { 35 | hid_device *peer = getPeer(env, self); 36 | if(!peer) 37 | { 38 | throwIOException(env, peer); 39 | return; /* not an error, freed previously */ 40 | } 41 | hid_close(peer); 42 | setPeer(env, self, NULL); 43 | } 44 | 45 | JNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_write 46 | (JNIEnv *env, jobject self, jbyteArray data) 47 | { 48 | hid_device *peer = getPeer(env, self); 49 | if(!peer) 50 | { 51 | throwIOException(env, peer); 52 | return 0; /* not an error, freed previously */ 53 | } 54 | 55 | jsize bufsize = env->GetArrayLength(data); 56 | jbyte *buf = env->GetByteArrayElements(data, NULL); 57 | int res = hid_write(peer, (const unsigned char*) buf, bufsize); 58 | env->ReleaseByteArrayElements(data, buf, JNI_ABORT); 59 | if(res==-1) 60 | { 61 | throwIOException(env, peer); 62 | return 0; /* not an error, freed previously */ 63 | } 64 | return res; 65 | } 66 | 67 | JNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_read 68 | (JNIEnv *env, jobject self, jbyteArray data) 69 | { 70 | hid_device *peer = getPeer(env, self); 71 | if(!peer) 72 | { 73 | throwIOException(env, peer); 74 | return 0; /* not an error, freed previously */ 75 | } 76 | 77 | jsize bufsize = env->GetArrayLength(data); 78 | jbyte *buf = env->GetByteArrayElements(data, NULL); 79 | int read = hid_read(peer, (unsigned char*) buf, bufsize); 80 | env->ReleaseByteArrayElements(data, buf, read==-1?JNI_ABORT:0); 81 | if(read==-1) 82 | { 83 | throwIOException(env, peer); 84 | return 0; /* not an error, freed previously */ 85 | } 86 | return read; 87 | } 88 | 89 | JNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_readTimeout 90 | (JNIEnv *env, jobject self, jbyteArray data, jint milliseconds ) 91 | { 92 | hid_device *peer = getPeer(env, self); 93 | if(!peer) 94 | { 95 | throwIOException(env, peer); 96 | return 0; /* not an error, freed previously */ 97 | } 98 | 99 | jsize bufsize = env->GetArrayLength(data); 100 | jbyte *buf = env->GetByteArrayElements(data, NULL); 101 | int read = hid_read_timeout(peer, (unsigned char*) buf, bufsize, milliseconds); 102 | env->ReleaseByteArrayElements(data, buf, read==-1?JNI_ABORT:0); 103 | if(read == 0) /* time out */ 104 | { 105 | return 0; 106 | } 107 | else if(read == -1) 108 | { 109 | throwIOException(env, peer); 110 | return 0; /* not an error, freed previously */ 111 | } 112 | return read; 113 | } 114 | 115 | JNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDDevice_enableBlocking 116 | (JNIEnv *env, jobject self) 117 | { 118 | hid_device *peer = getPeer(env, self); 119 | if(!peer) 120 | { 121 | throwIOException(env, peer); 122 | return; /* not an error, freed previously */ 123 | } 124 | int res = hid_set_nonblocking(peer,0); 125 | if(res!=0) 126 | { 127 | throwIOException(env, peer); 128 | return; /* not an error, freed previously */ 129 | } 130 | } 131 | 132 | JNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDDevice_disableBlocking 133 | (JNIEnv *env, jobject self) 134 | { 135 | hid_device *peer = getPeer(env, self); 136 | if(!peer) 137 | { 138 | throwIOException(env, peer); 139 | return; /* not an error, freed previously */ 140 | } 141 | int res = hid_set_nonblocking(peer, 1); 142 | if(res!=0) 143 | { 144 | throwIOException(env, peer); 145 | return; /* not an error, freed previously */ 146 | } 147 | } 148 | 149 | JNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_sendFeatureReport 150 | (JNIEnv *env, jobject self, jbyteArray data) 151 | { 152 | hid_device *peer = getPeer(env, self); 153 | if(!peer) 154 | { 155 | throwIOException(env, peer); 156 | return 0; /* not an error, freed previously */ 157 | } 158 | jsize bufsize = env->GetArrayLength(data); 159 | jbyte *buf = env->GetByteArrayElements(data, NULL); 160 | int res = hid_send_feature_report(peer, (const unsigned char*) buf, bufsize); 161 | env->ReleaseByteArrayElements(data, buf, JNI_ABORT); 162 | if(res==-1) 163 | { 164 | throwIOException(env, peer); 165 | return 0; /* not an error, freed previously */ 166 | } 167 | 168 | return res; 169 | } 170 | 171 | JNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_getFeatureReport 172 | (JNIEnv *env, jobject self, jbyteArray data) 173 | { 174 | hid_device *peer = getPeer(env, self); 175 | if(!peer) 176 | { 177 | throwIOException(env, peer); 178 | return 0; /* not an error, freed previously */ 179 | } 180 | 181 | jsize bufsize = env->GetArrayLength(data); 182 | jbyte *buf = env->GetByteArrayElements(data, NULL); 183 | int res = hid_get_feature_report(peer, (unsigned char*) buf, bufsize); 184 | env->ReleaseByteArrayElements(data, buf, res==-1?JNI_ABORT:0); 185 | if(res==-1) 186 | { 187 | throwIOException(env, peer); 188 | return 0; /* not an error, freed previously */ 189 | } 190 | 191 | return res; 192 | } 193 | 194 | JNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getManufacturerString 195 | (JNIEnv *env, jobject self) 196 | { 197 | hid_device *peer = getPeer(env, self); 198 | if(!peer) 199 | { 200 | throwIOException(env, peer); 201 | return NULL; /* not an error, freed previously */ 202 | } 203 | 204 | wchar_t data[MAX_BUFFER_SIZE]; 205 | int res = hid_get_manufacturer_string(peer, data, MAX_BUFFER_SIZE); 206 | if(res < 0) 207 | { 208 | /* We decided not to treat this as an error, but return an empty string in this case 209 | throwIOException(env, peer); 210 | return NULL; 211 | */ 212 | data[0] = 0; 213 | } 214 | 215 | char *u8 = convertToUTF8(env, data); 216 | jstring string = env->NewStringUTF(u8); 217 | free(u8); 218 | 219 | return string; 220 | } 221 | 222 | #include 223 | 224 | JNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getProductString 225 | (JNIEnv *env, jobject self) 226 | { 227 | hid_device *peer = getPeer(env, self); 228 | if(!peer) 229 | { 230 | throwIOException(env, peer); 231 | return NULL; /* not an error, freed previously */ 232 | } 233 | 234 | wchar_t data[MAX_BUFFER_SIZE]; 235 | int res = hid_get_product_string(peer, data, MAX_BUFFER_SIZE); 236 | if(res < 0) 237 | { 238 | /* We decided not to treat this as an error, but return an empty string in this case 239 | throwIOException(env, peer); 240 | return NULL; 241 | */ 242 | data[0] = 0; 243 | } 244 | 245 | char *u8 = convertToUTF8(env, data); 246 | jstring string = env->NewStringUTF(u8); 247 | free(u8); 248 | 249 | return string; 250 | } 251 | 252 | JNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getSerialNumberString 253 | (JNIEnv *env, jobject self) 254 | { 255 | hid_device *peer = getPeer(env, self); 256 | if(!peer) 257 | { 258 | throwIOException(env, peer); 259 | return NULL; /* not an error, freed previously */ 260 | } 261 | 262 | wchar_t data[MAX_BUFFER_SIZE]; 263 | int res = hid_get_serial_number_string(peer, data, MAX_BUFFER_SIZE); 264 | if(res < 0) 265 | { 266 | /* We decided not to treat this as an error, but return an empty string in this case 267 | throwIOException(env, peer); 268 | return NULL; 269 | */ 270 | data[0] = 0; 271 | } 272 | 273 | char *u8 = convertToUTF8(env, data); 274 | jstring string = env->NewStringUTF(u8); 275 | free(u8); 276 | 277 | return string; 278 | } 279 | 280 | JNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getIndexedString 281 | (JNIEnv *env, jobject self, jint index) 282 | { 283 | hid_device *peer = getPeer(env, self); 284 | if(!peer) 285 | { 286 | throwIOException(env, peer); 287 | return NULL; /* not an error, freed previously */ 288 | } 289 | 290 | wchar_t data[MAX_BUFFER_SIZE]; 291 | int res = hid_get_indexed_string(peer, index, data, MAX_BUFFER_SIZE); 292 | if(res < 0) 293 | { 294 | /* We decided not to treat this as an error, but return an empty string in this case 295 | throwIOException(env, peer); 296 | return NULL; 297 | */ 298 | data[0] = 0; 299 | } 300 | 301 | char *u8 = convertToUTF8(env, data); 302 | jstring string = env->NewStringUTF(u8); 303 | free(u8); 304 | 305 | return string; 306 | } 307 | -------------------------------------------------------------------------------- /jni-impl/HIDDeviceInfo.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "jni-stubs/com_codeminders_hidapi_HIDDeviceInfo.h" 3 | #include "hidapi/hidapi.h" 4 | #include "hid-java.h" 5 | 6 | JNIEXPORT jobject JNICALL Java_com_codeminders_hidapi_HIDDeviceInfo_open 7 | (JNIEnv *env, jobject obj) 8 | { 9 | jclass thiscls = env->FindClass(DEVINFO_CLASS); 10 | if (!thiscls) 11 | return NULL; 12 | 13 | jfieldID path_field_id = env->GetFieldID(thiscls, "path", "Ljava/lang/String;"); 14 | jstring jpathstr = (jstring) env->GetObjectField(obj, path_field_id); 15 | 16 | const char *jpathbytes = env->GetStringUTFChars(jpathstr, NULL); 17 | if(!jpathbytes) 18 | return NULL; 19 | 20 | hid_device *dev = hid_open_path(jpathbytes); 21 | env->ReleaseStringUTFChars(jpathstr, jpathbytes); 22 | if(!dev) 23 | return NULL; 24 | 25 | jlong peer = (jlong)dev; 26 | // Construct and return object 27 | jclass cls = env->FindClass(DEV_CLASS); 28 | if (cls == NULL) { 29 | return NULL; /* exception thrown */ 30 | } 31 | 32 | jmethodID cid = env->GetMethodID(cls, 33 | "", "(J)V"); 34 | if (cid == NULL) { 35 | return NULL; /* exception thrown */ 36 | } 37 | return env->NewObject(cls, cid, peer); 38 | } 39 | -------------------------------------------------------------------------------- /jni-impl/HIDManager.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include "jni-stubs/com_codeminders_hidapi_HIDManager.h" 7 | #include "hidapi/hidapi.h" 8 | #include "hid-java.h" 9 | 10 | #ifdef MAC_OS_X 11 | #include 12 | #include 13 | #include 14 | #endif 15 | 16 | #ifdef MAC_OS_X 17 | #define HID_RUN_LOOP 18 | #endif 19 | 20 | #define JNI_DEBUG 0 21 | 22 | 23 | static JNIEnv *m_env = NULL; 24 | static JavaVM *m_vm = NULL; 25 | 26 | /* JNI reference count */ 27 | static int jni_ref_count = 0; 28 | 29 | #ifdef HID_RUN_LOOP 30 | #define SLEEP_TIME 100 * 1000 31 | static volatile int squit = 0; 32 | static int hid_mgr_init = 0; 33 | static int cond = FALSE; 34 | static pthread_cond_t condition; 35 | static pthread_t runloop_thread = NULL; 36 | static CFRunLoopRef run_loop = NULL; 37 | static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 38 | 39 | #endif 40 | 41 | static int init_hid_mgr() 42 | { 43 | #ifdef HID_RUN_LOOP 44 | if(hid_mgr_init) 45 | { 46 | pthread_mutex_lock(&mutex); 47 | while(cond == FALSE){ 48 | pthread_cond_wait(&condition, &mutex); 49 | } 50 | pthread_mutex_unlock(&mutex); 51 | return 1; 52 | } 53 | return 0; 54 | #else 55 | return 1; 56 | #endif 57 | } 58 | 59 | #ifdef HID_RUN_LOOP 60 | 61 | static void *hid_runloop_thread(void *param) 62 | { 63 | SInt32 code = 0; 64 | 65 | if( NULL == m_env ) 66 | return NULL; 67 | 68 | int res = m_vm->AttachCurrentThread( (void**) &m_env, NULL ); 69 | if(res < 0){ 70 | #if JNI_DEBUG 71 | printf("Attached failed\n"); 72 | #endif 73 | return NULL; 74 | } 75 | 76 | run_loop = CFRunLoopGetCurrent(); 77 | 78 | pthread_mutex_lock(&mutex); 79 | 80 | if(hid_init() == -1){ 81 | pthread_cond_destroy(&condition); 82 | hid_mgr_init = 0; 83 | return NULL; 84 | } 85 | 86 | cond = true; 87 | pthread_cond_signal(&condition); 88 | pthread_mutex_unlock(&mutex); 89 | while(!squit) 90 | { 91 | code = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); 92 | if( code == kCFRunLoopRunFinished || code == kCFRunLoopRunStopped ) 93 | { 94 | break; 95 | } 96 | #if JNI_DEBUG 97 | printf("HID run loop thread\n"); 98 | #endif 99 | usleep(SLEEP_TIME); 100 | } 101 | if(m_vm){ 102 | m_vm->DetachCurrentThread(); 103 | } 104 | return NULL; 105 | } 106 | 107 | static int hid_runloop_startup() 108 | { 109 | if(hid_mgr_init) 110 | return 0; 111 | 112 | hid_mgr_init = 1; 113 | 114 | if(squit) 115 | { 116 | pthread_cond_destroy(&condition); 117 | pthread_join(runloop_thread, NULL); 118 | squit = 0; 119 | } 120 | else 121 | { 122 | pthread_attr_t attr; 123 | pthread_attr_init( &attr ); 124 | pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); 125 | pthread_cond_init(&condition, NULL); 126 | squit = 0; 127 | pthread_create(&runloop_thread, &attr, hid_runloop_thread, NULL); 128 | } 129 | hid_mgr_init = 1; 130 | return 0; 131 | } 132 | 133 | static void hid_runloop_exit() 134 | { 135 | squit = 1; 136 | pthread_cond_destroy(&condition); 137 | pthread_join(runloop_thread, NULL); 138 | m_env = NULL; 139 | m_vm = NULL; 140 | } 141 | 142 | static int hid_init_loop() 143 | { 144 | return hid_runloop_startup(); 145 | } 146 | 147 | static int hid_exit_loop() 148 | { 149 | if(init_hid_mgr()){ 150 | hid_runloop_exit(); 151 | hid_mgr_init = 0; 152 | } 153 | return 0; 154 | } 155 | 156 | #endif 157 | 158 | static jobject getPeer(JNIEnv *env, jobject self) 159 | { 160 | jclass cls = env->FindClass(HID_MANAGER_CLASS); 161 | assert(cls!=NULL); 162 | if (cls == NULL) 163 | return NULL; 164 | jfieldID fid = env->GetFieldID(cls, "peer", "J"); 165 | return (jobject)(env->GetLongField(self, fid)); 166 | } 167 | 168 | static void setPeer(JNIEnv *env, jobject self, jobject peer) 169 | { 170 | jclass cls = env->FindClass(HID_MANAGER_CLASS); 171 | assert(cls!=NULL); 172 | if (cls == NULL) 173 | return; 174 | jfieldID fid = env->GetFieldID(cls, "peer", "J"); 175 | jlong peerj = (jlong)peer; 176 | env->SetLongField(self, fid, peerj); 177 | } 178 | 179 | static void setIntField(JNIEnv *env, 180 | jclass cls, 181 | jobject obj, 182 | const char *name, 183 | int val) 184 | { 185 | jfieldID fid = env->GetFieldID(cls, name, "I"); 186 | env->SetIntField(obj, fid, val); 187 | } 188 | 189 | static void setStringField(JNIEnv *env, 190 | jclass cls, 191 | jobject obj, 192 | const char *name, 193 | const char *val) 194 | { 195 | jfieldID fid = env->GetFieldID(cls, name, "Ljava/lang/String;"); 196 | env->SetObjectField(obj, fid, val ? env->NewStringUTF(val) : NULL); 197 | } 198 | 199 | static void setUStringField(JNIEnv *env, 200 | jclass cls, 201 | jobject obj, 202 | const char *name, 203 | const wchar_t *val) 204 | { 205 | jfieldID fid = env->GetFieldID(cls, name, "Ljava/lang/String;"); 206 | 207 | if(val) 208 | { 209 | char *u8 = convertToUTF8(env, val); 210 | env->SetObjectField(obj, fid, env->NewStringUTF(u8)); 211 | free(u8); 212 | } 213 | else 214 | env->SetObjectField(obj, fid, NULL); 215 | } 216 | 217 | 218 | static jobject createHIDDeviceInfo(JNIEnv *env, jclass cls, struct hid_device_info *dev) 219 | { 220 | jmethodID cid = env->GetMethodID(cls, "", "()V"); 221 | if (cid == NULL) 222 | return NULL; /* exception thrown. */ 223 | 224 | if (dev == NULL) 225 | return NULL; 226 | 227 | jobject result = env->NewObject(cls, cid); 228 | 229 | setIntField(env, cls, result, "vendor_id", dev->vendor_id); 230 | setIntField(env, cls, result, "product_id", dev->product_id); 231 | setIntField(env, cls, result, "release_number", dev->release_number); 232 | setIntField(env, cls, result, "usage_page", dev->usage_page); 233 | setIntField(env, cls, result, "usage", dev->usage); 234 | setIntField(env, cls, result, "interface_number", dev->interface_number); 235 | 236 | setStringField(env, cls, result, "path", dev->path); 237 | setUStringField(env, cls, result, "serial_number", dev->serial_number); 238 | setUStringField(env, cls, result, "manufacturer_string", dev->manufacturer_string); 239 | setUStringField(env, cls, result, "product_string", dev->product_string); 240 | 241 | return result; 242 | } 243 | JNIEXPORT jobjectArray JNICALL 244 | Java_com_codeminders_hidapi_HIDManager_listDevices(JNIEnv *env, jobject obj) 245 | { 246 | struct hid_device_info *devs, *cur_dev; 247 | int res = 0; 248 | 249 | #ifdef HID_RUN_LOOP 250 | res = hid_init_loop(); 251 | #else 252 | res = hid_init(); 253 | #endif 254 | if(res != 0){ 255 | throwIOException(env, NULL); 256 | return NULL; 257 | } 258 | if(!init_hid_mgr()) 259 | { 260 | throwIOException(env, NULL); 261 | return NULL; 262 | } 263 | 264 | devs = hid_enumerate(0x0, 0x0); 265 | if(devs == NULL) 266 | { 267 | /* no exception thrown */ 268 | //throwIOException(env, NULL); 269 | #if JNI_DEBUG 270 | printf("No attached devices\n"); 271 | #endif 272 | return NULL; 273 | } 274 | 275 | cur_dev = devs; 276 | int size=0; 277 | while(cur_dev) 278 | { 279 | size++; 280 | cur_dev = cur_dev->next; 281 | } 282 | 283 | jclass infoCls = env->FindClass(DEVINFO_CLASS); 284 | if (infoCls == NULL) { 285 | return NULL; /* exception thrown */ 286 | } 287 | jobjectArray result= env->NewObjectArray(size, infoCls, NULL); 288 | cur_dev = devs; 289 | int i=0; 290 | while(cur_dev) 291 | { 292 | jobject x = createHIDDeviceInfo(env, infoCls, cur_dev); 293 | if(x == NULL) 294 | return NULL; /* exception thrown */ 295 | 296 | env->SetObjectArrayElement(result, i, x); 297 | env->DeleteLocalRef(x); 298 | i++; 299 | cur_dev = cur_dev->next; 300 | } 301 | hid_free_enumeration(devs); 302 | 303 | return result; 304 | } 305 | 306 | JNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDManager_init(JNIEnv *env, jobject obj) 307 | { 308 | int res = 0; 309 | jobject jobjRef = 0; 310 | if(NULL == m_env) 311 | { 312 | m_env = env; 313 | m_env->GetJavaVM( &m_vm ); 314 | } 315 | 316 | if(jni_ref_count == 0) 317 | { 318 | #ifdef HID_RUN_LOOP 319 | res = hid_init_loop(); 320 | #else 321 | res = hid_init(); 322 | #endif 323 | } 324 | if(res !=0 ) 325 | { 326 | throwIOException(env, NULL); 327 | return; 328 | } 329 | 330 | jobjRef = env->NewGlobalRef(obj); 331 | setPeer(env, obj, jobjRef); 332 | #if JNI_DEBUG 333 | printf("JNI - init peer(objRef) = %p \n", jobjRef); 334 | #endif 335 | 336 | jni_ref_count++; 337 | } 338 | 339 | JNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDManager_release(JNIEnv *env, jobject obj ) 340 | { 341 | int res = 0; 342 | jobject jobjRef = (jobject)getPeer(env, obj); 343 | #if JNI_DEBUG 344 | printf("JNI - release peer(jobjRef) = %p \n", jobjRef); 345 | #endif 346 | if(jobjRef){ 347 | env->DeleteGlobalRef(jobjRef); 348 | setPeer(env,obj,0); 349 | jni_ref_count--; 350 | } 351 | #if JNI_DEBUG 352 | printf("jni_ref_count = %d\n", jni_ref_count); 353 | #endif 354 | if(jni_ref_count>0){ 355 | return; 356 | } 357 | #ifdef HID_RUN_LOOP 358 | res = hid_exit_loop(); 359 | #else 360 | res = hid_exit(); 361 | #endif 362 | if(res !=0 ) 363 | { 364 | throwIOException(env, NULL); 365 | } 366 | #if JNI_DEBUG 367 | printf("JNI Release library!\n"); 368 | #endif 369 | } 370 | -------------------------------------------------------------------------------- /jni-impl/hid-java.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifdef _WIN32 6 | #include 7 | #else 8 | #include 9 | #endif 10 | 11 | #include "hidapi/hidapi.h" 12 | #include "hid-java.h" 13 | 14 | void throwIOException(JNIEnv *env, hid_device *device) 15 | { 16 | jclass exceptionClass; 17 | char *message = NULL; 18 | 19 | exceptionClass = env->FindClass("java/io/IOException"); 20 | if (exceptionClass == NULL) 21 | { 22 | /* Unable to find the exception class, give up. */ 23 | assert(0); 24 | return; 25 | } 26 | 27 | if(device) 28 | { 29 | const wchar_t *error = hid_error(device); 30 | if(error) 31 | message = convertToUTF8(env, error); 32 | } 33 | 34 | env->ThrowNew(exceptionClass, message ? message : ""); 35 | 36 | free(message); 37 | } 38 | 39 | char* convertToUTF8(JNIEnv *env, const wchar_t *str) 40 | { 41 | #ifdef _WIN32 42 | int sz = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); 43 | char *ret = (char *) malloc(sz + 1); 44 | WideCharToMultiByte(CP_UTF8, 0, str, -1, ret, sz, NULL, NULL); 45 | return ret; 46 | #else 47 | iconv_t cd = iconv_open ("UTF-8", "WCHAR_T"); 48 | if (cd == (iconv_t) -1) 49 | { 50 | /* Something went wrong. We could not recover from this */ 51 | 52 | jclass exceptionClass = env->FindClass("java/lang/Error"); 53 | if (exceptionClass == NULL) 54 | { 55 | /* Unable to find the exception class, give up. */ 56 | assert(0); 57 | return NULL; 58 | } 59 | 60 | env->ThrowNew(exceptionClass, "iconv_open failed"); 61 | return NULL; 62 | } 63 | size_t len = wcslen(str); 64 | size_t ulen = len*sizeof(wchar_t); 65 | char *uval = (char *)str; 66 | 67 | size_t u8l = len*6+3; //BOM+chars 68 | char *u8 = (char *) malloc(u8l+1); 69 | char *u8p = u8; 70 | int nconv = iconv(cd, &uval, &ulen, &u8p, &u8l); 71 | if(nconv == (size_t)-1) 72 | { 73 | iconv_close(cd); 74 | free(u8); 75 | jclass exceptionClass = env->FindClass("java/lang/Error"); 76 | if (exceptionClass == NULL) 77 | { 78 | /* Unable to find the exception class, give up. */ 79 | assert(0); 80 | return NULL; 81 | } 82 | env->ThrowNew(exceptionClass, "iconv failed"); 83 | return NULL; 84 | } 85 | *u8p='\0'; 86 | 87 | iconv_close(cd); 88 | return u8; 89 | #endif 90 | } 91 | -------------------------------------------------------------------------------- /jni-impl/hid-java.h: -------------------------------------------------------------------------------- 1 | #ifndef __HID_JAVA_H__ 2 | #define __HID_JAVA_H__ 3 | 4 | #define DEV_CLASS "com/codeminders/hidapi/HIDDevice" 5 | #define DEVINFO_CLASS "com/codeminders/hidapi/HIDDeviceInfo" 6 | #define HID_MANAGER_CLASS "com/codeminders/hidapi/HIDManager" 7 | 8 | 9 | #if defined(__APPLE__) 10 | #define MAC_OS_X 11 | #endif 12 | 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | void throwIOException(JNIEnv *env, hid_device *device); 19 | 20 | /* this call allocate buffer dynamically. return value should be 21 | released with free() routine */ 22 | char* convertToUTF8(JNIEnv *env, const wchar_t *str); 23 | 24 | #ifdef __cplusplus 25 | } 26 | #endif 27 | 28 | #endif // __HID_JAVA_H__ 29 | -------------------------------------------------------------------------------- /jni-stubs/com_codeminders_hidapi_HIDDevice.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_codeminders_hidapi_HIDDevice */ 4 | 5 | #ifndef _Included_com_codeminders_hidapi_HIDDevice 6 | #define _Included_com_codeminders_hidapi_HIDDevice 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: com_codeminders_hidapi_HIDDevice 12 | * Method: close 13 | * Signature: ()V 14 | */ 15 | JNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDDevice_close 16 | (JNIEnv *, jobject); 17 | 18 | /* 19 | * Class: com_codeminders_hidapi_HIDDevice 20 | * Method: write 21 | * Signature: ([B)I 22 | */ 23 | JNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_write 24 | (JNIEnv *, jobject, jbyteArray); 25 | 26 | /* 27 | * Class: com_codeminders_hidapi_HIDDevice 28 | * Method: read 29 | * Signature: ([B)I 30 | */ 31 | JNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_read 32 | (JNIEnv *, jobject, jbyteArray); 33 | 34 | /* 35 | * Class: com_codeminders_hidapi_HIDDevice 36 | * Method: readTimeout 37 | * Signature: ([BI)I 38 | */ 39 | JNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_readTimeout 40 | (JNIEnv *, jobject, jbyteArray, jint); 41 | 42 | /* 43 | * Class: com_codeminders_hidapi_HIDDevice 44 | * Method: enableBlocking 45 | * Signature: ()V 46 | */ 47 | JNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDDevice_enableBlocking 48 | (JNIEnv *, jobject); 49 | 50 | /* 51 | * Class: com_codeminders_hidapi_HIDDevice 52 | * Method: disableBlocking 53 | * Signature: ()V 54 | */ 55 | JNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDDevice_disableBlocking 56 | (JNIEnv *, jobject); 57 | 58 | /* 59 | * Class: com_codeminders_hidapi_HIDDevice 60 | * Method: sendFeatureReport 61 | * Signature: ([B)I 62 | */ 63 | JNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_sendFeatureReport 64 | (JNIEnv *, jobject, jbyteArray); 65 | 66 | /* 67 | * Class: com_codeminders_hidapi_HIDDevice 68 | * Method: getFeatureReport 69 | * Signature: ([B)I 70 | */ 71 | JNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_getFeatureReport 72 | (JNIEnv *, jobject, jbyteArray); 73 | 74 | /* 75 | * Class: com_codeminders_hidapi_HIDDevice 76 | * Method: getManufacturerString 77 | * Signature: ()Ljava/lang/String; 78 | */ 79 | JNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getManufacturerString 80 | (JNIEnv *, jobject); 81 | 82 | /* 83 | * Class: com_codeminders_hidapi_HIDDevice 84 | * Method: getProductString 85 | * Signature: ()Ljava/lang/String; 86 | */ 87 | JNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getProductString 88 | (JNIEnv *, jobject); 89 | 90 | /* 91 | * Class: com_codeminders_hidapi_HIDDevice 92 | * Method: getSerialNumberString 93 | * Signature: ()Ljava/lang/String; 94 | */ 95 | JNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getSerialNumberString 96 | (JNIEnv *, jobject); 97 | 98 | /* 99 | * Class: com_codeminders_hidapi_HIDDevice 100 | * Method: getIndexedString 101 | * Signature: (I)Ljava/lang/String; 102 | */ 103 | JNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getIndexedString 104 | (JNIEnv *, jobject, jint); 105 | 106 | #ifdef __cplusplus 107 | } 108 | #endif 109 | #endif 110 | -------------------------------------------------------------------------------- /jni-stubs/com_codeminders_hidapi_HIDDeviceInfo.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_codeminders_hidapi_HIDDeviceInfo */ 4 | 5 | #ifndef _Included_com_codeminders_hidapi_HIDDeviceInfo 6 | #define _Included_com_codeminders_hidapi_HIDDeviceInfo 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: com_codeminders_hidapi_HIDDeviceInfo 12 | * Method: open 13 | * Signature: ()Lcom/codeminders/hidapi/HIDDevice; 14 | */ 15 | JNIEXPORT jobject JNICALL Java_com_codeminders_hidapi_HIDDeviceInfo_open 16 | (JNIEnv *, jobject); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | #endif 22 | -------------------------------------------------------------------------------- /jni-stubs/com_codeminders_hidapi_HIDManager.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_codeminders_hidapi_HIDManager */ 4 | 5 | #ifndef _Included_com_codeminders_hidapi_HIDManager 6 | #define _Included_com_codeminders_hidapi_HIDManager 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* Inaccessible static: instance */ 11 | /* 12 | * Class: com_codeminders_hidapi_HIDManager 13 | * Method: listDevices 14 | * Signature: ()[Lcom/codeminders/hidapi/HIDDeviceInfo; 15 | */ 16 | JNIEXPORT jobjectArray JNICALL Java_com_codeminders_hidapi_HIDManager_listDevices 17 | (JNIEnv *, jobject); 18 | 19 | /* 20 | * Class: com_codeminders_hidapi_HIDManager 21 | * Method: init 22 | * Signature: ()V 23 | */ 24 | JNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDManager_init 25 | (JNIEnv *, jobject); 26 | 27 | /* 28 | * Class: com_codeminders_hidapi_HIDManager 29 | * Method: release 30 | * Signature: ()V 31 | */ 32 | JNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDManager_release 33 | (JNIEnv *, jobject); 34 | 35 | #ifdef __cplusplus 36 | } 37 | #endif 38 | #endif 39 | -------------------------------------------------------------------------------- /lib/maven-ant-tasks-2.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeminders/javahidapi/ac7cf8790baf63a51ee53617a5596baeac28942b/lib/maven-ant-tasks-2.1.3.jar -------------------------------------------------------------------------------- /lib/native/linux/libhidapi-jni-32.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeminders/javahidapi/ac7cf8790baf63a51ee53617a5596baeac28942b/lib/native/linux/libhidapi-jni-32.so -------------------------------------------------------------------------------- /lib/native/linux/libhidapi-jni-64.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeminders/javahidapi/ac7cf8790baf63a51ee53617a5596baeac28942b/lib/native/linux/libhidapi-jni-64.so -------------------------------------------------------------------------------- /lib/native/mac/libhidapi-jni-32.jnilib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeminders/javahidapi/ac7cf8790baf63a51ee53617a5596baeac28942b/lib/native/mac/libhidapi-jni-32.jnilib -------------------------------------------------------------------------------- /lib/native/mac/libhidapi-jni-64.jnilib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeminders/javahidapi/ac7cf8790baf63a51ee53617a5596baeac28942b/lib/native/mac/libhidapi-jni-64.jnilib -------------------------------------------------------------------------------- /lib/native/win/hidapi-jni-32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeminders/javahidapi/ac7cf8790baf63a51ee53617a5596baeac28942b/lib/native/win/hidapi-jni-32.dll -------------------------------------------------------------------------------- /lib/native/win/hidapi-jni-64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeminders/javahidapi/ac7cf8790baf63a51ee53617a5596baeac28942b/lib/native/win/hidapi-jni-64.dll -------------------------------------------------------------------------------- /linux/Makefile: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Simple Makefile for HIDAPI test program 3 | # 4 | # Alan Ott 5 | # Signal 11 Software 6 | # 2010-06-01 7 | ########################################### 8 | 9 | 10 | JNIOBJS=HIDManager.o HIDDeviceInfo.o HIDDevice.o hid-java.o 11 | JAVA5HEADERS=-I/opt/jdk1.5.0/include/ -I/opt/jdk1.5.0/include/linux 12 | JAVA6HEADERS=-I/usr/lib/jvm/java-6-openjdk/include/ -I/usr/lib/jvm/java-6-openjdk/include/linux 13 | JAVA7HEADERS=-I/usr/lib/jvm/jdk1.7.0/include/ -I/usr/lib/jvm/jdk1.7.0/include/linux 14 | JNIINCLUDES=-I.. -I../jni-impl $(JAVA5HEADERS) $(JAVA6HEADERS) $(JAVA7HEADERS) 15 | JNILIBS= 16 | JNISHAREDLIB=libhidapi-jni.so 17 | JNISHAREDLIBVER=1.0 18 | 19 | CC=gcc 20 | CXX=g++ 21 | COBJS=hid-libusb.o 22 | CPPOBJS=../hidtest/hidtest.o 23 | OBJS=$(COBJS) $(CPPOBJS) $(JNIOBJS) 24 | CFLAGS+=-fPIC -I../hidapi -g -c `pkg-config libusb-1.0 --cflags` $(JNIINCLUDES) 25 | LIBS=`pkg-config libusb-1.0 libudev --libs` -ludev -lpthread $(JNILIBS) 26 | 27 | all: hidtest $(JNISHAREDLIB) 28 | 29 | $(JNISHAREDLIB): $(OBJS) 30 | $(CXX) -shared $(COBJS) $(JNIOBJS) $(LIBS) -o $(JNISHAREDLIB) 31 | 32 | hidtest: $(OBJS) 33 | g++ -Wall -g $^ $(LIBS) -o hidtest 34 | 35 | %.o: ../jni-impl/%.cpp 36 | $(CXX) $(CFLAGS) $< -o $@ 37 | 38 | $(COBJS): %.o: %.c 39 | $(CC) $(CFLAGS) $< -o $@ 40 | 41 | $(CPPOBJS): %.o: %.cpp 42 | $(CXX) $(CFLAGS) $< -o $@ 43 | 44 | clean: 45 | rm -f $(OBJS) hidtest $(JNISHAREDLIB) 46 | 47 | .PHONY: clean 48 | -------------------------------------------------------------------------------- /linux/README.txt: -------------------------------------------------------------------------------- 1 | 2 | There are two implementations of HIDAPI for Linux. One (hid.c) uses the 3 | Linux hidraw driver, and the other (hid-libusb.c) uses libusb. Which one you 4 | use depends on your application. Complete functionality of the hidraw 5 | version depends on patches to the Linux kernel which are not currently in 6 | the mainline. These patches have to do with sending and receiving feature 7 | reports. The libusb implementation uses libusb to talk directly to the 8 | device, bypassing any Linux HID driver. The disadvantage of the libusb 9 | version is that it will only work with USB devices, while the hidraw 10 | implementation will work with Bluetooth devices as well. 11 | 12 | To use HIDAPI, simply drop either hid.c or hid-libusb.c into your 13 | application and build using the build parameters in the Makefile. 14 | 15 | By default, on Linux, the Makefile in this directory is configured to use 16 | the libusb implementation. To switch to the hidraw implementation, simply 17 | change hid-libusb.c to hid.c in the Makefile. 18 | 19 | 20 | Libusb Implementation notes 21 | ---------------------------- 22 | For the libusb implementation, libusb-1.0 must be installed. Libusb 1.0 is 23 | different than the legacy libusb 0.1 which is installed on many systems. To 24 | install libusb-1.0 on Ubuntu and other Debian-based systems, run: 25 | sudo apt-get install libusb-1.0-0-dev 26 | 27 | 28 | Hidraw Implementation notes 29 | ---------------------------- 30 | For the hidraw implementation, libudev headers and libraries are required to 31 | build hidapi programs. To install libudev libraries on Ubuntu, 32 | and other Debian-based systems, run: 33 | sudo apt-get install libudev-dev 34 | 35 | On Redhat-based systems, run the following as root: 36 | yum install libudev-devel 37 | 38 | Unfortunately, the hidraw driver, which the linux version of hidapi is based 39 | on, contains bugs in kernel versions < 2.6.36, which the client application 40 | should be aware of. 41 | 42 | Bugs (hidraw implementation only): 43 | ----------------------------------- 44 | On Kernel versions < 2.6.34, if your device uses numbered reports, an extra 45 | byte will be returned at the beginning of all reports returned from read() 46 | for hidraw devices. This is worked around in the libary. No action should be 47 | necessary in the client library. 48 | 49 | On Kernel versions < 2.6.35, reports will only be sent using a Set_Report 50 | transfer on the CONTROL endpoint. No data will ever be sent on an Interrupt 51 | Out endpoint if one exists. This is fixed in 2.6.35. In 2.6.35, OUTPUT 52 | reports will be sent to the device on the first INTERRUPT OUT endpoint if it 53 | exists; If it does not exist, OUTPUT reports will be sent on the CONTROL 54 | endpoint. 55 | 56 | On Kernel versions < 2.6.36, add an extra byte containing the report number 57 | to sent reports if numbered reports are used, and the device does not 58 | contain an INTERRPUT OUT endpoint for OUTPUT transfers. For example, if 59 | your device uses numbered reports and wants to send {0x2 0xff 0xff 0xff} to 60 | the device (0x2 is the report number), you must send {0x2 0x2 0xff 0xff 61 | 0xff}. If your device has the optional Interrupt OUT endpoint, this does not 62 | apply (but really on 2.6.35 only, because 2.6.34 won't use the interrupt 63 | out endpoint). 64 | -------------------------------------------------------------------------------- /linux/hid.c: -------------------------------------------------------------------------------- 1 | /******************************************************* 2 | HIDAPI - Multi-Platform library for 3 | communication with HID devices. 4 | 5 | Alan Ott 6 | Signal 11 Software 7 | 8 | 8/22/2009 9 | Linux Version - 6/2/2009 10 | 11 | Copyright 2009, All Rights Reserved. 12 | 13 | At the discretion of the user of this library, 14 | this software may be licensed under the terms of the 15 | GNU Public License v3, a BSD-Style license, or the 16 | original HIDAPI license as outlined in the LICENSE.txt, 17 | LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt 18 | files located at the root of the source distribution. 19 | These files may also be found in the public source 20 | code repository located at: 21 | http://github.com/signal11/hidapi . 22 | ********************************************************/ 23 | 24 | /* C */ 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | /* Unix */ 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | /* Linux */ 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include "hidapi.h" 47 | 48 | /* Definitions from linux/hidraw.h. Since these are new, some distros 49 | may not have header files which contain them. */ 50 | #ifndef HIDIOCSFEATURE 51 | #define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len) 52 | #endif 53 | #ifndef HIDIOCGFEATURE 54 | #define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len) 55 | #endif 56 | 57 | 58 | /* USB HID device property names */ 59 | const char *device_string_names[] = { 60 | "manufacturer", 61 | "product", 62 | "serial", 63 | }; 64 | 65 | /* Symbolic names for the properties above */ 66 | enum device_string_id { 67 | DEVICE_STRING_MANUFACTURER, 68 | DEVICE_STRING_PRODUCT, 69 | DEVICE_STRING_SERIAL, 70 | 71 | DEVICE_STRING_COUNT, 72 | }; 73 | 74 | struct hid_device_ { 75 | int device_handle; 76 | int blocking; 77 | int uses_numbered_reports; 78 | }; 79 | 80 | 81 | static __u32 kernel_version = 0; 82 | 83 | hid_device *new_hid_device() 84 | { 85 | hid_device *dev = calloc(1, sizeof(hid_device)); 86 | dev->device_handle = -1; 87 | dev->blocking = 1; 88 | dev->uses_numbered_reports = 0; 89 | 90 | return dev; 91 | } 92 | 93 | static void register_error(hid_device *device, const char *op) 94 | { 95 | 96 | } 97 | 98 | /* The caller must free the returned string with free(). */ 99 | static wchar_t *utf8_to_wchar_t(const char *utf8) 100 | { 101 | wchar_t *ret = NULL; 102 | 103 | if (utf8) { 104 | size_t wlen = mbstowcs(NULL, utf8, 0); 105 | if (wlen < 0) { 106 | return wcsdup(L""); 107 | } 108 | ret = calloc(wlen+1, sizeof(wchar_t)); 109 | mbstowcs(ret, utf8, wlen+1); 110 | ret[wlen] = 0x0000; 111 | } 112 | 113 | return ret; 114 | } 115 | 116 | /* Get an attribute value from a udev_device and return it as a whar_t 117 | string. The returned string must be freed with free() when done.*/ 118 | static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name) 119 | { 120 | return utf8_to_wchar_t(udev_device_get_sysattr_value(dev, udev_name)); 121 | } 122 | 123 | /* uses_numbered_reports() returns 1 if report_descriptor describes a device 124 | which contains numbered reports. */ 125 | static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) { 126 | int i = 0; 127 | int size_code; 128 | int data_len, key_size; 129 | 130 | while (i < size) { 131 | int key = report_descriptor[i]; 132 | 133 | /* Check for the Report ID key */ 134 | if (key == 0x85/*Report ID*/) { 135 | /* This device has a Report ID, which means it uses 136 | numbered reports. */ 137 | return 1; 138 | } 139 | 140 | //printf("key: %02hhx\n", key); 141 | 142 | if ((key & 0xf0) == 0xf0) { 143 | /* This is a Long Item. The next byte contains the 144 | length of the data section (value) for this key. 145 | See the HID specification, version 1.11, section 146 | 6.2.2.3, titled "Long Items." */ 147 | if (i+1 < size) 148 | data_len = report_descriptor[i+1]; 149 | else 150 | data_len = 0; /* malformed report */ 151 | key_size = 3; 152 | } 153 | else { 154 | /* This is a Short Item. The bottom two bits of the 155 | key contain the size code for the data section 156 | (value) for this key. Refer to the HID 157 | specification, version 1.11, section 6.2.2.2, 158 | titled "Short Items." */ 159 | size_code = key & 0x3; 160 | switch (size_code) { 161 | case 0: 162 | case 1: 163 | case 2: 164 | data_len = size_code; 165 | break; 166 | case 3: 167 | data_len = 4; 168 | break; 169 | default: 170 | /* Can't ever happen since size_code is & 0x3 */ 171 | data_len = 0; 172 | break; 173 | }; 174 | key_size = 1; 175 | } 176 | 177 | /* Skip over this key and it's associated data */ 178 | i += data_len + key_size; 179 | } 180 | 181 | /* Didn't find a Report ID key. Device doesn't use numbered reports. */ 182 | return 0; 183 | } 184 | 185 | /* 186 | * The caller is responsible for free()ing the (newly-allocated) character 187 | * strings pointed to by serial_number_utf8 and product_name_utf8 after use. 188 | */ 189 | int 190 | parse_uevent_info(const char *uevent, int *bus_type, 191 | unsigned short *vendor_id, unsigned short *product_id, 192 | char **serial_number_utf8, char **product_name_utf8) 193 | { 194 | char *tmp = strdup(uevent); 195 | char *saveptr = NULL; 196 | char *line; 197 | char *key; 198 | char *value; 199 | 200 | int found_id = 0; 201 | int found_serial = 0; 202 | int found_name = 0; 203 | 204 | line = strtok_r(tmp, "\n", &saveptr); 205 | while (line != NULL) { 206 | /* line: "KEY=value" */ 207 | key = line; 208 | value = strchr(line, '='); 209 | if (!value) { 210 | goto next_line; 211 | } 212 | *value = '\0'; 213 | value++; 214 | 215 | if (strcmp(key, "HID_ID") == 0) { 216 | /** 217 | * type vendor product 218 | * HID_ID=0003:000005AC:00008242 219 | **/ 220 | int ret = sscanf(value, "%x:%hx:%hx", bus_type, vendor_id, product_id); 221 | if (ret == 3) { 222 | found_id = 1; 223 | } 224 | } else if (strcmp(key, "HID_NAME") == 0) { 225 | /* The caller has to free the product name */ 226 | *product_name_utf8 = strdup(value); 227 | found_name = 1; 228 | } else if (strcmp(key, "HID_UNIQ") == 0) { 229 | /* The caller has to free the serial number */ 230 | *serial_number_utf8 = strdup(value); 231 | found_serial = 1; 232 | } 233 | 234 | next_line: 235 | line = strtok_r(NULL, "\n", &saveptr); 236 | } 237 | 238 | free(tmp); 239 | return (found_id && found_name && found_serial); 240 | } 241 | 242 | 243 | static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t *string, size_t maxlen) 244 | { 245 | struct udev *udev; 246 | struct udev_device *udev_dev, *parent, *hid_dev; 247 | struct stat s; 248 | int ret = -1; 249 | 250 | /* Create the udev object */ 251 | udev = udev_new(); 252 | if (!udev) { 253 | printf("Can't create udev\n"); 254 | return -1; 255 | } 256 | 257 | /* Get the dev_t (major/minor numbers) from the file handle. */ 258 | fstat(dev->device_handle, &s); 259 | /* Open a udev device from the dev_t. 'c' means character device. */ 260 | udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev); 261 | if (udev_dev) { 262 | hid_dev = udev_device_get_parent_with_subsystem_devtype( 263 | udev_dev, 264 | "hid", 265 | NULL); 266 | if (hid_dev) { 267 | unsigned short dev_vid; 268 | unsigned short dev_pid; 269 | char *serial_number_utf8 = NULL; 270 | char *product_name_utf8 = NULL; 271 | int bus_type; 272 | 273 | ret = parse_uevent_info( 274 | udev_device_get_sysattr_value(hid_dev, "uevent"), 275 | &bus_type, 276 | &dev_vid, 277 | &dev_pid, 278 | &serial_number_utf8, 279 | &product_name_utf8); 280 | 281 | if (bus_type == BUS_BLUETOOTH) { 282 | switch (key) { 283 | case DEVICE_STRING_MANUFACTURER: 284 | wcsncpy(string, L"", maxlen); 285 | ret = 0; 286 | break; 287 | case DEVICE_STRING_PRODUCT: 288 | ret = mbstowcs(string, product_name_utf8, maxlen); 289 | ret = (ret == (size_t)-1)? -1: 0; 290 | break; 291 | case DEVICE_STRING_SERIAL: 292 | ret = mbstowcs(string, serial_number_utf8, maxlen); 293 | ret = (ret == (size_t)-1)? -1: 0; 294 | break; 295 | default: 296 | ret = -1; 297 | break; 298 | } 299 | } 300 | else { 301 | /* This is a USB device. Find its parent USB Device node. */ 302 | parent = udev_device_get_parent_with_subsystem_devtype( 303 | udev_dev, 304 | "usb", 305 | "usb_device"); 306 | if (parent) { 307 | const char *str; 308 | const char *key_str = NULL; 309 | 310 | if (key >= 0 && key < DEVICE_STRING_COUNT) { 311 | key_str = device_string_names[key]; 312 | } else { 313 | ret = -1; 314 | goto end; 315 | } 316 | 317 | str = udev_device_get_sysattr_value(parent, key_str); 318 | if (str) { 319 | /* Convert the string from UTF-8 to wchar_t */ 320 | ret = mbstowcs(string, str, maxlen); 321 | ret = (ret == (size_t)-1)? -1: 0; 322 | goto end; 323 | } 324 | } 325 | } 326 | 327 | free(serial_number_utf8); 328 | free(product_name_utf8); 329 | } 330 | } 331 | 332 | end: 333 | udev_device_unref(udev_dev); 334 | // parent and hid_dev don't need to be (and can't be) unref'd. 335 | // I'm not sure why, but they'll throw double-free() errors. 336 | udev_unref(udev); 337 | 338 | return ret; 339 | } 340 | 341 | int HID_API_EXPORT hid_init(void) 342 | { 343 | const char *locale; 344 | 345 | /* Set the locale if it's not set. */ 346 | locale = setlocale(LC_CTYPE, NULL); 347 | if (!locale) 348 | setlocale(LC_CTYPE, ""); 349 | 350 | return 0; 351 | } 352 | 353 | int HID_API_EXPORT hid_exit(void) 354 | { 355 | /* Nothing to do for this in the Linux/hidraw implementation. */ 356 | return 0; 357 | } 358 | 359 | 360 | struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) 361 | { 362 | struct udev *udev; 363 | struct udev_enumerate *enumerate; 364 | struct udev_list_entry *devices, *dev_list_entry; 365 | 366 | struct hid_device_info *root = NULL; // return object 367 | struct hid_device_info *cur_dev = NULL; 368 | struct hid_device_info *prev_dev = NULL; // previous device 369 | 370 | hid_init(); 371 | 372 | /* Create the udev object */ 373 | udev = udev_new(); 374 | if (!udev) { 375 | printf("Can't create udev\n"); 376 | return NULL; 377 | } 378 | 379 | /* Create a list of the devices in the 'hidraw' subsystem. */ 380 | enumerate = udev_enumerate_new(udev); 381 | udev_enumerate_add_match_subsystem(enumerate, "hidraw"); 382 | udev_enumerate_scan_devices(enumerate); 383 | devices = udev_enumerate_get_list_entry(enumerate); 384 | /* For each item, see if it matches the vid/pid, and if so 385 | create a udev_device record for it */ 386 | udev_list_entry_foreach(dev_list_entry, devices) { 387 | const char *sysfs_path; 388 | const char *dev_path; 389 | const char *str; 390 | struct udev_device *raw_dev; // The device's hidraw udev node. 391 | struct udev_device *hid_dev; // The device's HID udev node. 392 | struct udev_device *usb_dev; // The device's USB udev node. 393 | struct udev_device *intf_dev; // The device's interface (in the USB sense). 394 | unsigned short dev_vid; 395 | unsigned short dev_pid; 396 | char *serial_number_utf8 = NULL; 397 | char *product_name_utf8 = NULL; 398 | int bus_type; 399 | int result; 400 | 401 | /* Get the filename of the /sys entry for the device 402 | and create a udev_device object (dev) representing it */ 403 | sysfs_path = udev_list_entry_get_name(dev_list_entry); 404 | raw_dev = udev_device_new_from_syspath(udev, sysfs_path); 405 | dev_path = udev_device_get_devnode(raw_dev); 406 | 407 | hid_dev = udev_device_get_parent_with_subsystem_devtype( 408 | raw_dev, 409 | "hid", 410 | NULL); 411 | 412 | if (!hid_dev) { 413 | /* Unable to find parent hid device. */ 414 | goto next; 415 | } 416 | 417 | result = parse_uevent_info( 418 | udev_device_get_sysattr_value(hid_dev, "uevent"), 419 | &bus_type, 420 | &dev_vid, 421 | &dev_pid, 422 | &serial_number_utf8, 423 | &product_name_utf8); 424 | 425 | if (!result) { 426 | /* parse_uevent_info() failed for at least one field. */ 427 | goto next; 428 | } 429 | 430 | if (bus_type != BUS_USB && bus_type != BUS_BLUETOOTH) { 431 | /* We only know how to handle USB and BT devices. */ 432 | goto next; 433 | } 434 | 435 | /* Check the VID/PID against the arguments */ 436 | if ((vendor_id == 0x0 && product_id == 0x0) || 437 | (vendor_id == dev_vid && product_id == dev_pid)) { 438 | struct hid_device_info *tmp; 439 | 440 | /* VID/PID match. Create the record. */ 441 | tmp = malloc(sizeof(struct hid_device_info)); 442 | if (cur_dev) { 443 | cur_dev->next = tmp; 444 | } 445 | else { 446 | root = tmp; 447 | } 448 | prev_dev = cur_dev; 449 | cur_dev = tmp; 450 | 451 | /* Fill out the record */ 452 | cur_dev->next = NULL; 453 | cur_dev->path = dev_path? strdup(dev_path): NULL; 454 | 455 | /* VID/PID */ 456 | cur_dev->vendor_id = dev_vid; 457 | cur_dev->product_id = dev_pid; 458 | 459 | /* Serial Number */ 460 | cur_dev->serial_number = utf8_to_wchar_t(serial_number_utf8); 461 | 462 | /* Release Number */ 463 | cur_dev->release_number = 0x0; 464 | 465 | /* Interface Number */ 466 | cur_dev->interface_number = -1; 467 | 468 | switch (bus_type) { 469 | case BUS_USB: 470 | /* The device pointed to by raw_dev contains information about 471 | the hidraw device. In order to get information about the 472 | USB device, get the parent device with the 473 | subsystem/devtype pair of "usb"/"usb_device". This will 474 | be several levels up the tree, but the function will find 475 | it. */ 476 | usb_dev = udev_device_get_parent_with_subsystem_devtype( 477 | raw_dev, 478 | "usb", 479 | "usb_device"); 480 | 481 | if (!usb_dev) { 482 | /* Free this device */ 483 | free(cur_dev->serial_number); 484 | free(cur_dev->path); 485 | free(cur_dev); 486 | 487 | /* Take it off the device list. */ 488 | if (prev_dev) { 489 | prev_dev->next = NULL; 490 | cur_dev = prev_dev; 491 | } 492 | else { 493 | cur_dev = root = NULL; 494 | } 495 | 496 | goto next; 497 | } 498 | 499 | /* Manufacturer and Product strings */ 500 | cur_dev->manufacturer_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_MANUFACTURER]); 501 | cur_dev->product_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_PRODUCT]); 502 | 503 | /* Release Number */ 504 | str = udev_device_get_sysattr_value(usb_dev, "bcdDevice"); 505 | cur_dev->release_number = (str)? strtol(str, NULL, 16): 0x0; 506 | 507 | /* Get a handle to the interface's udev node. */ 508 | intf_dev = udev_device_get_parent_with_subsystem_devtype( 509 | raw_dev, 510 | "usb", 511 | "usb_interface"); 512 | if (intf_dev) { 513 | str = udev_device_get_sysattr_value(intf_dev, "bInterfaceNumber"); 514 | cur_dev->interface_number = (str)? strtol(str, NULL, 16): -1; 515 | } 516 | 517 | break; 518 | 519 | case BUS_BLUETOOTH: 520 | /* Manufacturer and Product strings */ 521 | cur_dev->manufacturer_string = wcsdup(L""); 522 | cur_dev->product_string = utf8_to_wchar_t(product_name_utf8); 523 | 524 | break; 525 | 526 | default: 527 | /* Unknown device type - this should never happen, as we 528 | * check for USB and Bluetooth devices above */ 529 | break; 530 | } 531 | } 532 | 533 | next: 534 | free(serial_number_utf8); 535 | free(product_name_utf8); 536 | udev_device_unref(raw_dev); 537 | /* hid_dev, usb_dev and intf_dev don't need to be (and can't be) 538 | unref()d. It will cause a double-free() error. I'm not 539 | sure why. */ 540 | } 541 | /* Free the enumerator and udev objects. */ 542 | udev_enumerate_unref(enumerate); 543 | udev_unref(udev); 544 | 545 | return root; 546 | } 547 | 548 | void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs) 549 | { 550 | struct hid_device_info *d = devs; 551 | while (d) { 552 | struct hid_device_info *next = d->next; 553 | free(d->path); 554 | free(d->serial_number); 555 | free(d->manufacturer_string); 556 | free(d->product_string); 557 | free(d); 558 | d = next; 559 | } 560 | } 561 | 562 | hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) 563 | { 564 | struct hid_device_info *devs, *cur_dev; 565 | const char *path_to_open = NULL; 566 | hid_device *handle = NULL; 567 | 568 | devs = hid_enumerate(vendor_id, product_id); 569 | cur_dev = devs; 570 | while (cur_dev) { 571 | if (cur_dev->vendor_id == vendor_id && 572 | cur_dev->product_id == product_id) { 573 | if (serial_number) { 574 | if (wcscmp(serial_number, cur_dev->serial_number) == 0) { 575 | path_to_open = cur_dev->path; 576 | break; 577 | } 578 | } 579 | else { 580 | path_to_open = cur_dev->path; 581 | break; 582 | } 583 | } 584 | cur_dev = cur_dev->next; 585 | } 586 | 587 | if (path_to_open) { 588 | /* Open the device */ 589 | handle = hid_open_path(path_to_open); 590 | } 591 | 592 | hid_free_enumeration(devs); 593 | 594 | return handle; 595 | } 596 | 597 | hid_device * HID_API_EXPORT hid_open_path(const char *path) 598 | { 599 | hid_device *dev = NULL; 600 | 601 | hid_init(); 602 | 603 | dev = new_hid_device(); 604 | 605 | if (kernel_version == 0) { 606 | struct utsname name; 607 | int major, minor, release; 608 | int ret; 609 | uname(&name); 610 | ret = sscanf(name.release, "%d.%d.%d", &major, &minor, &release); 611 | if (ret == 3) { 612 | kernel_version = major << 16 | minor << 8 | release; 613 | //printf("Kernel Version: %d\n", kernel_version); 614 | } 615 | else { 616 | printf("Couldn't sscanf() version string %s\n", name.release); 617 | } 618 | } 619 | 620 | // OPEN HERE // 621 | dev->device_handle = open(path, O_RDWR); 622 | 623 | // If we have a good handle, return it. 624 | if (dev->device_handle > 0) { 625 | 626 | /* Get the report descriptor */ 627 | int res, desc_size = 0; 628 | struct hidraw_report_descriptor rpt_desc; 629 | 630 | memset(&rpt_desc, 0x0, sizeof(rpt_desc)); 631 | 632 | /* Get Report Descriptor Size */ 633 | res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size); 634 | if (res < 0) 635 | perror("HIDIOCGRDESCSIZE"); 636 | 637 | 638 | /* Get Report Descriptor */ 639 | rpt_desc.size = desc_size; 640 | res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc); 641 | if (res < 0) { 642 | perror("HIDIOCGRDESC"); 643 | } else { 644 | /* Determine if this device uses numbered reports. */ 645 | dev->uses_numbered_reports = 646 | uses_numbered_reports(rpt_desc.value, 647 | rpt_desc.size); 648 | } 649 | 650 | return dev; 651 | } 652 | else { 653 | // Unable to open any devices. 654 | free(dev); 655 | return NULL; 656 | } 657 | } 658 | 659 | 660 | int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) 661 | { 662 | int bytes_written; 663 | 664 | bytes_written = write(dev->device_handle, data, length); 665 | 666 | return bytes_written; 667 | } 668 | 669 | 670 | int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) 671 | { 672 | int bytes_read; 673 | 674 | if (milliseconds != 0) { 675 | /* milliseconds is -1 or > 0. In both cases, we want to 676 | call poll() and wait for data to arrive. -1 means 677 | INFINITE. */ 678 | int ret; 679 | struct pollfd fds; 680 | 681 | fds.fd = dev->device_handle; 682 | fds.events = POLLIN; 683 | fds.revents = 0; 684 | ret = poll(&fds, 1, milliseconds); 685 | if (ret == -1 || ret == 0) 686 | /* Error or timeout */ 687 | return ret; 688 | } 689 | 690 | bytes_read = read(dev->device_handle, data, length); 691 | if (bytes_read < 0 && errno == EAGAIN) 692 | bytes_read = 0; 693 | 694 | if (bytes_read >= 0 && 695 | kernel_version < KERNEL_VERSION(2,6,34) && 696 | dev->uses_numbered_reports) { 697 | /* Work around a kernel bug. Chop off the first byte. */ 698 | memmove(data, data+1, bytes_read); 699 | bytes_read--; 700 | } 701 | 702 | return bytes_read; 703 | } 704 | 705 | int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length) 706 | { 707 | return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); 708 | } 709 | 710 | int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) 711 | { 712 | int flags, res; 713 | 714 | flags = fcntl(dev->device_handle, F_GETFL, 0); 715 | if (flags >= 0) { 716 | if (nonblock) 717 | res = fcntl(dev->device_handle, F_SETFL, flags | O_NONBLOCK); 718 | else 719 | res = fcntl(dev->device_handle, F_SETFL, flags & ~O_NONBLOCK); 720 | } 721 | else 722 | return -1; 723 | 724 | if (res < 0) { 725 | return -1; 726 | } 727 | else { 728 | dev->blocking = !nonblock; 729 | return 0; /* Success */ 730 | } 731 | } 732 | 733 | 734 | int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) 735 | { 736 | int res; 737 | 738 | res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data); 739 | if (res < 0) 740 | perror("ioctl (SFEATURE)"); 741 | 742 | return res; 743 | } 744 | 745 | int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) 746 | { 747 | int res; 748 | 749 | res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data); 750 | if (res < 0) 751 | perror("ioctl (GFEATURE)"); 752 | 753 | 754 | return res; 755 | } 756 | 757 | 758 | void HID_API_EXPORT hid_close(hid_device *dev) 759 | { 760 | if (!dev) 761 | return; 762 | close(dev->device_handle); 763 | free(dev); 764 | } 765 | 766 | 767 | int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) 768 | { 769 | return get_device_string(dev, DEVICE_STRING_MANUFACTURER, string, maxlen); 770 | } 771 | 772 | int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) 773 | { 774 | return get_device_string(dev, DEVICE_STRING_PRODUCT, string, maxlen); 775 | } 776 | 777 | int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) 778 | { 779 | return get_device_string(dev, DEVICE_STRING_SERIAL, string, maxlen); 780 | } 781 | 782 | int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) 783 | { 784 | return -1; 785 | } 786 | 787 | 788 | HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) 789 | { 790 | return NULL; 791 | } 792 | -------------------------------------------------------------------------------- /mac/Makefile: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Simple Makefile for HIDAPI test program 3 | # 4 | # Alan Ott 5 | # Signal 11 Software 6 | # 2010-07-03 7 | ########################################### 8 | 9 | #ARCHFLAGS=-m32 10 | 11 | JNIOBJS=HIDManager.o HIDDeviceInfo.o HIDDevice.o hid-java.o 12 | JNIINCLUDES=-I.. -I../jni-impl -I/System/Library/Frameworks/JavaVM.framework/Headers 13 | JNILIBS=-l iconv 14 | JNISHAREDLIB=libhidapi-jni.jnilib 15 | JNISHAREDLIBVER=1.0 16 | 17 | CC=gcc 18 | CXX=g++ 19 | COBJS=hid.o 20 | CPPOBJS=../hidtest/hidtest.o 21 | OBJS=$(COBJS) $(CPPOBJS) $(JNIOBJS) 22 | CFLAGS+=$(ARCHFLAGS) -I../hidapi -g -c $(JNIINCLUDES) 23 | LIBS=-framework IOKit -framework CoreFoundation $(JNILIBS) 24 | 25 | all: hidtest $(JNISHAREDLIB) 26 | 27 | $(JNISHAREDLIB): $(OBJS) 28 | $(CXX) $(ARCHFLAGS) -dynamiclib -current_version $(JNISHAREDLIBVER) $(COBJS) $(JNIOBJS) $(LIBS) -o $(JNISHAREDLIB) 29 | 30 | hidtest: $(OBJS) 31 | $(CXX) $(ARCHFLAGS) -g $^ $(LIBS) -o hidtest 32 | 33 | %.o: ../jni-impl/%.cpp 34 | $(CXX) $(CFLAGS) $< -o $@ 35 | 36 | $(COBJS): %.o: %.c 37 | $(CC) $(CFLAGS) $< -o $@ 38 | 39 | $(CPPOBJS): %.o: %.cpp 40 | $(CXX) $(CFLAGS) $< -o $@ 41 | 42 | clean: 43 | rm -f *.o hidtest $(CPPOBJS) $(JNISHAREDLIB) 44 | 45 | .PHONY: clean 46 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.codeminders 6 | hidapi 7 | jar 8 | Java API for working with Human Interface USB Devices (HID) 9 | 1.1 10 | JNI wrapper around C/C++ HIDAPI library providing simple java API to work with devices such as USB gamepads, joysticks, keyboards etc. 11 | http://code.google.com/p/javahidapi 12 | 13 | 14 | New BSD License 15 | http://opensource.org/licenses/BSD-3-Clause 16 | repo 17 | 18 | 19 | 20 | scm:hg:http://code.google.com/p/javahidapi 21 | scm:hg:https://code.google.com/p/javahidapi 22 | http://code.google.com/p/javahidapi 23 | 24 | 25 | 26 | lord 27 | Vadim Zaliva 28 | lord@codeminders.com 29 | 30 | 31 | Alexander Sova 32 | Vadim Zaliva 33 | bird@codeminders.com 34 | 35 | 36 | dshmyga 37 | Denis Shmyga 38 | dshmyga@codeminders.com 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/com/codeminders/hidapi/ClassPathLibraryLoader.java: -------------------------------------------------------------------------------- 1 | package com.codeminders.hidapi; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | 8 | 9 | public class ClassPathLibraryLoader { 10 | 11 | private static final String[] HID_LIB_NAMES = { 12 | "/native/linux/libhidapi-jni-64.so", 13 | "/native/linux/libhidapi-jni-32.so", 14 | "/native/mac/libhidapi-jni-64.jnilib", 15 | "/native/mac/libhidapi-jni-32.jnilib", 16 | "/native/win/hidapi-jni-64.dll", 17 | "/native/win/hidapi-jni-32.dll" 18 | }; 19 | 20 | public static boolean loadNativeHIDLibrary() 21 | { 22 | boolean isHIDLibLoaded = false; 23 | 24 | for(String path : HID_LIB_NAMES) 25 | { 26 | try { 27 | // have to use a stream 28 | InputStream in = ClassPathLibraryLoader.class.getResourceAsStream(path); 29 | if (in != null) { 30 | try { 31 | // always write to different location 32 | String tempName = path.substring(path.lastIndexOf('/') + 1); 33 | File fileOut = File.createTempFile(tempName.substring(0, tempName.lastIndexOf('.')), tempName.substring(tempName.lastIndexOf('.'), tempName.length())); 34 | fileOut.deleteOnExit(); 35 | 36 | OutputStream out = new FileOutputStream(fileOut); 37 | byte[] buf = new byte[1024]; 38 | int len; 39 | while ((len = in.read(buf)) > 0){ 40 | out.write(buf, 0, len); 41 | } 42 | 43 | out.close(); 44 | Runtime.getRuntime().load(fileOut.toString()); 45 | isHIDLibLoaded = true; 46 | } finally { 47 | in.close(); 48 | } 49 | } 50 | } catch (Exception e) { 51 | // ignore 52 | } catch (UnsatisfiedLinkError e) { 53 | // ignore 54 | } 55 | 56 | if (isHIDLibLoaded) { 57 | break; 58 | } 59 | } 60 | 61 | return isHIDLibLoaded; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/com/codeminders/hidapi/HIDAPITest.java: -------------------------------------------------------------------------------- 1 | package com.codeminders.hidapi; 2 | 3 | import java.io.IOException; 4 | 5 | 6 | /** 7 | * This class demonstrates enumeration, reading and getting 8 | * notifications when a HID device is connected/disconnected. 9 | */ 10 | public class HIDAPITest 11 | { 12 | private static final long READ_UPDATE_DELAY_MS = 50L; 13 | 14 | static 15 | { 16 | System.loadLibrary("hidapi-jni"); 17 | } 18 | 19 | // "Afterglow" controller for PS3 20 | static final int VENDOR_ID = 3695; 21 | static final int PRODUCT_ID = 25346; 22 | private static final int BUFSIZE = 2048; 23 | 24 | /** 25 | * @param args input strings value. 26 | */ 27 | public static void main(String[] args) throws IOException 28 | { 29 | listDevices(); 30 | readDevice(); 31 | } 32 | 33 | /** 34 | * Static function to read an input report to a HID device. 35 | */ 36 | private static void readDevice() 37 | { 38 | HIDDevice dev; 39 | try 40 | { 41 | HIDManager hid_mgr = HIDManager.getInstance(); 42 | dev = hid_mgr.openById(VENDOR_ID, PRODUCT_ID, null); 43 | System.err.print("Manufacturer: " + dev.getManufacturerString() + "\n"); 44 | System.err.print("Product: " + dev.getProductString() + "\n"); 45 | System.err.print("Serial Number: " + dev.getSerialNumberString() + "\n"); 46 | try 47 | { 48 | byte[] buf = new byte[BUFSIZE]; 49 | dev.enableBlocking(); 50 | while(true) 51 | { 52 | int n = dev.read(buf); 53 | for(int i=0; iHIDDevice object. 26 | * Calls the close() native method. 27 | * @throws Throwable 28 | */ 29 | protected void finalize() throws Throwable 30 | { 31 | // It is important to call close() if user forgot to do so, 32 | // since it frees pointer to internal data structure. 33 | try 34 | { 35 | close(); 36 | } finally 37 | { 38 | super.finalize(); 39 | } 40 | } 41 | 42 | /** 43 | * Method to compare HIDDevice object instances. 44 | * 45 | * @param obj HIDDevice object reference 46 | * @return true if the HIDDevice object represent the same value; false otherwise 47 | */ 48 | public boolean equals(Object obj) 49 | { 50 | if(!(obj instanceof HIDDevice)) 51 | return false; 52 | return ((HIDDevice)obj).peer == peer; 53 | } 54 | 55 | /** 56 | * Returns a hash code for this HIDDevice object. 57 | * @return a hash code value for this object 58 | */ 59 | public int hashCode() 60 | { 61 | // Same hash code calculation as in Long 62 | return (int)(peer^(peer>>>32)); 63 | } 64 | 65 | /** 66 | * Close open device. Multiple calls allowed - id device was 67 | * already closed no exception will be thrown. 68 | * 69 | * @throws IOException if error occured opening this device 70 | */ 71 | public native void close() throws IOException; 72 | 73 | /** 74 | * Write an Output Report to a HID device. 75 | * 76 | * @param data the data to send, including the report number as the first byte 77 | * @return the actual number of bytes written 78 | * @throws IOException if write error occured 79 | */ 80 | public native int write(byte[] data) throws IOException; 81 | 82 | /** 83 | * Read an Input Report to a HID device. 84 | * 85 | * @param buf a buffer to put the read data into 86 | * @return the actual number of bytes read 87 | * @throws IOException if read error occured 88 | */ 89 | public native int read(byte[] buf) throws IOException; 90 | 91 | /** 92 | * Read an Input report from a HID device with timeout. 93 | * 94 | * @param buf a buffer to put the read data into. 95 | * @param milliseconds a timeout in milliseconds or -1 for blocking wait. 96 | * @return the number of bytes to read. For devices with 97 | * multiple reports, make sure to read an extra byte for 98 | * the report number. 99 | */ 100 | public native int readTimeout(byte[] buf, int milliseconds); 101 | 102 | /** 103 | * Enable blocking reads for this HIDDevice object. 104 | */ 105 | public native void enableBlocking() throws IOException; 106 | 107 | /** 108 | * Disable blocking reads for this HIDDevice object. 109 | */ 110 | public native void disableBlocking() throws IOException; 111 | 112 | /** 113 | * Send a Feature Report to the HID device. 114 | * @param data The data to send, including the report number as the first byte 115 | * @return the actual number of bytes written 116 | * @throws IOException 117 | */ 118 | public native int sendFeatureReport(byte[] data) throws IOException; 119 | 120 | /** 121 | * Get a Feature Report from a HID device. 122 | * @param buf a buffer to put the read data into 123 | * @return the actual number of bytes read and -1 on error 124 | * @throws IOException 125 | */ 126 | public native int getFeatureReport(byte[] buf) throws IOException; 127 | 128 | /** 129 | * Get The Manufacturer String from a HID device. 130 | * @return the string buffer to put the data into 131 | * @throws IOException 132 | */ 133 | public native String getManufacturerString() throws IOException; 134 | 135 | /** 136 | * Get The Product String from a HID device. 137 | * @return the string buffer to put the data into 138 | * @throws IOException 139 | */ 140 | public native String getProductString() throws IOException; 141 | 142 | /** 143 | * Get The Serial Number String from a HID device. 144 | * @return the string buffer to put the data into 145 | * @throws IOException 146 | */ 147 | public native String getSerialNumberString() throws IOException; 148 | 149 | /** 150 | * Get a string from a HID device, based on its string index. 151 | * @param string_index The index of the string to get. 152 | * @return the string buffer to put the data into 153 | * @throws IOException 154 | */ 155 | public native String getIndexedString(int string_index) throws IOException; 156 | 157 | } 158 | -------------------------------------------------------------------------------- /src/com/codeminders/hidapi/HIDDeviceInfo.java: -------------------------------------------------------------------------------- 1 | 2 | package com.codeminders.hidapi; 3 | 4 | import java.io.IOException; 5 | 6 | /** 7 | * Container class which contains HID device properties. 8 | * 9 | * @author lord 10 | */ 11 | public class HIDDeviceInfo 12 | { 13 | private String path; 14 | private int vendor_id; 15 | private int product_id; 16 | private String serial_number; 17 | private int release_number; 18 | private String manufacturer_string; 19 | private String product_string; 20 | private int usage_page; 21 | private int usage; 22 | private int interface_number; 23 | 24 | /** 25 | * Protected constructor, used from JNI Allocates a new 26 | * HIDDeviceInfo object. 27 | */ 28 | HIDDeviceInfo() 29 | { 30 | } 31 | 32 | /** 33 | * Get the platform-specific device path. 34 | * @return the string value 35 | */ 36 | public String getPath() 37 | { 38 | return path; 39 | } 40 | 41 | /** 42 | * Get the device USB vendor ID. 43 | * @return integer value 44 | */ 45 | public int getVendor_id() 46 | { 47 | return vendor_id; 48 | } 49 | 50 | /** 51 | * Get the device USB product ID. 52 | * @return the integer value 53 | */ 54 | public int getProduct_id() 55 | { 56 | return product_id; 57 | } 58 | 59 | /** 60 | * Get the device serial number. 61 | * @return the string value 62 | */ 63 | public String getSerial_number() 64 | { 65 | return serial_number; 66 | } 67 | 68 | /** 69 | * Get the device release number in binary-coded decimal, 70 | * also known as device version number. 71 | * @return the integer value 72 | */ 73 | public int getRelease_number() 74 | { 75 | return release_number; 76 | } 77 | 78 | /** 79 | * Get the device manufacturer string. 80 | * @return the string value 81 | */ 82 | public String getManufacturer_string() 83 | { 84 | return manufacturer_string; 85 | } 86 | 87 | /** 88 | * Get the device product string 89 | * @return the integer value 90 | */ 91 | public String getProduct_string() 92 | { 93 | return product_string; 94 | } 95 | 96 | /** 97 | * Get the device usage page (Windows/Mac only). 98 | * @return the integer value 99 | */ 100 | public int getUsage_page() 101 | { 102 | return usage_page; 103 | } 104 | 105 | /** 106 | * Get the device usage (Windows/Mac only). 107 | * @return the integer value 108 | */ 109 | public int getUsage() 110 | { 111 | return usage; 112 | } 113 | 114 | /** 115 | * Get the USB interface which this logical device 116 | * represents. Valid on both Linux implementations in all cases, 117 | * and valid on the Windows implementation only if the device 118 | * contains more than one interface. 119 | * @return the integer value 120 | */ 121 | public int getInterface_number() 122 | { 123 | return interface_number; 124 | } 125 | 126 | /** 127 | * Open a HID device using a path name from this class. 128 | * Used from JNI. 129 | * 130 | * @return return a reference to the HIDDevice object 131 | * @throws IOException 132 | */ 133 | public native HIDDevice open() throws IOException; 134 | 135 | /** 136 | * Override method for conversion this object to String object. 137 | * 138 | * @return return a reference to the String object 139 | */ 140 | @Override 141 | public String toString() 142 | { 143 | StringBuilder builder = new StringBuilder(); 144 | builder.append("HIDDeviceInfo [path="); 145 | builder.append(path); 146 | builder.append(", vendor_id="); 147 | builder.append(vendor_id); 148 | builder.append(", product_id="); 149 | builder.append(product_id); 150 | builder.append(", serial_number="); 151 | builder.append(serial_number); 152 | builder.append(", release_number="); 153 | builder.append(release_number); 154 | builder.append(", manufacturer_string="); 155 | builder.append(manufacturer_string); 156 | builder.append(", product_string="); 157 | builder.append(product_string); 158 | builder.append(", usage_page="); 159 | builder.append(usage_page); 160 | builder.append(", usage="); 161 | builder.append(usage); 162 | builder.append(", interface_number="); 163 | builder.append(interface_number); 164 | builder.append("]"); 165 | return builder.toString(); 166 | } 167 | 168 | } 169 | -------------------------------------------------------------------------------- /src/com/codeminders/hidapi/HIDDeviceNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.codeminders.hidapi; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * Thrown if HID Device with given criteria could not be found 7 | * 8 | * @author lord 9 | */ 10 | public class HIDDeviceNotFoundException extends IOException 11 | { 12 | /** 13 | * Constructs a HIDDeviceNotFoundException with no detailed error message. 14 | */ 15 | public HIDDeviceNotFoundException() 16 | { 17 | } 18 | 19 | /** 20 | * Constructs a HIDDeviceNotFoundException with the specified error message. 21 | */ 22 | public HIDDeviceNotFoundException(String message) 23 | { 24 | super(message); 25 | } 26 | } -------------------------------------------------------------------------------- /src/com/codeminders/hidapi/HIDManager.java: -------------------------------------------------------------------------------- 1 | 2 | package com.codeminders.hidapi; 3 | 4 | import java.io.IOException; 5 | 6 | /** 7 | * HIDManager.java 8 | * High-level interface to enumerate, find , open HID devices and 9 | * get connect/disconnect notifications. 10 | * 11 | * @version 1.0 12 | * @author lord 13 | * 14 | */ 15 | public class HIDManager 16 | { 17 | private static HIDManager instance = null; 18 | 19 | protected long peer; 20 | 21 | /** 22 | * Get list of all the HID devices attached to the system. 23 | * 24 | * @return list of devices 25 | * @throws IOException 26 | */ 27 | public native HIDDeviceInfo[] listDevices() throws IOException; 28 | 29 | /** 30 | * Initializing the underlying HID layer. 31 | * 32 | * @throws IOException 33 | */ 34 | private native void init() throws IOException; 35 | 36 | /** 37 | * Release underlying HID layer. This method must be called when 38 | * HIDManager object is no longer needed. Failure to 39 | * do so could cause memory leaks or unterminated threads. It is 40 | * safe to call this method multiple times. 41 | * 42 | */ 43 | public native void release(); 44 | 45 | /** 46 | * Constructor to create HID object manager. It must be invoked 47 | * from subclass constructor to ensure proper initialization. 48 | * 49 | * @throws IOException 50 | */ 51 | private HIDManager() throws IOException 52 | { 53 | init(); 54 | } 55 | 56 | /** 57 | * Release HID manager. Will call release(). 58 | * 59 | * @throws Throwable 60 | */ 61 | protected void finalize() throws Throwable 62 | { 63 | // It is important to call release() if user forgot to do so, 64 | // since it frees pointer internal data structures and stops 65 | // thread under MacOS 66 | try 67 | { 68 | release(); 69 | } finally 70 | { 71 | super.finalize(); 72 | } 73 | } 74 | 75 | /** 76 | * Convenience method to find and open device by path 77 | * 78 | * @param path USB device path 79 | * @return open device reference HIDDevice object 80 | * @throws IOException in case of internal error 81 | * @throws HIDDeviceNotFoundException if devive was not found 82 | */ 83 | public HIDDevice openByPath(String path) throws IOException, HIDDeviceNotFoundException 84 | { 85 | HIDDeviceInfo[] devs = listDevices(); 86 | for(HIDDeviceInfo d : devs) 87 | { 88 | if(d.getPath().equals(path)) 89 | return d.open(); 90 | } 91 | throw new HIDDeviceNotFoundException(); 92 | } 93 | 94 | /** 95 | * Convenience method to open a HID device using a Vendor ID 96 | * (VID), Product ID (PID) and optionally a serial number. 97 | * 98 | * @param vendor_id USB vendor ID 99 | * @param product_id USB product ID 100 | * @param serial_number USB device serial number (could be null) 101 | * @return open device 102 | * @throws IOException in case of internal error 103 | * @throws HIDDeviceNotFoundException if devive was not found 104 | */ 105 | public HIDDevice openById(int vendor_id, int product_id, String serial_number) throws IOException, HIDDeviceNotFoundException 106 | { 107 | HIDDeviceInfo[] devs = listDevices(); 108 | for(HIDDeviceInfo d : devs) 109 | { 110 | if(d.getVendor_id() == vendor_id && d.getProduct_id() == product_id 111 | && (serial_number == null || d.getSerial_number().equals(serial_number))) 112 | return d.open(); 113 | } 114 | throw new HIDDeviceNotFoundException(); 115 | } 116 | 117 | public static HIDManager getInstance() throws IOException { 118 | if(instance == null) { 119 | synchronized (HIDManager.class) { 120 | if (null == instance) { 121 | instance = new HIDManager(); 122 | } 123 | } 124 | } 125 | return instance; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/com/codeminders/hidapplet/HidApplet.java: -------------------------------------------------------------------------------- 1 | package com.codeminders.hidapplet; 2 | 3 | import com.codeminders.hidapi.HIDDeviceInfo; 4 | import com.codeminders.hidapi.HIDManager; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | import java.io.File; 9 | import java.io.FileOutputStream; 10 | import java.io.InputStream; 11 | import java.io.OutputStream;; 12 | 13 | public class HidApplet extends JApplet 14 | { 15 | /** 16 | * 17 | */ 18 | private static final long serialVersionUID = 619732094067421147L; 19 | HIDManager hid_mgr = null; 20 | @Override 21 | public void init() 22 | { 23 | String os = System.getProperty("os.name", "win").toLowerCase(); 24 | String arch = System.getProperty("os.arch", "x86"); 25 | boolean x64 = arch.indexOf("_64") != -1; 26 | String library; 27 | if (os.indexOf("win") != -1) 28 | { 29 | library = "hidapi-windows.dll"; 30 | } else if (os.indexOf("mac") != -1) 31 | { 32 | library = "hidapi-mac.so"; 33 | } else 34 | { 35 | library = "hidapi-unix.so"; 36 | } 37 | System.out.println("Using library: " + library); 38 | try 39 | { 40 | InputStream libSrc = getClass().getClassLoader().getResourceAsStream("native/" + library); 41 | if (libSrc == null) { 42 | System.err.println("No library found"); 43 | return; 44 | } 45 | 46 | File libFile = File.createTempFile("hdapi", ".lib"); 47 | System.out.println("Copying library to: " + libFile.getAbsolutePath()); 48 | 49 | byte buf[] = new byte[16384]; 50 | OutputStream libDest = new FileOutputStream(libFile); 51 | int l; 52 | while ((l = libSrc.read(buf)) > 0) 53 | libDest.write(buf, 0, l); 54 | 55 | libSrc.close(); 56 | libDest.close(); 57 | System.out.println("Loading native library"); 58 | System.load(libFile.getAbsolutePath()); 59 | System.out.println("Native library loaded"); 60 | System.out.println("Listing HID devices"); 61 | 62 | JTextArea results = new JTextArea(); 63 | results.setEditable(false); 64 | results.setEnabled(false); 65 | setLayout(new BorderLayout()); 66 | add(new JScrollPane(results), BorderLayout.CENTER); 67 | StringBuilder b = new StringBuilder(); 68 | hid_mgr = HIDManager.getInstance(); 69 | for (HIDDeviceInfo info : hid_mgr.listDevices()) 70 | b.append(info).append('\n'); 71 | results.setText(b.toString()); 72 | 73 | } catch (Exception ex) 74 | { 75 | ex.printStackTrace(); 76 | } 77 | 78 | } 79 | public void destroy() { 80 | if(null!=hid_mgr) 81 | hid_mgr.release(); 82 | } 83 | } 84 | 85 | -------------------------------------------------------------------------------- /windows/Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | OS=$(shell uname) 4 | 5 | ifneq (,$(findstring MINGW,$(OS))) 6 | FILE=Makefile.mingw 7 | endif 8 | 9 | ifeq ($(FILE), ) 10 | all: 11 | $(error Your platform ${OS} is not supported at this time.) 12 | endif 13 | 14 | include $(FILE) 15 | -------------------------------------------------------------------------------- /windows/Makefile.mingw: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Simple Makefile for HIDAPI test program 3 | # 4 | # Alan Ott 5 | # Signal 11 Software 6 | # 2010-06-01 7 | ########################################### 8 | 9 | all: hidtest 10 | 11 | CC=gcc 12 | CXX=g++ 13 | COBJS=hid.o 14 | CPPOBJS=../hidtest/hidtest.o 15 | OBJS=$(COBJS) $(CPPOBJS) 16 | CFLAGS=-I../hidapi -g -c 17 | LIBS= -lsetupapi 18 | 19 | 20 | hidtest: $(OBJS) 21 | g++ -g $^ $(LIBS) -o hidtest 22 | 23 | $(COBJS): %.o: %.c 24 | $(CC) $(CFLAGS) $< -o $@ 25 | 26 | $(CPPOBJS): %.o: %.cpp 27 | $(CXX) $(CFLAGS) $< -o $@ 28 | 29 | clean: 30 | rm *.o ../hidtest/*.o hidtest.exe 31 | 32 | .PHONY: clean 33 | -------------------------------------------------------------------------------- /windows/ddk_build/hidapi.def: -------------------------------------------------------------------------------- 1 | LIBRARY hidapi 2 | EXPORTS 3 | hid_open @1 4 | hid_write @2 5 | hid_read @3 6 | hid_close @4 7 | hid_get_product_string @5 8 | hid_get_manufacturer_string @6 9 | hid_get_serial_number_string @7 10 | hid_get_indexed_string @8 11 | hid_error @9 12 | hid_set_nonblocking @10 13 | hid_enumerate @11 14 | hid_open_path @12 15 | hid_send_feature_report @13 16 | hid_get_feature_report @14 17 | -------------------------------------------------------------------------------- /windows/ddk_build/makefile: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # 3 | # Copyright (C) Microsoft Corporation 1995, 1996 4 | # All Rights Reserved. 5 | # 6 | # MAKEFILE for HID directory 7 | # 8 | ############################################################################# 9 | 10 | !IFDEF WIN95_BUILD 11 | 12 | ROOT=..\..\..\.. 13 | 14 | VERSIONLIST = debug retail 15 | IS_32 = TRUE 16 | IS_SDK = TRUE 17 | IS_PRIVATE = TRUE 18 | IS_SDK = TRUE 19 | IS_DDK = TRUE 20 | WIN32 = TRUE 21 | COMMONMKFILE = hidapi.mk 22 | 23 | !include $(ROOT)\dev\master.mk 24 | 25 | 26 | !ELSE 27 | 28 | # 29 | # DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source 30 | # file to this component. This file merely indirects to the real make file 31 | # that is shared by all the driver components of the Windows NT DDK 32 | # 33 | 34 | !IF DEFINED(_NT_TARGET_VERSION) 35 | ! IF $(_NT_TARGET_VERSION)>=0x501 36 | ! INCLUDE $(NTMAKEENV)\makefile.def 37 | ! ELSE 38 | # Only warn once per directory 39 | ! INCLUDE $(NTMAKEENV)\makefile.plt 40 | ! IF "$(BUILD_PASS)"=="PASS1" 41 | ! message BUILDMSG: Warning : The sample "$(MAKEDIR)" is not valid for the current OS target. 42 | ! ENDIF 43 | ! ENDIF 44 | !ELSE 45 | ! INCLUDE $(NTMAKEENV)\makefile.def 46 | !ENDIF 47 | 48 | !ENDIF 49 | 50 | -------------------------------------------------------------------------------- /windows/ddk_build/sources: -------------------------------------------------------------------------------- 1 | TARGETNAME=hidapi 2 | TARGETTYPE=DYNLINK 3 | UMTYPE=console 4 | UMENTRY=main 5 | 6 | MSC_WARNING_LEVEL=/W3 /WX 7 | 8 | TARGETLIBS=$(SDK_LIB_PATH)\hid.lib \ 9 | $(SDK_LIB_PATH)\setupapi.lib \ 10 | $(SDK_LIB_PATH)\kernel32.lib \ 11 | $(SDK_LIB_PATH)\comdlg32.lib 12 | 13 | USE_MSVCRT=1 14 | 15 | INCLUDES= ..\..\hidapi 16 | SOURCES= ..\hid.c \ 17 | 18 | 19 | TARGET_DESTINATION=retail 20 | 21 | MUI=0 22 | MUI_COMMENT="HID Interface DLL" 23 | 24 | -------------------------------------------------------------------------------- /windows/hid.c: -------------------------------------------------------------------------------- 1 | /******************************************************* 2 | HIDAPI - Multi-Platform library for 3 | communication with HID devices. 4 | 5 | Alan Ott 6 | Signal 11 Software 7 | 8 | 8/22/2009 9 | 10 | Copyright 2009, All Rights Reserved. 11 | 12 | At the discretion of the user of this library, 13 | this software may be licensed under the terms of the 14 | GNU Public License v3, a BSD-Style license, or the 15 | original HIDAPI license as outlined in the LICENSE.txt, 16 | LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt 17 | files located at the root of the source distribution. 18 | These files may also be found in the public source 19 | code repository located at: 20 | http://github.com/signal11/hidapi . 21 | ********************************************************/ 22 | 23 | #include 24 | 25 | #ifndef _NTDEF_ 26 | typedef LONG NTSTATUS; 27 | #endif 28 | 29 | #ifdef __MINGW32__ 30 | #include 31 | #include 32 | #endif 33 | 34 | #ifdef __CYGWIN__ 35 | #include 36 | #define _wcsdup wcsdup 37 | #endif 38 | 39 | //#define HIDAPI_USE_DDK 40 | 41 | #ifdef __cplusplus 42 | extern "C" { 43 | #endif 44 | #include 45 | #include 46 | #ifdef HIDAPI_USE_DDK 47 | #include 48 | #endif 49 | 50 | // Copied from inc/ddk/hidclass.h, part of the Windows DDK. 51 | #define HID_OUT_CTL_CODE(id) \ 52 | CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 53 | #define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100) 54 | 55 | #ifdef __cplusplus 56 | } // extern "C" 57 | #endif 58 | 59 | #include 60 | #include 61 | 62 | 63 | #include "hidapi.h" 64 | 65 | #ifdef _MSC_VER 66 | // Thanks Microsoft, but I know how to use strncpy(). 67 | #pragma warning(disable:4996) 68 | #endif 69 | 70 | #ifdef __cplusplus 71 | extern "C" { 72 | #endif 73 | 74 | #ifndef HIDAPI_USE_DDK 75 | // Since we're not building with the DDK, and the HID header 76 | // files aren't part of the SDK, we have to define all this 77 | // stuff here. In lookup_functions(), the function pointers 78 | // defined below are set. 79 | typedef struct _HIDD_ATTRIBUTES{ 80 | ULONG Size; 81 | USHORT VendorID; 82 | USHORT ProductID; 83 | USHORT VersionNumber; 84 | } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; 85 | 86 | typedef USHORT USAGE; 87 | typedef struct _HIDP_CAPS { 88 | USAGE Usage; 89 | USAGE UsagePage; 90 | USHORT InputReportByteLength; 91 | USHORT OutputReportByteLength; 92 | USHORT FeatureReportByteLength; 93 | USHORT Reserved[17]; 94 | USHORT fields_not_used_by_hidapi[10]; 95 | } HIDP_CAPS, *PHIDP_CAPS; 96 | typedef void* PHIDP_PREPARSED_DATA; 97 | #define HIDP_STATUS_SUCCESS 0x110000 98 | 99 | typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib); 100 | typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len); 101 | typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); 102 | typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); 103 | typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length); 104 | typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length); 105 | typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len); 106 | typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data); 107 | typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data); 108 | typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps); 109 | 110 | static HidD_GetAttributes_ HidD_GetAttributes; 111 | static HidD_GetSerialNumberString_ HidD_GetSerialNumberString; 112 | static HidD_GetManufacturerString_ HidD_GetManufacturerString; 113 | static HidD_GetProductString_ HidD_GetProductString; 114 | static HidD_SetFeature_ HidD_SetFeature; 115 | static HidD_GetFeature_ HidD_GetFeature; 116 | static HidD_GetIndexedString_ HidD_GetIndexedString; 117 | static HidD_GetPreparsedData_ HidD_GetPreparsedData; 118 | static HidD_FreePreparsedData_ HidD_FreePreparsedData; 119 | static HidP_GetCaps_ HidP_GetCaps; 120 | 121 | static HMODULE lib_handle = NULL; 122 | static BOOLEAN initialized = FALSE; 123 | #endif // HIDAPI_USE_DDK 124 | 125 | struct hid_device_ { 126 | HANDLE device_handle; 127 | BOOL blocking; 128 | USHORT output_report_length; 129 | size_t input_report_length; 130 | void *last_error_str; 131 | DWORD last_error_num; 132 | BOOL read_pending; 133 | char *read_buf; 134 | OVERLAPPED ol; 135 | }; 136 | 137 | static hid_device *new_hid_device() 138 | { 139 | hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device)); 140 | dev->device_handle = INVALID_HANDLE_VALUE; 141 | dev->blocking = TRUE; 142 | dev->output_report_length = 0; 143 | dev->input_report_length = 0; 144 | dev->last_error_str = NULL; 145 | dev->last_error_num = 0; 146 | dev->read_pending = FALSE; 147 | dev->read_buf = NULL; 148 | memset(&dev->ol, 0, sizeof(dev->ol)); 149 | dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsignaled*/, NULL); 150 | 151 | return dev; 152 | } 153 | 154 | 155 | static void register_error(hid_device *device, const char *op) 156 | { 157 | WCHAR *ptr, *msg; 158 | 159 | FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | 160 | FORMAT_MESSAGE_FROM_SYSTEM | 161 | FORMAT_MESSAGE_IGNORE_INSERTS, 162 | NULL, 163 | GetLastError(), 164 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 165 | (LPWSTR)&msg, 0/*sz*/, 166 | NULL); 167 | 168 | // Get rid of the CR and LF that FormatMessage() sticks at the 169 | // end of the message. Thanks Microsoft! 170 | ptr = msg; 171 | while (*ptr) { 172 | if (*ptr == '\r') { 173 | *ptr = 0x0000; 174 | break; 175 | } 176 | ptr++; 177 | } 178 | 179 | // Store the message off in the Device entry so that 180 | // the hid_error() function can pick it up. 181 | LocalFree(device->last_error_str); 182 | device->last_error_str = msg; 183 | } 184 | 185 | #ifndef HIDAPI_USE_DDK 186 | static int lookup_functions() 187 | { 188 | lib_handle = LoadLibraryA("hid.dll"); 189 | if (lib_handle) { 190 | #define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1; 191 | RESOLVE(HidD_GetAttributes); 192 | RESOLVE(HidD_GetSerialNumberString); 193 | RESOLVE(HidD_GetManufacturerString); 194 | RESOLVE(HidD_GetProductString); 195 | RESOLVE(HidD_SetFeature); 196 | RESOLVE(HidD_GetFeature); 197 | RESOLVE(HidD_GetIndexedString); 198 | RESOLVE(HidD_GetPreparsedData); 199 | RESOLVE(HidD_FreePreparsedData); 200 | RESOLVE(HidP_GetCaps); 201 | #undef RESOLVE 202 | } 203 | else 204 | return -1; 205 | 206 | return 0; 207 | } 208 | #endif 209 | 210 | static HANDLE open_device(const char *path, BOOL enumerate) 211 | { 212 | HANDLE handle; 213 | DWORD desired_access = (enumerate)? 0: (GENERIC_WRITE | GENERIC_READ); 214 | DWORD share_mode = (enumerate)? 215 | FILE_SHARE_READ|FILE_SHARE_WRITE: 216 | FILE_SHARE_READ; 217 | 218 | handle = CreateFileA(path, 219 | desired_access, 220 | share_mode, 221 | NULL, 222 | OPEN_EXISTING, 223 | FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_NORMAL, 224 | 0); 225 | 226 | return handle; 227 | } 228 | 229 | int HID_API_EXPORT hid_init(void) 230 | { 231 | #ifndef HIDAPI_USE_DDK 232 | if (!initialized) { 233 | if (lookup_functions() < 0) { 234 | hid_exit(); 235 | return -1; 236 | } 237 | initialized = TRUE; 238 | } 239 | #endif 240 | return 0; 241 | } 242 | 243 | int HID_API_EXPORT hid_exit(void) 244 | { 245 | #ifndef HIDAPI_USE_DDK 246 | if (lib_handle) 247 | FreeLibrary(lib_handle); 248 | lib_handle = NULL; 249 | initialized = FALSE; 250 | #endif 251 | return 0; 252 | } 253 | 254 | struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id) 255 | { 256 | BOOL res; 257 | struct hid_device_info *root = NULL; // return object 258 | struct hid_device_info *cur_dev = NULL; 259 | 260 | // Windows objects for interacting with the driver. 261 | GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} }; 262 | SP_DEVINFO_DATA devinfo_data; 263 | SP_DEVICE_INTERFACE_DATA device_interface_data; 264 | SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL; 265 | HDEVINFO device_info_set = INVALID_HANDLE_VALUE; 266 | int device_index = 0; 267 | int i; 268 | 269 | if (hid_init() < 0) 270 | return NULL; 271 | 272 | // Initialize the Windows objects. 273 | memset(&devinfo_data, 0x0, sizeof(devinfo_data)); 274 | devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA); 275 | device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); 276 | 277 | // Get information for all the devices belonging to the HID class. 278 | device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); 279 | 280 | // Iterate over each device in the HID class, looking for the right one. 281 | 282 | for (;;) { 283 | HANDLE write_handle = INVALID_HANDLE_VALUE; 284 | DWORD required_size = 0; 285 | HIDD_ATTRIBUTES attrib; 286 | 287 | res = SetupDiEnumDeviceInterfaces(device_info_set, 288 | NULL, 289 | &InterfaceClassGuid, 290 | device_index, 291 | &device_interface_data); 292 | 293 | if (!res) { 294 | // A return of FALSE from this function means that 295 | // there are no more devices. 296 | break; 297 | } 298 | 299 | // Call with 0-sized detail size, and let the function 300 | // tell us how long the detail struct needs to be. The 301 | // size is put in &required_size. 302 | res = SetupDiGetDeviceInterfaceDetailA(device_info_set, 303 | &device_interface_data, 304 | NULL, 305 | 0, 306 | &required_size, 307 | NULL); 308 | 309 | // Allocate a long enough structure for device_interface_detail_data. 310 | device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size); 311 | device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); 312 | 313 | // Get the detailed data for this device. The detail data gives us 314 | // the device path for this device, which is then passed into 315 | // CreateFile() to get a handle to the device. 316 | res = SetupDiGetDeviceInterfaceDetailA(device_info_set, 317 | &device_interface_data, 318 | device_interface_detail_data, 319 | required_size, 320 | NULL, 321 | NULL); 322 | 323 | if (!res) { 324 | //register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail"); 325 | // Continue to the next device. 326 | goto cont; 327 | } 328 | 329 | // Make sure this device is of Setup Class "HIDClass" and has a 330 | // driver bound to it. 331 | for (i = 0; ; i++) { 332 | char driver_name[256]; 333 | 334 | // Populate devinfo_data. This function will return failure 335 | // when there are no more interfaces left. 336 | res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data); 337 | if (!res) 338 | goto cont; 339 | 340 | res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data, 341 | SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL); 342 | if (!res) 343 | goto cont; 344 | 345 | if (strcmp(driver_name, "HIDClass") == 0) { 346 | // See if there's a driver bound. 347 | res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data, 348 | SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL); 349 | if (res) 350 | break; 351 | } 352 | } 353 | 354 | //wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath); 355 | 356 | // Open a handle to the device 357 | write_handle = open_device(device_interface_detail_data->DevicePath, TRUE); 358 | 359 | // Check validity of write_handle. 360 | if (write_handle == INVALID_HANDLE_VALUE) { 361 | // Unable to open the device. 362 | //register_error(dev, "CreateFile"); 363 | goto cont_close; 364 | } 365 | 366 | 367 | // Get the Vendor ID and Product ID for this device. 368 | attrib.Size = sizeof(HIDD_ATTRIBUTES); 369 | HidD_GetAttributes(write_handle, &attrib); 370 | //wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID); 371 | 372 | // Check the VID/PID to see if we should add this 373 | // device to the enumeration list. 374 | if ((vendor_id == 0x0 && product_id == 0x0) || 375 | (attrib.VendorID == vendor_id && attrib.ProductID == product_id)) { 376 | 377 | #define WSTR_LEN 512 378 | const char *str; 379 | struct hid_device_info *tmp; 380 | PHIDP_PREPARSED_DATA pp_data = NULL; 381 | HIDP_CAPS caps; 382 | BOOLEAN res; 383 | NTSTATUS nt_res; 384 | wchar_t wstr[WSTR_LEN]; // TODO: Determine Size 385 | size_t len; 386 | 387 | /* VID/PID match. Create the record. */ 388 | tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info)); 389 | if (cur_dev) { 390 | cur_dev->next = tmp; 391 | } 392 | else { 393 | root = tmp; 394 | } 395 | cur_dev = tmp; 396 | 397 | // Get the Usage Page and Usage for this device. 398 | res = HidD_GetPreparsedData(write_handle, &pp_data); 399 | if (res) { 400 | nt_res = HidP_GetCaps(pp_data, &caps); 401 | if (nt_res == HIDP_STATUS_SUCCESS) { 402 | cur_dev->usage_page = caps.UsagePage; 403 | cur_dev->usage = caps.Usage; 404 | } 405 | 406 | HidD_FreePreparsedData(pp_data); 407 | } 408 | 409 | /* Fill out the record */ 410 | cur_dev->next = NULL; 411 | str = device_interface_detail_data->DevicePath; 412 | if (str) { 413 | len = strlen(str); 414 | cur_dev->path = (char*) calloc(len+1, sizeof(char)); 415 | strncpy(cur_dev->path, str, len+1); 416 | cur_dev->path[len] = '\0'; 417 | } 418 | else 419 | cur_dev->path = NULL; 420 | 421 | /* Serial Number */ 422 | res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr)); 423 | wstr[WSTR_LEN-1] = 0x0000; 424 | if (res) { 425 | cur_dev->serial_number = _wcsdup(wstr); 426 | } 427 | 428 | /* Manufacturer String */ 429 | res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr)); 430 | wstr[WSTR_LEN-1] = 0x0000; 431 | if (res) { 432 | cur_dev->manufacturer_string = _wcsdup(wstr); 433 | } 434 | 435 | /* Product String */ 436 | res = HidD_GetProductString(write_handle, wstr, sizeof(wstr)); 437 | wstr[WSTR_LEN-1] = 0x0000; 438 | if (res) { 439 | cur_dev->product_string = _wcsdup(wstr); 440 | } 441 | 442 | /* VID/PID */ 443 | cur_dev->vendor_id = attrib.VendorID; 444 | cur_dev->product_id = attrib.ProductID; 445 | 446 | /* Release Number */ 447 | cur_dev->release_number = attrib.VersionNumber; 448 | 449 | /* Interface Number. It can sometimes be parsed out of the path 450 | on Windows if a device has multiple interfaces. See 451 | http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or 452 | search for "Hardware IDs for HID Devices" at MSDN. If it's not 453 | in the path, it's set to -1. */ 454 | cur_dev->interface_number = -1; 455 | if (cur_dev->path) { 456 | char *interface_component = strstr(cur_dev->path, "&mi_"); 457 | if (interface_component) { 458 | char *hex_str = interface_component + 4; 459 | char *endptr = NULL; 460 | cur_dev->interface_number = strtol(hex_str, &endptr, 16); 461 | if (endptr == hex_str) { 462 | /* The parsing failed. Set interface_number to -1. */ 463 | cur_dev->interface_number = -1; 464 | } 465 | } 466 | } 467 | } 468 | 469 | cont_close: 470 | CloseHandle(write_handle); 471 | cont: 472 | // We no longer need the detail data. It can be freed 473 | free(device_interface_detail_data); 474 | 475 | device_index++; 476 | 477 | } 478 | 479 | // Close the device information handle. 480 | SetupDiDestroyDeviceInfoList(device_info_set); 481 | 482 | return root; 483 | 484 | } 485 | 486 | void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs) 487 | { 488 | // TODO: Merge this with the Linux version. This function is platform-independent. 489 | struct hid_device_info *d = devs; 490 | while (d) { 491 | struct hid_device_info *next = d->next; 492 | free(d->path); 493 | free(d->serial_number); 494 | free(d->manufacturer_string); 495 | free(d->product_string); 496 | free(d); 497 | d = next; 498 | } 499 | } 500 | 501 | 502 | HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) 503 | { 504 | // TODO: Merge this functions with the Linux version. This function should be platform independent. 505 | struct hid_device_info *devs, *cur_dev; 506 | const char *path_to_open = NULL; 507 | hid_device *handle = NULL; 508 | 509 | devs = hid_enumerate(vendor_id, product_id); 510 | cur_dev = devs; 511 | while (cur_dev) { 512 | if (cur_dev->vendor_id == vendor_id && 513 | cur_dev->product_id == product_id) { 514 | if (serial_number) { 515 | if (wcscmp(serial_number, cur_dev->serial_number) == 0) { 516 | path_to_open = cur_dev->path; 517 | break; 518 | } 519 | } 520 | else { 521 | path_to_open = cur_dev->path; 522 | break; 523 | } 524 | } 525 | cur_dev = cur_dev->next; 526 | } 527 | 528 | if (path_to_open) { 529 | /* Open the device */ 530 | handle = hid_open_path(path_to_open); 531 | } 532 | 533 | hid_free_enumeration(devs); 534 | 535 | return handle; 536 | } 537 | 538 | HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path) 539 | { 540 | hid_device *dev; 541 | HIDP_CAPS caps; 542 | PHIDP_PREPARSED_DATA pp_data = NULL; 543 | BOOLEAN res; 544 | NTSTATUS nt_res; 545 | 546 | if (hid_init() < 0) { 547 | return NULL; 548 | } 549 | 550 | dev = new_hid_device(); 551 | 552 | // Open a handle to the device 553 | dev->device_handle = open_device(path, FALSE); 554 | 555 | // Check validity of write_handle. 556 | if (dev->device_handle == INVALID_HANDLE_VALUE) { 557 | // Unable to open the device. 558 | register_error(dev, "CreateFile"); 559 | goto err; 560 | } 561 | 562 | // Get the Input Report length for the device. 563 | res = HidD_GetPreparsedData(dev->device_handle, &pp_data); 564 | if (!res) { 565 | register_error(dev, "HidD_GetPreparsedData"); 566 | goto err; 567 | } 568 | nt_res = HidP_GetCaps(pp_data, &caps); 569 | if (nt_res != HIDP_STATUS_SUCCESS) { 570 | register_error(dev, "HidP_GetCaps"); 571 | goto err_pp_data; 572 | } 573 | dev->output_report_length = caps.OutputReportByteLength; 574 | dev->input_report_length = caps.InputReportByteLength; 575 | HidD_FreePreparsedData(pp_data); 576 | 577 | dev->read_buf = (char*) malloc(dev->input_report_length); 578 | 579 | return dev; 580 | 581 | err_pp_data: 582 | HidD_FreePreparsedData(pp_data); 583 | err: 584 | CloseHandle(dev->device_handle); 585 | free(dev); 586 | return NULL; 587 | } 588 | 589 | int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length) 590 | { 591 | DWORD bytes_written; 592 | BOOL res; 593 | 594 | OVERLAPPED ol; 595 | unsigned char *buf; 596 | memset(&ol, 0, sizeof(ol)); 597 | 598 | /* Make sure the right number of bytes are passed to WriteFile. Windows 599 | expects the number of bytes which are in the _longest_ report (plus 600 | one for the report number) bytes even if the data is a report 601 | which is shorter than that. Windows gives us this value in 602 | caps.OutputReportByteLength. If a user passes in fewer bytes than this, 603 | create a temporary buffer which is the proper size. */ 604 | if (length >= dev->output_report_length) { 605 | /* The user passed the right number of bytes. Use the buffer as-is. */ 606 | buf = (unsigned char *) data; 607 | } else { 608 | /* Create a temporary buffer and copy the user's data 609 | into it, padding the rest with zeros. */ 610 | buf = (unsigned char *) malloc(dev->output_report_length); 611 | memcpy(buf, data, length); 612 | memset(buf + length, 0, dev->output_report_length - length); 613 | length = dev->output_report_length; 614 | } 615 | 616 | res = WriteFile(dev->device_handle, buf, length, NULL, &ol); 617 | 618 | if (!res) { 619 | if (GetLastError() != ERROR_IO_PENDING) { 620 | // WriteFile() failed. Return error. 621 | register_error(dev, "WriteFile"); 622 | bytes_written = -1; 623 | goto end_of_function; 624 | } 625 | } 626 | 627 | // Wait here until the write is done. This makes 628 | // hid_write() synchronous. 629 | res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/); 630 | if (!res) { 631 | // The Write operation failed. 632 | register_error(dev, "WriteFile"); 633 | bytes_written = -1; 634 | goto end_of_function; 635 | } 636 | 637 | end_of_function: 638 | if (buf != data) 639 | free(buf); 640 | 641 | return bytes_written; 642 | } 643 | 644 | 645 | int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) 646 | { 647 | DWORD bytes_read = 0; 648 | BOOL res; 649 | 650 | // Copy the handle for convenience. 651 | HANDLE ev = dev->ol.hEvent; 652 | 653 | if (!dev->read_pending) { 654 | // Start an Overlapped I/O read. 655 | dev->read_pending = TRUE; 656 | memset(dev->read_buf, 0, dev->input_report_length); 657 | ResetEvent(ev); 658 | res = ReadFile(dev->device_handle, dev->read_buf, dev->input_report_length, &bytes_read, &dev->ol); 659 | 660 | if (!res) { 661 | if (GetLastError() != ERROR_IO_PENDING) { 662 | // ReadFile() has failed. 663 | // Clean up and return error. 664 | CancelIo(dev->device_handle); 665 | dev->read_pending = FALSE; 666 | goto end_of_function; 667 | } 668 | } 669 | } 670 | 671 | if (milliseconds >= 0) { 672 | // See if there is any data yet. 673 | res = WaitForSingleObject(ev, milliseconds); 674 | if (res != WAIT_OBJECT_0) { 675 | // There was no data this time. Return zero bytes available, 676 | // but leave the Overlapped I/O running. 677 | return 0; 678 | } 679 | } 680 | 681 | // Either WaitForSingleObject() told us that ReadFile has completed, or 682 | // we are in non-blocking mode. Get the number of bytes read. The actual 683 | // data has been copied to the data[] array which was passed to ReadFile(). 684 | res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/); 685 | 686 | // Set pending back to false, even if GetOverlappedResult() returned error. 687 | dev->read_pending = FALSE; 688 | 689 | if (res && bytes_read > 0) { 690 | if (dev->read_buf[0] == 0x0) { 691 | /* If report numbers aren't being used, but Windows sticks a report 692 | number (0x0) on the beginning of the report anyway. To make this 693 | work like the other platforms, and to make it work more like the 694 | HID spec, we'll skip over this byte. */ 695 | size_t copy_len; 696 | bytes_read--; 697 | copy_len = length > bytes_read ? bytes_read : length; 698 | memcpy(data, dev->read_buf+1, copy_len); 699 | } 700 | else { 701 | /* Copy the whole buffer, report number and all. */ 702 | size_t copy_len = length > bytes_read ? bytes_read : length; 703 | memcpy(data, dev->read_buf, copy_len); 704 | } 705 | } 706 | 707 | end_of_function: 708 | if (!res) { 709 | register_error(dev, "GetOverlappedResult"); 710 | return -1; 711 | } 712 | 713 | return bytes_read; 714 | } 715 | 716 | int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length) 717 | { 718 | return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); 719 | } 720 | 721 | int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock) 722 | { 723 | dev->blocking = !nonblock; 724 | return 0; /* Success */ 725 | } 726 | 727 | int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) 728 | { 729 | BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, length); 730 | if (!res) { 731 | register_error(dev, "HidD_SetFeature"); 732 | return -1; 733 | } 734 | 735 | return length; 736 | } 737 | 738 | 739 | int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) 740 | { 741 | BOOL res; 742 | #if 0 743 | res = HidD_GetFeature(dev->device_handle, data, length); 744 | if (!res) { 745 | register_error(dev, "HidD_GetFeature"); 746 | return -1; 747 | } 748 | return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */ 749 | #else 750 | DWORD bytes_returned; 751 | 752 | OVERLAPPED ol; 753 | memset(&ol, 0, sizeof(ol)); 754 | 755 | res = DeviceIoControl(dev->device_handle, 756 | IOCTL_HID_GET_FEATURE, 757 | data, length, 758 | data, length, 759 | &bytes_returned, &ol); 760 | 761 | if (!res) { 762 | if (GetLastError() != ERROR_IO_PENDING) { 763 | // DeviceIoControl() failed. Return error. 764 | register_error(dev, "Send Feature Report DeviceIoControl"); 765 | return -1; 766 | } 767 | } 768 | 769 | // Wait here until the write is done. This makes 770 | // hid_get_feature_report() synchronous. 771 | res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/); 772 | if (!res) { 773 | // The operation failed. 774 | register_error(dev, "Send Feature Report GetOverLappedResult"); 775 | return -1; 776 | } 777 | return bytes_returned; 778 | #endif 779 | } 780 | 781 | void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev) 782 | { 783 | if (!dev) 784 | return; 785 | CancelIo(dev->device_handle); 786 | CloseHandle(dev->ol.hEvent); 787 | CloseHandle(dev->device_handle); 788 | LocalFree(dev->last_error_str); 789 | free(dev->read_buf); 790 | free(dev); 791 | } 792 | 793 | int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) 794 | { 795 | BOOL res; 796 | 797 | res = HidD_GetManufacturerString(dev->device_handle, string, 2 * maxlen); 798 | if (!res) { 799 | register_error(dev, "HidD_GetManufacturerString"); 800 | return -1; 801 | } 802 | 803 | return 0; 804 | } 805 | 806 | int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) 807 | { 808 | BOOL res; 809 | 810 | res = HidD_GetProductString(dev->device_handle, string, 2 * maxlen); 811 | if (!res) { 812 | register_error(dev, "HidD_GetProductString"); 813 | return -1; 814 | } 815 | 816 | return 0; 817 | } 818 | 819 | int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) 820 | { 821 | BOOL res; 822 | 823 | res = HidD_GetSerialNumberString(dev->device_handle, string, 2 * maxlen); 824 | if (!res) { 825 | register_error(dev, "HidD_GetSerialNumberString"); 826 | return -1; 827 | } 828 | 829 | return 0; 830 | } 831 | 832 | int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) 833 | { 834 | BOOL res; 835 | 836 | res = HidD_GetIndexedString(dev->device_handle, string_index, string, 2 * maxlen); 837 | if (!res) { 838 | register_error(dev, "HidD_GetIndexedString"); 839 | return -1; 840 | } 841 | 842 | return 0; 843 | } 844 | 845 | 846 | HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) 847 | { 848 | return (wchar_t*)dev->last_error_str; 849 | } 850 | 851 | 852 | //#define PICPGM 853 | //#define S11 854 | #define P32 855 | #ifdef S11 856 | unsigned short VendorID = 0xa0a0; 857 | unsigned short ProductID = 0x0001; 858 | #endif 859 | 860 | #ifdef P32 861 | unsigned short VendorID = 0x04d8; 862 | unsigned short ProductID = 0x3f; 863 | #endif 864 | 865 | 866 | #ifdef PICPGM 867 | unsigned short VendorID = 0x04d8; 868 | unsigned short ProductID = 0x0033; 869 | #endif 870 | 871 | 872 | #if 0 873 | int __cdecl main(int argc, char* argv[]) 874 | { 875 | int res; 876 | unsigned char buf[65]; 877 | 878 | UNREFERENCED_PARAMETER(argc); 879 | UNREFERENCED_PARAMETER(argv); 880 | 881 | // Set up the command buffer. 882 | memset(buf,0x00,sizeof(buf)); 883 | buf[0] = 0; 884 | buf[1] = 0x81; 885 | 886 | 887 | // Open the device. 888 | int handle = open(VendorID, ProductID, L"12345"); 889 | if (handle < 0) 890 | printf("unable to open device\n"); 891 | 892 | 893 | // Toggle LED (cmd 0x80) 894 | buf[1] = 0x80; 895 | res = write(handle, buf, 65); 896 | if (res < 0) 897 | printf("Unable to write()\n"); 898 | 899 | // Request state (cmd 0x81) 900 | buf[1] = 0x81; 901 | write(handle, buf, 65); 902 | if (res < 0) 903 | printf("Unable to write() (2)\n"); 904 | 905 | // Read requested state 906 | read(handle, buf, 65); 907 | if (res < 0) 908 | printf("Unable to read()\n"); 909 | 910 | // Print out the returned buffer. 911 | for (int i = 0; i < 4; i++) 912 | printf("buf[%d]: %d\n", i, buf[i]); 913 | 914 | return 0; 915 | } 916 | #endif 917 | 918 | #ifdef __cplusplus 919 | } // extern "C" 920 | #endif 921 | -------------------------------------------------------------------------------- /windows/hidapi-jni/hidapi-jni.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 29 | 32 | 35 | 38 | 41 | 44 | 56 | 59 | 62 | 65 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 95 | 101 | 104 | 107 | 110 | 113 | 116 | 124 | 127 | 130 | 133 | 137 | 140 | 143 | 146 | 149 | 152 | 155 | 158 | 159 | 167 | 170 | 173 | 176 | 179 | 182 | 195 | 198 | 201 | 204 | 214 | 217 | 220 | 223 | 226 | 229 | 232 | 235 | 236 | 242 | 245 | 248 | 251 | 254 | 257 | 264 | 267 | 270 | 273 | 277 | 280 | 283 | 286 | 289 | 292 | 295 | 298 | 299 | 300 | 301 | 302 | 303 | 308 | 311 | 312 | 315 | 318 | 319 | 322 | 323 | 326 | 327 | 330 | 331 | 334 | 335 | 336 | 337 | 342 | 343 | 348 | 349 | 352 | 353 | 354 | 355 | 356 | 357 | -------------------------------------------------------------------------------- /windows/hidapi.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hidapi", "hidapi.vcproj", "{A107C21C-418A-4697-BB10-20C3AA60E2E4}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hidtest", "hidtest.vcproj", "{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {A107C21C-418A-4697-BB10-20C3AA60E2E4} = {A107C21C-418A-4697-BB10-20C3AA60E2E4} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hidapi-jni", "hidapi-jni\hidapi-jni.vcproj", "{CD28213A-B767-4E33-B6A6-D366323D0528}" 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Win32 = Debug|Win32 16 | Debug|x64 = Debug|x64 17 | Release|Win32 = Release|Win32 18 | Release|x64 = Release|x64 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|Win32.ActiveCfg = Debug|Win32 22 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|Win32.Build.0 = Debug|Win32 23 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|x64.ActiveCfg = Debug|x64 24 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|x64.Build.0 = Debug|x64 25 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|Win32.ActiveCfg = Release|Win32 26 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|Win32.Build.0 = Release|Win32 27 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|x64.ActiveCfg = Release|x64 28 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|x64.Build.0 = Release|x64 29 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|Win32.ActiveCfg = Debug|Win32 30 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|Win32.Build.0 = Debug|Win32 31 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|x64.ActiveCfg = Debug|x64 32 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|x64.Build.0 = Debug|x64 33 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|Win32.ActiveCfg = Release|Win32 34 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|Win32.Build.0 = Release|Win32 35 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|x64.ActiveCfg = Release|x64 36 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|x64.Build.0 = Release|x64 37 | {CD28213A-B767-4E33-B6A6-D366323D0528}.Debug|Win32.ActiveCfg = Debug|Win32 38 | {CD28213A-B767-4E33-B6A6-D366323D0528}.Debug|Win32.Build.0 = Debug|Win32 39 | {CD28213A-B767-4E33-B6A6-D366323D0528}.Debug|x64.ActiveCfg = Debug|x64 40 | {CD28213A-B767-4E33-B6A6-D366323D0528}.Debug|x64.Build.0 = Debug|x64 41 | {CD28213A-B767-4E33-B6A6-D366323D0528}.Release|Win32.ActiveCfg = Release|Win32 42 | {CD28213A-B767-4E33-B6A6-D366323D0528}.Release|Win32.Build.0 = Release|Win32 43 | {CD28213A-B767-4E33-B6A6-D366323D0528}.Release|x64.ActiveCfg = Release|x64 44 | {CD28213A-B767-4E33-B6A6-D366323D0528}.Release|x64.Build.0 = Release|x64 45 | EndGlobalSection 46 | GlobalSection(SolutionProperties) = preSolution 47 | HideSolutionNode = FALSE 48 | EndGlobalSection 49 | EndGlobal 50 | -------------------------------------------------------------------------------- /windows/hidapi.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 29 | 32 | 35 | 38 | 41 | 44 | 56 | 59 | 62 | 65 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 95 | 103 | 106 | 109 | 112 | 115 | 118 | 130 | 133 | 136 | 139 | 149 | 152 | 155 | 158 | 161 | 164 | 167 | 170 | 171 | 177 | 180 | 183 | 186 | 189 | 192 | 203 | 206 | 209 | 212 | 217 | 220 | 223 | 226 | 229 | 232 | 235 | 238 | 239 | 245 | 248 | 251 | 254 | 257 | 260 | 269 | 272 | 275 | 278 | 282 | 285 | 288 | 291 | 294 | 297 | 300 | 303 | 304 | 305 | 306 | 307 | 308 | 313 | 316 | 317 | 318 | 323 | 326 | 327 | 328 | 333 | 334 | 335 | 336 | 337 | 338 | -------------------------------------------------------------------------------- /windows/hidapi.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {A107C21C-418A-4697-BB10-20C3AA60E2E4} 23 | hidapi 24 | Win32Proj 25 | 26 | 27 | 28 | DynamicLibrary 29 | Unicode 30 | true 31 | 32 | 33 | DynamicLibrary 34 | Unicode 35 | true 36 | 37 | 38 | DynamicLibrary 39 | Unicode 40 | 41 | 42 | DynamicLibrary 43 | Unicode 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | <_ProjectFileVersion>10.0.30319.1 63 | $(SolutionDir)$(Configuration)\ 64 | $(SolutionDir)$(Configuration)\ 65 | $(Configuration)\ 66 | $(Configuration)\ 67 | true 68 | true 69 | $(SolutionDir)$(Configuration)\ 70 | $(SolutionDir)$(Configuration)\ 71 | $(Configuration)\ 72 | $(Configuration)\ 73 | false 74 | false 75 | $(ProjectName)-jni 76 | $(ProjectName)-jni 77 | 78 | 79 | 80 | Disabled 81 | ..\hidapi;..;$(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;%(AdditionalIncludeDirectories) 82 | WIN32;_DEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions) 83 | true 84 | EnableFastChecks 85 | MultiThreadedDebugDLL 86 | 87 | 88 | Level3 89 | EditAndContinue 90 | 91 | 92 | setupapi.lib;%(AdditionalDependencies) 93 | $(OutDir)$(ProjectName)-jni.dll 94 | true 95 | Windows 96 | $(TargetDir)$(TargetName).lib 97 | MachineX86 98 | 99 | 100 | 101 | 102 | Disabled 103 | ..\hidapi;..;$(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;%(AdditionalIncludeDirectories) 104 | WIN32;_DEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions) 105 | EnableFastChecks 106 | MultiThreadedDebugDLL 107 | 108 | 109 | Level3 110 | ProgramDatabase 111 | 112 | 113 | setupapi.lib;%(AdditionalDependencies) 114 | $(OutDir)$(ProjectName)-jni.dll 115 | true 116 | Windows 117 | $(TargetDir)$(TargetName).lib 118 | 119 | 120 | 121 | 122 | MaxSpeed 123 | true 124 | ..\hidapi;%(AdditionalIncludeDirectories) 125 | WIN32;NDEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions) 126 | MultiThreadedDLL 127 | true 128 | 129 | 130 | Level3 131 | ProgramDatabase 132 | 133 | 134 | setupapi.lib;%(AdditionalDependencies) 135 | true 136 | Windows 137 | true 138 | true 139 | MachineX86 140 | 141 | 142 | 143 | 144 | MaxSpeed 145 | true 146 | ..\hidapi;%(AdditionalIncludeDirectories) 147 | WIN32;NDEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions) 148 | MultiThreadedDLL 149 | true 150 | 151 | 152 | Level3 153 | ProgramDatabase 154 | 155 | 156 | setupapi.lib;%(AdditionalDependencies) 157 | true 158 | Windows 159 | true 160 | true 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /windows/hidapi.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | 35 | 36 | Header Files 37 | 38 | 39 | -------------------------------------------------------------------------------- /windows/hidtest.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 17 | 18 | 19 | 20 | 21 | 28 | 31 | 34 | 37 | 40 | 43 | 53 | 56 | 59 | 62 | 70 | 73 | 76 | 79 | 82 | 85 | 88 | 93 | 94 | 102 | 105 | 108 | 111 | 114 | 117 | 127 | 130 | 133 | 136 | 146 | 149 | 152 | 155 | 158 | 161 | 164 | 169 | 170 | 176 | 179 | 182 | 185 | 188 | 191 | 199 | 202 | 205 | 208 | 213 | 216 | 219 | 222 | 225 | 228 | 231 | 234 | 235 | 241 | 244 | 247 | 250 | 253 | 256 | 262 | 265 | 268 | 271 | 276 | 279 | 282 | 285 | 288 | 291 | 294 | 297 | 298 | 299 | 300 | 301 | 302 | 307 | 310 | 311 | 312 | 317 | 318 | 323 | 324 | 325 | 326 | 327 | 328 | -------------------------------------------------------------------------------- /windows/hidtest.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712} 23 | hidtest 24 | 25 | 26 | 27 | Application 28 | MultiByte 29 | true 30 | 31 | 32 | Application 33 | MultiByte 34 | true 35 | 36 | 37 | Application 38 | MultiByte 39 | 40 | 41 | Application 42 | MultiByte 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | <_ProjectFileVersion>10.0.30319.1 62 | $(SolutionDir)$(Configuration)\ 63 | $(SolutionDir)$(Configuration)\ 64 | $(Configuration)\ 65 | $(Configuration)\ 66 | $(SolutionDir)$(Configuration)\ 67 | $(SolutionDir)$(Configuration)\ 68 | $(Configuration)\ 69 | $(Configuration)\ 70 | 71 | 72 | 73 | Disabled 74 | ..\hidapi;%(AdditionalIncludeDirectories) 75 | true 76 | EnableFastChecks 77 | MultiThreadedDebugDLL 78 | Level3 79 | EditAndContinue 80 | 81 | 82 | hidapi-jni.lib;%(AdditionalDependencies) 83 | ..\windows\Debug;%(AdditionalLibraryDirectories) 84 | true 85 | Console 86 | MachineX86 87 | 88 | 89 | Copying hidapi.dll to the local direcotry. 90 | 91 | 92 | 93 | 94 | 95 | 96 | Disabled 97 | ..\hidapi;%(AdditionalIncludeDirectories) 98 | EnableFastChecks 99 | MultiThreadedDebugDLL 100 | Level3 101 | ProgramDatabase 102 | 103 | 104 | hidapi-jni.lib;%(AdditionalDependencies) 105 | ..\windows\Debug;%(AdditionalLibraryDirectories) 106 | true 107 | Console 108 | 109 | 110 | Copying hidapi.dll to the local direcotry. 111 | 112 | 113 | 114 | 115 | 116 | 117 | MaxSpeed 118 | true 119 | ..\hidapi;%(AdditionalIncludeDirectories) 120 | MultiThreadedDLL 121 | true 122 | Level3 123 | ProgramDatabase 124 | 125 | 126 | hidapi.lib;%(AdditionalDependencies) 127 | ..\windows\Release;%(AdditionalLibraryDirectories) 128 | true 129 | Console 130 | true 131 | true 132 | MachineX86 133 | 134 | 135 | Copying hidapi.dll to the local direcotry. 136 | 137 | 138 | 139 | 140 | 141 | 142 | MaxSpeed 143 | true 144 | ..\hidapi;%(AdditionalIncludeDirectories) 145 | MultiThreadedDLL 146 | true 147 | Level3 148 | ProgramDatabase 149 | 150 | 151 | hidapi.lib;%(AdditionalDependencies) 152 | ..\windows\Release;%(AdditionalLibraryDirectories) 153 | true 154 | Console 155 | true 156 | true 157 | 158 | 159 | Copying hidapi.dll to the local direcotry. 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | {a107c21c-418a-4697-bb10-20c3aa60e2e4} 170 | false 171 | 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /windows/hidtest.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | --------------------------------------------------------------------------------