Atlas - SDL_windowssensor.c

Home / ext / SDL / src / sensor / windows Lines: 1 | Size: 15825 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#ifdef SDL_SENSOR_WINDOWS 24 25#include "SDL_windowssensor.h" 26#include "../SDL_syssensor.h" 27#include "../../core/windows/SDL_windows.h" 28 29#define COBJMACROS 30#include <initguid.h> 31#include <sensorsapi.h> 32#include <sensors.h> 33 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 486
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.