summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/sensor
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/sensor
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/sensor')
-rw-r--r--contrib/SDL-3.2.8/src/sensor/SDL_sensor.c622
-rw-r--r--contrib/SDL-3.2.8/src/sensor/SDL_sensor_c.h59
-rw-r--r--contrib/SDL-3.2.8/src/sensor/SDL_syssensor.h110
-rw-r--r--contrib/SDL-3.2.8/src/sensor/android/SDL_androidsensor.c288
-rw-r--r--contrib/SDL-3.2.8/src/sensor/android/SDL_androidsensor.h21
-rw-r--r--contrib/SDL-3.2.8/src/sensor/coremotion/SDL_coremotionsensor.h27
-rw-r--r--contrib/SDL-3.2.8/src/sensor/coremotion/SDL_coremotionsensor.m214
-rw-r--r--contrib/SDL-3.2.8/src/sensor/dummy/SDL_dummysensor.c93
-rw-r--r--contrib/SDL-3.2.8/src/sensor/dummy/SDL_dummysensor.h21
-rw-r--r--contrib/SDL-3.2.8/src/sensor/n3ds/SDL_n3dssensor.c203
-rw-r--r--contrib/SDL-3.2.8/src/sensor/vita/SDL_vitasensor.c204
-rw-r--r--contrib/SDL-3.2.8/src/sensor/vita/SDL_vitasensor.h29
-rw-r--r--contrib/SDL-3.2.8/src/sensor/windows/SDL_windowssensor.c485
-rw-r--r--contrib/SDL-3.2.8/src/sensor/windows/SDL_windowssensor.h21
14 files changed, 2397 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/sensor/SDL_sensor.c b/contrib/SDL-3.2.8/src/sensor/SDL_sensor.c
new file mode 100644
index 0000000..60e829a
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/sensor/SDL_sensor.c
@@ -0,0 +1,622 @@
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// This is the sensor API for Simple DirectMedia Layer
24
25#include "SDL_syssensor.h"
26
27#include "../events/SDL_events_c.h"
28#include "../joystick/SDL_gamepad_c.h"
29
30static SDL_SensorDriver *SDL_sensor_drivers[] = {
31#ifdef SDL_SENSOR_ANDROID
32 &SDL_ANDROID_SensorDriver,
33#endif
34#ifdef SDL_SENSOR_COREMOTION
35 &SDL_COREMOTION_SensorDriver,
36#endif
37#ifdef SDL_SENSOR_WINDOWS
38 &SDL_WINDOWS_SensorDriver,
39#endif
40#ifdef SDL_SENSOR_VITA
41 &SDL_VITA_SensorDriver,
42#endif
43#ifdef SDL_SENSOR_N3DS
44 &SDL_N3DS_SensorDriver,
45#endif
46#if defined(SDL_SENSOR_DUMMY) || defined(SDL_SENSOR_DISABLED)
47 &SDL_DUMMY_SensorDriver
48#endif
49};
50
51#ifndef SDL_THREAD_SAFETY_ANALYSIS
52static
53#endif
54SDL_Mutex *SDL_sensor_lock = NULL; // This needs to support recursive locks
55static SDL_AtomicInt SDL_sensor_lock_pending;
56static int SDL_sensors_locked;
57static bool SDL_sensors_initialized;
58static SDL_Sensor *SDL_sensors SDL_GUARDED_BY(SDL_sensor_lock) = NULL;
59
60#define CHECK_SENSOR_MAGIC(sensor, result) \
61 if (!SDL_ObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR)) { \
62 SDL_InvalidParamError("sensor"); \
63 SDL_UnlockSensors(); \
64 return result; \
65 }
66
67bool SDL_SensorsInitialized(void)
68{
69 return SDL_sensors_initialized;
70}
71
72void SDL_LockSensors(void)
73{
74 (void)SDL_AtomicIncRef(&SDL_sensor_lock_pending);
75 SDL_LockMutex(SDL_sensor_lock);
76 (void)SDL_AtomicDecRef(&SDL_sensor_lock_pending);
77
78 ++SDL_sensors_locked;
79}
80
81void SDL_UnlockSensors(void)
82{
83 bool last_unlock = false;
84
85 --SDL_sensors_locked;
86
87 if (!SDL_sensors_initialized) {
88 // NOTE: There's a small window here where another thread could lock the mutex after we've checked for pending locks
89 if (!SDL_sensors_locked && SDL_GetAtomicInt(&SDL_sensor_lock_pending) == 0) {
90 last_unlock = true;
91 }
92 }
93
94 /* The last unlock after sensors are uninitialized will cleanup the mutex,
95 * allowing applications to lock sensors while reinitializing the system.
96 */
97 if (last_unlock) {
98 SDL_Mutex *sensor_lock = SDL_sensor_lock;
99
100 SDL_LockMutex(sensor_lock);
101 {
102 SDL_UnlockMutex(SDL_sensor_lock);
103
104 SDL_sensor_lock = NULL;
105 }
106 SDL_UnlockMutex(sensor_lock);
107 SDL_DestroyMutex(sensor_lock);
108 } else {
109 SDL_UnlockMutex(SDL_sensor_lock);
110 }
111}
112
113bool SDL_SensorsLocked(void)
114{
115 return (SDL_sensors_locked > 0);
116}
117
118void SDL_AssertSensorsLocked(void)
119{
120 SDL_assert(SDL_SensorsLocked());
121}
122
123bool SDL_InitSensors(void)
124{
125 int i;
126 bool status;
127
128 // Create the sensor list lock
129 if (SDL_sensor_lock == NULL) {
130 SDL_sensor_lock = SDL_CreateMutex();
131 }
132
133 if (!SDL_InitSubSystem(SDL_INIT_EVENTS)) {
134 return false;
135 }
136
137 SDL_LockSensors();
138
139 SDL_sensors_initialized = true;
140
141 status = false;
142 for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {
143 if (SDL_sensor_drivers[i]->Init()) {
144 status = true;
145 }
146 }
147
148 SDL_UnlockSensors();
149
150 if (!status) {
151 SDL_QuitSensors();
152 }
153
154 return status;
155}
156
157bool SDL_SensorsOpened(void)
158{
159 bool opened;
160
161 SDL_LockSensors();
162 {
163 if (SDL_sensors != NULL) {
164 opened = true;
165 } else {
166 opened = false;
167 }
168 }
169 SDL_UnlockSensors();
170
171 return opened;
172}
173
174SDL_SensorID *SDL_GetSensors(int *count)
175{
176 int i, num_sensors, device_index;
177 int sensor_index = 0, total_sensors = 0;
178 SDL_SensorID *sensors;
179
180 SDL_LockSensors();
181 {
182 for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {
183 total_sensors += SDL_sensor_drivers[i]->GetCount();
184 }
185
186 sensors = (SDL_SensorID *)SDL_malloc((total_sensors + 1) * sizeof(*sensors));
187 if (sensors) {
188 if (count) {
189 *count = total_sensors;
190 }
191
192 for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {
193 num_sensors = SDL_sensor_drivers[i]->GetCount();
194 for (device_index = 0; device_index < num_sensors; ++device_index) {
195 SDL_assert(sensor_index < total_sensors);
196 sensors[sensor_index] = SDL_sensor_drivers[i]->GetDeviceInstanceID(device_index);
197 SDL_assert(sensors[sensor_index] > 0);
198 ++sensor_index;
199 }
200 }
201 SDL_assert(sensor_index == total_sensors);
202 sensors[sensor_index] = 0;
203 } else {
204 if (count) {
205 *count = 0;
206 }
207 }
208 }
209 SDL_UnlockSensors();
210
211 return sensors;
212}
213
214/*
215 * Get the driver and device index for a sensor instance ID
216 * This should be called while the sensor lock is held, to prevent another thread from updating the list
217 */
218static bool SDL_GetDriverAndSensorIndex(SDL_SensorID instance_id, SDL_SensorDriver **driver, int *driver_index)
219{
220 int i, num_sensors, device_index;
221
222 if (instance_id > 0) {
223 for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {
224 num_sensors = SDL_sensor_drivers[i]->GetCount();
225 for (device_index = 0; device_index < num_sensors; ++device_index) {
226 SDL_SensorID sensor_id = SDL_sensor_drivers[i]->GetDeviceInstanceID(device_index);
227 if (sensor_id == instance_id) {
228 *driver = SDL_sensor_drivers[i];
229 *driver_index = device_index;
230 return true;
231 }
232 }
233 }
234 }
235 SDL_SetError("Sensor %" SDL_PRIu32 " not found", instance_id);
236 return false;
237}
238
239/*
240 * Get the implementation dependent name of a sensor
241 */
242const char *SDL_GetSensorNameForID(SDL_SensorID instance_id)
243{
244 SDL_SensorDriver *driver;
245 int device_index;
246 const char *name = NULL;
247
248 SDL_LockSensors();
249 if (SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) {
250 name = SDL_GetPersistentString(driver->GetDeviceName(device_index));
251 }
252 SDL_UnlockSensors();
253
254 return name;
255}
256
257SDL_SensorType SDL_GetSensorTypeForID(SDL_SensorID instance_id)
258{
259 SDL_SensorDriver *driver;
260 int device_index;
261 SDL_SensorType type = SDL_SENSOR_INVALID;
262
263 SDL_LockSensors();
264 if (SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) {
265 type = driver->GetDeviceType(device_index);
266 }
267 SDL_UnlockSensors();
268
269 return type;
270}
271
272int SDL_GetSensorNonPortableTypeForID(SDL_SensorID instance_id)
273{
274 SDL_SensorDriver *driver;
275 int device_index;
276 int type = -1;
277
278 SDL_LockSensors();
279 if (SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) {
280 type = driver->GetDeviceNonPortableType(device_index);
281 }
282 SDL_UnlockSensors();
283
284 return type;
285}
286
287/*
288 * Open a sensor for use - the index passed as an argument refers to
289 * the N'th sensor on the system. This index is the value which will
290 * identify this sensor in future sensor events.
291 *
292 * This function returns a sensor identifier, or NULL if an error occurred.
293 */
294SDL_Sensor *SDL_OpenSensor(SDL_SensorID instance_id)
295{
296 SDL_SensorDriver *driver;
297 int device_index;
298 SDL_Sensor *sensor;
299 SDL_Sensor *sensorlist;
300 const char *sensorname = NULL;
301
302 SDL_LockSensors();
303
304 if (!SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) {
305 SDL_UnlockSensors();
306 return NULL;
307 }
308
309 sensorlist = SDL_sensors;
310 /* If the sensor is already open, return it
311 * it is important that we have a single sensor * for each instance id
312 */
313 while (sensorlist) {
314 if (instance_id == sensorlist->instance_id) {
315 sensor = sensorlist;
316 ++sensor->ref_count;
317 SDL_UnlockSensors();
318 return sensor;
319 }
320 sensorlist = sensorlist->next;
321 }
322
323 // Create and initialize the sensor
324 sensor = (SDL_Sensor *)SDL_calloc(1, sizeof(*sensor));
325 if (!sensor) {
326 SDL_UnlockSensors();
327 return NULL;
328 }
329 SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, true);
330 sensor->driver = driver;
331 sensor->instance_id = instance_id;
332 sensor->type = driver->GetDeviceType(device_index);
333 sensor->non_portable_type = driver->GetDeviceNonPortableType(device_index);
334
335 if (!driver->Open(sensor, device_index)) {
336 SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, false);
337 SDL_free(sensor);
338 SDL_UnlockSensors();
339 return NULL;
340 }
341
342 sensorname = driver->GetDeviceName(device_index);
343 if (sensorname) {
344 sensor->name = SDL_strdup(sensorname);
345 } else {
346 sensor->name = NULL;
347 }
348
349 // Add sensor to list
350 ++sensor->ref_count;
351 // Link the sensor in the list
352 sensor->next = SDL_sensors;
353 SDL_sensors = sensor;
354
355 driver->Update(sensor);
356
357 SDL_UnlockSensors();
358
359 return sensor;
360}
361
362/*
363 * Find the SDL_Sensor that owns this instance id
364 */
365SDL_Sensor *SDL_GetSensorFromID(SDL_SensorID instance_id)
366{
367 SDL_Sensor *sensor;
368
369 SDL_LockSensors();
370 for (sensor = SDL_sensors; sensor; sensor = sensor->next) {
371 if (sensor->instance_id == instance_id) {
372 break;
373 }
374 }
375 SDL_UnlockSensors();
376 return sensor;
377}
378
379/*
380 * Get the properties associated with a sensor.
381 */
382SDL_PropertiesID SDL_GetSensorProperties(SDL_Sensor *sensor)
383{
384 SDL_PropertiesID result;
385
386 SDL_LockSensors();
387 {
388 CHECK_SENSOR_MAGIC(sensor, 0);
389
390 if (sensor->props == 0) {
391 sensor->props = SDL_CreateProperties();
392 }
393 result = sensor->props;
394 }
395 SDL_UnlockSensors();
396
397 return result;
398}
399
400/*
401 * Get the friendly name of this sensor
402 */
403const char *SDL_GetSensorName(SDL_Sensor *sensor)
404{
405 const char *result;
406
407 SDL_LockSensors();
408 {
409 CHECK_SENSOR_MAGIC(sensor, NULL);
410
411 result = SDL_GetPersistentString(sensor->name);
412 }
413 SDL_UnlockSensors();
414
415 return result;
416}
417
418/*
419 * Get the type of this sensor
420 */
421SDL_SensorType SDL_GetSensorType(SDL_Sensor *sensor)
422{
423 SDL_SensorType result;
424
425 SDL_LockSensors();
426 {
427 CHECK_SENSOR_MAGIC(sensor, SDL_SENSOR_INVALID);
428
429 result = sensor->type;
430 }
431 SDL_UnlockSensors();
432
433 return result;
434}
435
436/*
437 * Get the platform dependent type of this sensor
438 */
439int SDL_GetSensorNonPortableType(SDL_Sensor *sensor)
440{
441 int result;
442
443 SDL_LockSensors();
444 {
445 CHECK_SENSOR_MAGIC(sensor, -1);
446
447 result = sensor->non_portable_type;
448 }
449 SDL_UnlockSensors();
450
451 return result;
452}
453
454/*
455 * Get the instance id for this opened sensor
456 */
457SDL_SensorID SDL_GetSensorID(SDL_Sensor *sensor)
458{
459 SDL_SensorID result;
460
461 SDL_LockSensors();
462 {
463 CHECK_SENSOR_MAGIC(sensor, 0);
464
465 result = sensor->instance_id;
466 }
467 SDL_UnlockSensors();
468
469 return result;
470}
471
472/*
473 * Get the current state of this sensor
474 */
475bool SDL_GetSensorData(SDL_Sensor *sensor, float *data, int num_values)
476{
477 SDL_LockSensors();
478 {
479 CHECK_SENSOR_MAGIC(sensor, false);
480
481 num_values = SDL_min(num_values, SDL_arraysize(sensor->data));
482 SDL_memcpy(data, sensor->data, num_values * sizeof(*data));
483 }
484 SDL_UnlockSensors();
485
486 return true;
487}
488
489/*
490 * Close a sensor previously opened with SDL_OpenSensor()
491 */
492void SDL_CloseSensor(SDL_Sensor *sensor)
493{
494 SDL_Sensor *sensorlist;
495 SDL_Sensor *sensorlistprev;
496
497 SDL_LockSensors();
498 {
499 CHECK_SENSOR_MAGIC(sensor,);
500
501 // First decrement ref count
502 if (--sensor->ref_count > 0) {
503 SDL_UnlockSensors();
504 return;
505 }
506
507 SDL_DestroyProperties(sensor->props);
508
509 sensor->driver->Close(sensor);
510 sensor->hwdata = NULL;
511 SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, false);
512
513 sensorlist = SDL_sensors;
514 sensorlistprev = NULL;
515 while (sensorlist) {
516 if (sensor == sensorlist) {
517 if (sensorlistprev) {
518 // unlink this entry
519 sensorlistprev->next = sensorlist->next;
520 } else {
521 SDL_sensors = sensor->next;
522 }
523 break;
524 }
525 sensorlistprev = sensorlist;
526 sensorlist = sensorlist->next;
527 }
528
529 // Free the data associated with this sensor
530 SDL_free(sensor->name);
531 SDL_free(sensor);
532 }
533 SDL_UnlockSensors();
534}
535
536void SDL_QuitSensors(void)
537{
538 int i;
539
540 SDL_LockSensors();
541
542 // Stop the event polling
543 while (SDL_sensors) {
544 SDL_sensors->ref_count = 1;
545 SDL_CloseSensor(SDL_sensors);
546 }
547
548 // Quit the sensor setup
549 for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {
550 SDL_sensor_drivers[i]->Quit();
551 }
552
553 SDL_QuitSubSystem(SDL_INIT_EVENTS);
554
555 SDL_sensors_initialized = false;
556
557 SDL_UnlockSensors();
558}
559
560// These are global for SDL_syssensor.c and SDL_events.c
561
562void SDL_SendSensorUpdate(Uint64 timestamp, SDL_Sensor *sensor, Uint64 sensor_timestamp, float *data, int num_values)
563{
564 SDL_AssertSensorsLocked();
565
566 // Allow duplicate events, for things like steps and heartbeats
567
568 // Update internal sensor state
569 num_values = SDL_min(num_values, SDL_arraysize(sensor->data));
570 SDL_memcpy(sensor->data, data, num_values * sizeof(*data));
571
572 // Post the event, if desired
573 if (SDL_EventEnabled(SDL_EVENT_SENSOR_UPDATE)) {
574 SDL_Event event;
575 event.type = SDL_EVENT_SENSOR_UPDATE;
576 event.common.timestamp = timestamp;
577 event.sensor.which = sensor->instance_id;
578 num_values = SDL_min(num_values, SDL_arraysize(event.sensor.data));
579 SDL_memset(event.sensor.data, 0, sizeof(event.sensor.data));
580 SDL_memcpy(event.sensor.data, data, num_values * sizeof(*data));
581 event.sensor.sensor_timestamp = sensor_timestamp;
582 SDL_PushEvent(&event);
583 }
584
585 SDL_GamepadSensorWatcher(timestamp, sensor->instance_id, sensor_timestamp, data, num_values);
586}
587
588void SDL_UpdateSensor(SDL_Sensor *sensor)
589{
590 SDL_LockSensors();
591 {
592 CHECK_SENSOR_MAGIC(sensor,);
593
594 sensor->driver->Update(sensor);
595 }
596 SDL_UnlockSensors();
597}
598
599void SDL_UpdateSensors(void)
600{
601 int i;
602 SDL_Sensor *sensor;
603
604 if (!SDL_WasInit(SDL_INIT_SENSOR)) {
605 return;
606 }
607
608 SDL_LockSensors();
609
610 for (sensor = SDL_sensors; sensor; sensor = sensor->next) {
611 sensor->driver->Update(sensor);
612 }
613
614 /* this needs to happen AFTER walking the sensor list above, so that any
615 dangling hardware data from removed devices can be free'd
616 */
617 for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {
618 SDL_sensor_drivers[i]->Detect();
619 }
620
621 SDL_UnlockSensors();
622}
diff --git a/contrib/SDL-3.2.8/src/sensor/SDL_sensor_c.h b/contrib/SDL-3.2.8/src/sensor/SDL_sensor_c.h
new file mode 100644
index 0000000..26a988e
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/sensor/SDL_sensor_c.h
@@ -0,0 +1,59 @@
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#ifndef SDL_sensor_c_h_
24#define SDL_sensor_c_h_
25
26#ifdef SDL_THREAD_SAFETY_ANALYSIS
27extern SDL_Mutex *SDL_sensor_lock;
28#endif
29
30struct SDL_SensorDriver;
31
32// Useful functions and variables from SDL_sensor.c
33
34// Initialization and shutdown functions
35extern bool SDL_InitSensors(void);
36extern void SDL_QuitSensors(void);
37
38// Return whether the sensor system is currently initialized
39extern bool SDL_SensorsInitialized(void);
40
41// Return whether the sensors are currently locked
42extern bool SDL_SensorsLocked(void);
43
44// Make sure we currently have the sensors locked
45extern void SDL_AssertSensorsLocked(void) SDL_ASSERT_CAPABILITY(SDL_sensor_lock);
46
47extern void SDL_LockSensors(void) SDL_ACQUIRE(SDL_sensor_lock);
48extern void SDL_UnlockSensors(void) SDL_RELEASE(SDL_sensor_lock);
49
50// Function to return whether there are any sensors opened by the application
51extern bool SDL_SensorsOpened(void);
52
53// Update an individual sensor, used by gamepad sensor fusion
54extern void SDL_UpdateSensor(SDL_Sensor *sensor);
55
56// Internal event queueing functions
57extern void SDL_SendSensorUpdate(Uint64 timestamp, SDL_Sensor *sensor, Uint64 sensor_timestamp, float *data, int num_values);
58
59#endif // SDL_sensor_c_h_
diff --git a/contrib/SDL-3.2.8/src/sensor/SDL_syssensor.h b/contrib/SDL-3.2.8/src/sensor/SDL_syssensor.h
new file mode 100644
index 0000000..1ce63e5
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/sensor/SDL_syssensor.h
@@ -0,0 +1,110 @@
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#ifndef SDL_syssensor_c_h_
24#define SDL_syssensor_c_h_
25
26// This is the system specific header for the SDL sensor API
27
28#include "SDL_sensor_c.h"
29
30#define _guarded SDL_GUARDED_BY(SDL_sensor_lock)
31
32// The SDL sensor structure
33struct SDL_Sensor
34{
35 SDL_SensorID instance_id _guarded; // Device instance, monotonically increasing from 0
36 char *name _guarded; // Sensor name - system dependent
37 SDL_SensorType type _guarded; // Type of the sensor
38 int non_portable_type _guarded; // Platform dependent type of the sensor
39
40 float data[16] _guarded; // The current state of the sensor
41
42 struct SDL_SensorDriver *driver _guarded;
43
44 struct sensor_hwdata *hwdata _guarded; // Driver dependent information
45
46 SDL_PropertiesID props _guarded;
47
48 int ref_count _guarded; // Reference count for multiple opens
49
50 struct SDL_Sensor *next _guarded; // pointer to next sensor we have allocated
51};
52
53#undef _guarded
54
55typedef struct SDL_SensorDriver
56{
57 /* Function to scan the system for sensors.
58 * sensor 0 should be the system default sensor.
59 * This function should return 0, or -1 on an unrecoverable fatal error.
60 */
61 bool (*Init)(void);
62
63 // Function to return the number of sensors available right now
64 int (*GetCount)(void);
65
66 // Function to check to see if the available sensors have changed
67 void (*Detect)(void);
68
69 // Function to get the device-dependent name of a sensor
70 const char *(*GetDeviceName)(int device_index);
71
72 // Function to get the type of a sensor
73 SDL_SensorType (*GetDeviceType)(int device_index);
74
75 // Function to get the platform dependent type of a sensor
76 int (*GetDeviceNonPortableType)(int device_index);
77
78 // Function to get the current instance id of the sensor located at device_index
79 SDL_SensorID (*GetDeviceInstanceID)(int device_index);
80
81 /* Function to open a sensor for use.
82 The sensor to open is specified by the device index.
83 It returns 0, or -1 if there is an error.
84 */
85 bool (*Open)(SDL_Sensor *sensor, int device_index);
86
87 /* Function to update the state of a sensor - called as a device poll.
88 * This function shouldn't update the sensor structure directly,
89 * but instead should call SDL_SendSensorUpdate() to deliver events
90 * and update sensor device state.
91 */
92 void (*Update)(SDL_Sensor *sensor);
93
94 // Function to close a sensor after use
95 void (*Close)(SDL_Sensor *sensor);
96
97 // Function to perform any system-specific sensor related cleanup
98 void (*Quit)(void);
99
100} SDL_SensorDriver;
101
102// The available sensor drivers
103extern SDL_SensorDriver SDL_ANDROID_SensorDriver;
104extern SDL_SensorDriver SDL_COREMOTION_SensorDriver;
105extern SDL_SensorDriver SDL_WINDOWS_SensorDriver;
106extern SDL_SensorDriver SDL_DUMMY_SensorDriver;
107extern SDL_SensorDriver SDL_VITA_SensorDriver;
108extern SDL_SensorDriver SDL_N3DS_SensorDriver;
109
110#endif // SDL_syssensor_h_
diff --git a/contrib/SDL-3.2.8/src/sensor/android/SDL_androidsensor.c b/contrib/SDL-3.2.8/src/sensor/android/SDL_androidsensor.c
new file mode 100644
index 0000000..87981a1
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/sensor/android/SDL_androidsensor.c
@@ -0,0 +1,288 @@
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_ANDROID
24
25// This is the system specific header for the SDL sensor API
26#include <android/sensor.h>
27
28#include "SDL_androidsensor.h"
29#include "../SDL_syssensor.h"
30#include "../SDL_sensor_c.h"
31#include "../../thread/SDL_systhread.h"
32
33#ifndef LOOPER_ID_USER
34#define LOOPER_ID_USER 3
35#endif
36
37typedef struct
38{
39 ASensorRef asensor;
40 SDL_SensorID instance_id;
41 ASensorEventQueue *event_queue;
42 SDL_Sensor *sensor;
43} SDL_AndroidSensor;
44
45typedef struct
46{
47 SDL_AtomicInt running;
48 SDL_Thread *thread;
49 SDL_Semaphore *sem;
50} SDL_AndroidSensorThreadContext;
51
52static ASensorManager *SDL_sensor_manager;
53static ALooper *SDL_sensor_looper;
54static SDL_AndroidSensorThreadContext SDL_sensor_thread_context;
55static SDL_AndroidSensor *SDL_sensors SDL_GUARDED_BY(SDL_sensors_lock);
56static int SDL_sensors_count;
57
58static int SDLCALL SDL_ANDROID_SensorThread(void *data)
59{
60 SDL_AndroidSensorThreadContext *ctx = (SDL_AndroidSensorThreadContext *)data;
61 int i, events;
62 ASensorEvent event;
63 struct android_poll_source *source;
64
65 SDL_SetCurrentThreadPriority(SDL_THREAD_PRIORITY_HIGH);
66
67 SDL_sensor_looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
68 SDL_SignalSemaphore(ctx->sem);
69
70 while (SDL_GetAtomicInt(&ctx->running)) {
71 Uint64 timestamp = SDL_GetTicksNS();
72
73 if (ALooper_pollOnce(-1, NULL, &events, (void **)&source) == LOOPER_ID_USER) {
74 SDL_LockSensors();
75 for (i = 0; i < SDL_sensors_count; ++i) {
76 if (!SDL_sensors[i].event_queue) {
77 continue;
78 }
79
80 SDL_zero(event);
81 while (ASensorEventQueue_getEvents(SDL_sensors[i].event_queue, &event, 1) > 0) {
82 SDL_SendSensorUpdate(timestamp, SDL_sensors[i].sensor, timestamp, event.data, SDL_arraysize(event.data));
83 }
84 }
85 SDL_UnlockSensors();
86 }
87 }
88
89 SDL_sensor_looper = NULL;
90
91 return 0;
92}
93
94static void SDL_ANDROID_StopSensorThread(SDL_AndroidSensorThreadContext *ctx)
95{
96 SDL_SetAtomicInt(&ctx->running, false);
97
98 if (ctx->thread) {
99 int result;
100
101 if (SDL_sensor_looper) {
102 ALooper_wake(SDL_sensor_looper);
103 }
104 SDL_WaitThread(ctx->thread, &result);
105 ctx->thread = NULL;
106 }
107
108 if (ctx->sem) {
109 SDL_DestroySemaphore(ctx->sem);
110 ctx->sem = NULL;
111 }
112}
113
114static bool SDL_ANDROID_StartSensorThread(SDL_AndroidSensorThreadContext *ctx)
115{
116 ctx->sem = SDL_CreateSemaphore(0);
117 if (!ctx->sem) {
118 SDL_ANDROID_StopSensorThread(ctx);
119 return false;
120 }
121
122 SDL_SetAtomicInt(&ctx->running, true);
123 ctx->thread = SDL_CreateThread(SDL_ANDROID_SensorThread, "Sensors", ctx);
124 if (!ctx->thread) {
125 SDL_ANDROID_StopSensorThread(ctx);
126 return false;
127 }
128
129 // Wait for the sensor thread to start
130 SDL_WaitSemaphore(ctx->sem);
131
132 return true;
133}
134
135static bool SDL_ANDROID_SensorInit(void)
136{
137 int i, sensors_count;
138 ASensorList sensors;
139
140 SDL_sensor_manager = ASensorManager_getInstance();
141 if (!SDL_sensor_manager) {
142 return SDL_SetError("Couldn't create sensor manager");
143 }
144
145 // FIXME: Is the sensor list dynamic?
146 sensors_count = ASensorManager_getSensorList(SDL_sensor_manager, &sensors);
147 if (sensors_count > 0) {
148 SDL_sensors = (SDL_AndroidSensor *)SDL_calloc(sensors_count, sizeof(*SDL_sensors));
149 if (!SDL_sensors) {
150 return false;
151 }
152
153 for (i = 0; i < sensors_count; ++i) {
154 SDL_sensors[i].asensor = sensors[i];
155 SDL_sensors[i].instance_id = SDL_GetNextObjectID();
156 }
157 SDL_sensors_count = sensors_count;
158 }
159
160 if (!SDL_ANDROID_StartSensorThread(&SDL_sensor_thread_context)) {
161 return false;
162 }
163 return true;
164}
165
166static int SDL_ANDROID_SensorGetCount(void)
167{
168 return SDL_sensors_count;
169}
170
171static void SDL_ANDROID_SensorDetect(void)
172{
173}
174
175static const char *SDL_ANDROID_SensorGetDeviceName(int device_index)
176{
177 return ASensor_getName(SDL_sensors[device_index].asensor);
178}
179
180static SDL_SensorType SDL_ANDROID_SensorGetDeviceType(int device_index)
181{
182 switch (ASensor_getType(SDL_sensors[device_index].asensor)) {
183 case 0x00000001:
184 return SDL_SENSOR_ACCEL;
185 case 0x00000004:
186 return SDL_SENSOR_GYRO;
187 default:
188 return SDL_SENSOR_UNKNOWN;
189 }
190}
191
192static int SDL_ANDROID_SensorGetDeviceNonPortableType(int device_index)
193{
194 return ASensor_getType(SDL_sensors[device_index].asensor);
195}
196
197static SDL_SensorID SDL_ANDROID_SensorGetDeviceInstanceID(int device_index)
198{
199 return SDL_sensors[device_index].instance_id;
200}
201
202static bool SDL_ANDROID_SensorOpen(SDL_Sensor *sensor, int device_index)
203{
204 int delay_us, min_delay_us;
205
206 SDL_LockSensors();
207 {
208 SDL_sensors[device_index].sensor = sensor;
209 SDL_sensors[device_index].event_queue = ASensorManager_createEventQueue(SDL_sensor_manager, SDL_sensor_looper, LOOPER_ID_USER, NULL, NULL);
210 if (!SDL_sensors[device_index].event_queue) {
211 SDL_UnlockSensors();
212 return SDL_SetError("Couldn't create sensor event queue");
213 }
214
215 if (ASensorEventQueue_enableSensor(SDL_sensors[device_index].event_queue, SDL_sensors[device_index].asensor) < 0) {
216 ASensorManager_destroyEventQueue(SDL_sensor_manager, SDL_sensors[device_index].event_queue);
217 SDL_sensors[device_index].event_queue = NULL;
218 SDL_UnlockSensors();
219 return SDL_SetError("Couldn't enable sensor");
220 }
221
222 // Use 60 Hz update rate if possible
223 // FIXME: Maybe add a hint for this?
224 delay_us = 1000000 / 60;
225 min_delay_us = ASensor_getMinDelay(SDL_sensors[device_index].asensor);
226 if (delay_us < min_delay_us) {
227 delay_us = min_delay_us;
228 }
229 ASensorEventQueue_setEventRate(SDL_sensors[device_index].event_queue, SDL_sensors[device_index].asensor, delay_us);
230 }
231 SDL_UnlockSensors();
232
233 return true;
234}
235
236static void SDL_ANDROID_SensorUpdate(SDL_Sensor *sensor)
237{
238}
239
240static void SDL_ANDROID_SensorClose(SDL_Sensor *sensor)
241{
242 int i;
243
244 for (i = 0; i < SDL_sensors_count; ++i) {
245 if (SDL_sensors[i].sensor == sensor) {
246 SDL_LockSensors();
247 {
248 ASensorEventQueue_disableSensor(SDL_sensors[i].event_queue, SDL_sensors[i].asensor);
249 ASensorManager_destroyEventQueue(SDL_sensor_manager, SDL_sensors[i].event_queue);
250 SDL_sensors[i].event_queue = NULL;
251 SDL_sensors[i].sensor = NULL;
252 }
253 SDL_UnlockSensors();
254 break;
255 }
256 }
257}
258
259static void SDL_ANDROID_SensorQuit(void)
260{
261 // All sensors are closed, but we need to unblock the sensor thread
262 SDL_AssertSensorsLocked();
263 SDL_UnlockSensors();
264 SDL_ANDROID_StopSensorThread(&SDL_sensor_thread_context);
265 SDL_LockSensors();
266
267 if (SDL_sensors) {
268 SDL_free(SDL_sensors);
269 SDL_sensors = NULL;
270 SDL_sensors_count = 0;
271 }
272}
273
274SDL_SensorDriver SDL_ANDROID_SensorDriver = {
275 SDL_ANDROID_SensorInit,
276 SDL_ANDROID_SensorGetCount,
277 SDL_ANDROID_SensorDetect,
278 SDL_ANDROID_SensorGetDeviceName,
279 SDL_ANDROID_SensorGetDeviceType,
280 SDL_ANDROID_SensorGetDeviceNonPortableType,
281 SDL_ANDROID_SensorGetDeviceInstanceID,
282 SDL_ANDROID_SensorOpen,
283 SDL_ANDROID_SensorUpdate,
284 SDL_ANDROID_SensorClose,
285 SDL_ANDROID_SensorQuit,
286};
287
288#endif // SDL_SENSOR_ANDROID
diff --git a/contrib/SDL-3.2.8/src/sensor/android/SDL_androidsensor.h b/contrib/SDL-3.2.8/src/sensor/android/SDL_androidsensor.h
new file mode 100644
index 0000000..4b0c6f8
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/sensor/android/SDL_androidsensor.h
@@ -0,0 +1,21 @@
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"
diff --git a/contrib/SDL-3.2.8/src/sensor/coremotion/SDL_coremotionsensor.h b/contrib/SDL-3.2.8/src/sensor/coremotion/SDL_coremotionsensor.h
new file mode 100644
index 0000000..09fc0dc
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/sensor/coremotion/SDL_coremotionsensor.h
@@ -0,0 +1,27 @@
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// The private structure used to keep track of a sensor
24struct sensor_hwdata
25{
26 float data[3];
27};
diff --git a/contrib/SDL-3.2.8/src/sensor/coremotion/SDL_coremotionsensor.m b/contrib/SDL-3.2.8/src/sensor/coremotion/SDL_coremotionsensor.m
new file mode 100644
index 0000000..e5f890f
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/sensor/coremotion/SDL_coremotionsensor.m
@@ -0,0 +1,214 @@
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_COREMOTION
24
25// This is the system specific header for the SDL sensor API
26#include <CoreMotion/CoreMotion.h>
27
28#include "SDL_coremotionsensor.h"
29#include "../SDL_syssensor.h"
30#include "../SDL_sensor_c.h"
31
32typedef struct
33{
34 SDL_SensorType type;
35 SDL_SensorID instance_id;
36} SDL_CoreMotionSensor;
37
38static CMMotionManager *SDL_motion_manager;
39static SDL_CoreMotionSensor *SDL_sensors;
40static int SDL_sensors_count;
41
42static bool SDL_COREMOTION_SensorInit(void)
43{
44 int i, sensors_count = 0;
45
46 if (!SDL_motion_manager) {
47 SDL_motion_manager = [[CMMotionManager alloc] init];
48 }
49
50 if (SDL_motion_manager.accelerometerAvailable) {
51 ++sensors_count;
52 }
53 if (SDL_motion_manager.gyroAvailable) {
54 ++sensors_count;
55 }
56
57 if (sensors_count > 0) {
58 SDL_sensors = (SDL_CoreMotionSensor *)SDL_calloc(sensors_count, sizeof(*SDL_sensors));
59 if (!SDL_sensors) {
60 return false;
61 }
62
63 i = 0;
64 if (SDL_motion_manager.accelerometerAvailable) {
65 SDL_sensors[i].type = SDL_SENSOR_ACCEL;
66 SDL_sensors[i].instance_id = SDL_GetNextObjectID();
67 ++i;
68 }
69 if (SDL_motion_manager.gyroAvailable) {
70 SDL_sensors[i].type = SDL_SENSOR_GYRO;
71 SDL_sensors[i].instance_id = SDL_GetNextObjectID();
72 ++i;
73 }
74 SDL_sensors_count = sensors_count;
75 }
76 return true;
77}
78
79static int SDL_COREMOTION_SensorGetCount(void)
80{
81 return SDL_sensors_count;
82}
83
84static void SDL_COREMOTION_SensorDetect(void)
85{
86}
87
88static const char *SDL_COREMOTION_SensorGetDeviceName(int device_index)
89{
90 switch (SDL_sensors[device_index].type) {
91 case SDL_SENSOR_ACCEL:
92 return "Accelerometer";
93 case SDL_SENSOR_GYRO:
94 return "Gyro";
95 default:
96 return "Unknown";
97 }
98}
99
100static SDL_SensorType SDL_COREMOTION_SensorGetDeviceType(int device_index)
101{
102 return SDL_sensors[device_index].type;
103}
104
105static int SDL_COREMOTION_SensorGetDeviceNonPortableType(int device_index)
106{
107 return SDL_sensors[device_index].type;
108}
109
110static SDL_SensorID SDL_COREMOTION_SensorGetDeviceInstanceID(int device_index)
111{
112 return SDL_sensors[device_index].instance_id;
113}
114
115static bool SDL_COREMOTION_SensorOpen(SDL_Sensor *sensor, int device_index)
116{
117 struct sensor_hwdata *hwdata;
118
119 hwdata = (struct sensor_hwdata *)SDL_calloc(1, sizeof(*hwdata));
120 if (hwdata == NULL) {
121 return false;
122 }
123 sensor->hwdata = hwdata;
124
125 switch (sensor->type) {
126 case SDL_SENSOR_ACCEL:
127 [SDL_motion_manager startAccelerometerUpdates];
128 break;
129 case SDL_SENSOR_GYRO:
130 [SDL_motion_manager startGyroUpdates];
131 break;
132 default:
133 break;
134 }
135 return true;
136}
137
138static void SDL_COREMOTION_SensorUpdate(SDL_Sensor *sensor)
139{
140 Uint64 timestamp = SDL_GetTicksNS();
141
142 switch (sensor->type) {
143 case SDL_SENSOR_ACCEL:
144 {
145 CMAccelerometerData *accelerometerData = SDL_motion_manager.accelerometerData;
146 if (accelerometerData) {
147 CMAcceleration acceleration = accelerometerData.acceleration;
148 float data[3];
149 data[0] = -acceleration.x * SDL_STANDARD_GRAVITY;
150 data[1] = -acceleration.y * SDL_STANDARD_GRAVITY;
151 data[2] = -acceleration.z * SDL_STANDARD_GRAVITY;
152 if (SDL_memcmp(data, sensor->hwdata->data, sizeof(data)) != 0) {
153 SDL_SendSensorUpdate(timestamp, sensor, timestamp, data, SDL_arraysize(data));
154 SDL_memcpy(sensor->hwdata->data, data, sizeof(data));
155 }
156 }
157 } break;
158 case SDL_SENSOR_GYRO:
159 {
160 CMGyroData *gyroData = SDL_motion_manager.gyroData;
161 if (gyroData) {
162 CMRotationRate rotationRate = gyroData.rotationRate;
163 float data[3];
164 data[0] = rotationRate.x;
165 data[1] = rotationRate.y;
166 data[2] = rotationRate.z;
167 if (SDL_memcmp(data, sensor->hwdata->data, sizeof(data)) != 0) {
168 SDL_SendSensorUpdate(timestamp, sensor, timestamp, data, SDL_arraysize(data));
169 SDL_memcpy(sensor->hwdata->data, data, sizeof(data));
170 }
171 }
172 } break;
173 default:
174 break;
175 }
176}
177
178static void SDL_COREMOTION_SensorClose(SDL_Sensor *sensor)
179{
180 if (sensor->hwdata) {
181 switch (sensor->type) {
182 case SDL_SENSOR_ACCEL:
183 [SDL_motion_manager stopAccelerometerUpdates];
184 break;
185 case SDL_SENSOR_GYRO:
186 [SDL_motion_manager stopGyroUpdates];
187 break;
188 default:
189 break;
190 }
191 SDL_free(sensor->hwdata);
192 sensor->hwdata = NULL;
193 }
194}
195
196static void SDL_COREMOTION_SensorQuit(void)
197{
198}
199
200SDL_SensorDriver SDL_COREMOTION_SensorDriver = {
201 SDL_COREMOTION_SensorInit,
202 SDL_COREMOTION_SensorGetCount,
203 SDL_COREMOTION_SensorDetect,
204 SDL_COREMOTION_SensorGetDeviceName,
205 SDL_COREMOTION_SensorGetDeviceType,
206 SDL_COREMOTION_SensorGetDeviceNonPortableType,
207 SDL_COREMOTION_SensorGetDeviceInstanceID,
208 SDL_COREMOTION_SensorOpen,
209 SDL_COREMOTION_SensorUpdate,
210 SDL_COREMOTION_SensorClose,
211 SDL_COREMOTION_SensorQuit,
212};
213
214#endif // SDL_SENSOR_COREMOTION
diff --git a/contrib/SDL-3.2.8/src/sensor/dummy/SDL_dummysensor.c b/contrib/SDL-3.2.8/src/sensor/dummy/SDL_dummysensor.c
new file mode 100644
index 0000000..ce8145d
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/sensor/dummy/SDL_dummysensor.c
@@ -0,0 +1,93 @@
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#if defined(SDL_SENSOR_DUMMY) || defined(SDL_SENSOR_DISABLED)
24
25#include "SDL_dummysensor.h"
26#include "../SDL_syssensor.h"
27
28static bool SDL_DUMMY_SensorInit(void)
29{
30 return true;
31}
32
33static int SDL_DUMMY_SensorGetCount(void)
34{
35 return 0;
36}
37
38static void SDL_DUMMY_SensorDetect(void)
39{
40}
41
42static const char *SDL_DUMMY_SensorGetDeviceName(int device_index)
43{
44 return NULL;
45}
46
47static SDL_SensorType SDL_DUMMY_SensorGetDeviceType(int device_index)
48{
49 return SDL_SENSOR_INVALID;
50}
51
52static int SDL_DUMMY_SensorGetDeviceNonPortableType(int device_index)
53{
54 return -1;
55}
56
57static SDL_SensorID SDL_DUMMY_SensorGetDeviceInstanceID(int device_index)
58{
59 return -1;
60}
61
62static bool SDL_DUMMY_SensorOpen(SDL_Sensor *sensor, int device_index)
63{
64 return SDL_Unsupported();
65}
66
67static void SDL_DUMMY_SensorUpdate(SDL_Sensor *sensor)
68{
69}
70
71static void SDL_DUMMY_SensorClose(SDL_Sensor *sensor)
72{
73}
74
75static void SDL_DUMMY_SensorQuit(void)
76{
77}
78
79SDL_SensorDriver SDL_DUMMY_SensorDriver = {
80 SDL_DUMMY_SensorInit,
81 SDL_DUMMY_SensorGetCount,
82 SDL_DUMMY_SensorDetect,
83 SDL_DUMMY_SensorGetDeviceName,
84 SDL_DUMMY_SensorGetDeviceType,
85 SDL_DUMMY_SensorGetDeviceNonPortableType,
86 SDL_DUMMY_SensorGetDeviceInstanceID,
87 SDL_DUMMY_SensorOpen,
88 SDL_DUMMY_SensorUpdate,
89 SDL_DUMMY_SensorClose,
90 SDL_DUMMY_SensorQuit,
91};
92
93#endif // SDL_SENSOR_DUMMY || SDL_SENSOR_DISABLED
diff --git a/contrib/SDL-3.2.8/src/sensor/dummy/SDL_dummysensor.h b/contrib/SDL-3.2.8/src/sensor/dummy/SDL_dummysensor.h
new file mode 100644
index 0000000..4b0c6f8
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/sensor/dummy/SDL_dummysensor.h
@@ -0,0 +1,21 @@
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"
diff --git a/contrib/SDL-3.2.8/src/sensor/n3ds/SDL_n3dssensor.c b/contrib/SDL-3.2.8/src/sensor/n3ds/SDL_n3dssensor.c
new file mode 100644
index 0000000..ac36e70
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/sensor/n3ds/SDL_n3dssensor.c
@@ -0,0 +1,203 @@
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
22#include "SDL_internal.h"
23
24#ifdef SDL_SENSOR_N3DS
25
26#include <3ds.h>
27
28#include "../SDL_syssensor.h"
29
30// 1 accelerometer and 1 gyroscope
31#define N3DS_SENSOR_COUNT 2
32
33typedef struct
34{
35 SDL_SensorType type;
36 SDL_SensorID instance_id;
37} SDL_N3DSSensor;
38
39static SDL_N3DSSensor N3DS_sensors[N3DS_SENSOR_COUNT];
40
41static bool InitN3DSServices(void);
42static void UpdateN3DSAccelerometer(SDL_Sensor *sensor);
43static void UpdateN3DSGyroscope(SDL_Sensor *sensor);
44
45static bool IsDeviceIndexValid(int device_index)
46{
47 return device_index >= 0 && device_index < N3DS_SENSOR_COUNT;
48}
49
50static bool N3DS_SensorInit(void)
51{
52 if (!InitN3DSServices()) {
53 return SDL_SetError("Failed to initialise N3DS services");
54 }
55
56 N3DS_sensors[0].type = SDL_SENSOR_ACCEL;
57 N3DS_sensors[0].instance_id = SDL_GetNextObjectID();
58 N3DS_sensors[1].type = SDL_SENSOR_GYRO;
59 N3DS_sensors[1].instance_id = SDL_GetNextObjectID();
60 return true;
61}
62
63static bool InitN3DSServices(void)
64{
65 if (R_FAILED(hidInit())) {
66 return false;
67 }
68
69 if (R_FAILED(HIDUSER_EnableAccelerometer())) {
70 return false;
71 }
72
73 if (R_FAILED(HIDUSER_EnableGyroscope())) {
74 return false;
75 }
76 return true;
77}
78
79static int N3DS_SensorGetCount(void)
80{
81 return N3DS_SENSOR_COUNT;
82}
83
84static void N3DS_SensorDetect(void)
85{
86}
87
88static const char *N3DS_SensorGetDeviceName(int device_index)
89{
90 if (IsDeviceIndexValid(device_index)) {
91 switch (N3DS_sensors[device_index].type) {
92 case SDL_SENSOR_ACCEL:
93 return "Accelerometer";
94 case SDL_SENSOR_GYRO:
95 return "Gyroscope";
96 default:
97 return "Unknown";
98 }
99 }
100
101 return NULL;
102}
103
104static SDL_SensorType N3DS_SensorGetDeviceType(int device_index)
105{
106 if (IsDeviceIndexValid(device_index)) {
107 return N3DS_sensors[device_index].type;
108 }
109 return SDL_SENSOR_INVALID;
110}
111
112static int N3DS_SensorGetDeviceNonPortableType(int device_index)
113{
114 return (int)N3DS_SensorGetDeviceType(device_index);
115}
116
117static SDL_SensorID N3DS_SensorGetDeviceInstanceID(int device_index)
118{
119 if (IsDeviceIndexValid(device_index)) {
120 return N3DS_sensors[device_index].instance_id;
121 }
122 return -1;
123}
124
125static bool N3DS_SensorOpen(SDL_Sensor *sensor, int device_index)
126{
127 return true;
128}
129
130static void N3DS_SensorUpdate(SDL_Sensor *sensor)
131{
132 switch (sensor->type) {
133 case SDL_SENSOR_ACCEL:
134 UpdateN3DSAccelerometer(sensor);
135 break;
136 case SDL_SENSOR_GYRO:
137 UpdateN3DSGyroscope(sensor);
138 break;
139 default:
140 break;
141 }
142}
143
144static void UpdateN3DSAccelerometer(SDL_Sensor *sensor)
145{
146 static accelVector previous_state = { 0, 0, 0 };
147 accelVector current_state;
148 float data[3];
149 Uint64 timestamp = SDL_GetTicksNS();
150
151 hidAccelRead(&current_state);
152 if (SDL_memcmp(&previous_state, &current_state, sizeof(accelVector)) != 0) {
153 SDL_memcpy(&previous_state, &current_state, sizeof(accelVector));
154 data[0] = (float)current_state.x * SDL_STANDARD_GRAVITY;
155 data[1] = (float)current_state.y * SDL_STANDARD_GRAVITY;
156 data[2] = (float)current_state.z * SDL_STANDARD_GRAVITY;
157 SDL_SendSensorUpdate(timestamp, sensor, timestamp, data, sizeof(data));
158 }
159}
160
161static void UpdateN3DSGyroscope(SDL_Sensor *sensor)
162{
163 static angularRate previous_state = { 0, 0, 0 };
164 angularRate current_state;
165 float data[3];
166 Uint64 timestamp = SDL_GetTicksNS();
167
168 hidGyroRead(&current_state);
169 if (SDL_memcmp(&previous_state, &current_state, sizeof(angularRate)) != 0) {
170 SDL_memcpy(&previous_state, &current_state, sizeof(angularRate));
171 data[0] = (float)current_state.x;
172 data[1] = (float)current_state.y;
173 data[2] = (float)current_state.z;
174 SDL_SendSensorUpdate(timestamp, sensor, timestamp, data, sizeof(data));
175 }
176}
177
178static void N3DS_SensorClose(SDL_Sensor *sensor)
179{
180}
181
182static void N3DS_SensorQuit(void)
183{
184 HIDUSER_DisableGyroscope();
185 HIDUSER_DisableAccelerometer();
186 hidExit();
187}
188
189SDL_SensorDriver SDL_N3DS_SensorDriver = {
190 .Init = N3DS_SensorInit,
191 .GetCount = N3DS_SensorGetCount,
192 .Detect = N3DS_SensorDetect,
193 .GetDeviceName = N3DS_SensorGetDeviceName,
194 .GetDeviceType = N3DS_SensorGetDeviceType,
195 .GetDeviceNonPortableType = N3DS_SensorGetDeviceNonPortableType,
196 .GetDeviceInstanceID = N3DS_SensorGetDeviceInstanceID,
197 .Open = N3DS_SensorOpen,
198 .Update = N3DS_SensorUpdate,
199 .Close = N3DS_SensorClose,
200 .Quit = N3DS_SensorQuit,
201};
202
203#endif // SDL_SENSOR_N3DS
diff --git a/contrib/SDL-3.2.8/src/sensor/vita/SDL_vitasensor.c b/contrib/SDL-3.2.8/src/sensor/vita/SDL_vitasensor.c
new file mode 100644
index 0000000..0acc215
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/sensor/vita/SDL_vitasensor.c
@@ -0,0 +1,204 @@
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_VITA
24
25#include "SDL_vitasensor.h"
26#include "../SDL_syssensor.h"
27#include <psp2/motion.h>
28
29#ifndef SCE_MOTION_MAX_NUM_STATES
30#define SCE_MOTION_MAX_NUM_STATES 64
31#endif
32
33typedef struct
34{
35 SDL_SensorType type;
36 SDL_SensorID instance_id;
37} SDL_VitaSensor;
38
39static SDL_VitaSensor *SDL_sensors;
40static int SDL_sensors_count;
41
42static bool SDL_VITA_SensorInit(void)
43{
44 sceMotionReset();
45 sceMotionStartSampling();
46 // not sure if these are needed, we are reading unfiltered state
47 sceMotionSetAngleThreshold(0);
48 sceMotionSetDeadband(SCE_FALSE);
49 sceMotionSetTiltCorrection(SCE_FALSE);
50
51 SDL_sensors_count = 2;
52
53 SDL_sensors = (SDL_VitaSensor *)SDL_calloc(SDL_sensors_count, sizeof(*SDL_sensors));
54 if (!SDL_sensors) {
55 return false;
56 }
57
58 SDL_sensors[0].type = SDL_SENSOR_ACCEL;
59 SDL_sensors[0].instance_id = SDL_GetNextObjectID();
60 SDL_sensors[1].type = SDL_SENSOR_GYRO;
61 SDL_sensors[1].instance_id = SDL_GetNextObjectID();
62
63 return true;
64}
65
66static int SDL_VITA_SensorGetCount(void)
67{
68 return SDL_sensors_count;
69}
70
71static void SDL_VITA_SensorDetect(void)
72{
73}
74
75static const char *SDL_VITA_SensorGetDeviceName(int device_index)
76{
77 if (device_index < SDL_sensors_count) {
78 switch (SDL_sensors[device_index].type) {
79 case SDL_SENSOR_ACCEL:
80 return "Accelerometer";
81 case SDL_SENSOR_GYRO:
82 return "Gyro";
83 default:
84 return "Unknown";
85 }
86 }
87
88 return NULL;
89}
90
91static SDL_SensorType SDL_VITA_SensorGetDeviceType(int device_index)
92{
93 if (device_index < SDL_sensors_count) {
94 return SDL_sensors[device_index].type;
95 }
96
97 return SDL_SENSOR_INVALID;
98}
99
100static int SDL_VITA_SensorGetDeviceNonPortableType(int device_index)
101{
102 if (device_index < SDL_sensors_count) {
103 return SDL_sensors[device_index].type;
104 }
105 return -1;
106}
107
108static SDL_SensorID SDL_VITA_SensorGetDeviceInstanceID(int device_index)
109{
110 if (device_index < SDL_sensors_count) {
111 return SDL_sensors[device_index].instance_id;
112 }
113 return -1;
114}
115
116static bool SDL_VITA_SensorOpen(SDL_Sensor *sensor, int device_index)
117{
118 struct sensor_hwdata *hwdata;
119
120 hwdata = (struct sensor_hwdata *)SDL_calloc(1, sizeof(*hwdata));
121 if (!hwdata) {
122 return false;
123 }
124 sensor->hwdata = hwdata;
125
126 return true;
127}
128
129static void SDL_VITA_SensorUpdate(SDL_Sensor *sensor)
130{
131 int err = 0;
132 SceMotionSensorState motionState[SCE_MOTION_MAX_NUM_STATES];
133 Uint64 timestamp = SDL_GetTicksNS();
134
135 SDL_zero(motionState);
136 err = sceMotionGetSensorState(motionState, SCE_MOTION_MAX_NUM_STATES);
137 if (err != 0) {
138 return;
139 }
140
141 for (int i = 0; i < SCE_MOTION_MAX_NUM_STATES; i++) {
142 if (sensor->hwdata->counter < motionState[i].counter) {
143 unsigned int tick = motionState[i].timestamp;
144 unsigned int delta;
145
146 sensor->hwdata->counter = motionState[i].counter;
147
148 if (sensor->hwdata->last_tick > tick) {
149 SDL_COMPILE_TIME_ASSERT(tick, sizeof(tick) == sizeof(Uint32));
150 delta = (SDL_MAX_UINT32 - sensor->hwdata->last_tick + tick + 1);
151 } else {
152 delta = (tick - sensor->hwdata->last_tick);
153 }
154 sensor->hwdata->sensor_timestamp += SDL_US_TO_NS(delta);
155 sensor->hwdata->last_tick = tick;
156
157 switch (sensor->type) {
158 case SDL_SENSOR_ACCEL:
159 {
160 float data[3];
161 data[0] = motionState[i].accelerometer.x * SDL_STANDARD_GRAVITY;
162 data[1] = motionState[i].accelerometer.y * SDL_STANDARD_GRAVITY;
163 data[2] = motionState[i].accelerometer.z * SDL_STANDARD_GRAVITY;
164 SDL_SendSensorUpdate(timestamp, sensor, sensor->hwdata->sensor_timestamp, data, SDL_arraysize(data));
165 } break;
166 case SDL_SENSOR_GYRO:
167 {
168 float data[3];
169 data[0] = motionState[i].gyro.x;
170 data[1] = motionState[i].gyro.y;
171 data[2] = motionState[i].gyro.z;
172 SDL_SendSensorUpdate(timestamp, sensor, sensor->hwdata->sensor_timestamp, data, SDL_arraysize(data));
173 } break;
174 default:
175 break;
176 }
177 }
178 }
179}
180
181static void SDL_VITA_SensorClose(SDL_Sensor *sensor)
182{
183}
184
185static void SDL_VITA_SensorQuit(void)
186{
187 sceMotionStopSampling();
188}
189
190SDL_SensorDriver SDL_VITA_SensorDriver = {
191 SDL_VITA_SensorInit,
192 SDL_VITA_SensorGetCount,
193 SDL_VITA_SensorDetect,
194 SDL_VITA_SensorGetDeviceName,
195 SDL_VITA_SensorGetDeviceType,
196 SDL_VITA_SensorGetDeviceNonPortableType,
197 SDL_VITA_SensorGetDeviceInstanceID,
198 SDL_VITA_SensorOpen,
199 SDL_VITA_SensorUpdate,
200 SDL_VITA_SensorClose,
201 SDL_VITA_SensorQuit,
202};
203
204#endif // SDL_SENSOR_VITA
diff --git a/contrib/SDL-3.2.8/src/sensor/vita/SDL_vitasensor.h b/contrib/SDL-3.2.8/src/sensor/vita/SDL_vitasensor.h
new file mode 100644
index 0000000..f07b659
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/sensor/vita/SDL_vitasensor.h
@@ -0,0 +1,29 @@
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// The private structure used to keep track of a sensor
24struct sensor_hwdata
25{
26 Uint32 counter;
27 unsigned int last_tick;
28 Uint64 sensor_timestamp;
29};
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
diff --git a/contrib/SDL-3.2.8/src/sensor/windows/SDL_windowssensor.h b/contrib/SDL-3.2.8/src/sensor/windows/SDL_windowssensor.h
new file mode 100644
index 0000000..4b0c6f8
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/sensor/windows/SDL_windowssensor.h
@@ -0,0 +1,21 @@
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"