src/sensor/windows/SDL_windowssensor.c
changeset 13710 a1a6885cff94
child 13714 0d9ea2541827
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/sensor/windows/SDL_windowssensor.c	Wed Apr 08 08:34:27 2020 -0700
     1.3 @@ -0,0 +1,480 @@
     1.4 +/*
     1.5 +  Simple DirectMedia Layer
     1.6 +  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
     1.7 +
     1.8 +  This software is provided 'as-is', without any express or implied
     1.9 +  warranty.  In no event will the authors be held liable for any damages
    1.10 +  arising from the use of this software.
    1.11 +
    1.12 +  Permission is granted to anyone to use this software for any purpose,
    1.13 +  including commercial applications, and to alter it and redistribute it
    1.14 +  freely, subject to the following restrictions:
    1.15 +
    1.16 +  1. The origin of this software must not be misrepresented; you must not
    1.17 +     claim that you wrote the original software. If you use this software
    1.18 +     in a product, an acknowledgment in the product documentation would be
    1.19 +     appreciated but is not required.
    1.20 +  2. Altered source versions must be plainly marked as such, and must not be
    1.21 +     misrepresented as being the original software.
    1.22 +  3. This notice may not be removed or altered from any source distribution.
    1.23 +*/
    1.24 +#include "../../SDL_internal.h"
    1.25 +
    1.26 +#include "SDL_config.h"
    1.27 +
    1.28 +#if defined(SDL_SENSOR_WINDOWS)
    1.29 +
    1.30 +#include "SDL_error.h"
    1.31 +#include "SDL_mutex.h"
    1.32 +#include "SDL_sensor.h"
    1.33 +#include "SDL_windowssensor.h"
    1.34 +#include "../SDL_syssensor.h"
    1.35 +#include "../../core/windows/SDL_windows.h"
    1.36 +
    1.37 +#define COBJMACROS
    1.38 +#include <InitGuid.h>
    1.39 +#include <SensorsApi.h>
    1.40 +#include <Sensors.h>
    1.41 +
    1.42 +DEFINE_GUID(CLSID_SensorManager, 0x77A1C827, 0xFCD2, 0x4689, 0x89, 0x15, 0x9D, 0x61, 0x3C, 0xC5, 0xFA, 0x3E);
    1.43 +DEFINE_GUID(IID_SensorManager, 0xBD77DB67, 0x45A8, 0x42DC, 0x8D, 0x00, 0x6D, 0xCF, 0x15, 0xF8, 0x37, 0x7A);
    1.44 +DEFINE_GUID(IID_SensorManagerEvents, 0x9B3B0B86, 0x266A, 0x4AAD, 0xB2, 0x1F, 0xFD, 0xE5, 0x50, 0x10, 0x01, 0xB7);
    1.45 +DEFINE_GUID(IID_SensorEvents, 0x5D8DCC91, 0x4641, 0x47E7, 0xB7, 0xC3, 0xB7, 0x4F, 0x48, 0xA6, 0xC3, 0x91);
    1.46 +
    1.47 +DEFINE_PROPERTYKEY(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND, 0X3F8A69A2, 0X7C5, 0X4E48, 0XA9, 0X65, 0XCD, 0X79, 0X7A, 0XAB, 0X56, 0XD5, 10); //[VT_R8]
    1.48 +DEFINE_PROPERTYKEY(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND, 0X3F8A69A2, 0X7C5, 0X4E48, 0XA9, 0X65, 0XCD, 0X79, 0X7A, 0XAB, 0X56, 0XD5, 11); //[VT_R8]
    1.49 +DEFINE_PROPERTYKEY(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND, 0X3F8A69A2, 0X7C5, 0X4E48, 0XA9, 0X65, 0XCD, 0X79, 0X7A, 0XAB, 0X56, 0XD5, 12); //[VT_R8]
    1.50 +
    1.51 +typedef struct
    1.52 +{
    1.53 +	SDL_SensorID id;
    1.54 +	ISensor *sensor;
    1.55 +	SENSOR_ID sensor_id;
    1.56 +	char *name;
    1.57 +	SDL_SensorType type;
    1.58 +	SDL_Sensor *sensor_opened;
    1.59 +
    1.60 +} SDL_Windows_Sensor;
    1.61 +
    1.62 +static SDL_bool SDL_windowscoinit;
    1.63 +static ISensorManager *SDL_sensor_manager;
    1.64 +static int SDL_num_sensors;
    1.65 +static SDL_Windows_Sensor *SDL_sensors;
    1.66 +
    1.67 +static int ConnectSensor(ISensor *sensor);
    1.68 +static int DisconnectSensor(ISensor *sensor);
    1.69 +
    1.70 +static HRESULT STDMETHODCALLTYPE ISensorManagerEventsVtbl_QueryInterface(ISensorManagerEvents * This, REFIID riid, void **ppvObject)
    1.71 +{
    1.72 +	if (!ppvObject) {
    1.73 +		return E_INVALIDARG;
    1.74 +	}
    1.75 +
    1.76 +	*ppvObject = NULL;
    1.77 +	if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &IID_SensorManagerEvents)) {
    1.78 +		*ppvObject = This;
    1.79 +		return S_OK;
    1.80 +	}
    1.81 +	return E_NOINTERFACE;
    1.82 +}
    1.83 +
    1.84 +static ULONG STDMETHODCALLTYPE ISensorManagerEventsVtbl_AddRef(ISensorManagerEvents * This)
    1.85 +{
    1.86 +	return 1;
    1.87 +}
    1.88 +
    1.89 +static ULONG STDMETHODCALLTYPE ISensorManagerEventsVtbl_Release(ISensorManagerEvents * This)
    1.90 +{
    1.91 +	return 1;
    1.92 +}
    1.93 +
    1.94 +static HRESULT STDMETHODCALLTYPE ISensorManagerEventsVtbl_OnSensorEnter(ISensorManagerEvents * This, ISensor *pSensor, SensorState state)
    1.95 +{
    1.96 +	ConnectSensor(pSensor);
    1.97 +	return S_OK;
    1.98 +}
    1.99 +
   1.100 +static ISensorManagerEventsVtbl sensor_manager_events_vtbl = {
   1.101 +	ISensorManagerEventsVtbl_QueryInterface,
   1.102 +	ISensorManagerEventsVtbl_AddRef,
   1.103 +	ISensorManagerEventsVtbl_Release,
   1.104 +	ISensorManagerEventsVtbl_OnSensorEnter
   1.105 +};
   1.106 +static ISensorManagerEvents sensor_manager_events = {
   1.107 +	&sensor_manager_events_vtbl
   1.108 +};
   1.109 +
   1.110 +static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_QueryInterface(ISensorEvents * This, REFIID riid, void **ppvObject)
   1.111 +{
   1.112 +	if (!ppvObject) {
   1.113 +		return E_INVALIDARG;
   1.114 +	}
   1.115 +
   1.116 +	*ppvObject = NULL;
   1.117 +	if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &IID_SensorEvents)) {
   1.118 +		*ppvObject = This;
   1.119 +		return S_OK;
   1.120 +	}
   1.121 +	return E_NOINTERFACE;
   1.122 +}
   1.123 +
   1.124 +static ULONG STDMETHODCALLTYPE ISensorEventsVtbl_AddRef(ISensorEvents * This)
   1.125 +{
   1.126 +	return 1;
   1.127 +}
   1.128 +
   1.129 +static ULONG STDMETHODCALLTYPE ISensorEventsVtbl_Release(ISensorEvents * This)
   1.130 +{
   1.131 +	return 1;
   1.132 +}
   1.133 +
   1.134 +static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnStateChanged(ISensorEvents * This, ISensor *pSensor, SensorState state)
   1.135 +{
   1.136 +#ifdef DEBUG_SENSORS
   1.137 +	int i;
   1.138 +
   1.139 +	SDL_LockSensors();
   1.140 +	for (i = 0; i < SDL_num_sensors; ++i) {
   1.141 +		if (pSensor == SDL_sensors[i].sensor) {
   1.142 +			SDL_Log("Sensor %s state changed to %d\n", SDL_sensors[i].name, state);
   1.143 +		}
   1.144 +	}
   1.145 +	SDL_UnlockSensors();
   1.146 +#endif
   1.147 +	return S_OK;
   1.148 +}
   1.149 +
   1.150 +static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnDataUpdated(ISensorEvents * This, ISensor *pSensor, ISensorDataReport *pNewData)
   1.151 +{
   1.152 +	int i;
   1.153 +
   1.154 +	SDL_LockSensors();
   1.155 +	for (i = 0; i < SDL_num_sensors; ++i) {
   1.156 +		if (pSensor == SDL_sensors[i].sensor) {
   1.157 +			if (SDL_sensors[i].sensor_opened) {
   1.158 +				HRESULT hrX, hrY, hrZ;
   1.159 +				PROPVARIANT valueX, valueY, valueZ;
   1.160 +
   1.161 +#ifdef DEBUG_SENSORS
   1.162 +				SDL_Log("Sensor %s data updated\n", SDL_sensors[i].name);
   1.163 +#endif
   1.164 +				switch (SDL_sensors[i].type) {
   1.165 +				case SDL_SENSOR_ACCEL:
   1.166 +					hrX = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_X_G, &valueX);
   1.167 +					hrY = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_Y_G, &valueY);
   1.168 +					hrZ = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_Z_G, &valueZ);
   1.169 +					if (SUCCEEDED(hrX) && SUCCEEDED(hrY) && SUCCEEDED(hrZ) &&
   1.170 +						valueX.vt == VT_R8 && valueY.vt == VT_R8 && valueZ.vt == VT_R8) {
   1.171 +						float values[3];
   1.172 +
   1.173 +						values[0] = (float)valueX.dblVal;
   1.174 +						values[1] = (float)valueY.dblVal;
   1.175 +						values[2] = (float)valueZ.dblVal;
   1.176 +						SDL_PrivateSensorUpdate(SDL_sensors[i].sensor_opened, values, 3);
   1.177 +					}
   1.178 +					break;
   1.179 +				case SDL_SENSOR_GYRO:
   1.180 +					hrX = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND, &valueX);
   1.181 +					hrY = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND, &valueY);
   1.182 +					hrZ = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND, &valueZ);
   1.183 +					if (SUCCEEDED(hrX) && SUCCEEDED(hrY) && SUCCEEDED(hrZ) &&
   1.184 +						valueX.vt == VT_R8 && valueY.vt == VT_R8 && valueZ.vt == VT_R8) {
   1.185 +						float values[3];
   1.186 +
   1.187 +						values[0] = (float)(valueX.dblVal * (M_PI / 180.0));
   1.188 +						values[1] = (float)(valueY.dblVal * (M_PI / 180.0));
   1.189 +						values[2] = (float)(valueZ.dblVal * (M_PI / 180.0));
   1.190 +						SDL_PrivateSensorUpdate(SDL_sensors[i].sensor_opened, values, 3);
   1.191 +					}
   1.192 +					break;
   1.193 +				default:
   1.194 +					/* FIXME: Need to know how to interpret the data for this sensor */
   1.195 +					break;
   1.196 +				}
   1.197 +			}
   1.198 +			break;
   1.199 +		}
   1.200 +	}
   1.201 +	SDL_UnlockSensors();
   1.202 +
   1.203 +	return S_OK;
   1.204 +}
   1.205 +
   1.206 +static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnEvent(ISensorEvents * This, ISensor *pSensor, REFGUID eventID, IPortableDeviceValues *pEventData)
   1.207 +{
   1.208 +#ifdef DEBUG_SENSORS
   1.209 +	int i;
   1.210 +
   1.211 +	SDL_LockSensors();
   1.212 +	for (i = 0; i < SDL_num_sensors; ++i) {
   1.213 +		if (pSensor == SDL_sensors[i].sensor) {
   1.214 +			SDL_Log("Sensor %s event occurred\n", SDL_sensors[i].name);
   1.215 +		}
   1.216 +	}
   1.217 +	SDL_UnlockSensors();
   1.218 +#endif
   1.219 +	return S_OK;
   1.220 +}
   1.221 +
   1.222 +static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnLeave(ISensorEvents * This, REFSENSOR_ID ID)
   1.223 +{
   1.224 +	int i;
   1.225 +
   1.226 +	SDL_LockSensors();
   1.227 +	for (i = 0; i < SDL_num_sensors; ++i) {
   1.228 +		if (WIN_IsEqualIID(ID, &SDL_sensors[i].sensor_id)) {
   1.229 +#ifdef DEBUG_SENSORS
   1.230 +			SDL_Log("Sensor %s disconnected\n", SDL_sensors[i].name);
   1.231 +#endif
   1.232 +			DisconnectSensor(SDL_sensors[i].sensor);
   1.233 +		}
   1.234 +	}
   1.235 +	SDL_UnlockSensors();
   1.236 +
   1.237 +	return S_OK;
   1.238 +}
   1.239 +
   1.240 +static ISensorEventsVtbl sensor_events_vtbl = {
   1.241 +	ISensorEventsVtbl_QueryInterface,
   1.242 +	ISensorEventsVtbl_AddRef,
   1.243 +	ISensorEventsVtbl_Release,
   1.244 +	ISensorEventsVtbl_OnStateChanged,
   1.245 +	ISensorEventsVtbl_OnDataUpdated,
   1.246 +	ISensorEventsVtbl_OnEvent,
   1.247 +	ISensorEventsVtbl_OnLeave
   1.248 +};
   1.249 +static ISensorEvents sensor_events = {
   1.250 +	&sensor_events_vtbl
   1.251 +};
   1.252 +
   1.253 +static int ConnectSensor(ISensor *sensor)
   1.254 +{
   1.255 +	SDL_Windows_Sensor *new_sensor, *new_sensors;
   1.256 +	HRESULT hr;
   1.257 +	SENSOR_ID sensor_id;
   1.258 +	SENSOR_TYPE_ID type_id;
   1.259 +	SDL_SensorType type;
   1.260 +	BSTR bstr_name = NULL;
   1.261 +	char *name;
   1.262 +
   1.263 +	hr = ISensor_GetID(sensor, &sensor_id);
   1.264 +	if (FAILED(hr)) {
   1.265 +		return SDL_SetError("Couldn't get sensor ID: 0x%.4x", hr);
   1.266 +	}
   1.267 +
   1.268 +	hr = ISensor_GetType(sensor, &type_id);
   1.269 +	if (FAILED(hr)) {
   1.270 +		return SDL_SetError("Couldn't get sensor type: 0x%.4x", hr);
   1.271 +	}
   1.272 +
   1.273 +	if (WIN_IsEqualIID(&type_id, &SENSOR_TYPE_ACCELEROMETER_3D)) {
   1.274 +		type = SDL_SENSOR_ACCEL;
   1.275 +	} else if (WIN_IsEqualIID(&type_id, &SENSOR_TYPE_GYROMETER_3D)) {
   1.276 +		type = SDL_SENSOR_GYRO;
   1.277 +	} else {
   1.278 +		return SDL_SetError("Unknown sensor type");
   1.279 +	}
   1.280 +
   1.281 +	hr = ISensor_GetFriendlyName(sensor, &bstr_name);
   1.282 +	if (SUCCEEDED(hr) && bstr_name) {
   1.283 +		name = WIN_StringToUTF8(bstr_name);
   1.284 +	} else {
   1.285 +		name = SDL_strdup("Unknown Sensor");
   1.286 +	}
   1.287 +	if (!name) {
   1.288 +		return SDL_OutOfMemory();
   1.289 +	}
   1.290 +
   1.291 +	SDL_LockSensors();
   1.292 +	new_sensors = (SDL_Windows_Sensor *)SDL_realloc(SDL_sensors, (SDL_num_sensors + 1) * sizeof(SDL_Windows_Sensor));
   1.293 +	if (new_sensors == NULL) {
   1.294 +		SDL_UnlockSensors();
   1.295 +		return SDL_OutOfMemory();
   1.296 +	}
   1.297 +
   1.298 +	ISensor_AddRef(sensor);
   1.299 +	ISensor_SetEventSink(sensor, &sensor_events);
   1.300 +
   1.301 +	SDL_sensors = new_sensors;
   1.302 +	new_sensor = &SDL_sensors[SDL_num_sensors];
   1.303 +	++SDL_num_sensors;
   1.304 +
   1.305 +	new_sensor->id = SDL_GetNextSensorInstanceID();
   1.306 +	new_sensor->sensor = sensor;
   1.307 +	new_sensor->type = type;
   1.308 +	new_sensor->name = name;
   1.309 +
   1.310 +	SDL_UnlockSensors();
   1.311 +
   1.312 +	return 0;
   1.313 +}
   1.314 +
   1.315 +static int DisconnectSensor(ISensor *sensor)
   1.316 +{
   1.317 +	SDL_Windows_Sensor *old_sensor;
   1.318 +	int i;
   1.319 +
   1.320 +	SDL_LockSensors();
   1.321 +	for (i = 0; i < SDL_num_sensors; ++i) {
   1.322 +		old_sensor = &SDL_sensors[i];
   1.323 +		if (sensor == old_sensor->sensor) {
   1.324 +			ISensor_SetEventSink(sensor, NULL);
   1.325 +			ISensor_Release(sensor);
   1.326 +			SDL_free(old_sensor->name);
   1.327 +			--SDL_num_sensors;
   1.328 +			if (i < SDL_num_sensors) {
   1.329 +				SDL_memmove(&SDL_sensors[i], &SDL_sensors[i + 1], (SDL_num_sensors - i) * sizeof(SDL_sensors[i]));
   1.330 +			}
   1.331 +			break;
   1.332 +		}
   1.333 +	}
   1.334 +	SDL_UnlockSensors();
   1.335 +
   1.336 +	return 0;
   1.337 +}
   1.338 +
   1.339 +static int
   1.340 +SDL_WINDOWS_SensorInit(void)
   1.341 +{
   1.342 +	HRESULT hr;
   1.343 +	ISensorCollection *sensor_collection = NULL;
   1.344 +
   1.345 +	while (!IsDebuggerPresent()) Sleep(100);
   1.346 +
   1.347 +	if (WIN_CoInitialize() == S_OK) {
   1.348 +		SDL_windowscoinit = SDL_TRUE;
   1.349 +	}
   1.350 +
   1.351 +	hr = CoCreateInstance(&CLSID_SensorManager, NULL, CLSCTX_INPROC_SERVER, &IID_SensorManager, &SDL_sensor_manager);
   1.352 +	if (FAILED(hr)) {
   1.353 +		return SDL_SetError("Couldn't create the sensor manager: 0x%.4x", hr);
   1.354 +	}
   1.355 +
   1.356 +	hr = ISensorManager_SetEventSink(SDL_sensor_manager, &sensor_manager_events);
   1.357 +	if (FAILED(hr)) {
   1.358 +		ISensorManager_Release(SDL_sensor_manager);
   1.359 +		return SDL_SetError("Couldn't set the sensor manager event sink: 0x%.4x", hr);
   1.360 +	}
   1.361 +
   1.362 +	hr = ISensorManager_GetSensorsByCategory(SDL_sensor_manager, &SENSOR_CATEGORY_ALL, &sensor_collection);
   1.363 +	if (SUCCEEDED(hr)) {
   1.364 +		ULONG i, count;
   1.365 +
   1.366 +		hr = ISensorCollection_GetCount(sensor_collection, &count);
   1.367 +		if (SUCCEEDED(hr)) {
   1.368 +			for (i = 0; i < count; ++i) {
   1.369 +				ISensor *sensor;
   1.370 +
   1.371 +				hr = ISensorCollection_GetAt(sensor_collection, i, &sensor);
   1.372 +				if (SUCCEEDED(hr)) {
   1.373 +					SensorState state;
   1.374 +
   1.375 +					hr = ISensor_GetState(sensor, &state);
   1.376 +					if (SUCCEEDED(hr)) {
   1.377 +						ISensorManagerEventsVtbl_OnSensorEnter(&sensor_manager_events, sensor, state);
   1.378 +					}
   1.379 +					ISensorManager_Release(sensor);
   1.380 +				}
   1.381 +			}
   1.382 +		}
   1.383 +		ISensorCollection_Release(sensor_collection);
   1.384 +	}
   1.385 +    return 0;
   1.386 +}
   1.387 +
   1.388 +static int
   1.389 +SDL_WINDOWS_SensorGetCount(void)
   1.390 +{
   1.391 +    return SDL_num_sensors;
   1.392 +}
   1.393 +
   1.394 +static void
   1.395 +SDL_WINDOWS_SensorDetect(void)
   1.396 +{
   1.397 +}
   1.398 +
   1.399 +static const char *
   1.400 +SDL_WINDOWS_SensorGetDeviceName(int device_index)
   1.401 +{
   1.402 +    return SDL_sensors[device_index].name;
   1.403 +}
   1.404 +
   1.405 +static SDL_SensorType
   1.406 +SDL_WINDOWS_SensorGetDeviceType(int device_index)
   1.407 +{
   1.408 +	return SDL_sensors[device_index].type;
   1.409 +}
   1.410 +
   1.411 +static int
   1.412 +SDL_WINDOWS_SensorGetDeviceNonPortableType(int device_index)
   1.413 +{
   1.414 +    return -1;
   1.415 +}
   1.416 +
   1.417 +static SDL_SensorID
   1.418 +SDL_WINDOWS_SensorGetDeviceInstanceID(int device_index)
   1.419 +{
   1.420 +    return SDL_sensors[device_index].id;
   1.421 +}
   1.422 +
   1.423 +static int
   1.424 +SDL_WINDOWS_SensorOpen(SDL_Sensor *sensor, int device_index)
   1.425 +{
   1.426 +	SDL_sensors[device_index].sensor_opened = sensor;
   1.427 +    return 0;
   1.428 +}
   1.429 +
   1.430 +static void
   1.431 +SDL_WINDOWS_SensorUpdate(SDL_Sensor *sensor)
   1.432 +{
   1.433 +}
   1.434 +
   1.435 +static void
   1.436 +SDL_WINDOWS_SensorClose(SDL_Sensor *sensor)
   1.437 +{
   1.438 +	int i;
   1.439 +
   1.440 +	for (i = 0; i < SDL_num_sensors; ++i) {
   1.441 +		if (sensor == SDL_sensors[i].sensor_opened) {
   1.442 +			SDL_sensors[i].sensor_opened = NULL;
   1.443 +			break;
   1.444 +		}
   1.445 +	}
   1.446 +}
   1.447 +
   1.448 +static void
   1.449 +SDL_WINDOWS_SensorQuit(void)
   1.450 +{
   1.451 +	while (SDL_num_sensors > 0) {
   1.452 +		DisconnectSensor(SDL_sensors[0].sensor);
   1.453 +	}
   1.454 +
   1.455 +	if (SDL_sensor_manager) {
   1.456 +		ISensorManager_SetEventSink(SDL_sensor_manager, NULL);
   1.457 +		ISensorManager_Release(SDL_sensor_manager);
   1.458 +		SDL_sensor_manager = NULL;
   1.459 +	}
   1.460 +
   1.461 +	if (SDL_windowscoinit) {
   1.462 +		WIN_CoUninitialize();
   1.463 +	}
   1.464 +}
   1.465 +
   1.466 +SDL_SensorDriver SDL_WINDOWS_SensorDriver =
   1.467 +{
   1.468 +    SDL_WINDOWS_SensorInit,
   1.469 +    SDL_WINDOWS_SensorGetCount,
   1.470 +    SDL_WINDOWS_SensorDetect,
   1.471 +    SDL_WINDOWS_SensorGetDeviceName,
   1.472 +    SDL_WINDOWS_SensorGetDeviceType,
   1.473 +    SDL_WINDOWS_SensorGetDeviceNonPortableType,
   1.474 +    SDL_WINDOWS_SensorGetDeviceInstanceID,
   1.475 +    SDL_WINDOWS_SensorOpen,
   1.476 +    SDL_WINDOWS_SensorUpdate,
   1.477 +    SDL_WINDOWS_SensorClose,
   1.478 +    SDL_WINDOWS_SensorQuit,
   1.479 +};
   1.480 +
   1.481 +#endif /* SDL_SENSOR_WINDOWS */
   1.482 +
   1.483 +/* vi: set ts=4 sw=4 expandtab: */