summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/sensor/windows/SDL_windowssensor.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/SDL-3.2.8/src/sensor/windows/SDL_windowssensor.c')
-rw-r--r--contrib/SDL-3.2.8/src/sensor/windows/SDL_windowssensor.c485
1 files changed, 485 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/sensor/windows/SDL_windowssensor.c b/contrib/SDL-3.2.8/src/sensor/windows/SDL_windowssensor.c
new file mode 100644
index 0000000..059747e
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/sensor/windows/SDL_windowssensor.c
@@ -0,0 +1,485 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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#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
34DEFINE_GUID(SDL_CLSID_SensorManager, 0x77A1C827, 0xFCD2, 0x4689, 0x89, 0x15, 0x9D, 0x61, 0x3C, 0xC5, 0xFA, 0x3E);
35DEFINE_GUID(SDL_IID_SensorManager, 0xBD77DB67, 0x45A8, 0x42DC, 0x8D, 0x00, 0x6D, 0xCF, 0x15, 0xF8, 0x37, 0x7A);
36DEFINE_GUID(SDL_IID_SensorManagerEvents, 0x9B3B0B86, 0x266A, 0x4AAD, 0xB2, 0x1F, 0xFD, 0xE5, 0x50, 0x10, 0x01, 0xB7);
37DEFINE_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
40DEFINE_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]
41DEFINE_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]
42DEFINE_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
44typedef 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
55static bool SDL_windowscoinit;
56static ISensorManager *SDL_sensor_manager;
57static int SDL_num_sensors;
58static SDL_Windows_Sensor *SDL_sensors;
59
60static bool ConnectSensor(ISensor *sensor);
61static bool DisconnectSensor(ISensor *sensor);
62
63static 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
77static ULONG STDMETHODCALLTYPE ISensorManagerEventsVtbl_AddRef(ISensorManagerEvents *This)
78{
79 return 1;
80}
81
82static ULONG STDMETHODCALLTYPE ISensorManagerEventsVtbl_Release(ISensorManagerEvents *This)
83{
84 return 1;
85}
86
87static HRESULT STDMETHODCALLTYPE ISensorManagerEventsVtbl_OnSensorEnter(ISensorManagerEvents *This, ISensor *pSensor, SensorState state)
88{
89 ConnectSensor(pSensor);
90 return S_OK;
91}
92
93static ISensorManagerEventsVtbl sensor_manager_events_vtbl = {
94 ISensorManagerEventsVtbl_QueryInterface,
95 ISensorManagerEventsVtbl_AddRef,
96 ISensorManagerEventsVtbl_Release,
97 ISensorManagerEventsVtbl_OnSensorEnter
98};
99static ISensorManagerEvents sensor_manager_events = {
100 &sensor_manager_events_vtbl
101};
102
103static 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
117static ULONG STDMETHODCALLTYPE ISensorEventsVtbl_AddRef(ISensorEvents *This)
118{
119 return 1;
120}
121
122static ULONG STDMETHODCALLTYPE ISensorEventsVtbl_Release(ISensorEvents *This)
123{
124 return 1;
125}
126
127static 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
143static 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
214static 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
230static 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
248static 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};
257static ISensorEvents sensor_events = {
258 &sensor_events_vtbl
259};
260
261static 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
328static 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
355static 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
403static int SDL_WINDOWS_SensorGetCount(void)
404{
405 return SDL_num_sensors;
406}
407
408static void SDL_WINDOWS_SensorDetect(void)
409{
410}
411
412static const char *SDL_WINDOWS_SensorGetDeviceName(int device_index)
413{
414 return SDL_sensors[device_index].name;
415}
416
417static SDL_SensorType SDL_WINDOWS_SensorGetDeviceType(int device_index)
418{
419 return SDL_sensors[device_index].type;
420}
421
422static int SDL_WINDOWS_SensorGetDeviceNonPortableType(int device_index)
423{
424 return -1;
425}
426
427static SDL_SensorID SDL_WINDOWS_SensorGetDeviceInstanceID(int device_index)
428{
429 return SDL_sensors[device_index].id;
430}
431
432static bool SDL_WINDOWS_SensorOpen(SDL_Sensor *sensor, int device_index)
433{
434 SDL_sensors[device_index].sensor_opened = sensor;
435 return true;
436}
437
438static void SDL_WINDOWS_SensorUpdate(SDL_Sensor *sensor)
439{
440}
441
442static 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
454static 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
471SDL_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