spnav_win32_test

changeset 0:21f1554e2884

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 07 Jul 2013 04:21:49 +0300
parents
children 55a06a416ca8
files .hgignore main.cpp spnav_winapi_test.sln spnav_winapi_test.vcproj
diffstat 4 files changed, 461 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Sun Jul 07 04:21:49 2013 +0300
     1.3 @@ -0,0 +1,6 @@
     1.4 +\.o$
     1.5 +\.d$
     1.6 +\.swp$
     1.7 +\.suo$
     1.8 +^Debug/
     1.9 +^Release/
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/main.cpp	Sun Jul 07 04:21:49 2013 +0300
     2.3 @@ -0,0 +1,238 @@
     2.4 +#include <stdio.h>
     2.5 +#include <stdlib.h>
     2.6 +#include <signal.h>
     2.7 +#include <assert.h>
     2.8 +#include <windows.h>
     2.9 +extern "C" {
    2.10 +#include <hidsdi.h>
    2.11 +#include <setupapi.h>
    2.12 +}
    2.13 +
    2.14 +typedef __int16 int16_t;
    2.15 +typedef unsigned __int32 uint32_t;
    2.16 +
    2.17 +/* TODO: notification
    2.18 +    Obtain the Windows GUID for HID devices by way of a call to HidD_GetHidGuid()
    2.19 +    Clear the contents of a DEV_BROADCAST_DEVICEINTERFACE structure 0.
    2.20 +    Assign the members of the structure such that you specify the HID GUID.
    2.21 +    Register the application for device notifications by calling the function RegisterDeviceNotification().
    2.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.
    2.23 +*/
    2.24 +
    2.25 +#pragma pack(push, 1)
    2.26 +union Report {
    2.27 +	unsigned char type;
    2.28 +
    2.29 +	struct { int16_t x, y, z; } motion;
    2.30 +	struct { uint32_t state; } button;
    2.31 +};
    2.32 +#pragma pack(pop)
    2.33 +
    2.34 +static int WINAPI console_handler(DWORD s);
    2.35 +
    2.36 +bool done;
    2.37 +
    2.38 +int main()
    2.39 +{
    2.40 +	HANDLE dev_handle = 0;
    2.41 +	Report *report = 0;
    2.42 +
    2.43 +	GUID hid_guid;
    2.44 +	HidD_GetHidGuid(&hid_guid);
    2.45 +
    2.46 +	HDEVINFO devs = SetupDiGetClassDevs(&hid_guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    2.47 +	if(!devs) {
    2.48 +		fprintf(stderr, "failed to retrieve all USB HID devices\n");
    2.49 +		return 1;
    2.50 +	}
    2.51 +
    2.52 +	for(int i=0; ; i++) {
    2.53 +		SP_DEVICE_INTERFACE_DATA dev_data;
    2.54 +		dev_data.cbSize = sizeof dev_data;
    2.55 +
    2.56 +		if(!SetupDiEnumDeviceInterfaces(devs, 0, &hid_guid, i, &dev_data)) {
    2.57 +			if(GetLastError() != ERROR_NO_MORE_ITEMS) {
    2.58 +				fprintf(stderr, "failed to enumarate device %d\n", i);
    2.59 +			}
    2.60 +			break;
    2.61 +		}
    2.62 +
    2.63 +		DWORD bufsz;
    2.64 +		SetupDiGetDeviceInterfaceDetail(devs, &dev_data, 0, 0, &bufsz, 0);
    2.65 +
    2.66 +		SP_DEVICE_INTERFACE_DETAIL_DATA *dev_details = (SP_DEVICE_INTERFACE_DETAIL_DATA*)malloc(bufsz);
    2.67 +		assert(dev_details);
    2.68 +		dev_details->cbSize = sizeof *dev_details;
    2.69 +
    2.70 +		if(!SetupDiGetDeviceInterfaceDetail(devs, &dev_data, dev_details, bufsz, &bufsz, 0)) {
    2.71 +			int err = GetLastError();
    2.72 +			fprintf(stderr, "failed to get interface %d details\n", i);
    2.73 +			continue;
    2.74 +		}
    2.75 +		dev_handle = CreateFile(dev_details->DevicePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
    2.76 +		if(!dev_handle) {
    2.77 +			fprintf(stderr, "failed to open device file: %s\n", dev_details->DevicePath);
    2.78 +			free(dev_details);
    2.79 +			continue;
    2.80 +		}
    2.81 +		free(dev_details);
    2.82 +
    2.83 +		HIDD_ATTRIBUTES attr;
    2.84 +		attr.Size = sizeof attr;
    2.85 +		if(!HidD_GetAttributes(dev_handle, &attr)) {
    2.86 +			CloseHandle(dev_handle);
    2.87 +			dev_handle = 0;
    2.88 +			continue;
    2.89 +		}
    2.90 +
    2.91 +		char name[256];
    2.92 +		if(!HidD_GetProductString(dev_handle, name, sizeof name)) {
    2.93 +			strcpy(name, "<unknown>");
    2.94 +		}
    2.95 +
    2.96 +		printf("Device: %x:%x: %s\n", (unsigned int)attr.VendorID, (unsigned int)attr.ProductID, name);
    2.97 +
    2.98 +		if(attr.VendorID == 0x46d && attr.ProductID == 0xc626) {
    2.99 +			break;	// found it
   2.100 +		}
   2.101 +
   2.102 +		CloseHandle(dev_handle);
   2.103 +		dev_handle = 0;
   2.104 +	}
   2.105 +	SetupDiDestroyDeviceInfoList(devs);
   2.106 +
   2.107 +	if(!dev_handle) {
   2.108 +		fprintf(stderr, "failed to find matching USB HID device\n");
   2.109 +		return 1;
   2.110 +	}
   2.111 +
   2.112 +	printf("device found\n");
   2.113 +	_HIDP_PREPARSED_DATA *predata;
   2.114 +
   2.115 +	if(!HidD_GetPreparsedData(dev_handle, &predata)) {
   2.116 +		fprintf(stderr, "failed to get preparsed data(?)\n");
   2.117 +		goto cleanup;
   2.118 +	}
   2.119 +
   2.120 +	HIDP_CAPS caps;
   2.121 +	if(!HidP_GetCaps(predata, &caps)) {
   2.122 +		fprintf(stderr, "failed to retrieve device capabilities\n");
   2.123 +		HidD_FreePreparsedData(predata);
   2.124 +		goto cleanup;
   2.125 +	}
   2.126 +
   2.127 +	unsigned short num_value_caps = caps.NumberInputValueCaps;
   2.128 +	HIDP_VALUE_CAPS *value_caps = (HIDP_VALUE_CAPS*)malloc(num_value_caps * sizeof *value_caps);
   2.129 +	if(!value_caps) {
   2.130 +		perror("failed to allocate value caps array");
   2.131 +		HidD_FreePreparsedData(predata);
   2.132 +		goto cleanup;
   2.133 +	}
   2.134 +
   2.135 +	if(HidP_GetValueCaps(HidP_Input, value_caps, &num_value_caps, predata) != HIDP_STATUS_SUCCESS) {
   2.136 +		fprintf(stderr, "failed to retrieve device value capabilities\n");
   2.137 +		HidD_FreePreparsedData(predata);
   2.138 +		goto cleanup;
   2.139 +	}
   2.140 +	HidD_FreePreparsedData(predata);
   2.141 +
   2.142 +	int min_val = 0;
   2.143 +	int max_val = 0;
   2.144 +	for(unsigned int i=0; i<num_value_caps; i++) {
   2.145 +		printf("Usage page: %d\n", (int)value_caps[i].UsagePage);
   2.146 +		printf("Report ID: %d\n", (int)value_caps[i].ReportID);
   2.147 +		printf("Logical range: %d - %d\n", (int)value_caps[i].LogicalMin, (int)value_caps[i].LogicalMax);
   2.148 +		if(i == 0) {
   2.149 +			min_val = value_caps[i].LogicalMin;
   2.150 +			max_val = value_caps[i].LogicalMax;
   2.151 +		}
   2.152 +	}
   2.153 +	int val_range = max_val - min_val;
   2.154 +	printf("value range: %d\n", val_range);
   2.155 +
   2.156 +	int report_size = caps.InputReportByteLength;
   2.157 +	if(!(report = (Report*)malloc(report_size))) {
   2.158 +		perror("failed to allocate input report buffer");
   2.159 +		goto cleanup;
   2.160 +	}
   2.161 +
   2.162 +	//signal(SIGINT, sig_handler);
   2.163 +	if(!SetConsoleCtrlHandler(console_handler, 1)) {
   2.164 +		fprintf(stderr, "failed to install console control handler\n");
   2.165 +	}
   2.166 +
   2.167 +	static uint32_t bnstate = 0;
   2.168 +
   2.169 +	while(!done) {
   2.170 +		if(WaitForSingleObject(dev_handle, INFINITE) != 0) {
   2.171 +			fprintf(stderr, "error while waiting for device events\n");
   2.172 +			break;
   2.173 +		}
   2.174 +
   2.175 +		DWORD num_read;
   2.176 +		if(!ReadFile(dev_handle, report, report_size, &num_read, 0)) {
   2.177 +			fprintf(stderr, "failed to read input report\n");
   2.178 +			continue;
   2.179 +		}
   2.180 +
   2.181 +		switch(report->type) {
   2.182 +		case 1:	/* translation */
   2.183 +			{
   2.184 +				int x = report->motion.x;
   2.185 +				int y = report->motion.y;
   2.186 +				int z = report->motion.z;
   2.187 +				if(val_range != 0) {
   2.188 +					x = 100 * (x - min_val) / val_range - 50;
   2.189 +					y = 100 * (y - min_val) / val_range - 50;
   2.190 +					z = 100 * (z - min_val) / val_range - 50;
   2.191 +				}
   2.192 +				printf("MOTION %4d %4d %4d\n", x, y, z);
   2.193 +			}
   2.194 +			break;
   2.195 +
   2.196 +		case 2:	/* rotation */
   2.197 +			{
   2.198 +				int x = report->motion.x;
   2.199 +				int y = report->motion.y;
   2.200 +				int z = report->motion.z;
   2.201 +				if(val_range != 0) {
   2.202 +					x = 100 * (x - min_val) / val_range - 50;
   2.203 +					y = 100 * (y - min_val) / val_range - 50;
   2.204 +					z = 100 * (z - min_val) / val_range - 50;
   2.205 +				}
   2.206 +				printf("ROTATE %4d %4d %4d\n", x, y, z);
   2.207 +			}
   2.208 +			break;
   2.209 +
   2.210 +		case 3:
   2.211 +			bnstate = report->button.state;
   2.212 +			fputs("B: ", stdout);
   2.213 +			for(int i=0; i<24; i++) {
   2.214 +				int bn = 23 - i;
   2.215 +				if(bnstate & (1 << bn)) {
   2.216 +					fputc('1', stdout);
   2.217 +				} else {
   2.218 +					fputc('0', stdout);
   2.219 +				}
   2.220 +			}
   2.221 +			fputc('\n', stdout);
   2.222 +			break;
   2.223 +
   2.224 +		default:
   2.225 +			printf("unknown event type: %d\n", (int)report->type);
   2.226 +		}
   2.227 +	}
   2.228 +
   2.229 +cleanup:
   2.230 +	CloseHandle(dev_handle);
   2.231 +	return 0;
   2.232 +}
   2.233 +
   2.234 +static int WINAPI console_handler(DWORD s)
   2.235 +{
   2.236 +	if(s == CTRL_C_EVENT) {
   2.237 +		printf("Caught interrupt signal, quitting...\n");
   2.238 +		done = true;
   2.239 +	}
   2.240 +	return 0;
   2.241 +}
   2.242 \ No newline at end of file
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/spnav_winapi_test.sln	Sun Jul 07 04:21:49 2013 +0300
     3.3 @@ -0,0 +1,20 @@
     3.4 +
     3.5 +Microsoft Visual Studio Solution File, Format Version 10.00
     3.6 +# Visual Studio 2008
     3.7 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spnav_winapi_test", "spnav_winapi_test.vcproj", "{023D90F5-CE0A-412F-96F4-0B17444D21BB}"
     3.8 +EndProject
     3.9 +Global
    3.10 +	GlobalSection(SolutionConfigurationPlatforms) = preSolution
    3.11 +		Debug|Win32 = Debug|Win32
    3.12 +		Release|Win32 = Release|Win32
    3.13 +	EndGlobalSection
    3.14 +	GlobalSection(ProjectConfigurationPlatforms) = postSolution
    3.15 +		{023D90F5-CE0A-412F-96F4-0B17444D21BB}.Debug|Win32.ActiveCfg = Debug|Win32
    3.16 +		{023D90F5-CE0A-412F-96F4-0B17444D21BB}.Debug|Win32.Build.0 = Debug|Win32
    3.17 +		{023D90F5-CE0A-412F-96F4-0B17444D21BB}.Release|Win32.ActiveCfg = Release|Win32
    3.18 +		{023D90F5-CE0A-412F-96F4-0B17444D21BB}.Release|Win32.Build.0 = Release|Win32
    3.19 +	EndGlobalSection
    3.20 +	GlobalSection(SolutionProperties) = preSolution
    3.21 +		HideSolutionNode = FALSE
    3.22 +	EndGlobalSection
    3.23 +EndGlobal
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/spnav_winapi_test.vcproj	Sun Jul 07 04:21:49 2013 +0300
     4.3 @@ -0,0 +1,197 @@
     4.4 +<?xml version="1.0" encoding="Windows-1252"?>
     4.5 +<VisualStudioProject
     4.6 +	ProjectType="Visual C++"
     4.7 +	Version="9.00"
     4.8 +	Name="spnav_winapi_test"
     4.9 +	ProjectGUID="{023D90F5-CE0A-412F-96F4-0B17444D21BB}"
    4.10 +	RootNamespace="spnav_winapi_test"
    4.11 +	Keyword="Win32Proj"
    4.12 +	TargetFrameworkVersion="196613"
    4.13 +	>
    4.14 +	<Platforms>
    4.15 +		<Platform
    4.16 +			Name="Win32"
    4.17 +		/>
    4.18 +	</Platforms>
    4.19 +	<ToolFiles>
    4.20 +	</ToolFiles>
    4.21 +	<Configurations>
    4.22 +		<Configuration
    4.23 +			Name="Debug|Win32"
    4.24 +			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
    4.25 +			IntermediateDirectory="$(ConfigurationName)"
    4.26 +			ConfigurationType="1"
    4.27 +			CharacterSet="2"
    4.28 +			>
    4.29 +			<Tool
    4.30 +				Name="VCPreBuildEventTool"
    4.31 +			/>
    4.32 +			<Tool
    4.33 +				Name="VCCustomBuildTool"
    4.34 +			/>
    4.35 +			<Tool
    4.36 +				Name="VCXMLDataGeneratorTool"
    4.37 +			/>
    4.38 +			<Tool
    4.39 +				Name="VCWebServiceProxyGeneratorTool"
    4.40 +			/>
    4.41 +			<Tool
    4.42 +				Name="VCMIDLTool"
    4.43 +			/>
    4.44 +			<Tool
    4.45 +				Name="VCCLCompilerTool"
    4.46 +				Optimization="0"
    4.47 +				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
    4.48 +				MinimalRebuild="true"
    4.49 +				BasicRuntimeChecks="3"
    4.50 +				RuntimeLibrary="3"
    4.51 +				UsePrecompiledHeader="0"
    4.52 +				WarningLevel="3"
    4.53 +				DebugInformationFormat="4"
    4.54 +				DisableSpecificWarnings="4996;4244"
    4.55 +			/>
    4.56 +			<Tool
    4.57 +				Name="VCManagedResourceCompilerTool"
    4.58 +			/>
    4.59 +			<Tool
    4.60 +				Name="VCResourceCompilerTool"
    4.61 +			/>
    4.62 +			<Tool
    4.63 +				Name="VCPreLinkEventTool"
    4.64 +			/>
    4.65 +			<Tool
    4.66 +				Name="VCLinkerTool"
    4.67 +				AdditionalDependencies="hid.lib setupapi.lib"
    4.68 +				LinkIncremental="2"
    4.69 +				GenerateDebugInformation="true"
    4.70 +				SubSystem="1"
    4.71 +				TargetMachine="1"
    4.72 +			/>
    4.73 +			<Tool
    4.74 +				Name="VCALinkTool"
    4.75 +			/>
    4.76 +			<Tool
    4.77 +				Name="VCManifestTool"
    4.78 +			/>
    4.79 +			<Tool
    4.80 +				Name="VCXDCMakeTool"
    4.81 +			/>
    4.82 +			<Tool
    4.83 +				Name="VCBscMakeTool"
    4.84 +			/>
    4.85 +			<Tool
    4.86 +				Name="VCFxCopTool"
    4.87 +			/>
    4.88 +			<Tool
    4.89 +				Name="VCAppVerifierTool"
    4.90 +			/>
    4.91 +			<Tool
    4.92 +				Name="VCPostBuildEventTool"
    4.93 +			/>
    4.94 +		</Configuration>
    4.95 +		<Configuration
    4.96 +			Name="Release|Win32"
    4.97 +			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
    4.98 +			IntermediateDirectory="$(ConfigurationName)"
    4.99 +			ConfigurationType="1"
   4.100 +			CharacterSet="2"
   4.101 +			WholeProgramOptimization="1"
   4.102 +			>
   4.103 +			<Tool
   4.104 +				Name="VCPreBuildEventTool"
   4.105 +			/>
   4.106 +			<Tool
   4.107 +				Name="VCCustomBuildTool"
   4.108 +			/>
   4.109 +			<Tool
   4.110 +				Name="VCXMLDataGeneratorTool"
   4.111 +			/>
   4.112 +			<Tool
   4.113 +				Name="VCWebServiceProxyGeneratorTool"
   4.114 +			/>
   4.115 +			<Tool
   4.116 +				Name="VCMIDLTool"
   4.117 +			/>
   4.118 +			<Tool
   4.119 +				Name="VCCLCompilerTool"
   4.120 +				Optimization="2"
   4.121 +				EnableIntrinsicFunctions="true"
   4.122 +				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
   4.123 +				RuntimeLibrary="2"
   4.124 +				EnableFunctionLevelLinking="true"
   4.125 +				UsePrecompiledHeader="0"
   4.126 +				WarningLevel="3"
   4.127 +				DebugInformationFormat="3"
   4.128 +				DisableSpecificWarnings="4996;4244"
   4.129 +			/>
   4.130 +			<Tool
   4.131 +				Name="VCManagedResourceCompilerTool"
   4.132 +			/>
   4.133 +			<Tool
   4.134 +				Name="VCResourceCompilerTool"
   4.135 +			/>
   4.136 +			<Tool
   4.137 +				Name="VCPreLinkEventTool"
   4.138 +			/>
   4.139 +			<Tool
   4.140 +				Name="VCLinkerTool"
   4.141 +				AdditionalDependencies="hid.lib setupapi.lib"
   4.142 +				LinkIncremental="1"
   4.143 +				GenerateDebugInformation="true"
   4.144 +				SubSystem="1"
   4.145 +				OptimizeReferences="2"
   4.146 +				EnableCOMDATFolding="2"
   4.147 +				TargetMachine="1"
   4.148 +			/>
   4.149 +			<Tool
   4.150 +				Name="VCALinkTool"
   4.151 +			/>
   4.152 +			<Tool
   4.153 +				Name="VCManifestTool"
   4.154 +			/>
   4.155 +			<Tool
   4.156 +				Name="VCXDCMakeTool"
   4.157 +			/>
   4.158 +			<Tool
   4.159 +				Name="VCBscMakeTool"
   4.160 +			/>
   4.161 +			<Tool
   4.162 +				Name="VCFxCopTool"
   4.163 +			/>
   4.164 +			<Tool
   4.165 +				Name="VCAppVerifierTool"
   4.166 +			/>
   4.167 +			<Tool
   4.168 +				Name="VCPostBuildEventTool"
   4.169 +			/>
   4.170 +		</Configuration>
   4.171 +	</Configurations>
   4.172 +	<References>
   4.173 +	</References>
   4.174 +	<Files>
   4.175 +		<Filter
   4.176 +			Name="Source Files"
   4.177 +			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
   4.178 +			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
   4.179 +			>
   4.180 +			<File
   4.181 +				RelativePath=".\main.cpp"
   4.182 +				>
   4.183 +			</File>
   4.184 +		</Filter>
   4.185 +		<Filter
   4.186 +			Name="Header Files"
   4.187 +			Filter="h;hpp;hxx;hm;inl;inc;xsd"
   4.188 +			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
   4.189 +			>
   4.190 +		</Filter>
   4.191 +		<Filter
   4.192 +			Name="Resource Files"
   4.193 +			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
   4.194 +			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
   4.195 +			>
   4.196 +		</Filter>
   4.197 +	</Files>
   4.198 +	<Globals>
   4.199 +	</Globals>
   4.200 +</VisualStudioProject>