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