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