1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22
23 #include "SDL_config.h"
24
25 #if defined(SDL_SENSOR_WINDOWS)
26
27 #include "SDL_error.h"
28 #include "SDL_mutex.h"
29 #include "SDL_sensor.h"
30 #include "SDL_windowssensor.h"
31 #include "../SDL_syssensor.h"
32 #include "../../core/windows/SDL_windows.h"
33
34 #define COBJMACROS
35 #include <initguid.h>
36 #include <sensorsapi.h>
37 #include <sensors.h>
38
39 DEFINE_GUID(SDL_CLSID_SensorManager, 0x77A1C827, 0xFCD2, 0x4689, 0x89, 0x15, 0x9D, 0x61, 0x3C, 0xC5, 0xFA, 0x3E);
40 DEFINE_GUID(SDL_IID_SensorManager, 0xBD77DB67, 0x45A8, 0x42DC, 0x8D, 0x00, 0x6D, 0xCF, 0x15, 0xF8, 0x37, 0x7A);
41 DEFINE_GUID(SDL_IID_SensorManagerEvents, 0x9B3B0B86, 0x266A, 0x4AAD, 0xB2, 0x1F, 0xFD, 0xE5, 0x50, 0x10, 0x01, 0xB7);
42 DEFINE_GUID(SDL_IID_SensorEvents, 0x5D8DCC91, 0x4641, 0x47E7, 0xB7, 0xC3, 0xB7, 0x4F, 0x48, 0xA6, 0xC3, 0x91);
43
44 /* These constants aren't available in Visual Studio 2015 or earlier Windows SDK */
45 DEFINE_PROPERTYKEY(SDL_SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND, 0X3F8A69A2, 0X7C5, 0X4E48, 0XA9, 0X65, 0XCD, 0X79, 0X7A, 0XAB, 0X56, 0XD5, 10); //[VT_R8]
46 DEFINE_PROPERTYKEY(SDL_SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND, 0X3F8A69A2, 0X7C5, 0X4E48, 0XA9, 0X65, 0XCD, 0X79, 0X7A, 0XAB, 0X56, 0XD5, 11); //[VT_R8]
47 DEFINE_PROPERTYKEY(SDL_SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND, 0X3F8A69A2, 0X7C5, 0X4E48, 0XA9, 0X65, 0XCD, 0X79, 0X7A, 0XAB, 0X56, 0XD5, 12); //[VT_R8]
48
49 typedef struct
50 {
51 SDL_SensorID id;
52 ISensor *sensor;
53 SENSOR_ID sensor_id;
54 char *name;
55 SDL_SensorType type;
56 SDL_Sensor *sensor_opened;
57
58 } SDL_Windows_Sensor;
59
60 static SDL_bool SDL_windowscoinit;
61 static ISensorManager *SDL_sensor_manager;
62 static int SDL_num_sensors;
63 static SDL_Windows_Sensor *SDL_sensors;
64
65 static int ConnectSensor(ISensor *sensor);
66 static int DisconnectSensor(ISensor *sensor);
67
ISensorManagerEventsVtbl_QueryInterface(ISensorManagerEvents * This,REFIID riid,void ** ppvObject)68 static HRESULT STDMETHODCALLTYPE ISensorManagerEventsVtbl_QueryInterface(ISensorManagerEvents * This, REFIID riid, void **ppvObject)
69 {
70 if (!ppvObject) {
71 return E_INVALIDARG;
72 }
73
74 *ppvObject = NULL;
75 if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &SDL_IID_SensorManagerEvents)) {
76 *ppvObject = This;
77 return S_OK;
78 }
79 return E_NOINTERFACE;
80 }
81
ISensorManagerEventsVtbl_AddRef(ISensorManagerEvents * This)82 static ULONG STDMETHODCALLTYPE ISensorManagerEventsVtbl_AddRef(ISensorManagerEvents * This)
83 {
84 return 1;
85 }
86
ISensorManagerEventsVtbl_Release(ISensorManagerEvents * This)87 static ULONG STDMETHODCALLTYPE ISensorManagerEventsVtbl_Release(ISensorManagerEvents * This)
88 {
89 return 1;
90 }
91
ISensorManagerEventsVtbl_OnSensorEnter(ISensorManagerEvents * This,ISensor * pSensor,SensorState state)92 static HRESULT STDMETHODCALLTYPE ISensorManagerEventsVtbl_OnSensorEnter(ISensorManagerEvents * This, ISensor *pSensor, SensorState state)
93 {
94 ConnectSensor(pSensor);
95 return S_OK;
96 }
97
98 static ISensorManagerEventsVtbl sensor_manager_events_vtbl = {
99 ISensorManagerEventsVtbl_QueryInterface,
100 ISensorManagerEventsVtbl_AddRef,
101 ISensorManagerEventsVtbl_Release,
102 ISensorManagerEventsVtbl_OnSensorEnter
103 };
104 static ISensorManagerEvents sensor_manager_events = {
105 &sensor_manager_events_vtbl
106 };
107
ISensorEventsVtbl_QueryInterface(ISensorEvents * This,REFIID riid,void ** ppvObject)108 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_QueryInterface(ISensorEvents * This, REFIID riid, void **ppvObject)
109 {
110 if (!ppvObject) {
111 return E_INVALIDARG;
112 }
113
114 *ppvObject = NULL;
115 if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &SDL_IID_SensorEvents)) {
116 *ppvObject = This;
117 return S_OK;
118 }
119 return E_NOINTERFACE;
120 }
121
ISensorEventsVtbl_AddRef(ISensorEvents * This)122 static ULONG STDMETHODCALLTYPE ISensorEventsVtbl_AddRef(ISensorEvents * This)
123 {
124 return 1;
125 }
126
ISensorEventsVtbl_Release(ISensorEvents * This)127 static ULONG STDMETHODCALLTYPE ISensorEventsVtbl_Release(ISensorEvents * This)
128 {
129 return 1;
130 }
131
ISensorEventsVtbl_OnStateChanged(ISensorEvents * This,ISensor * pSensor,SensorState state)132 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnStateChanged(ISensorEvents * This, ISensor *pSensor, SensorState state)
133 {
134 #ifdef DEBUG_SENSORS
135 int i;
136
137 SDL_LockSensors();
138 for (i = 0; i < SDL_num_sensors; ++i) {
139 if (pSensor == SDL_sensors[i].sensor) {
140 SDL_Log("Sensor %s state changed to %d\n", SDL_sensors[i].name, state);
141 }
142 }
143 SDL_UnlockSensors();
144 #endif
145 return S_OK;
146 }
147
ISensorEventsVtbl_OnDataUpdated(ISensorEvents * This,ISensor * pSensor,ISensorDataReport * pNewData)148 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnDataUpdated(ISensorEvents * This, ISensor *pSensor, ISensorDataReport *pNewData)
149 {
150 int i;
151
152 SDL_LockSensors();
153 for (i = 0; i < SDL_num_sensors; ++i) {
154 if (pSensor == SDL_sensors[i].sensor) {
155 if (SDL_sensors[i].sensor_opened) {
156 HRESULT hrX, hrY, hrZ;
157 PROPVARIANT valueX, valueY, valueZ;
158
159 #ifdef DEBUG_SENSORS
160 SDL_Log("Sensor %s data updated\n", SDL_sensors[i].name);
161 #endif
162 switch (SDL_sensors[i].type) {
163 case SDL_SENSOR_ACCEL:
164 hrX = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_X_G, &valueX);
165 hrY = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_Y_G, &valueY);
166 hrZ = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_Z_G, &valueZ);
167 if (SUCCEEDED(hrX) && SUCCEEDED(hrY) && SUCCEEDED(hrZ) &&
168 valueX.vt == VT_R8 && valueY.vt == VT_R8 && valueZ.vt == VT_R8) {
169 float values[3];
170
171 values[0] = (float)valueX.dblVal * SDL_STANDARD_GRAVITY;
172 values[1] = (float)valueY.dblVal * SDL_STANDARD_GRAVITY;
173 values[2] = (float)valueZ.dblVal * SDL_STANDARD_GRAVITY;
174 SDL_PrivateSensorUpdate(SDL_sensors[i].sensor_opened, values, 3);
175 }
176 break;
177 case SDL_SENSOR_GYRO:
178 hrX = ISensorDataReport_GetSensorValue(pNewData, &SDL_SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND, &valueX);
179 hrY = ISensorDataReport_GetSensorValue(pNewData, &SDL_SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND, &valueY);
180 hrZ = ISensorDataReport_GetSensorValue(pNewData, &SDL_SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND, &valueZ);
181 if (SUCCEEDED(hrX) && SUCCEEDED(hrY) && SUCCEEDED(hrZ) &&
182 valueX.vt == VT_R8 && valueY.vt == VT_R8 && valueZ.vt == VT_R8) {
183 const float DEGREES_TO_RADIANS = (float)(M_PI / 180.0f);
184 float values[3];
185
186 values[0] = (float)valueX.dblVal * DEGREES_TO_RADIANS;
187 values[1] = (float)valueY.dblVal * DEGREES_TO_RADIANS;
188 values[2] = (float)valueZ.dblVal * DEGREES_TO_RADIANS;
189 SDL_PrivateSensorUpdate(SDL_sensors[i].sensor_opened, values, 3);
190 }
191 break;
192 default:
193 /* FIXME: Need to know how to interpret the data for this sensor */
194 break;
195 }
196 }
197 break;
198 }
199 }
200 SDL_UnlockSensors();
201
202 return S_OK;
203 }
204
ISensorEventsVtbl_OnEvent(ISensorEvents * This,ISensor * pSensor,REFGUID eventID,IPortableDeviceValues * pEventData)205 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnEvent(ISensorEvents * This, ISensor *pSensor, REFGUID eventID, IPortableDeviceValues *pEventData)
206 {
207 #ifdef DEBUG_SENSORS
208 int i;
209
210 SDL_LockSensors();
211 for (i = 0; i < SDL_num_sensors; ++i) {
212 if (pSensor == SDL_sensors[i].sensor) {
213 SDL_Log("Sensor %s event occurred\n", SDL_sensors[i].name);
214 }
215 }
216 SDL_UnlockSensors();
217 #endif
218 return S_OK;
219 }
220
ISensorEventsVtbl_OnLeave(ISensorEvents * This,REFSENSOR_ID ID)221 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnLeave(ISensorEvents * This, REFSENSOR_ID ID)
222 {
223 int i;
224
225 SDL_LockSensors();
226 for (i = 0; i < SDL_num_sensors; ++i) {
227 if (WIN_IsEqualIID(ID, &SDL_sensors[i].sensor_id)) {
228 #ifdef DEBUG_SENSORS
229 SDL_Log("Sensor %s disconnected\n", SDL_sensors[i].name);
230 #endif
231 DisconnectSensor(SDL_sensors[i].sensor);
232 }
233 }
234 SDL_UnlockSensors();
235
236 return S_OK;
237 }
238
239 static ISensorEventsVtbl sensor_events_vtbl = {
240 ISensorEventsVtbl_QueryInterface,
241 ISensorEventsVtbl_AddRef,
242 ISensorEventsVtbl_Release,
243 ISensorEventsVtbl_OnStateChanged,
244 ISensorEventsVtbl_OnDataUpdated,
245 ISensorEventsVtbl_OnEvent,
246 ISensorEventsVtbl_OnLeave
247 };
248 static ISensorEvents sensor_events = {
249 &sensor_events_vtbl
250 };
251
ConnectSensor(ISensor * sensor)252 static int ConnectSensor(ISensor *sensor)
253 {
254 SDL_Windows_Sensor *new_sensor, *new_sensors;
255 HRESULT hr;
256 SENSOR_ID sensor_id;
257 SENSOR_TYPE_ID type_id;
258 SDL_SensorType type;
259 BSTR bstr_name = NULL;
260 char *name;
261
262 hr = ISensor_GetID(sensor, &sensor_id);
263 if (FAILED(hr)) {
264 return WIN_SetErrorFromHRESULT("Couldn't get sensor ID", hr);
265 }
266
267 hr = ISensor_GetType(sensor, &type_id);
268 if (FAILED(hr)) {
269 return WIN_SetErrorFromHRESULT("Couldn't get sensor type", hr);
270 }
271
272 if (WIN_IsEqualIID(&type_id, &SENSOR_TYPE_ACCELEROMETER_3D)) {
273 type = SDL_SENSOR_ACCEL;
274 } else if (WIN_IsEqualIID(&type_id, &SENSOR_TYPE_GYROMETER_3D)) {
275 type = SDL_SENSOR_GYRO;
276 } else {
277 return SDL_SetError("Unknown sensor type");
278 }
279
280 hr = ISensor_GetFriendlyName(sensor, &bstr_name);
281 if (SUCCEEDED(hr) && bstr_name) {
282 name = WIN_StringToUTF8W(bstr_name);
283 } else {
284 name = SDL_strdup("Unknown Sensor");
285 }
286 if (bstr_name != NULL) {
287 SysFreeString(bstr_name);
288 }
289 if (!name) {
290 return SDL_OutOfMemory();
291 }
292
293 SDL_LockSensors();
294 new_sensors = (SDL_Windows_Sensor *)SDL_realloc(SDL_sensors, (SDL_num_sensors + 1) * sizeof(SDL_Windows_Sensor));
295 if (new_sensors == NULL) {
296 SDL_UnlockSensors();
297 SDL_free(name);
298 return SDL_OutOfMemory();
299 }
300
301 ISensor_AddRef(sensor);
302 ISensor_SetEventSink(sensor, &sensor_events);
303
304 SDL_sensors = new_sensors;
305 new_sensor = &SDL_sensors[SDL_num_sensors];
306 ++SDL_num_sensors;
307
308 SDL_zerop(new_sensor);
309 new_sensor->id = SDL_GetNextSensorInstanceID();
310 new_sensor->sensor = sensor;
311 new_sensor->type = type;
312 new_sensor->name = name;
313
314 SDL_UnlockSensors();
315
316 return 0;
317 }
318
DisconnectSensor(ISensor * sensor)319 static int DisconnectSensor(ISensor *sensor)
320 {
321 SDL_Windows_Sensor *old_sensor;
322 int i;
323
324 SDL_LockSensors();
325 for (i = 0; i < SDL_num_sensors; ++i) {
326 old_sensor = &SDL_sensors[i];
327 if (sensor == old_sensor->sensor) {
328 ISensor_SetEventSink(sensor, NULL);
329 ISensor_Release(sensor);
330 SDL_free(old_sensor->name);
331 --SDL_num_sensors;
332 if (i < SDL_num_sensors) {
333 SDL_memmove(&SDL_sensors[i], &SDL_sensors[i + 1], (SDL_num_sensors - i) * sizeof(SDL_sensors[i]));
334 }
335 break;
336 }
337 }
338 SDL_UnlockSensors();
339
340 return 0;
341 }
342
343 static int
SDL_WINDOWS_SensorInit(void)344 SDL_WINDOWS_SensorInit(void)
345 {
346 HRESULT hr;
347 ISensorCollection *sensor_collection = NULL;
348
349 if (WIN_CoInitialize() == S_OK) {
350 SDL_windowscoinit = SDL_TRUE;
351 }
352
353 hr = CoCreateInstance(&SDL_CLSID_SensorManager, NULL, CLSCTX_INPROC_SERVER, &SDL_IID_SensorManager, (LPVOID *) &SDL_sensor_manager);
354 if (FAILED(hr)) {
355 /* If we can't create a sensor manager (i.e. on Wine), we won't have any sensors, but don't fail the init */
356 return 0; /* WIN_SetErrorFromHRESULT("Couldn't create the sensor manager", hr); */
357 }
358
359 hr = ISensorManager_SetEventSink(SDL_sensor_manager, &sensor_manager_events);
360 if (FAILED(hr)) {
361 ISensorManager_Release(SDL_sensor_manager);
362 SDL_sensor_manager = NULL;
363 return WIN_SetErrorFromHRESULT("Couldn't set the sensor manager event sink", hr);
364 }
365
366 hr = ISensorManager_GetSensorsByCategory(SDL_sensor_manager, &SENSOR_CATEGORY_ALL, &sensor_collection);
367 if (SUCCEEDED(hr)) {
368 ULONG i, count;
369
370 hr = ISensorCollection_GetCount(sensor_collection, &count);
371 if (SUCCEEDED(hr)) {
372 for (i = 0; i < count; ++i) {
373 ISensor *sensor;
374
375 hr = ISensorCollection_GetAt(sensor_collection, i, &sensor);
376 if (SUCCEEDED(hr)) {
377 SensorState state;
378
379 hr = ISensor_GetState(sensor, &state);
380 if (SUCCEEDED(hr)) {
381 ISensorManagerEventsVtbl_OnSensorEnter(&sensor_manager_events, sensor, state);
382 }
383 ISensorManager_Release(sensor);
384 }
385 }
386 }
387 ISensorCollection_Release(sensor_collection);
388 }
389 return 0;
390 }
391
392 static int
SDL_WINDOWS_SensorGetCount(void)393 SDL_WINDOWS_SensorGetCount(void)
394 {
395 return SDL_num_sensors;
396 }
397
398 static void
SDL_WINDOWS_SensorDetect(void)399 SDL_WINDOWS_SensorDetect(void)
400 {
401 }
402
403 static const char *
SDL_WINDOWS_SensorGetDeviceName(int device_index)404 SDL_WINDOWS_SensorGetDeviceName(int device_index)
405 {
406 return SDL_sensors[device_index].name;
407 }
408
409 static SDL_SensorType
SDL_WINDOWS_SensorGetDeviceType(int device_index)410 SDL_WINDOWS_SensorGetDeviceType(int device_index)
411 {
412 return SDL_sensors[device_index].type;
413 }
414
415 static int
SDL_WINDOWS_SensorGetDeviceNonPortableType(int device_index)416 SDL_WINDOWS_SensorGetDeviceNonPortableType(int device_index)
417 {
418 return -1;
419 }
420
421 static SDL_SensorID
SDL_WINDOWS_SensorGetDeviceInstanceID(int device_index)422 SDL_WINDOWS_SensorGetDeviceInstanceID(int device_index)
423 {
424 return SDL_sensors[device_index].id;
425 }
426
427 static int
SDL_WINDOWS_SensorOpen(SDL_Sensor * sensor,int device_index)428 SDL_WINDOWS_SensorOpen(SDL_Sensor *sensor, int device_index)
429 {
430 SDL_sensors[device_index].sensor_opened = sensor;
431 return 0;
432 }
433
434 static void
SDL_WINDOWS_SensorUpdate(SDL_Sensor * sensor)435 SDL_WINDOWS_SensorUpdate(SDL_Sensor *sensor)
436 {
437 }
438
439 static void
SDL_WINDOWS_SensorClose(SDL_Sensor * sensor)440 SDL_WINDOWS_SensorClose(SDL_Sensor *sensor)
441 {
442 int i;
443
444 for (i = 0; i < SDL_num_sensors; ++i) {
445 if (sensor == SDL_sensors[i].sensor_opened) {
446 SDL_sensors[i].sensor_opened = NULL;
447 break;
448 }
449 }
450 }
451
452 static void
SDL_WINDOWS_SensorQuit(void)453 SDL_WINDOWS_SensorQuit(void)
454 {
455 while (SDL_num_sensors > 0) {
456 DisconnectSensor(SDL_sensors[0].sensor);
457 }
458
459 if (SDL_sensor_manager) {
460 ISensorManager_SetEventSink(SDL_sensor_manager, NULL);
461 ISensorManager_Release(SDL_sensor_manager);
462 SDL_sensor_manager = NULL;
463 }
464
465 if (SDL_windowscoinit) {
466 WIN_CoUninitialize();
467 }
468 }
469
470 SDL_SensorDriver SDL_WINDOWS_SensorDriver =
471 {
472 SDL_WINDOWS_SensorInit,
473 SDL_WINDOWS_SensorGetCount,
474 SDL_WINDOWS_SensorDetect,
475 SDL_WINDOWS_SensorGetDeviceName,
476 SDL_WINDOWS_SensorGetDeviceType,
477 SDL_WINDOWS_SensorGetDeviceNonPortableType,
478 SDL_WINDOWS_SensorGetDeviceInstanceID,
479 SDL_WINDOWS_SensorOpen,
480 SDL_WINDOWS_SensorUpdate,
481 SDL_WINDOWS_SensorClose,
482 SDL_WINDOWS_SensorQuit,
483 };
484
485 #endif /* SDL_SENSOR_WINDOWS */
486
487 /* vi: set ts=4 sw=4 expandtab: */
488