spnav_win32_test

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