├── .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 |
--------------------------------------------------------------------------------