From 5a079a2d114f96d4847d1ee305d5b7c16eeec50e Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 27 Dec 2025 12:03:39 -0800 Subject: Initial commit --- contrib/SDL-3.2.8/src/sensor/SDL_sensor.c | 622 +++++++++++++++++++++ contrib/SDL-3.2.8/src/sensor/SDL_sensor_c.h | 59 ++ contrib/SDL-3.2.8/src/sensor/SDL_syssensor.h | 110 ++++ .../src/sensor/android/SDL_androidsensor.c | 288 ++++++++++ .../src/sensor/android/SDL_androidsensor.h | 21 + .../src/sensor/coremotion/SDL_coremotionsensor.h | 27 + .../src/sensor/coremotion/SDL_coremotionsensor.m | 214 +++++++ .../SDL-3.2.8/src/sensor/dummy/SDL_dummysensor.c | 93 +++ .../SDL-3.2.8/src/sensor/dummy/SDL_dummysensor.h | 21 + contrib/SDL-3.2.8/src/sensor/n3ds/SDL_n3dssensor.c | 203 +++++++ contrib/SDL-3.2.8/src/sensor/vita/SDL_vitasensor.c | 204 +++++++ contrib/SDL-3.2.8/src/sensor/vita/SDL_vitasensor.h | 29 + .../src/sensor/windows/SDL_windowssensor.c | 485 ++++++++++++++++ .../src/sensor/windows/SDL_windowssensor.h | 21 + 14 files changed, 2397 insertions(+) create mode 100644 contrib/SDL-3.2.8/src/sensor/SDL_sensor.c create mode 100644 contrib/SDL-3.2.8/src/sensor/SDL_sensor_c.h create mode 100644 contrib/SDL-3.2.8/src/sensor/SDL_syssensor.h create mode 100644 contrib/SDL-3.2.8/src/sensor/android/SDL_androidsensor.c create mode 100644 contrib/SDL-3.2.8/src/sensor/android/SDL_androidsensor.h create mode 100644 contrib/SDL-3.2.8/src/sensor/coremotion/SDL_coremotionsensor.h create mode 100644 contrib/SDL-3.2.8/src/sensor/coremotion/SDL_coremotionsensor.m create mode 100644 contrib/SDL-3.2.8/src/sensor/dummy/SDL_dummysensor.c create mode 100644 contrib/SDL-3.2.8/src/sensor/dummy/SDL_dummysensor.h create mode 100644 contrib/SDL-3.2.8/src/sensor/n3ds/SDL_n3dssensor.c create mode 100644 contrib/SDL-3.2.8/src/sensor/vita/SDL_vitasensor.c create mode 100644 contrib/SDL-3.2.8/src/sensor/vita/SDL_vitasensor.h create mode 100644 contrib/SDL-3.2.8/src/sensor/windows/SDL_windowssensor.c create mode 100644 contrib/SDL-3.2.8/src/sensor/windows/SDL_windowssensor.h (limited to 'contrib/SDL-3.2.8/src/sensor') 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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// This is the sensor API for Simple DirectMedia Layer + +#include "SDL_syssensor.h" + +#include "../events/SDL_events_c.h" +#include "../joystick/SDL_gamepad_c.h" + +static SDL_SensorDriver *SDL_sensor_drivers[] = { +#ifdef SDL_SENSOR_ANDROID + &SDL_ANDROID_SensorDriver, +#endif +#ifdef SDL_SENSOR_COREMOTION + &SDL_COREMOTION_SensorDriver, +#endif +#ifdef SDL_SENSOR_WINDOWS + &SDL_WINDOWS_SensorDriver, +#endif +#ifdef SDL_SENSOR_VITA + &SDL_VITA_SensorDriver, +#endif +#ifdef SDL_SENSOR_N3DS + &SDL_N3DS_SensorDriver, +#endif +#if defined(SDL_SENSOR_DUMMY) || defined(SDL_SENSOR_DISABLED) + &SDL_DUMMY_SensorDriver +#endif +}; + +#ifndef SDL_THREAD_SAFETY_ANALYSIS +static +#endif +SDL_Mutex *SDL_sensor_lock = NULL; // This needs to support recursive locks +static SDL_AtomicInt SDL_sensor_lock_pending; +static int SDL_sensors_locked; +static bool SDL_sensors_initialized; +static SDL_Sensor *SDL_sensors SDL_GUARDED_BY(SDL_sensor_lock) = NULL; + +#define CHECK_SENSOR_MAGIC(sensor, result) \ + if (!SDL_ObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR)) { \ + SDL_InvalidParamError("sensor"); \ + SDL_UnlockSensors(); \ + return result; \ + } + +bool SDL_SensorsInitialized(void) +{ + return SDL_sensors_initialized; +} + +void SDL_LockSensors(void) +{ + (void)SDL_AtomicIncRef(&SDL_sensor_lock_pending); + SDL_LockMutex(SDL_sensor_lock); + (void)SDL_AtomicDecRef(&SDL_sensor_lock_pending); + + ++SDL_sensors_locked; +} + +void SDL_UnlockSensors(void) +{ + bool last_unlock = false; + + --SDL_sensors_locked; + + if (!SDL_sensors_initialized) { + // NOTE: There's a small window here where another thread could lock the mutex after we've checked for pending locks + if (!SDL_sensors_locked && SDL_GetAtomicInt(&SDL_sensor_lock_pending) == 0) { + last_unlock = true; + } + } + + /* The last unlock after sensors are uninitialized will cleanup the mutex, + * allowing applications to lock sensors while reinitializing the system. + */ + if (last_unlock) { + SDL_Mutex *sensor_lock = SDL_sensor_lock; + + SDL_LockMutex(sensor_lock); + { + SDL_UnlockMutex(SDL_sensor_lock); + + SDL_sensor_lock = NULL; + } + SDL_UnlockMutex(sensor_lock); + SDL_DestroyMutex(sensor_lock); + } else { + SDL_UnlockMutex(SDL_sensor_lock); + } +} + +bool SDL_SensorsLocked(void) +{ + return (SDL_sensors_locked > 0); +} + +void SDL_AssertSensorsLocked(void) +{ + SDL_assert(SDL_SensorsLocked()); +} + +bool SDL_InitSensors(void) +{ + int i; + bool status; + + // Create the sensor list lock + if (SDL_sensor_lock == NULL) { + SDL_sensor_lock = SDL_CreateMutex(); + } + + if (!SDL_InitSubSystem(SDL_INIT_EVENTS)) { + return false; + } + + SDL_LockSensors(); + + SDL_sensors_initialized = true; + + status = false; + for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { + if (SDL_sensor_drivers[i]->Init()) { + status = true; + } + } + + SDL_UnlockSensors(); + + if (!status) { + SDL_QuitSensors(); + } + + return status; +} + +bool SDL_SensorsOpened(void) +{ + bool opened; + + SDL_LockSensors(); + { + if (SDL_sensors != NULL) { + opened = true; + } else { + opened = false; + } + } + SDL_UnlockSensors(); + + return opened; +} + +SDL_SensorID *SDL_GetSensors(int *count) +{ + int i, num_sensors, device_index; + int sensor_index = 0, total_sensors = 0; + SDL_SensorID *sensors; + + SDL_LockSensors(); + { + for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { + total_sensors += SDL_sensor_drivers[i]->GetCount(); + } + + sensors = (SDL_SensorID *)SDL_malloc((total_sensors + 1) * sizeof(*sensors)); + if (sensors) { + if (count) { + *count = total_sensors; + } + + for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { + num_sensors = SDL_sensor_drivers[i]->GetCount(); + for (device_index = 0; device_index < num_sensors; ++device_index) { + SDL_assert(sensor_index < total_sensors); + sensors[sensor_index] = SDL_sensor_drivers[i]->GetDeviceInstanceID(device_index); + SDL_assert(sensors[sensor_index] > 0); + ++sensor_index; + } + } + SDL_assert(sensor_index == total_sensors); + sensors[sensor_index] = 0; + } else { + if (count) { + *count = 0; + } + } + } + SDL_UnlockSensors(); + + return sensors; +} + +/* + * Get the driver and device index for a sensor instance ID + * This should be called while the sensor lock is held, to prevent another thread from updating the list + */ +static bool SDL_GetDriverAndSensorIndex(SDL_SensorID instance_id, SDL_SensorDriver **driver, int *driver_index) +{ + int i, num_sensors, device_index; + + if (instance_id > 0) { + for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { + num_sensors = SDL_sensor_drivers[i]->GetCount(); + for (device_index = 0; device_index < num_sensors; ++device_index) { + SDL_SensorID sensor_id = SDL_sensor_drivers[i]->GetDeviceInstanceID(device_index); + if (sensor_id == instance_id) { + *driver = SDL_sensor_drivers[i]; + *driver_index = device_index; + return true; + } + } + } + } + SDL_SetError("Sensor %" SDL_PRIu32 " not found", instance_id); + return false; +} + +/* + * Get the implementation dependent name of a sensor + */ +const char *SDL_GetSensorNameForID(SDL_SensorID instance_id) +{ + SDL_SensorDriver *driver; + int device_index; + const char *name = NULL; + + SDL_LockSensors(); + if (SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) { + name = SDL_GetPersistentString(driver->GetDeviceName(device_index)); + } + SDL_UnlockSensors(); + + return name; +} + +SDL_SensorType SDL_GetSensorTypeForID(SDL_SensorID instance_id) +{ + SDL_SensorDriver *driver; + int device_index; + SDL_SensorType type = SDL_SENSOR_INVALID; + + SDL_LockSensors(); + if (SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) { + type = driver->GetDeviceType(device_index); + } + SDL_UnlockSensors(); + + return type; +} + +int SDL_GetSensorNonPortableTypeForID(SDL_SensorID instance_id) +{ + SDL_SensorDriver *driver; + int device_index; + int type = -1; + + SDL_LockSensors(); + if (SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) { + type = driver->GetDeviceNonPortableType(device_index); + } + SDL_UnlockSensors(); + + return type; +} + +/* + * Open a sensor for use - the index passed as an argument refers to + * the N'th sensor on the system. This index is the value which will + * identify this sensor in future sensor events. + * + * This function returns a sensor identifier, or NULL if an error occurred. + */ +SDL_Sensor *SDL_OpenSensor(SDL_SensorID instance_id) +{ + SDL_SensorDriver *driver; + int device_index; + SDL_Sensor *sensor; + SDL_Sensor *sensorlist; + const char *sensorname = NULL; + + SDL_LockSensors(); + + if (!SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) { + SDL_UnlockSensors(); + return NULL; + } + + sensorlist = SDL_sensors; + /* If the sensor is already open, return it + * it is important that we have a single sensor * for each instance id + */ + while (sensorlist) { + if (instance_id == sensorlist->instance_id) { + sensor = sensorlist; + ++sensor->ref_count; + SDL_UnlockSensors(); + return sensor; + } + sensorlist = sensorlist->next; + } + + // Create and initialize the sensor + sensor = (SDL_Sensor *)SDL_calloc(1, sizeof(*sensor)); + if (!sensor) { + SDL_UnlockSensors(); + return NULL; + } + SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, true); + sensor->driver = driver; + sensor->instance_id = instance_id; + sensor->type = driver->GetDeviceType(device_index); + sensor->non_portable_type = driver->GetDeviceNonPortableType(device_index); + + if (!driver->Open(sensor, device_index)) { + SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, false); + SDL_free(sensor); + SDL_UnlockSensors(); + return NULL; + } + + sensorname = driver->GetDeviceName(device_index); + if (sensorname) { + sensor->name = SDL_strdup(sensorname); + } else { + sensor->name = NULL; + } + + // Add sensor to list + ++sensor->ref_count; + // Link the sensor in the list + sensor->next = SDL_sensors; + SDL_sensors = sensor; + + driver->Update(sensor); + + SDL_UnlockSensors(); + + return sensor; +} + +/* + * Find the SDL_Sensor that owns this instance id + */ +SDL_Sensor *SDL_GetSensorFromID(SDL_SensorID instance_id) +{ + SDL_Sensor *sensor; + + SDL_LockSensors(); + for (sensor = SDL_sensors; sensor; sensor = sensor->next) { + if (sensor->instance_id == instance_id) { + break; + } + } + SDL_UnlockSensors(); + return sensor; +} + +/* + * Get the properties associated with a sensor. + */ +SDL_PropertiesID SDL_GetSensorProperties(SDL_Sensor *sensor) +{ + SDL_PropertiesID result; + + SDL_LockSensors(); + { + CHECK_SENSOR_MAGIC(sensor, 0); + + if (sensor->props == 0) { + sensor->props = SDL_CreateProperties(); + } + result = sensor->props; + } + SDL_UnlockSensors(); + + return result; +} + +/* + * Get the friendly name of this sensor + */ +const char *SDL_GetSensorName(SDL_Sensor *sensor) +{ + const char *result; + + SDL_LockSensors(); + { + CHECK_SENSOR_MAGIC(sensor, NULL); + + result = SDL_GetPersistentString(sensor->name); + } + SDL_UnlockSensors(); + + return result; +} + +/* + * Get the type of this sensor + */ +SDL_SensorType SDL_GetSensorType(SDL_Sensor *sensor) +{ + SDL_SensorType result; + + SDL_LockSensors(); + { + CHECK_SENSOR_MAGIC(sensor, SDL_SENSOR_INVALID); + + result = sensor->type; + } + SDL_UnlockSensors(); + + return result; +} + +/* + * Get the platform dependent type of this sensor + */ +int SDL_GetSensorNonPortableType(SDL_Sensor *sensor) +{ + int result; + + SDL_LockSensors(); + { + CHECK_SENSOR_MAGIC(sensor, -1); + + result = sensor->non_portable_type; + } + SDL_UnlockSensors(); + + return result; +} + +/* + * Get the instance id for this opened sensor + */ +SDL_SensorID SDL_GetSensorID(SDL_Sensor *sensor) +{ + SDL_SensorID result; + + SDL_LockSensors(); + { + CHECK_SENSOR_MAGIC(sensor, 0); + + result = sensor->instance_id; + } + SDL_UnlockSensors(); + + return result; +} + +/* + * Get the current state of this sensor + */ +bool SDL_GetSensorData(SDL_Sensor *sensor, float *data, int num_values) +{ + SDL_LockSensors(); + { + CHECK_SENSOR_MAGIC(sensor, false); + + num_values = SDL_min(num_values, SDL_arraysize(sensor->data)); + SDL_memcpy(data, sensor->data, num_values * sizeof(*data)); + } + SDL_UnlockSensors(); + + return true; +} + +/* + * Close a sensor previously opened with SDL_OpenSensor() + */ +void SDL_CloseSensor(SDL_Sensor *sensor) +{ + SDL_Sensor *sensorlist; + SDL_Sensor *sensorlistprev; + + SDL_LockSensors(); + { + CHECK_SENSOR_MAGIC(sensor,); + + // First decrement ref count + if (--sensor->ref_count > 0) { + SDL_UnlockSensors(); + return; + } + + SDL_DestroyProperties(sensor->props); + + sensor->driver->Close(sensor); + sensor->hwdata = NULL; + SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, false); + + sensorlist = SDL_sensors; + sensorlistprev = NULL; + while (sensorlist) { + if (sensor == sensorlist) { + if (sensorlistprev) { + // unlink this entry + sensorlistprev->next = sensorlist->next; + } else { + SDL_sensors = sensor->next; + } + break; + } + sensorlistprev = sensorlist; + sensorlist = sensorlist->next; + } + + // Free the data associated with this sensor + SDL_free(sensor->name); + SDL_free(sensor); + } + SDL_UnlockSensors(); +} + +void SDL_QuitSensors(void) +{ + int i; + + SDL_LockSensors(); + + // Stop the event polling + while (SDL_sensors) { + SDL_sensors->ref_count = 1; + SDL_CloseSensor(SDL_sensors); + } + + // Quit the sensor setup + for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { + SDL_sensor_drivers[i]->Quit(); + } + + SDL_QuitSubSystem(SDL_INIT_EVENTS); + + SDL_sensors_initialized = false; + + SDL_UnlockSensors(); +} + +// These are global for SDL_syssensor.c and SDL_events.c + +void SDL_SendSensorUpdate(Uint64 timestamp, SDL_Sensor *sensor, Uint64 sensor_timestamp, float *data, int num_values) +{ + SDL_AssertSensorsLocked(); + + // Allow duplicate events, for things like steps and heartbeats + + // Update internal sensor state + num_values = SDL_min(num_values, SDL_arraysize(sensor->data)); + SDL_memcpy(sensor->data, data, num_values * sizeof(*data)); + + // Post the event, if desired + if (SDL_EventEnabled(SDL_EVENT_SENSOR_UPDATE)) { + SDL_Event event; + event.type = SDL_EVENT_SENSOR_UPDATE; + event.common.timestamp = timestamp; + event.sensor.which = sensor->instance_id; + num_values = SDL_min(num_values, SDL_arraysize(event.sensor.data)); + SDL_memset(event.sensor.data, 0, sizeof(event.sensor.data)); + SDL_memcpy(event.sensor.data, data, num_values * sizeof(*data)); + event.sensor.sensor_timestamp = sensor_timestamp; + SDL_PushEvent(&event); + } + + SDL_GamepadSensorWatcher(timestamp, sensor->instance_id, sensor_timestamp, data, num_values); +} + +void SDL_UpdateSensor(SDL_Sensor *sensor) +{ + SDL_LockSensors(); + { + CHECK_SENSOR_MAGIC(sensor,); + + sensor->driver->Update(sensor); + } + SDL_UnlockSensors(); +} + +void SDL_UpdateSensors(void) +{ + int i; + SDL_Sensor *sensor; + + if (!SDL_WasInit(SDL_INIT_SENSOR)) { + return; + } + + SDL_LockSensors(); + + for (sensor = SDL_sensors; sensor; sensor = sensor->next) { + sensor->driver->Update(sensor); + } + + /* this needs to happen AFTER walking the sensor list above, so that any + dangling hardware data from removed devices can be free'd + */ + for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { + SDL_sensor_drivers[i]->Detect(); + } + + SDL_UnlockSensors(); +} 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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef SDL_sensor_c_h_ +#define SDL_sensor_c_h_ + +#ifdef SDL_THREAD_SAFETY_ANALYSIS +extern SDL_Mutex *SDL_sensor_lock; +#endif + +struct SDL_SensorDriver; + +// Useful functions and variables from SDL_sensor.c + +// Initialization and shutdown functions +extern bool SDL_InitSensors(void); +extern void SDL_QuitSensors(void); + +// Return whether the sensor system is currently initialized +extern bool SDL_SensorsInitialized(void); + +// Return whether the sensors are currently locked +extern bool SDL_SensorsLocked(void); + +// Make sure we currently have the sensors locked +extern void SDL_AssertSensorsLocked(void) SDL_ASSERT_CAPABILITY(SDL_sensor_lock); + +extern void SDL_LockSensors(void) SDL_ACQUIRE(SDL_sensor_lock); +extern void SDL_UnlockSensors(void) SDL_RELEASE(SDL_sensor_lock); + +// Function to return whether there are any sensors opened by the application +extern bool SDL_SensorsOpened(void); + +// Update an individual sensor, used by gamepad sensor fusion +extern void SDL_UpdateSensor(SDL_Sensor *sensor); + +// Internal event queueing functions +extern void SDL_SendSensorUpdate(Uint64 timestamp, SDL_Sensor *sensor, Uint64 sensor_timestamp, float *data, int num_values); + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef SDL_syssensor_c_h_ +#define SDL_syssensor_c_h_ + +// This is the system specific header for the SDL sensor API + +#include "SDL_sensor_c.h" + +#define _guarded SDL_GUARDED_BY(SDL_sensor_lock) + +// The SDL sensor structure +struct SDL_Sensor +{ + SDL_SensorID instance_id _guarded; // Device instance, monotonically increasing from 0 + char *name _guarded; // Sensor name - system dependent + SDL_SensorType type _guarded; // Type of the sensor + int non_portable_type _guarded; // Platform dependent type of the sensor + + float data[16] _guarded; // The current state of the sensor + + struct SDL_SensorDriver *driver _guarded; + + struct sensor_hwdata *hwdata _guarded; // Driver dependent information + + SDL_PropertiesID props _guarded; + + int ref_count _guarded; // Reference count for multiple opens + + struct SDL_Sensor *next _guarded; // pointer to next sensor we have allocated +}; + +#undef _guarded + +typedef struct SDL_SensorDriver +{ + /* Function to scan the system for sensors. + * sensor 0 should be the system default sensor. + * This function should return 0, or -1 on an unrecoverable fatal error. + */ + bool (*Init)(void); + + // Function to return the number of sensors available right now + int (*GetCount)(void); + + // Function to check to see if the available sensors have changed + void (*Detect)(void); + + // Function to get the device-dependent name of a sensor + const char *(*GetDeviceName)(int device_index); + + // Function to get the type of a sensor + SDL_SensorType (*GetDeviceType)(int device_index); + + // Function to get the platform dependent type of a sensor + int (*GetDeviceNonPortableType)(int device_index); + + // Function to get the current instance id of the sensor located at device_index + SDL_SensorID (*GetDeviceInstanceID)(int device_index); + + /* Function to open a sensor for use. + The sensor to open is specified by the device index. + It returns 0, or -1 if there is an error. + */ + bool (*Open)(SDL_Sensor *sensor, int device_index); + + /* Function to update the state of a sensor - called as a device poll. + * This function shouldn't update the sensor structure directly, + * but instead should call SDL_SendSensorUpdate() to deliver events + * and update sensor device state. + */ + void (*Update)(SDL_Sensor *sensor); + + // Function to close a sensor after use + void (*Close)(SDL_Sensor *sensor); + + // Function to perform any system-specific sensor related cleanup + void (*Quit)(void); + +} SDL_SensorDriver; + +// The available sensor drivers +extern SDL_SensorDriver SDL_ANDROID_SensorDriver; +extern SDL_SensorDriver SDL_COREMOTION_SensorDriver; +extern SDL_SensorDriver SDL_WINDOWS_SensorDriver; +extern SDL_SensorDriver SDL_DUMMY_SensorDriver; +extern SDL_SensorDriver SDL_VITA_SensorDriver; +extern SDL_SensorDriver SDL_N3DS_SensorDriver; + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_SENSOR_ANDROID + +// This is the system specific header for the SDL sensor API +#include + +#include "SDL_androidsensor.h" +#include "../SDL_syssensor.h" +#include "../SDL_sensor_c.h" +#include "../../thread/SDL_systhread.h" + +#ifndef LOOPER_ID_USER +#define LOOPER_ID_USER 3 +#endif + +typedef struct +{ + ASensorRef asensor; + SDL_SensorID instance_id; + ASensorEventQueue *event_queue; + SDL_Sensor *sensor; +} SDL_AndroidSensor; + +typedef struct +{ + SDL_AtomicInt running; + SDL_Thread *thread; + SDL_Semaphore *sem; +} SDL_AndroidSensorThreadContext; + +static ASensorManager *SDL_sensor_manager; +static ALooper *SDL_sensor_looper; +static SDL_AndroidSensorThreadContext SDL_sensor_thread_context; +static SDL_AndroidSensor *SDL_sensors SDL_GUARDED_BY(SDL_sensors_lock); +static int SDL_sensors_count; + +static int SDLCALL SDL_ANDROID_SensorThread(void *data) +{ + SDL_AndroidSensorThreadContext *ctx = (SDL_AndroidSensorThreadContext *)data; + int i, events; + ASensorEvent event; + struct android_poll_source *source; + + SDL_SetCurrentThreadPriority(SDL_THREAD_PRIORITY_HIGH); + + SDL_sensor_looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); + SDL_SignalSemaphore(ctx->sem); + + while (SDL_GetAtomicInt(&ctx->running)) { + Uint64 timestamp = SDL_GetTicksNS(); + + if (ALooper_pollOnce(-1, NULL, &events, (void **)&source) == LOOPER_ID_USER) { + SDL_LockSensors(); + for (i = 0; i < SDL_sensors_count; ++i) { + if (!SDL_sensors[i].event_queue) { + continue; + } + + SDL_zero(event); + while (ASensorEventQueue_getEvents(SDL_sensors[i].event_queue, &event, 1) > 0) { + SDL_SendSensorUpdate(timestamp, SDL_sensors[i].sensor, timestamp, event.data, SDL_arraysize(event.data)); + } + } + SDL_UnlockSensors(); + } + } + + SDL_sensor_looper = NULL; + + return 0; +} + +static void SDL_ANDROID_StopSensorThread(SDL_AndroidSensorThreadContext *ctx) +{ + SDL_SetAtomicInt(&ctx->running, false); + + if (ctx->thread) { + int result; + + if (SDL_sensor_looper) { + ALooper_wake(SDL_sensor_looper); + } + SDL_WaitThread(ctx->thread, &result); + ctx->thread = NULL; + } + + if (ctx->sem) { + SDL_DestroySemaphore(ctx->sem); + ctx->sem = NULL; + } +} + +static bool SDL_ANDROID_StartSensorThread(SDL_AndroidSensorThreadContext *ctx) +{ + ctx->sem = SDL_CreateSemaphore(0); + if (!ctx->sem) { + SDL_ANDROID_StopSensorThread(ctx); + return false; + } + + SDL_SetAtomicInt(&ctx->running, true); + ctx->thread = SDL_CreateThread(SDL_ANDROID_SensorThread, "Sensors", ctx); + if (!ctx->thread) { + SDL_ANDROID_StopSensorThread(ctx); + return false; + } + + // Wait for the sensor thread to start + SDL_WaitSemaphore(ctx->sem); + + return true; +} + +static bool SDL_ANDROID_SensorInit(void) +{ + int i, sensors_count; + ASensorList sensors; + + SDL_sensor_manager = ASensorManager_getInstance(); + if (!SDL_sensor_manager) { + return SDL_SetError("Couldn't create sensor manager"); + } + + // FIXME: Is the sensor list dynamic? + sensors_count = ASensorManager_getSensorList(SDL_sensor_manager, &sensors); + if (sensors_count > 0) { + SDL_sensors = (SDL_AndroidSensor *)SDL_calloc(sensors_count, sizeof(*SDL_sensors)); + if (!SDL_sensors) { + return false; + } + + for (i = 0; i < sensors_count; ++i) { + SDL_sensors[i].asensor = sensors[i]; + SDL_sensors[i].instance_id = SDL_GetNextObjectID(); + } + SDL_sensors_count = sensors_count; + } + + if (!SDL_ANDROID_StartSensorThread(&SDL_sensor_thread_context)) { + return false; + } + return true; +} + +static int SDL_ANDROID_SensorGetCount(void) +{ + return SDL_sensors_count; +} + +static void SDL_ANDROID_SensorDetect(void) +{ +} + +static const char *SDL_ANDROID_SensorGetDeviceName(int device_index) +{ + return ASensor_getName(SDL_sensors[device_index].asensor); +} + +static SDL_SensorType SDL_ANDROID_SensorGetDeviceType(int device_index) +{ + switch (ASensor_getType(SDL_sensors[device_index].asensor)) { + case 0x00000001: + return SDL_SENSOR_ACCEL; + case 0x00000004: + return SDL_SENSOR_GYRO; + default: + return SDL_SENSOR_UNKNOWN; + } +} + +static int SDL_ANDROID_SensorGetDeviceNonPortableType(int device_index) +{ + return ASensor_getType(SDL_sensors[device_index].asensor); +} + +static SDL_SensorID SDL_ANDROID_SensorGetDeviceInstanceID(int device_index) +{ + return SDL_sensors[device_index].instance_id; +} + +static bool SDL_ANDROID_SensorOpen(SDL_Sensor *sensor, int device_index) +{ + int delay_us, min_delay_us; + + SDL_LockSensors(); + { + SDL_sensors[device_index].sensor = sensor; + SDL_sensors[device_index].event_queue = ASensorManager_createEventQueue(SDL_sensor_manager, SDL_sensor_looper, LOOPER_ID_USER, NULL, NULL); + if (!SDL_sensors[device_index].event_queue) { + SDL_UnlockSensors(); + return SDL_SetError("Couldn't create sensor event queue"); + } + + if (ASensorEventQueue_enableSensor(SDL_sensors[device_index].event_queue, SDL_sensors[device_index].asensor) < 0) { + ASensorManager_destroyEventQueue(SDL_sensor_manager, SDL_sensors[device_index].event_queue); + SDL_sensors[device_index].event_queue = NULL; + SDL_UnlockSensors(); + return SDL_SetError("Couldn't enable sensor"); + } + + // Use 60 Hz update rate if possible + // FIXME: Maybe add a hint for this? + delay_us = 1000000 / 60; + min_delay_us = ASensor_getMinDelay(SDL_sensors[device_index].asensor); + if (delay_us < min_delay_us) { + delay_us = min_delay_us; + } + ASensorEventQueue_setEventRate(SDL_sensors[device_index].event_queue, SDL_sensors[device_index].asensor, delay_us); + } + SDL_UnlockSensors(); + + return true; +} + +static void SDL_ANDROID_SensorUpdate(SDL_Sensor *sensor) +{ +} + +static void SDL_ANDROID_SensorClose(SDL_Sensor *sensor) +{ + int i; + + for (i = 0; i < SDL_sensors_count; ++i) { + if (SDL_sensors[i].sensor == sensor) { + SDL_LockSensors(); + { + ASensorEventQueue_disableSensor(SDL_sensors[i].event_queue, SDL_sensors[i].asensor); + ASensorManager_destroyEventQueue(SDL_sensor_manager, SDL_sensors[i].event_queue); + SDL_sensors[i].event_queue = NULL; + SDL_sensors[i].sensor = NULL; + } + SDL_UnlockSensors(); + break; + } + } +} + +static void SDL_ANDROID_SensorQuit(void) +{ + // All sensors are closed, but we need to unblock the sensor thread + SDL_AssertSensorsLocked(); + SDL_UnlockSensors(); + SDL_ANDROID_StopSensorThread(&SDL_sensor_thread_context); + SDL_LockSensors(); + + if (SDL_sensors) { + SDL_free(SDL_sensors); + SDL_sensors = NULL; + SDL_sensors_count = 0; + } +} + +SDL_SensorDriver SDL_ANDROID_SensorDriver = { + SDL_ANDROID_SensorInit, + SDL_ANDROID_SensorGetCount, + SDL_ANDROID_SensorDetect, + SDL_ANDROID_SensorGetDeviceName, + SDL_ANDROID_SensorGetDeviceType, + SDL_ANDROID_SensorGetDeviceNonPortableType, + SDL_ANDROID_SensorGetDeviceInstanceID, + SDL_ANDROID_SensorOpen, + SDL_ANDROID_SensorUpdate, + SDL_ANDROID_SensorClose, + SDL_ANDROID_SensorQuit, +}; + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// The private structure used to keep track of a sensor +struct sensor_hwdata +{ + float data[3]; +}; 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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_SENSOR_COREMOTION + +// This is the system specific header for the SDL sensor API +#include + +#include "SDL_coremotionsensor.h" +#include "../SDL_syssensor.h" +#include "../SDL_sensor_c.h" + +typedef struct +{ + SDL_SensorType type; + SDL_SensorID instance_id; +} SDL_CoreMotionSensor; + +static CMMotionManager *SDL_motion_manager; +static SDL_CoreMotionSensor *SDL_sensors; +static int SDL_sensors_count; + +static bool SDL_COREMOTION_SensorInit(void) +{ + int i, sensors_count = 0; + + if (!SDL_motion_manager) { + SDL_motion_manager = [[CMMotionManager alloc] init]; + } + + if (SDL_motion_manager.accelerometerAvailable) { + ++sensors_count; + } + if (SDL_motion_manager.gyroAvailable) { + ++sensors_count; + } + + if (sensors_count > 0) { + SDL_sensors = (SDL_CoreMotionSensor *)SDL_calloc(sensors_count, sizeof(*SDL_sensors)); + if (!SDL_sensors) { + return false; + } + + i = 0; + if (SDL_motion_manager.accelerometerAvailable) { + SDL_sensors[i].type = SDL_SENSOR_ACCEL; + SDL_sensors[i].instance_id = SDL_GetNextObjectID(); + ++i; + } + if (SDL_motion_manager.gyroAvailable) { + SDL_sensors[i].type = SDL_SENSOR_GYRO; + SDL_sensors[i].instance_id = SDL_GetNextObjectID(); + ++i; + } + SDL_sensors_count = sensors_count; + } + return true; +} + +static int SDL_COREMOTION_SensorGetCount(void) +{ + return SDL_sensors_count; +} + +static void SDL_COREMOTION_SensorDetect(void) +{ +} + +static const char *SDL_COREMOTION_SensorGetDeviceName(int device_index) +{ + switch (SDL_sensors[device_index].type) { + case SDL_SENSOR_ACCEL: + return "Accelerometer"; + case SDL_SENSOR_GYRO: + return "Gyro"; + default: + return "Unknown"; + } +} + +static SDL_SensorType SDL_COREMOTION_SensorGetDeviceType(int device_index) +{ + return SDL_sensors[device_index].type; +} + +static int SDL_COREMOTION_SensorGetDeviceNonPortableType(int device_index) +{ + return SDL_sensors[device_index].type; +} + +static SDL_SensorID SDL_COREMOTION_SensorGetDeviceInstanceID(int device_index) +{ + return SDL_sensors[device_index].instance_id; +} + +static bool SDL_COREMOTION_SensorOpen(SDL_Sensor *sensor, int device_index) +{ + struct sensor_hwdata *hwdata; + + hwdata = (struct sensor_hwdata *)SDL_calloc(1, sizeof(*hwdata)); + if (hwdata == NULL) { + return false; + } + sensor->hwdata = hwdata; + + switch (sensor->type) { + case SDL_SENSOR_ACCEL: + [SDL_motion_manager startAccelerometerUpdates]; + break; + case SDL_SENSOR_GYRO: + [SDL_motion_manager startGyroUpdates]; + break; + default: + break; + } + return true; +} + +static void SDL_COREMOTION_SensorUpdate(SDL_Sensor *sensor) +{ + Uint64 timestamp = SDL_GetTicksNS(); + + switch (sensor->type) { + case SDL_SENSOR_ACCEL: + { + CMAccelerometerData *accelerometerData = SDL_motion_manager.accelerometerData; + if (accelerometerData) { + CMAcceleration acceleration = accelerometerData.acceleration; + float data[3]; + data[0] = -acceleration.x * SDL_STANDARD_GRAVITY; + data[1] = -acceleration.y * SDL_STANDARD_GRAVITY; + data[2] = -acceleration.z * SDL_STANDARD_GRAVITY; + if (SDL_memcmp(data, sensor->hwdata->data, sizeof(data)) != 0) { + SDL_SendSensorUpdate(timestamp, sensor, timestamp, data, SDL_arraysize(data)); + SDL_memcpy(sensor->hwdata->data, data, sizeof(data)); + } + } + } break; + case SDL_SENSOR_GYRO: + { + CMGyroData *gyroData = SDL_motion_manager.gyroData; + if (gyroData) { + CMRotationRate rotationRate = gyroData.rotationRate; + float data[3]; + data[0] = rotationRate.x; + data[1] = rotationRate.y; + data[2] = rotationRate.z; + if (SDL_memcmp(data, sensor->hwdata->data, sizeof(data)) != 0) { + SDL_SendSensorUpdate(timestamp, sensor, timestamp, data, SDL_arraysize(data)); + SDL_memcpy(sensor->hwdata->data, data, sizeof(data)); + } + } + } break; + default: + break; + } +} + +static void SDL_COREMOTION_SensorClose(SDL_Sensor *sensor) +{ + if (sensor->hwdata) { + switch (sensor->type) { + case SDL_SENSOR_ACCEL: + [SDL_motion_manager stopAccelerometerUpdates]; + break; + case SDL_SENSOR_GYRO: + [SDL_motion_manager stopGyroUpdates]; + break; + default: + break; + } + SDL_free(sensor->hwdata); + sensor->hwdata = NULL; + } +} + +static void SDL_COREMOTION_SensorQuit(void) +{ +} + +SDL_SensorDriver SDL_COREMOTION_SensorDriver = { + SDL_COREMOTION_SensorInit, + SDL_COREMOTION_SensorGetCount, + SDL_COREMOTION_SensorDetect, + SDL_COREMOTION_SensorGetDeviceName, + SDL_COREMOTION_SensorGetDeviceType, + SDL_COREMOTION_SensorGetDeviceNonPortableType, + SDL_COREMOTION_SensorGetDeviceInstanceID, + SDL_COREMOTION_SensorOpen, + SDL_COREMOTION_SensorUpdate, + SDL_COREMOTION_SensorClose, + SDL_COREMOTION_SensorQuit, +}; + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#if defined(SDL_SENSOR_DUMMY) || defined(SDL_SENSOR_DISABLED) + +#include "SDL_dummysensor.h" +#include "../SDL_syssensor.h" + +static bool SDL_DUMMY_SensorInit(void) +{ + return true; +} + +static int SDL_DUMMY_SensorGetCount(void) +{ + return 0; +} + +static void SDL_DUMMY_SensorDetect(void) +{ +} + +static const char *SDL_DUMMY_SensorGetDeviceName(int device_index) +{ + return NULL; +} + +static SDL_SensorType SDL_DUMMY_SensorGetDeviceType(int device_index) +{ + return SDL_SENSOR_INVALID; +} + +static int SDL_DUMMY_SensorGetDeviceNonPortableType(int device_index) +{ + return -1; +} + +static SDL_SensorID SDL_DUMMY_SensorGetDeviceInstanceID(int device_index) +{ + return -1; +} + +static bool SDL_DUMMY_SensorOpen(SDL_Sensor *sensor, int device_index) +{ + return SDL_Unsupported(); +} + +static void SDL_DUMMY_SensorUpdate(SDL_Sensor *sensor) +{ +} + +static void SDL_DUMMY_SensorClose(SDL_Sensor *sensor) +{ +} + +static void SDL_DUMMY_SensorQuit(void) +{ +} + +SDL_SensorDriver SDL_DUMMY_SensorDriver = { + SDL_DUMMY_SensorInit, + SDL_DUMMY_SensorGetCount, + SDL_DUMMY_SensorDetect, + SDL_DUMMY_SensorGetDeviceName, + SDL_DUMMY_SensorGetDeviceType, + SDL_DUMMY_SensorGetDeviceNonPortableType, + SDL_DUMMY_SensorGetDeviceInstanceID, + SDL_DUMMY_SensorOpen, + SDL_DUMMY_SensorUpdate, + SDL_DUMMY_SensorClose, + SDL_DUMMY_SensorQuit, +}; + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "SDL_internal.h" + +#ifdef SDL_SENSOR_N3DS + +#include <3ds.h> + +#include "../SDL_syssensor.h" + +// 1 accelerometer and 1 gyroscope +#define N3DS_SENSOR_COUNT 2 + +typedef struct +{ + SDL_SensorType type; + SDL_SensorID instance_id; +} SDL_N3DSSensor; + +static SDL_N3DSSensor N3DS_sensors[N3DS_SENSOR_COUNT]; + +static bool InitN3DSServices(void); +static void UpdateN3DSAccelerometer(SDL_Sensor *sensor); +static void UpdateN3DSGyroscope(SDL_Sensor *sensor); + +static bool IsDeviceIndexValid(int device_index) +{ + return device_index >= 0 && device_index < N3DS_SENSOR_COUNT; +} + +static bool N3DS_SensorInit(void) +{ + if (!InitN3DSServices()) { + return SDL_SetError("Failed to initialise N3DS services"); + } + + N3DS_sensors[0].type = SDL_SENSOR_ACCEL; + N3DS_sensors[0].instance_id = SDL_GetNextObjectID(); + N3DS_sensors[1].type = SDL_SENSOR_GYRO; + N3DS_sensors[1].instance_id = SDL_GetNextObjectID(); + return true; +} + +static bool InitN3DSServices(void) +{ + if (R_FAILED(hidInit())) { + return false; + } + + if (R_FAILED(HIDUSER_EnableAccelerometer())) { + return false; + } + + if (R_FAILED(HIDUSER_EnableGyroscope())) { + return false; + } + return true; +} + +static int N3DS_SensorGetCount(void) +{ + return N3DS_SENSOR_COUNT; +} + +static void N3DS_SensorDetect(void) +{ +} + +static const char *N3DS_SensorGetDeviceName(int device_index) +{ + if (IsDeviceIndexValid(device_index)) { + switch (N3DS_sensors[device_index].type) { + case SDL_SENSOR_ACCEL: + return "Accelerometer"; + case SDL_SENSOR_GYRO: + return "Gyroscope"; + default: + return "Unknown"; + } + } + + return NULL; +} + +static SDL_SensorType N3DS_SensorGetDeviceType(int device_index) +{ + if (IsDeviceIndexValid(device_index)) { + return N3DS_sensors[device_index].type; + } + return SDL_SENSOR_INVALID; +} + +static int N3DS_SensorGetDeviceNonPortableType(int device_index) +{ + return (int)N3DS_SensorGetDeviceType(device_index); +} + +static SDL_SensorID N3DS_SensorGetDeviceInstanceID(int device_index) +{ + if (IsDeviceIndexValid(device_index)) { + return N3DS_sensors[device_index].instance_id; + } + return -1; +} + +static bool N3DS_SensorOpen(SDL_Sensor *sensor, int device_index) +{ + return true; +} + +static void N3DS_SensorUpdate(SDL_Sensor *sensor) +{ + switch (sensor->type) { + case SDL_SENSOR_ACCEL: + UpdateN3DSAccelerometer(sensor); + break; + case SDL_SENSOR_GYRO: + UpdateN3DSGyroscope(sensor); + break; + default: + break; + } +} + +static void UpdateN3DSAccelerometer(SDL_Sensor *sensor) +{ + static accelVector previous_state = { 0, 0, 0 }; + accelVector current_state; + float data[3]; + Uint64 timestamp = SDL_GetTicksNS(); + + hidAccelRead(¤t_state); + if (SDL_memcmp(&previous_state, ¤t_state, sizeof(accelVector)) != 0) { + SDL_memcpy(&previous_state, ¤t_state, sizeof(accelVector)); + data[0] = (float)current_state.x * SDL_STANDARD_GRAVITY; + data[1] = (float)current_state.y * SDL_STANDARD_GRAVITY; + data[2] = (float)current_state.z * SDL_STANDARD_GRAVITY; + SDL_SendSensorUpdate(timestamp, sensor, timestamp, data, sizeof(data)); + } +} + +static void UpdateN3DSGyroscope(SDL_Sensor *sensor) +{ + static angularRate previous_state = { 0, 0, 0 }; + angularRate current_state; + float data[3]; + Uint64 timestamp = SDL_GetTicksNS(); + + hidGyroRead(¤t_state); + if (SDL_memcmp(&previous_state, ¤t_state, sizeof(angularRate)) != 0) { + SDL_memcpy(&previous_state, ¤t_state, sizeof(angularRate)); + data[0] = (float)current_state.x; + data[1] = (float)current_state.y; + data[2] = (float)current_state.z; + SDL_SendSensorUpdate(timestamp, sensor, timestamp, data, sizeof(data)); + } +} + +static void N3DS_SensorClose(SDL_Sensor *sensor) +{ +} + +static void N3DS_SensorQuit(void) +{ + HIDUSER_DisableGyroscope(); + HIDUSER_DisableAccelerometer(); + hidExit(); +} + +SDL_SensorDriver SDL_N3DS_SensorDriver = { + .Init = N3DS_SensorInit, + .GetCount = N3DS_SensorGetCount, + .Detect = N3DS_SensorDetect, + .GetDeviceName = N3DS_SensorGetDeviceName, + .GetDeviceType = N3DS_SensorGetDeviceType, + .GetDeviceNonPortableType = N3DS_SensorGetDeviceNonPortableType, + .GetDeviceInstanceID = N3DS_SensorGetDeviceInstanceID, + .Open = N3DS_SensorOpen, + .Update = N3DS_SensorUpdate, + .Close = N3DS_SensorClose, + .Quit = N3DS_SensorQuit, +}; + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_SENSOR_VITA + +#include "SDL_vitasensor.h" +#include "../SDL_syssensor.h" +#include + +#ifndef SCE_MOTION_MAX_NUM_STATES +#define SCE_MOTION_MAX_NUM_STATES 64 +#endif + +typedef struct +{ + SDL_SensorType type; + SDL_SensorID instance_id; +} SDL_VitaSensor; + +static SDL_VitaSensor *SDL_sensors; +static int SDL_sensors_count; + +static bool SDL_VITA_SensorInit(void) +{ + sceMotionReset(); + sceMotionStartSampling(); + // not sure if these are needed, we are reading unfiltered state + sceMotionSetAngleThreshold(0); + sceMotionSetDeadband(SCE_FALSE); + sceMotionSetTiltCorrection(SCE_FALSE); + + SDL_sensors_count = 2; + + SDL_sensors = (SDL_VitaSensor *)SDL_calloc(SDL_sensors_count, sizeof(*SDL_sensors)); + if (!SDL_sensors) { + return false; + } + + SDL_sensors[0].type = SDL_SENSOR_ACCEL; + SDL_sensors[0].instance_id = SDL_GetNextObjectID(); + SDL_sensors[1].type = SDL_SENSOR_GYRO; + SDL_sensors[1].instance_id = SDL_GetNextObjectID(); + + return true; +} + +static int SDL_VITA_SensorGetCount(void) +{ + return SDL_sensors_count; +} + +static void SDL_VITA_SensorDetect(void) +{ +} + +static const char *SDL_VITA_SensorGetDeviceName(int device_index) +{ + if (device_index < SDL_sensors_count) { + switch (SDL_sensors[device_index].type) { + case SDL_SENSOR_ACCEL: + return "Accelerometer"; + case SDL_SENSOR_GYRO: + return "Gyro"; + default: + return "Unknown"; + } + } + + return NULL; +} + +static SDL_SensorType SDL_VITA_SensorGetDeviceType(int device_index) +{ + if (device_index < SDL_sensors_count) { + return SDL_sensors[device_index].type; + } + + return SDL_SENSOR_INVALID; +} + +static int SDL_VITA_SensorGetDeviceNonPortableType(int device_index) +{ + if (device_index < SDL_sensors_count) { + return SDL_sensors[device_index].type; + } + return -1; +} + +static SDL_SensorID SDL_VITA_SensorGetDeviceInstanceID(int device_index) +{ + if (device_index < SDL_sensors_count) { + return SDL_sensors[device_index].instance_id; + } + return -1; +} + +static bool SDL_VITA_SensorOpen(SDL_Sensor *sensor, int device_index) +{ + struct sensor_hwdata *hwdata; + + hwdata = (struct sensor_hwdata *)SDL_calloc(1, sizeof(*hwdata)); + if (!hwdata) { + return false; + } + sensor->hwdata = hwdata; + + return true; +} + +static void SDL_VITA_SensorUpdate(SDL_Sensor *sensor) +{ + int err = 0; + SceMotionSensorState motionState[SCE_MOTION_MAX_NUM_STATES]; + Uint64 timestamp = SDL_GetTicksNS(); + + SDL_zero(motionState); + err = sceMotionGetSensorState(motionState, SCE_MOTION_MAX_NUM_STATES); + if (err != 0) { + return; + } + + for (int i = 0; i < SCE_MOTION_MAX_NUM_STATES; i++) { + if (sensor->hwdata->counter < motionState[i].counter) { + unsigned int tick = motionState[i].timestamp; + unsigned int delta; + + sensor->hwdata->counter = motionState[i].counter; + + if (sensor->hwdata->last_tick > tick) { + SDL_COMPILE_TIME_ASSERT(tick, sizeof(tick) == sizeof(Uint32)); + delta = (SDL_MAX_UINT32 - sensor->hwdata->last_tick + tick + 1); + } else { + delta = (tick - sensor->hwdata->last_tick); + } + sensor->hwdata->sensor_timestamp += SDL_US_TO_NS(delta); + sensor->hwdata->last_tick = tick; + + switch (sensor->type) { + case SDL_SENSOR_ACCEL: + { + float data[3]; + data[0] = motionState[i].accelerometer.x * SDL_STANDARD_GRAVITY; + data[1] = motionState[i].accelerometer.y * SDL_STANDARD_GRAVITY; + data[2] = motionState[i].accelerometer.z * SDL_STANDARD_GRAVITY; + SDL_SendSensorUpdate(timestamp, sensor, sensor->hwdata->sensor_timestamp, data, SDL_arraysize(data)); + } break; + case SDL_SENSOR_GYRO: + { + float data[3]; + data[0] = motionState[i].gyro.x; + data[1] = motionState[i].gyro.y; + data[2] = motionState[i].gyro.z; + SDL_SendSensorUpdate(timestamp, sensor, sensor->hwdata->sensor_timestamp, data, SDL_arraysize(data)); + } break; + default: + break; + } + } + } +} + +static void SDL_VITA_SensorClose(SDL_Sensor *sensor) +{ +} + +static void SDL_VITA_SensorQuit(void) +{ + sceMotionStopSampling(); +} + +SDL_SensorDriver SDL_VITA_SensorDriver = { + SDL_VITA_SensorInit, + SDL_VITA_SensorGetCount, + SDL_VITA_SensorDetect, + SDL_VITA_SensorGetDeviceName, + SDL_VITA_SensorGetDeviceType, + SDL_VITA_SensorGetDeviceNonPortableType, + SDL_VITA_SensorGetDeviceInstanceID, + SDL_VITA_SensorOpen, + SDL_VITA_SensorUpdate, + SDL_VITA_SensorClose, + SDL_VITA_SensorQuit, +}; + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// The private structure used to keep track of a sensor +struct sensor_hwdata +{ + Uint32 counter; + unsigned int last_tick; + Uint64 sensor_timestamp; +}; 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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_SENSOR_WINDOWS + +#include "SDL_windowssensor.h" +#include "../SDL_syssensor.h" +#include "../../core/windows/SDL_windows.h" + +#define COBJMACROS +#include +#include +#include + +DEFINE_GUID(SDL_CLSID_SensorManager, 0x77A1C827, 0xFCD2, 0x4689, 0x89, 0x15, 0x9D, 0x61, 0x3C, 0xC5, 0xFA, 0x3E); +DEFINE_GUID(SDL_IID_SensorManager, 0xBD77DB67, 0x45A8, 0x42DC, 0x8D, 0x00, 0x6D, 0xCF, 0x15, 0xF8, 0x37, 0x7A); +DEFINE_GUID(SDL_IID_SensorManagerEvents, 0x9B3B0B86, 0x266A, 0x4AAD, 0xB2, 0x1F, 0xFD, 0xE5, 0x50, 0x10, 0x01, 0xB7); +DEFINE_GUID(SDL_IID_SensorEvents, 0x5D8DCC91, 0x4641, 0x47E7, 0xB7, 0xC3, 0xB7, 0x4F, 0x48, 0xA6, 0xC3, 0x91); + +// These constants aren't available in Visual Studio 2015 or earlier Windows SDK +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] +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] +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] + +typedef struct +{ + SDL_SensorID id; + ISensor *sensor; + SENSOR_ID sensor_id; + char *name; + SDL_SensorType type; + SDL_Sensor *sensor_opened; + +} SDL_Windows_Sensor; + +static bool SDL_windowscoinit; +static ISensorManager *SDL_sensor_manager; +static int SDL_num_sensors; +static SDL_Windows_Sensor *SDL_sensors; + +static bool ConnectSensor(ISensor *sensor); +static bool DisconnectSensor(ISensor *sensor); + +static HRESULT STDMETHODCALLTYPE ISensorManagerEventsVtbl_QueryInterface(ISensorManagerEvents *This, REFIID riid, void **ppvObject) +{ + if (!ppvObject) { + return E_INVALIDARG; + } + + *ppvObject = NULL; + if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &SDL_IID_SensorManagerEvents)) { + *ppvObject = This; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE ISensorManagerEventsVtbl_AddRef(ISensorManagerEvents *This) +{ + return 1; +} + +static ULONG STDMETHODCALLTYPE ISensorManagerEventsVtbl_Release(ISensorManagerEvents *This) +{ + return 1; +} + +static HRESULT STDMETHODCALLTYPE ISensorManagerEventsVtbl_OnSensorEnter(ISensorManagerEvents *This, ISensor *pSensor, SensorState state) +{ + ConnectSensor(pSensor); + return S_OK; +} + +static ISensorManagerEventsVtbl sensor_manager_events_vtbl = { + ISensorManagerEventsVtbl_QueryInterface, + ISensorManagerEventsVtbl_AddRef, + ISensorManagerEventsVtbl_Release, + ISensorManagerEventsVtbl_OnSensorEnter +}; +static ISensorManagerEvents sensor_manager_events = { + &sensor_manager_events_vtbl +}; + +static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_QueryInterface(ISensorEvents *This, REFIID riid, void **ppvObject) +{ + if (!ppvObject) { + return E_INVALIDARG; + } + + *ppvObject = NULL; + if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &SDL_IID_SensorEvents)) { + *ppvObject = This; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE ISensorEventsVtbl_AddRef(ISensorEvents *This) +{ + return 1; +} + +static ULONG STDMETHODCALLTYPE ISensorEventsVtbl_Release(ISensorEvents *This) +{ + return 1; +} + +static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnStateChanged(ISensorEvents *This, ISensor *pSensor, SensorState state) +{ +#ifdef DEBUG_SENSORS + int i; + + SDL_LockSensors(); + for (i = 0; i < SDL_num_sensors; ++i) { + if (pSensor == SDL_sensors[i].sensor) { + SDL_Log("Sensor %s state changed to %d", SDL_sensors[i].name, state); + } + } + SDL_UnlockSensors(); +#endif + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnDataUpdated(ISensorEvents *This, ISensor *pSensor, ISensorDataReport *pNewData) +{ + int i; + Uint64 timestamp = SDL_GetTicksNS(); + + SDL_LockSensors(); + for (i = 0; i < SDL_num_sensors; ++i) { + if (pSensor == SDL_sensors[i].sensor) { + if (SDL_sensors[i].sensor_opened) { + HRESULT hrX, hrY, hrZ; + PROPVARIANT valueX = { 0 }, valueY = { 0 }, valueZ = { 0 }; + SYSTEMTIME sensor_systemtime; + FILETIME sensor_filetime; + Uint64 sensor_timestamp; + +#ifdef DEBUG_SENSORS + SDL_Log("Sensor %s data updated", SDL_sensors[i].name); +#endif + if (SUCCEEDED(ISensorDataReport_GetTimestamp(pNewData, &sensor_systemtime)) && + SystemTimeToFileTime(&sensor_systemtime, &sensor_filetime)) { + ULARGE_INTEGER sensor_time; + sensor_time.u.HighPart = sensor_filetime.dwHighDateTime; + sensor_time.u.LowPart = sensor_filetime.dwLowDateTime; + sensor_timestamp = sensor_time.QuadPart * 100; + } else { + sensor_timestamp = timestamp; + } + + switch (SDL_sensors[i].type) { + case SDL_SENSOR_ACCEL: + hrX = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_X_G, &valueX); + hrY = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_Y_G, &valueY); + hrZ = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_Z_G, &valueZ); + if (SUCCEEDED(hrX) && SUCCEEDED(hrY) && SUCCEEDED(hrZ) && + valueX.vt == VT_R8 && valueY.vt == VT_R8 && valueZ.vt == VT_R8) { + float values[3]; + + values[0] = (float)valueX.dblVal * SDL_STANDARD_GRAVITY; + values[1] = (float)valueY.dblVal * SDL_STANDARD_GRAVITY; + values[2] = (float)valueZ.dblVal * SDL_STANDARD_GRAVITY; + SDL_SendSensorUpdate(timestamp, SDL_sensors[i].sensor_opened, sensor_timestamp, values, 3); + } + break; + case SDL_SENSOR_GYRO: + hrX = ISensorDataReport_GetSensorValue(pNewData, &SDL_SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND, &valueX); + hrY = ISensorDataReport_GetSensorValue(pNewData, &SDL_SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND, &valueY); + hrZ = ISensorDataReport_GetSensorValue(pNewData, &SDL_SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND, &valueZ); + if (SUCCEEDED(hrX) && SUCCEEDED(hrY) && SUCCEEDED(hrZ) && + valueX.vt == VT_R8 && valueY.vt == VT_R8 && valueZ.vt == VT_R8) { + const float DEGREES_TO_RADIANS = (SDL_PI_F / 180.0f); + float values[3]; + + values[0] = (float)valueX.dblVal * DEGREES_TO_RADIANS; + values[1] = (float)valueY.dblVal * DEGREES_TO_RADIANS; + values[2] = (float)valueZ.dblVal * DEGREES_TO_RADIANS; + SDL_SendSensorUpdate(timestamp, SDL_sensors[i].sensor_opened, sensor_timestamp, values, 3); + } + break; + default: + // FIXME: Need to know how to interpret the data for this sensor + break; + } + } + break; + } + } + SDL_UnlockSensors(); + + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnEvent(ISensorEvents *This, ISensor *pSensor, REFGUID eventID, IPortableDeviceValues *pEventData) +{ +#ifdef DEBUG_SENSORS + int i; + + SDL_LockSensors(); + for (i = 0; i < SDL_num_sensors; ++i) { + if (pSensor == SDL_sensors[i].sensor) { + SDL_Log("Sensor %s event occurred", SDL_sensors[i].name); + } + } + SDL_UnlockSensors(); +#endif + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnLeave(ISensorEvents *This, REFSENSOR_ID ID) +{ + int i; + + SDL_LockSensors(); + for (i = 0; i < SDL_num_sensors; ++i) { + if (WIN_IsEqualIID(ID, &SDL_sensors[i].sensor_id)) { +#ifdef DEBUG_SENSORS + SDL_Log("Sensor %s disconnected", SDL_sensors[i].name); +#endif + DisconnectSensor(SDL_sensors[i].sensor); + } + } + SDL_UnlockSensors(); + + return S_OK; +} + +static ISensorEventsVtbl sensor_events_vtbl = { + ISensorEventsVtbl_QueryInterface, + ISensorEventsVtbl_AddRef, + ISensorEventsVtbl_Release, + ISensorEventsVtbl_OnStateChanged, + ISensorEventsVtbl_OnDataUpdated, + ISensorEventsVtbl_OnEvent, + ISensorEventsVtbl_OnLeave +}; +static ISensorEvents sensor_events = { + &sensor_events_vtbl +}; + +static bool ConnectSensor(ISensor *sensor) +{ + SDL_Windows_Sensor *new_sensor, *new_sensors; + HRESULT hr; + SENSOR_ID sensor_id; + SENSOR_TYPE_ID type_id; + SDL_SensorType type; + BSTR bstr_name = NULL; + char *name; + + hr = ISensor_GetID(sensor, &sensor_id); + if (FAILED(hr)) { + return WIN_SetErrorFromHRESULT("Couldn't get sensor ID", hr); + } + + hr = ISensor_GetType(sensor, &type_id); + if (FAILED(hr)) { + return WIN_SetErrorFromHRESULT("Couldn't get sensor type", hr); + } + + if (WIN_IsEqualIID(&type_id, &SENSOR_TYPE_ACCELEROMETER_3D)) { + type = SDL_SENSOR_ACCEL; + } else if (WIN_IsEqualIID(&type_id, &SENSOR_TYPE_GYROMETER_3D)) { + type = SDL_SENSOR_GYRO; + } else { + return SDL_SetError("Unknown sensor type"); + } + + hr = ISensor_GetFriendlyName(sensor, &bstr_name); + if (SUCCEEDED(hr) && bstr_name) { + name = WIN_StringToUTF8W(bstr_name); + } else { + name = SDL_strdup("Unknown Sensor"); + } + if (bstr_name != NULL) { + SysFreeString(bstr_name); + } + if (!name) { + return false; + } + + SDL_LockSensors(); + new_sensors = (SDL_Windows_Sensor *)SDL_realloc(SDL_sensors, (SDL_num_sensors + 1) * sizeof(SDL_Windows_Sensor)); + if (!new_sensors) { + SDL_UnlockSensors(); + SDL_free(name); + return false; + } + + ISensor_AddRef(sensor); + ISensor_SetEventSink(sensor, &sensor_events); + + SDL_sensors = new_sensors; + new_sensor = &SDL_sensors[SDL_num_sensors]; + ++SDL_num_sensors; + + SDL_zerop(new_sensor); + new_sensor->id = SDL_GetNextObjectID(); + new_sensor->sensor = sensor; + new_sensor->type = type; + new_sensor->name = name; + + SDL_UnlockSensors(); + + return true; +} + +static bool DisconnectSensor(ISensor *sensor) +{ + SDL_Windows_Sensor *old_sensor; + int i; + + SDL_LockSensors(); + for (i = 0; i < SDL_num_sensors; ++i) { + old_sensor = &SDL_sensors[i]; + if (sensor == old_sensor->sensor) { + /* This call hangs for some reason: + * https://github.com/libsdl-org/SDL/issues/5288 + */ + // ISensor_SetEventSink(sensor, NULL); + ISensor_Release(sensor); + SDL_free(old_sensor->name); + --SDL_num_sensors; + if (i < SDL_num_sensors) { + SDL_memmove(&SDL_sensors[i], &SDL_sensors[i + 1], (SDL_num_sensors - i) * sizeof(SDL_sensors[i])); + } + break; + } + } + SDL_UnlockSensors(); + + return true; +} + +static bool SDL_WINDOWS_SensorInit(void) +{ + HRESULT hr; + ISensorCollection *sensor_collection = NULL; + + if (WIN_CoInitialize() == S_OK) { + SDL_windowscoinit = true; + } + + hr = CoCreateInstance(&SDL_CLSID_SensorManager, NULL, CLSCTX_INPROC_SERVER, &SDL_IID_SensorManager, (LPVOID *)&SDL_sensor_manager); + if (FAILED(hr)) { + // If we can't create a sensor manager (i.e. on Wine), we won't have any sensors, but don't fail the init + return true; // WIN_SetErrorFromHRESULT("Couldn't create the sensor manager", hr); + } + + hr = ISensorManager_SetEventSink(SDL_sensor_manager, &sensor_manager_events); + if (FAILED(hr)) { + ISensorManager_Release(SDL_sensor_manager); + SDL_sensor_manager = NULL; + return WIN_SetErrorFromHRESULT("Couldn't set the sensor manager event sink", hr); + } + + hr = ISensorManager_GetSensorsByCategory(SDL_sensor_manager, &SENSOR_CATEGORY_ALL, &sensor_collection); + if (SUCCEEDED(hr)) { + ULONG i, count; + + hr = ISensorCollection_GetCount(sensor_collection, &count); + if (SUCCEEDED(hr)) { + for (i = 0; i < count; ++i) { + ISensor *sensor; + + hr = ISensorCollection_GetAt(sensor_collection, i, &sensor); + if (SUCCEEDED(hr)) { + SensorState state; + + hr = ISensor_GetState(sensor, &state); + if (SUCCEEDED(hr)) { + ISensorManagerEventsVtbl_OnSensorEnter(&sensor_manager_events, sensor, state); + } + ISensorManager_Release(sensor); + } + } + } + ISensorCollection_Release(sensor_collection); + } + return true; +} + +static int SDL_WINDOWS_SensorGetCount(void) +{ + return SDL_num_sensors; +} + +static void SDL_WINDOWS_SensorDetect(void) +{ +} + +static const char *SDL_WINDOWS_SensorGetDeviceName(int device_index) +{ + return SDL_sensors[device_index].name; +} + +static SDL_SensorType SDL_WINDOWS_SensorGetDeviceType(int device_index) +{ + return SDL_sensors[device_index].type; +} + +static int SDL_WINDOWS_SensorGetDeviceNonPortableType(int device_index) +{ + return -1; +} + +static SDL_SensorID SDL_WINDOWS_SensorGetDeviceInstanceID(int device_index) +{ + return SDL_sensors[device_index].id; +} + +static bool SDL_WINDOWS_SensorOpen(SDL_Sensor *sensor, int device_index) +{ + SDL_sensors[device_index].sensor_opened = sensor; + return true; +} + +static void SDL_WINDOWS_SensorUpdate(SDL_Sensor *sensor) +{ +} + +static void SDL_WINDOWS_SensorClose(SDL_Sensor *sensor) +{ + int i; + + for (i = 0; i < SDL_num_sensors; ++i) { + if (sensor == SDL_sensors[i].sensor_opened) { + SDL_sensors[i].sensor_opened = NULL; + break; + } + } +} + +static void SDL_WINDOWS_SensorQuit(void) +{ + while (SDL_num_sensors > 0) { + DisconnectSensor(SDL_sensors[0].sensor); + } + + if (SDL_sensor_manager) { + ISensorManager_SetEventSink(SDL_sensor_manager, NULL); + ISensorManager_Release(SDL_sensor_manager); + SDL_sensor_manager = NULL; + } + + if (SDL_windowscoinit) { + WIN_CoUninitialize(); + } +} + +SDL_SensorDriver SDL_WINDOWS_SensorDriver = { + SDL_WINDOWS_SensorInit, + SDL_WINDOWS_SensorGetCount, + SDL_WINDOWS_SensorDetect, + SDL_WINDOWS_SensorGetDeviceName, + SDL_WINDOWS_SensorGetDeviceType, + SDL_WINDOWS_SensorGetDeviceNonPortableType, + SDL_WINDOWS_SensorGetDeviceInstanceID, + SDL_WINDOWS_SensorOpen, + SDL_WINDOWS_SensorUpdate, + SDL_WINDOWS_SensorClose, + SDL_WINDOWS_SensorQuit, +}; + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" -- cgit v1.2.3