spnav_win32_test

view main.cpp @ 0:21f1554e2884

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 07 Jul 2013 04:21:49 +0300
parents
children 55a06a416ca8
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <signal.h>
4 #include <assert.h>
5 #include <windows.h>
6 extern "C" {
7 #include <hidsdi.h>
8 #include <setupapi.h>
9 }
11 typedef __int16 int16_t;
12 typedef unsigned __int32 uint32_t;
14 /* TODO: notification
15 Obtain the Windows GUID for HID devices by way of a call to HidD_GetHidGuid()
16 Clear the contents of a DEV_BROADCAST_DEVICEINTERFACE structure 0.
17 Assign the members of the structure such that you specify the HID GUID.
18 Register the application for device notifications by calling the function RegisterDeviceNotification().
19 If the previous step returns an invalid handle, then an error has occurred, and the function should return an error. Otherwise, the return is successful.
20 */
22 #pragma pack(push, 1)
23 union Report {
24 unsigned char type;
26 struct { int16_t x, y, z; } motion;
27 struct { uint32_t state; } button;
28 };
29 #pragma pack(pop)
31 static int WINAPI console_handler(DWORD s);
33 bool done;
35 int main()
36 {
37 HANDLE dev_handle = 0;
38 Report *report = 0;
40 GUID hid_guid;
41 HidD_GetHidGuid(&hid_guid);
43 HDEVINFO devs = SetupDiGetClassDevs(&hid_guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
44 if(!devs) {
45 fprintf(stderr, "failed to retrieve all USB HID devices\n");
46 return 1;
47 }
49 for(int i=0; ; i++) {
50 SP_DEVICE_INTERFACE_DATA dev_data;
51 dev_data.cbSize = sizeof dev_data;
53 if(!SetupDiEnumDeviceInterfaces(devs, 0, &hid_guid, i, &dev_data)) {
54 if(GetLastError() != ERROR_NO_MORE_ITEMS) {
55 fprintf(stderr, "failed to enumarate device %d\n", i);
56 }
57 break;
58 }
60 DWORD bufsz;
61 SetupDiGetDeviceInterfaceDetail(devs, &dev_data, 0, 0, &bufsz, 0);
63 SP_DEVICE_INTERFACE_DETAIL_DATA *dev_details = (SP_DEVICE_INTERFACE_DETAIL_DATA*)malloc(bufsz);
64 assert(dev_details);
65 dev_details->cbSize = sizeof *dev_details;
67 if(!SetupDiGetDeviceInterfaceDetail(devs, &dev_data, dev_details, bufsz, &bufsz, 0)) {
68 int err = GetLastError();
69 fprintf(stderr, "failed to get interface %d details\n", i);
70 continue;
71 }
72 dev_handle = CreateFile(dev_details->DevicePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
73 if(!dev_handle) {
74 fprintf(stderr, "failed to open device file: %s\n", dev_details->DevicePath);
75 free(dev_details);
76 continue;
77 }
78 free(dev_details);
80 HIDD_ATTRIBUTES attr;
81 attr.Size = sizeof attr;
82 if(!HidD_GetAttributes(dev_handle, &attr)) {
83 CloseHandle(dev_handle);
84 dev_handle = 0;
85 continue;
86 }
88 char name[256];
89 if(!HidD_GetProductString(dev_handle, name, sizeof name)) {
90 strcpy(name, "<unknown>");
91 }
93 printf("Device: %x:%x: %s\n", (unsigned int)attr.VendorID, (unsigned int)attr.ProductID, name);
95 if(attr.VendorID == 0x46d && attr.ProductID == 0xc626) {
96 break; // found it
97 }
99 CloseHandle(dev_handle);
100 dev_handle = 0;
101 }
102 SetupDiDestroyDeviceInfoList(devs);
104 if(!dev_handle) {
105 fprintf(stderr, "failed to find matching USB HID device\n");
106 return 1;
107 }
109 printf("device found\n");
110 _HIDP_PREPARSED_DATA *predata;
112 if(!HidD_GetPreparsedData(dev_handle, &predata)) {
113 fprintf(stderr, "failed to get preparsed data(?)\n");
114 goto cleanup;
115 }
117 HIDP_CAPS caps;
118 if(!HidP_GetCaps(predata, &caps)) {
119 fprintf(stderr, "failed to retrieve device capabilities\n");
120 HidD_FreePreparsedData(predata);
121 goto cleanup;
122 }
124 unsigned short num_value_caps = caps.NumberInputValueCaps;
125 HIDP_VALUE_CAPS *value_caps = (HIDP_VALUE_CAPS*)malloc(num_value_caps * sizeof *value_caps);
126 if(!value_caps) {
127 perror("failed to allocate value caps array");
128 HidD_FreePreparsedData(predata);
129 goto cleanup;
130 }
132 if(HidP_GetValueCaps(HidP_Input, value_caps, &num_value_caps, predata) != HIDP_STATUS_SUCCESS) {
133 fprintf(stderr, "failed to retrieve device value capabilities\n");
134 HidD_FreePreparsedData(predata);
135 goto cleanup;
136 }
137 HidD_FreePreparsedData(predata);
139 int min_val = 0;
140 int max_val = 0;
141 for(unsigned int i=0; i<num_value_caps; i++) {
142 printf("Usage page: %d\n", (int)value_caps[i].UsagePage);
143 printf("Report ID: %d\n", (int)value_caps[i].ReportID);
144 printf("Logical range: %d - %d\n", (int)value_caps[i].LogicalMin, (int)value_caps[i].LogicalMax);
145 if(i == 0) {
146 min_val = value_caps[i].LogicalMin;
147 max_val = value_caps[i].LogicalMax;
148 }
149 }
150 int val_range = max_val - min_val;
151 printf("value range: %d\n", val_range);
153 int report_size = caps.InputReportByteLength;
154 if(!(report = (Report*)malloc(report_size))) {
155 perror("failed to allocate input report buffer");
156 goto cleanup;
157 }
159 //signal(SIGINT, sig_handler);
160 if(!SetConsoleCtrlHandler(console_handler, 1)) {
161 fprintf(stderr, "failed to install console control handler\n");
162 }
164 static uint32_t bnstate = 0;
166 while(!done) {
167 if(WaitForSingleObject(dev_handle, INFINITE) != 0) {
168 fprintf(stderr, "error while waiting for device events\n");
169 break;
170 }
172 DWORD num_read;
173 if(!ReadFile(dev_handle, report, report_size, &num_read, 0)) {
174 fprintf(stderr, "failed to read input report\n");
175 continue;
176 }
178 switch(report->type) {
179 case 1: /* translation */
180 {
181 int x = report->motion.x;
182 int y = report->motion.y;
183 int z = report->motion.z;
184 if(val_range != 0) {
185 x = 100 * (x - min_val) / val_range - 50;
186 y = 100 * (y - min_val) / val_range - 50;
187 z = 100 * (z - min_val) / val_range - 50;
188 }
189 printf("MOTION %4d %4d %4d\n", x, y, z);
190 }
191 break;
193 case 2: /* rotation */
194 {
195 int x = report->motion.x;
196 int y = report->motion.y;
197 int z = report->motion.z;
198 if(val_range != 0) {
199 x = 100 * (x - min_val) / val_range - 50;
200 y = 100 * (y - min_val) / val_range - 50;
201 z = 100 * (z - min_val) / val_range - 50;
202 }
203 printf("ROTATE %4d %4d %4d\n", x, y, z);
204 }
205 break;
207 case 3:
208 bnstate = report->button.state;
209 fputs("B: ", stdout);
210 for(int i=0; i<24; i++) {
211 int bn = 23 - i;
212 if(bnstate & (1 << bn)) {
213 fputc('1', stdout);
214 } else {
215 fputc('0', stdout);
216 }
217 }
218 fputc('\n', stdout);
219 break;
221 default:
222 printf("unknown event type: %d\n", (int)report->type);
223 }
224 }
226 cleanup:
227 CloseHandle(dev_handle);
228 return 0;
229 }
231 static int WINAPI console_handler(DWORD s)
232 {
233 if(s == CTRL_C_EVENT) {
234 printf("Caught interrupt signal, quitting...\n");
235 done = true;
236 }
237 return 0;