1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-16 14:00:40 +00:00

Support adding advanced joypad features

This commit is contained in:
Nintorch
2025-10-20 19:28:06 +05:00
parent 36b92128b1
commit 7ae67813a1
9 changed files with 560 additions and 3 deletions

View File

@@ -986,6 +986,15 @@ void Input::set_joy_axis(int p_device, JoyAxis p_axis, float p_value) {
_joy_axis[c] = p_value;
}
void Input::set_joy_features(int p_device, JoypadFeatures *p_features) {
Joypad *joypad = joy_names.getptr(p_device);
if (!joypad) {
return;
}
joypad->features = p_features;
_update_joypad_features(p_device);
}
void Input::start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration) {
_THREAD_SAFE_METHOD_
if (p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) {
@@ -1478,6 +1487,15 @@ void Input::_update_action_cache(const StringName &p_action_name, ActionState &r
}
}
void Input::_update_joypad_features(int p_device) {
Joypad *joypad = joy_names.getptr(p_device);
if (!joypad || joypad->features == nullptr) {
return;
}
// Do something based on the features. For example, we can save the information about
// the joypad having motion sensors, LED light, etc.
}
Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button) {
JoyEvent event;

View File

@@ -79,6 +79,15 @@ public:
CURSOR_MAX
};
class JoypadFeatures {
public:
virtual ~JoypadFeatures() {}
// None at the moment, but later we can add new features like:
// virtual bool has_joy_accelerometer() const { return false; }
// virtual bool set_joy_accelerometer_enabled(bool p_enable) { return false; }
};
static constexpr int32_t JOYPADS_MAX = 16;
typedef void (*EventDispatchFunc)(const Ref<InputEvent> &p_event);
@@ -174,6 +183,7 @@ private:
int mapping = -1;
int hat_current = 0;
Dictionary info;
Input::JoypadFeatures *features = nullptr;
};
VelocityTrack mouse_velocity_track;
@@ -253,6 +263,7 @@ private:
void _button_event(int p_device, JoyButton p_index, bool p_pressed);
void _axis_event(int p_device, JoyAxis p_axis, float p_value);
void _update_action_cache(const StringName &p_action_name, ActionState &r_action_state);
void _update_joypad_features(int p_device);
void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated);
@@ -346,6 +357,8 @@ public:
void set_gyroscope(const Vector3 &p_gyroscope);
void set_joy_axis(int p_device, JoyAxis p_axis, float p_value);
void set_joy_features(int p_device, JoypadFeatures *p_features);
void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0);
void stop_joy_vibration(int p_device);
void vibrate_handheld(int p_duration_ms = 500, float p_amplitude = -1.0);

View File

@@ -178,6 +178,7 @@ if env["builtin_sdl"]:
"joystick/windows/SDL_xinputjoystick.c",
"thread/generic/SDL_syscond.c",
"thread/generic/SDL_sysrwlock.c",
"sensor/windows/SDL_windowssensor.c",
"thread/windows/SDL_syscond_cv.c",
"thread/windows/SDL_sysmutex.c",
"thread/windows/SDL_sysrwlock_srw.c",

View File

@@ -47,7 +47,6 @@
#define SDL_DIALOG_DISABLED 1
#define SDL_FILESYSTEM_DUMMY 1
#define SDL_FSOPS_DUMMY 1
#define SDL_SENSOR_DISABLED 1
#define SDL_GPU_DISABLED 1
#define SDL_RENDER_DISABLED 1
#define SDL_POWER_DISABLED 1
@@ -73,6 +72,7 @@
#define SDL_THREAD_GENERIC_RWLOCK_SUFFIX 1
#define SDL_THREAD_WINDOWS 1
#define SDL_TIMER_WINDOWS 1
#define SDL_SENSOR_WINDOWS 1
// Linux defines
#elif defined(SDL_PLATFORM_LINUX)
@@ -113,6 +113,7 @@
#define SDL_HAPTIC_LINUX 1
#define SDL_TIMER_UNIX 1
#define SDL_JOYSTICK_LINUX 1
#define SDL_JOYSTICK_HIDAPI 1
#define SDL_INPUT_LINUXEV 1
#define SDL_THREAD_PTHREAD 1
@@ -126,8 +127,10 @@
#define SDL_HAPTIC_IOKIT 1
#define SDL_JOYSTICK_IOKIT 1
#define SDL_JOYSTICK_MFI 1
#define SDL_JOYSTICK_HIDAPI 1
#define SDL_TIMER_UNIX 1
#define SDL_THREAD_PTHREAD 1
#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1
// Other platforms are not supported (for now)
#else

View File

@@ -208,6 +208,8 @@ void JoypadSDL::process_events() {
device_name,
joypads[joy_id].guid,
joypad_info);
Input::get_singleton()->set_joy_features(joy_id, &joypads[joy_id]);
}
// An event for an attached joypad
} else if (sdl_event.type >= SDL_EVENT_JOYSTICK_AXIS_MOTION && sdl_event.type < SDL_EVENT_FINGER_DOWN && sdl_instance_id_to_joypad_id.has(sdl_event.jdevice.which)) {
@@ -299,4 +301,12 @@ void JoypadSDL::close_joypad(int p_pad_idx) {
}
}
SDL_Joystick *JoypadSDL::Joypad::get_sdl_joystick() const {
return SDL_GetJoystickFromID(sdl_instance_idx);
}
SDL_Gamepad *JoypadSDL::Joypad::get_sdl_gamepad() const {
return SDL_GetGamepadFromID(sdl_instance_idx);
}
#endif // SDL_ENABLED

View File

@@ -35,6 +35,8 @@
typedef uint32_t SDL_JoystickID;
typedef struct HWND__ *HWND;
typedef struct SDL_Joystick SDL_Joystick;
typedef struct SDL_Gamepad SDL_Gamepad;
class JoypadSDL {
public:
@@ -50,7 +52,8 @@ public:
void process_events();
private:
struct Joypad {
class Joypad : public Input::JoypadFeatures {
public:
bool attached = false;
StringName guid;
@@ -58,6 +61,9 @@ private:
bool supports_force_feedback = false;
uint64_t ff_effect_timestamp = 0;
SDL_Joystick *get_sdl_joystick() const;
SDL_Gamepad *get_sdl_gamepad() const;
};
static JoypadSDL *singleton;

View File

@@ -0,0 +1,485 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
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 <initguid.h>
#include <sensorsapi.h>
#include <sensors.h>
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

View File

@@ -0,0 +1,21 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
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"

View File

@@ -61,7 +61,7 @@ mkdir $target/loadso
cp -rv loadso/dlopen $target/loadso
mkdir $target/sensor
cp -rv sensor/{*.{c,h},dummy} $target/sensor
cp -rv sensor/{*.{c,h},dummy,windows} $target/sensor
mkdir $target/thread
cp -rv thread/{*.{c,h},pthread,windows} $target/thread