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