SDL  2.0
SDL_windowssensor.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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 {
52  ISensor *sensor;
53  SENSOR_ID sensor_id;
54  char *name;
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 
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 
82 static ULONG STDMETHODCALLTYPE ISensorManagerEventsVtbl_AddRef(ISensorManagerEvents * This)
83 {
84  return 1;
85 }
86 
87 static ULONG STDMETHODCALLTYPE ISensorManagerEventsVtbl_Release(ISensorManagerEvents * This)
88 {
89  return 1;
90 }
91 
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 
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 
122 static ULONG STDMETHODCALLTYPE ISensorEventsVtbl_AddRef(ISensorEvents * This)
123 {
124  return 1;
125 }
126 
127 static ULONG STDMETHODCALLTYPE ISensorEventsVtbl_Release(ISensorEvents * This)
128 {
129  return 1;
130 }
131 
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  }
144 #endif
145  return S_OK;
146 }
147 
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  }
201 
202  return S_OK;
203 }
204 
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  }
217 #endif
218  return S_OK;
219 }
220 
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  }
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 
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;
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)) {
274  } else if (WIN_IsEqualIID(&type_id, &SENSOR_TYPE_GYROMETER_3D)) {
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_StringToUTF8(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) {
297  return SDL_OutOfMemory();
298  }
299 
300  ISensor_AddRef(sensor);
301  ISensor_SetEventSink(sensor, &sensor_events);
302 
303  SDL_sensors = new_sensors;
304  new_sensor = &SDL_sensors[SDL_num_sensors];
305  ++SDL_num_sensors;
306 
307  SDL_zerop(new_sensor);
308  new_sensor->id = SDL_GetNextSensorInstanceID();
309  new_sensor->sensor = sensor;
310  new_sensor->type = type;
311  new_sensor->name = name;
312 
314 
315  return 0;
316 }
317 
318 static int DisconnectSensor(ISensor *sensor)
319 {
320  SDL_Windows_Sensor *old_sensor;
321  int i;
322 
323  SDL_LockSensors();
324  for (i = 0; i < SDL_num_sensors; ++i) {
325  old_sensor = &SDL_sensors[i];
326  if (sensor == old_sensor->sensor) {
327  ISensor_SetEventSink(sensor, NULL);
328  ISensor_Release(sensor);
329  SDL_free(old_sensor->name);
330  --SDL_num_sensors;
331  if (i < SDL_num_sensors) {
332  SDL_memmove(&SDL_sensors[i], &SDL_sensors[i + 1], (SDL_num_sensors - i) * sizeof(SDL_sensors[i]));
333  }
334  break;
335  }
336  }
338 
339  return 0;
340 }
341 
342 static int
343 SDL_WINDOWS_SensorInit(void)
344 {
345  HRESULT hr;
346  ISensorCollection *sensor_collection = NULL;
347 
348  if (WIN_CoInitialize() == S_OK) {
349  SDL_windowscoinit = SDL_TRUE;
350  }
351 
352  hr = CoCreateInstance(&SDL_CLSID_SensorManager, NULL, CLSCTX_INPROC_SERVER, &SDL_IID_SensorManager, (LPVOID *) &SDL_sensor_manager);
353  if (FAILED(hr)) {
354  return WIN_SetErrorFromHRESULT("Couldn't create the sensor manager", hr);
355  }
356 
357  hr = ISensorManager_SetEventSink(SDL_sensor_manager, &sensor_manager_events);
358  if (FAILED(hr)) {
359  ISensorManager_Release(SDL_sensor_manager);
360  return WIN_SetErrorFromHRESULT("Couldn't set the sensor manager event sink", hr);
361  }
362 
363  hr = ISensorManager_GetSensorsByCategory(SDL_sensor_manager, &SENSOR_CATEGORY_ALL, &sensor_collection);
364  if (SUCCEEDED(hr)) {
365  ULONG i, count;
366 
367  hr = ISensorCollection_GetCount(sensor_collection, &count);
368  if (SUCCEEDED(hr)) {
369  for (i = 0; i < count; ++i) {
370  ISensor *sensor;
371 
372  hr = ISensorCollection_GetAt(sensor_collection, i, &sensor);
373  if (SUCCEEDED(hr)) {
374  SensorState state;
375 
376  hr = ISensor_GetState(sensor, &state);
377  if (SUCCEEDED(hr)) {
378  ISensorManagerEventsVtbl_OnSensorEnter(&sensor_manager_events, sensor, state);
379  }
380  ISensorManager_Release(sensor);
381  }
382  }
383  }
384  ISensorCollection_Release(sensor_collection);
385  }
386  return 0;
387 }
388 
389 static int
390 SDL_WINDOWS_SensorGetCount(void)
391 {
392  return SDL_num_sensors;
393 }
394 
395 static void
396 SDL_WINDOWS_SensorDetect(void)
397 {
398 }
399 
400 static const char *
401 SDL_WINDOWS_SensorGetDeviceName(int device_index)
402 {
403  return SDL_sensors[device_index].name;
404 }
405 
406 static SDL_SensorType
407 SDL_WINDOWS_SensorGetDeviceType(int device_index)
408 {
409  return SDL_sensors[device_index].type;
410 }
411 
412 static int
413 SDL_WINDOWS_SensorGetDeviceNonPortableType(int device_index)
414 {
415  return -1;
416 }
417 
418 static SDL_SensorID
419 SDL_WINDOWS_SensorGetDeviceInstanceID(int device_index)
420 {
421  return SDL_sensors[device_index].id;
422 }
423 
424 static int
425 SDL_WINDOWS_SensorOpen(SDL_Sensor *sensor, int device_index)
426 {
427  SDL_sensors[device_index].sensor_opened = sensor;
428  return 0;
429 }
430 
431 static void
432 SDL_WINDOWS_SensorUpdate(SDL_Sensor *sensor)
433 {
434 }
435 
436 static void
437 SDL_WINDOWS_SensorClose(SDL_Sensor *sensor)
438 {
439  int i;
440 
441  for (i = 0; i < SDL_num_sensors; ++i) {
442  if (sensor == SDL_sensors[i].sensor_opened) {
443  SDL_sensors[i].sensor_opened = NULL;
444  break;
445  }
446  }
447 }
448 
449 static void
450 SDL_WINDOWS_SensorQuit(void)
451 {
452  while (SDL_num_sensors > 0) {
453  DisconnectSensor(SDL_sensors[0].sensor);
454  }
455 
456  if (SDL_sensor_manager) {
457  ISensorManager_SetEventSink(SDL_sensor_manager, NULL);
458  ISensorManager_Release(SDL_sensor_manager);
459  SDL_sensor_manager = NULL;
460  }
461 
462  if (SDL_windowscoinit) {
464  }
465 }
466 
468 {
469  SDL_WINDOWS_SensorInit,
470  SDL_WINDOWS_SensorGetCount,
471  SDL_WINDOWS_SensorDetect,
472  SDL_WINDOWS_SensorGetDeviceName,
473  SDL_WINDOWS_SensorGetDeviceType,
474  SDL_WINDOWS_SensorGetDeviceNonPortableType,
475  SDL_WINDOWS_SensorGetDeviceInstanceID,
476  SDL_WINDOWS_SensorOpen,
477  SDL_WINDOWS_SensorUpdate,
478  SDL_WINDOWS_SensorClose,
479  SDL_WINDOWS_SensorQuit,
480 };
481 
482 #endif /* SDL_SENSOR_WINDOWS */
483 
484 /* vi: set ts=4 sw=4 expandtab: */
#define SUCCEEDED(x)
Definition: SDL_directx.h:51
#define S_OK
Definition: SDL_directx.h:47
#define E_NOINTERFACE
Definition: SDL_directx.h:61
#define E_INVALIDARG
Definition: SDL_directx.h:67
#define FAILED(x)
Definition: SDL_directx.h:54
#define SDL_SetError
#define SDL_UnlockSensors
#define SDL_realloc
#define SDL_free
#define SDL_strdup
#define SDL_Log
#define SDL_memmove
#define SDL_LockSensors
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
GLuint id
GLenum GLsizei GLsizei GLint * values
GLuint const GLchar * name
static SDL_Sensor * SDL_sensors
Definition: SDL_sensor.c:48
SDL_SensorID SDL_GetNextSensorInstanceID()
Definition: SDL_sensor.c:114
int SDL_PrivateSensorUpdate(SDL_Sensor *sensor, float *data, int num_values)
Definition: SDL_sensor.c:478
Sint32 SDL_SensorID
Definition: SDL_sensor.h:60
#define SDL_STANDARD_GRAVITY
Definition: SDL_sensor.h:99
SDL_SensorType
Definition: SDL_sensor.h:70
@ SDL_SENSOR_GYRO
Definition: SDL_sensor.h:74
@ SDL_SENSOR_ACCEL
Definition: SDL_sensor.h:73
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
#define SDL_zerop(x)
Definition: SDL_stdinc.h:427
SDL_SensorDriver SDL_WINDOWS_SensorDriver
struct xkb_state * state
HRESULT WIN_CoInitialize(void)
void WIN_CoUninitialize(void)
BOOL WIN_IsEqualIID(REFIID a, REFIID b)
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:46
int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:163