spnav_win32_test
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/main.cpp Sun Jul 07 04:21:49 2013 +0300 1.3 @@ -0,0 +1,238 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <signal.h> 1.7 +#include <assert.h> 1.8 +#include <windows.h> 1.9 +extern "C" { 1.10 +#include <hidsdi.h> 1.11 +#include <setupapi.h> 1.12 +} 1.13 + 1.14 +typedef __int16 int16_t; 1.15 +typedef unsigned __int32 uint32_t; 1.16 + 1.17 +/* TODO: notification 1.18 + Obtain the Windows GUID for HID devices by way of a call to HidD_GetHidGuid() 1.19 + Clear the contents of a DEV_BROADCAST_DEVICEINTERFACE structure 0. 1.20 + Assign the members of the structure such that you specify the HID GUID. 1.21 + Register the application for device notifications by calling the function RegisterDeviceNotification(). 1.22 + 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. 1.23 +*/ 1.24 + 1.25 +#pragma pack(push, 1) 1.26 +union Report { 1.27 + unsigned char type; 1.28 + 1.29 + struct { int16_t x, y, z; } motion; 1.30 + struct { uint32_t state; } button; 1.31 +}; 1.32 +#pragma pack(pop) 1.33 + 1.34 +static int WINAPI console_handler(DWORD s); 1.35 + 1.36 +bool done; 1.37 + 1.38 +int main() 1.39 +{ 1.40 + HANDLE dev_handle = 0; 1.41 + Report *report = 0; 1.42 + 1.43 + GUID hid_guid; 1.44 + HidD_GetHidGuid(&hid_guid); 1.45 + 1.46 + HDEVINFO devs = SetupDiGetClassDevs(&hid_guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); 1.47 + if(!devs) { 1.48 + fprintf(stderr, "failed to retrieve all USB HID devices\n"); 1.49 + return 1; 1.50 + } 1.51 + 1.52 + for(int i=0; ; i++) { 1.53 + SP_DEVICE_INTERFACE_DATA dev_data; 1.54 + dev_data.cbSize = sizeof dev_data; 1.55 + 1.56 + if(!SetupDiEnumDeviceInterfaces(devs, 0, &hid_guid, i, &dev_data)) { 1.57 + if(GetLastError() != ERROR_NO_MORE_ITEMS) { 1.58 + fprintf(stderr, "failed to enumarate device %d\n", i); 1.59 + } 1.60 + break; 1.61 + } 1.62 + 1.63 + DWORD bufsz; 1.64 + SetupDiGetDeviceInterfaceDetail(devs, &dev_data, 0, 0, &bufsz, 0); 1.65 + 1.66 + SP_DEVICE_INTERFACE_DETAIL_DATA *dev_details = (SP_DEVICE_INTERFACE_DETAIL_DATA*)malloc(bufsz); 1.67 + assert(dev_details); 1.68 + dev_details->cbSize = sizeof *dev_details; 1.69 + 1.70 + if(!SetupDiGetDeviceInterfaceDetail(devs, &dev_data, dev_details, bufsz, &bufsz, 0)) { 1.71 + int err = GetLastError(); 1.72 + fprintf(stderr, "failed to get interface %d details\n", i); 1.73 + continue; 1.74 + } 1.75 + dev_handle = CreateFile(dev_details->DevicePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); 1.76 + if(!dev_handle) { 1.77 + fprintf(stderr, "failed to open device file: %s\n", dev_details->DevicePath); 1.78 + free(dev_details); 1.79 + continue; 1.80 + } 1.81 + free(dev_details); 1.82 + 1.83 + HIDD_ATTRIBUTES attr; 1.84 + attr.Size = sizeof attr; 1.85 + if(!HidD_GetAttributes(dev_handle, &attr)) { 1.86 + CloseHandle(dev_handle); 1.87 + dev_handle = 0; 1.88 + continue; 1.89 + } 1.90 + 1.91 + char name[256]; 1.92 + if(!HidD_GetProductString(dev_handle, name, sizeof name)) { 1.93 + strcpy(name, "<unknown>"); 1.94 + } 1.95 + 1.96 + printf("Device: %x:%x: %s\n", (unsigned int)attr.VendorID, (unsigned int)attr.ProductID, name); 1.97 + 1.98 + if(attr.VendorID == 0x46d && attr.ProductID == 0xc626) { 1.99 + break; // found it 1.100 + } 1.101 + 1.102 + CloseHandle(dev_handle); 1.103 + dev_handle = 0; 1.104 + } 1.105 + SetupDiDestroyDeviceInfoList(devs); 1.106 + 1.107 + if(!dev_handle) { 1.108 + fprintf(stderr, "failed to find matching USB HID device\n"); 1.109 + return 1; 1.110 + } 1.111 + 1.112 + printf("device found\n"); 1.113 + _HIDP_PREPARSED_DATA *predata; 1.114 + 1.115 + if(!HidD_GetPreparsedData(dev_handle, &predata)) { 1.116 + fprintf(stderr, "failed to get preparsed data(?)\n"); 1.117 + goto cleanup; 1.118 + } 1.119 + 1.120 + HIDP_CAPS caps; 1.121 + if(!HidP_GetCaps(predata, &caps)) { 1.122 + fprintf(stderr, "failed to retrieve device capabilities\n"); 1.123 + HidD_FreePreparsedData(predata); 1.124 + goto cleanup; 1.125 + } 1.126 + 1.127 + unsigned short num_value_caps = caps.NumberInputValueCaps; 1.128 + HIDP_VALUE_CAPS *value_caps = (HIDP_VALUE_CAPS*)malloc(num_value_caps * sizeof *value_caps); 1.129 + if(!value_caps) { 1.130 + perror("failed to allocate value caps array"); 1.131 + HidD_FreePreparsedData(predata); 1.132 + goto cleanup; 1.133 + } 1.134 + 1.135 + if(HidP_GetValueCaps(HidP_Input, value_caps, &num_value_caps, predata) != HIDP_STATUS_SUCCESS) { 1.136 + fprintf(stderr, "failed to retrieve device value capabilities\n"); 1.137 + HidD_FreePreparsedData(predata); 1.138 + goto cleanup; 1.139 + } 1.140 + HidD_FreePreparsedData(predata); 1.141 + 1.142 + int min_val = 0; 1.143 + int max_val = 0; 1.144 + for(unsigned int i=0; i<num_value_caps; i++) { 1.145 + printf("Usage page: %d\n", (int)value_caps[i].UsagePage); 1.146 + printf("Report ID: %d\n", (int)value_caps[i].ReportID); 1.147 + printf("Logical range: %d - %d\n", (int)value_caps[i].LogicalMin, (int)value_caps[i].LogicalMax); 1.148 + if(i == 0) { 1.149 + min_val = value_caps[i].LogicalMin; 1.150 + max_val = value_caps[i].LogicalMax; 1.151 + } 1.152 + } 1.153 + int val_range = max_val - min_val; 1.154 + printf("value range: %d\n", val_range); 1.155 + 1.156 + int report_size = caps.InputReportByteLength; 1.157 + if(!(report = (Report*)malloc(report_size))) { 1.158 + perror("failed to allocate input report buffer"); 1.159 + goto cleanup; 1.160 + } 1.161 + 1.162 + //signal(SIGINT, sig_handler); 1.163 + if(!SetConsoleCtrlHandler(console_handler, 1)) { 1.164 + fprintf(stderr, "failed to install console control handler\n"); 1.165 + } 1.166 + 1.167 + static uint32_t bnstate = 0; 1.168 + 1.169 + while(!done) { 1.170 + if(WaitForSingleObject(dev_handle, INFINITE) != 0) { 1.171 + fprintf(stderr, "error while waiting for device events\n"); 1.172 + break; 1.173 + } 1.174 + 1.175 + DWORD num_read; 1.176 + if(!ReadFile(dev_handle, report, report_size, &num_read, 0)) { 1.177 + fprintf(stderr, "failed to read input report\n"); 1.178 + continue; 1.179 + } 1.180 + 1.181 + switch(report->type) { 1.182 + case 1: /* translation */ 1.183 + { 1.184 + int x = report->motion.x; 1.185 + int y = report->motion.y; 1.186 + int z = report->motion.z; 1.187 + if(val_range != 0) { 1.188 + x = 100 * (x - min_val) / val_range - 50; 1.189 + y = 100 * (y - min_val) / val_range - 50; 1.190 + z = 100 * (z - min_val) / val_range - 50; 1.191 + } 1.192 + printf("MOTION %4d %4d %4d\n", x, y, z); 1.193 + } 1.194 + break; 1.195 + 1.196 + case 2: /* rotation */ 1.197 + { 1.198 + int x = report->motion.x; 1.199 + int y = report->motion.y; 1.200 + int z = report->motion.z; 1.201 + if(val_range != 0) { 1.202 + x = 100 * (x - min_val) / val_range - 50; 1.203 + y = 100 * (y - min_val) / val_range - 50; 1.204 + z = 100 * (z - min_val) / val_range - 50; 1.205 + } 1.206 + printf("ROTATE %4d %4d %4d\n", x, y, z); 1.207 + } 1.208 + break; 1.209 + 1.210 + case 3: 1.211 + bnstate = report->button.state; 1.212 + fputs("B: ", stdout); 1.213 + for(int i=0; i<24; i++) { 1.214 + int bn = 23 - i; 1.215 + if(bnstate & (1 << bn)) { 1.216 + fputc('1', stdout); 1.217 + } else { 1.218 + fputc('0', stdout); 1.219 + } 1.220 + } 1.221 + fputc('\n', stdout); 1.222 + break; 1.223 + 1.224 + default: 1.225 + printf("unknown event type: %d\n", (int)report->type); 1.226 + } 1.227 + } 1.228 + 1.229 +cleanup: 1.230 + CloseHandle(dev_handle); 1.231 + return 0; 1.232 +} 1.233 + 1.234 +static int WINAPI console_handler(DWORD s) 1.235 +{ 1.236 + if(s == CTRL_C_EVENT) { 1.237 + printf("Caught interrupt signal, quitting...\n"); 1.238 + done = true; 1.239 + } 1.240 + return 0; 1.241 +} 1.242 \ No newline at end of file