SDL_windowssensor.c (14936B)
1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20 */ 21 #include "../../SDL_internal.h" 22 23 #include "SDL_config.h" 24 25 #if defined(SDL_SENSOR_WINDOWS) 26 27 #include "SDL_error.h" 28 #include "SDL_mutex.h" 29 #include "SDL_sensor.h" 30 #include "SDL_windowssensor.h" 31 #include "../SDL_syssensor.h" 32 #include "../../core/windows/SDL_windows.h" 33 34 #define COBJMACROS 35 #include <initguid.h> 36 #include <sensorsapi.h> 37 #include <sensors.h> 38 39 DEFINE_GUID(SDL_CLSID_SensorManager, 0x77A1C827, 0xFCD2, 0x4689, 0x89, 0x15, 0x9D, 0x61, 0x3C, 0xC5, 0xFA, 0x3E); 40 DEFINE_GUID(SDL_IID_SensorManager, 0xBD77DB67, 0x45A8, 0x42DC, 0x8D, 0x00, 0x6D, 0xCF, 0x15, 0xF8, 0x37, 0x7A); 41 DEFINE_GUID(SDL_IID_SensorManagerEvents, 0x9B3B0B86, 0x266A, 0x4AAD, 0xB2, 0x1F, 0xFD, 0xE5, 0x50, 0x10, 0x01, 0xB7); 42 DEFINE_GUID(SDL_IID_SensorEvents, 0x5D8DCC91, 0x4641, 0x47E7, 0xB7, 0xC3, 0xB7, 0x4F, 0x48, 0xA6, 0xC3, 0x91); 43 44 /* These constants aren't available in Visual Studio 2015 or earlier Windows SDK */ 45 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] 46 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] 47 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] 48 49 typedef struct 50 { 51 SDL_SensorID id; 52 ISensor *sensor; 53 SENSOR_ID sensor_id; 54 char *name; 55 SDL_SensorType type; 56 SDL_Sensor *sensor_opened; 57 58 } SDL_Windows_Sensor; 59 60 static SDL_bool SDL_windowscoinit; 61 static ISensorManager *SDL_sensor_manager; 62 static int SDL_num_sensors; 63 static SDL_Windows_Sensor *SDL_sensors; 64 65 static int ConnectSensor(ISensor *sensor); 66 static int DisconnectSensor(ISensor *sensor); 67 68 static HRESULT STDMETHODCALLTYPE ISensorManagerEventsVtbl_QueryInterface(ISensorManagerEvents * This, REFIID riid, void **ppvObject) 69 { 70 if (!ppvObject) { 71 return E_INVALIDARG; 72 } 73 74 *ppvObject = NULL; 75 if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &SDL_IID_SensorManagerEvents)) { 76 *ppvObject = This; 77 return S_OK; 78 } 79 return E_NOINTERFACE; 80 } 81 82 static ULONG STDMETHODCALLTYPE ISensorManagerEventsVtbl_AddRef(ISensorManagerEvents * This) 83 { 84 return 1; 85 } 86 87 static ULONG STDMETHODCALLTYPE ISensorManagerEventsVtbl_Release(ISensorManagerEvents * This) 88 { 89 return 1; 90 } 91 92 static HRESULT STDMETHODCALLTYPE ISensorManagerEventsVtbl_OnSensorEnter(ISensorManagerEvents * This, ISensor *pSensor, SensorState state) 93 { 94 ConnectSensor(pSensor); 95 return S_OK; 96 } 97 98 static ISensorManagerEventsVtbl sensor_manager_events_vtbl = { 99 ISensorManagerEventsVtbl_QueryInterface, 100 ISensorManagerEventsVtbl_AddRef, 101 ISensorManagerEventsVtbl_Release, 102 ISensorManagerEventsVtbl_OnSensorEnter 103 }; 104 static ISensorManagerEvents sensor_manager_events = { 105 &sensor_manager_events_vtbl 106 }; 107 108 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_QueryInterface(ISensorEvents * This, REFIID riid, void **ppvObject) 109 { 110 if (!ppvObject) { 111 return E_INVALIDARG; 112 } 113 114 *ppvObject = NULL; 115 if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &SDL_IID_SensorEvents)) { 116 *ppvObject = This; 117 return S_OK; 118 } 119 return E_NOINTERFACE; 120 } 121 122 static ULONG STDMETHODCALLTYPE ISensorEventsVtbl_AddRef(ISensorEvents * This) 123 { 124 return 1; 125 } 126 127 static ULONG STDMETHODCALLTYPE ISensorEventsVtbl_Release(ISensorEvents * This) 128 { 129 return 1; 130 } 131 132 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnStateChanged(ISensorEvents * This, ISensor *pSensor, SensorState state) 133 { 134 #ifdef DEBUG_SENSORS 135 int i; 136 137 SDL_LockSensors(); 138 for (i = 0; i < SDL_num_sensors; ++i) { 139 if (pSensor == SDL_sensors[i].sensor) { 140 SDL_Log("Sensor %s state changed to %d\n", SDL_sensors[i].name, state); 141 } 142 } 143 SDL_UnlockSensors(); 144 #endif 145 return S_OK; 146 } 147 148 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnDataUpdated(ISensorEvents * This, ISensor *pSensor, ISensorDataReport *pNewData) 149 { 150 int i; 151 152 SDL_LockSensors(); 153 for (i = 0; i < SDL_num_sensors; ++i) { 154 if (pSensor == SDL_sensors[i].sensor) { 155 if (SDL_sensors[i].sensor_opened) { 156 HRESULT hrX, hrY, hrZ; 157 PROPVARIANT valueX, valueY, valueZ; 158 159 #ifdef DEBUG_SENSORS 160 SDL_Log("Sensor %s data updated\n", SDL_sensors[i].name); 161 #endif 162 switch (SDL_sensors[i].type) { 163 case SDL_SENSOR_ACCEL: 164 hrX = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_X_G, &valueX); 165 hrY = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_Y_G, &valueY); 166 hrZ = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_Z_G, &valueZ); 167 if (SUCCEEDED(hrX) && SUCCEEDED(hrY) && SUCCEEDED(hrZ) && 168 valueX.vt == VT_R8 && valueY.vt == VT_R8 && valueZ.vt == VT_R8) { 169 float values[3]; 170 171 values[0] = (float)valueX.dblVal * SDL_STANDARD_GRAVITY; 172 values[1] = (float)valueY.dblVal * SDL_STANDARD_GRAVITY; 173 values[2] = (float)valueZ.dblVal * SDL_STANDARD_GRAVITY; 174 SDL_PrivateSensorUpdate(SDL_sensors[i].sensor_opened, values, 3); 175 } 176 break; 177 case SDL_SENSOR_GYRO: 178 hrX = ISensorDataReport_GetSensorValue(pNewData, &SDL_SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND, &valueX); 179 hrY = ISensorDataReport_GetSensorValue(pNewData, &SDL_SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND, &valueY); 180 hrZ = ISensorDataReport_GetSensorValue(pNewData, &SDL_SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND, &valueZ); 181 if (SUCCEEDED(hrX) && SUCCEEDED(hrY) && SUCCEEDED(hrZ) && 182 valueX.vt == VT_R8 && valueY.vt == VT_R8 && valueZ.vt == VT_R8) { 183 const float DEGREES_TO_RADIANS = (float)(M_PI / 180.0f); 184 float values[3]; 185 186 values[0] = (float)valueX.dblVal * DEGREES_TO_RADIANS; 187 values[1] = (float)valueY.dblVal * DEGREES_TO_RADIANS; 188 values[2] = (float)valueZ.dblVal * DEGREES_TO_RADIANS; 189 SDL_PrivateSensorUpdate(SDL_sensors[i].sensor_opened, values, 3); 190 } 191 break; 192 default: 193 /* FIXME: Need to know how to interpret the data for this sensor */ 194 break; 195 } 196 } 197 break; 198 } 199 } 200 SDL_UnlockSensors(); 201 202 return S_OK; 203 } 204 205 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnEvent(ISensorEvents * This, ISensor *pSensor, REFGUID eventID, IPortableDeviceValues *pEventData) 206 { 207 #ifdef DEBUG_SENSORS 208 int i; 209 210 SDL_LockSensors(); 211 for (i = 0; i < SDL_num_sensors; ++i) { 212 if (pSensor == SDL_sensors[i].sensor) { 213 SDL_Log("Sensor %s event occurred\n", SDL_sensors[i].name); 214 } 215 } 216 SDL_UnlockSensors(); 217 #endif 218 return S_OK; 219 } 220 221 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnLeave(ISensorEvents * This, REFSENSOR_ID ID) 222 { 223 int i; 224 225 SDL_LockSensors(); 226 for (i = 0; i < SDL_num_sensors; ++i) { 227 if (WIN_IsEqualIID(ID, &SDL_sensors[i].sensor_id)) { 228 #ifdef DEBUG_SENSORS 229 SDL_Log("Sensor %s disconnected\n", SDL_sensors[i].name); 230 #endif 231 DisconnectSensor(SDL_sensors[i].sensor); 232 } 233 } 234 SDL_UnlockSensors(); 235 236 return S_OK; 237 } 238 239 static ISensorEventsVtbl sensor_events_vtbl = { 240 ISensorEventsVtbl_QueryInterface, 241 ISensorEventsVtbl_AddRef, 242 ISensorEventsVtbl_Release, 243 ISensorEventsVtbl_OnStateChanged, 244 ISensorEventsVtbl_OnDataUpdated, 245 ISensorEventsVtbl_OnEvent, 246 ISensorEventsVtbl_OnLeave 247 }; 248 static ISensorEvents sensor_events = { 249 &sensor_events_vtbl 250 }; 251 252 static int ConnectSensor(ISensor *sensor) 253 { 254 SDL_Windows_Sensor *new_sensor, *new_sensors; 255 HRESULT hr; 256 SENSOR_ID sensor_id; 257 SENSOR_TYPE_ID type_id; 258 SDL_SensorType type; 259 BSTR bstr_name = NULL; 260 char *name; 261 262 hr = ISensor_GetID(sensor, &sensor_id); 263 if (FAILED(hr)) { 264 return WIN_SetErrorFromHRESULT("Couldn't get sensor ID", hr); 265 } 266 267 hr = ISensor_GetType(sensor, &type_id); 268 if (FAILED(hr)) { 269 return WIN_SetErrorFromHRESULT("Couldn't get sensor type", hr); 270 } 271 272 if (WIN_IsEqualIID(&type_id, &SENSOR_TYPE_ACCELEROMETER_3D)) { 273 type = SDL_SENSOR_ACCEL; 274 } else if (WIN_IsEqualIID(&type_id, &SENSOR_TYPE_GYROMETER_3D)) { 275 type = SDL_SENSOR_GYRO; 276 } else { 277 return SDL_SetError("Unknown sensor type"); 278 } 279 280 hr = ISensor_GetFriendlyName(sensor, &bstr_name); 281 if (SUCCEEDED(hr) && bstr_name) { 282 name = WIN_StringToUTF8(bstr_name); 283 } else { 284 name = SDL_strdup("Unknown Sensor"); 285 } 286 if (bstr_name != NULL) { 287 SysFreeString(bstr_name); 288 } 289 if (!name) { 290 return SDL_OutOfMemory(); 291 } 292 293 SDL_LockSensors(); 294 new_sensors = (SDL_Windows_Sensor *)SDL_realloc(SDL_sensors, (SDL_num_sensors + 1) * sizeof(SDL_Windows_Sensor)); 295 if (new_sensors == NULL) { 296 SDL_UnlockSensors(); 297 return SDL_OutOfMemory(); 298 } 299 300 ISensor_AddRef(sensor); 301 ISensor_SetEventSink(sensor, &sensor_events); 302 303 SDL_sensors = new_sensors; 304 new_sensor = &SDL_sensors[SDL_num_sensors]; 305 ++SDL_num_sensors; 306 307 SDL_zerop(new_sensor); 308 new_sensor->id = SDL_GetNextSensorInstanceID(); 309 new_sensor->sensor = sensor; 310 new_sensor->type = type; 311 new_sensor->name = name; 312 313 SDL_UnlockSensors(); 314 315 return 0; 316 } 317 318 static int DisconnectSensor(ISensor *sensor) 319 { 320 SDL_Windows_Sensor *old_sensor; 321 int i; 322 323 SDL_LockSensors(); 324 for (i = 0; i < SDL_num_sensors; ++i) { 325 old_sensor = &SDL_sensors[i]; 326 if (sensor == old_sensor->sensor) { 327 ISensor_SetEventSink(sensor, NULL); 328 ISensor_Release(sensor); 329 SDL_free(old_sensor->name); 330 --SDL_num_sensors; 331 if (i < SDL_num_sensors) { 332 SDL_memmove(&SDL_sensors[i], &SDL_sensors[i + 1], (SDL_num_sensors - i) * sizeof(SDL_sensors[i])); 333 } 334 break; 335 } 336 } 337 SDL_UnlockSensors(); 338 339 return 0; 340 } 341 342 static int 343 SDL_WINDOWS_SensorInit(void) 344 { 345 HRESULT hr; 346 ISensorCollection *sensor_collection = NULL; 347 348 if (WIN_CoInitialize() == S_OK) { 349 SDL_windowscoinit = SDL_TRUE; 350 } 351 352 hr = CoCreateInstance(&SDL_CLSID_SensorManager, NULL, CLSCTX_INPROC_SERVER, &SDL_IID_SensorManager, (LPVOID *) &SDL_sensor_manager); 353 if (FAILED(hr)) { 354 return WIN_SetErrorFromHRESULT("Couldn't create the sensor manager", hr); 355 } 356 357 hr = ISensorManager_SetEventSink(SDL_sensor_manager, &sensor_manager_events); 358 if (FAILED(hr)) { 359 ISensorManager_Release(SDL_sensor_manager); 360 return WIN_SetErrorFromHRESULT("Couldn't set the sensor manager event sink", hr); 361 } 362 363 hr = ISensorManager_GetSensorsByCategory(SDL_sensor_manager, &SENSOR_CATEGORY_ALL, &sensor_collection); 364 if (SUCCEEDED(hr)) { 365 ULONG i, count; 366 367 hr = ISensorCollection_GetCount(sensor_collection, &count); 368 if (SUCCEEDED(hr)) { 369 for (i = 0; i < count; ++i) { 370 ISensor *sensor; 371 372 hr = ISensorCollection_GetAt(sensor_collection, i, &sensor); 373 if (SUCCEEDED(hr)) { 374 SensorState state; 375 376 hr = ISensor_GetState(sensor, &state); 377 if (SUCCEEDED(hr)) { 378 ISensorManagerEventsVtbl_OnSensorEnter(&sensor_manager_events, sensor, state); 379 } 380 ISensorManager_Release(sensor); 381 } 382 } 383 } 384 ISensorCollection_Release(sensor_collection); 385 } 386 return 0; 387 } 388 389 static int 390 SDL_WINDOWS_SensorGetCount(void) 391 { 392 return SDL_num_sensors; 393 } 394 395 static void 396 SDL_WINDOWS_SensorDetect(void) 397 { 398 } 399 400 static const char * 401 SDL_WINDOWS_SensorGetDeviceName(int device_index) 402 { 403 return SDL_sensors[device_index].name; 404 } 405 406 static SDL_SensorType 407 SDL_WINDOWS_SensorGetDeviceType(int device_index) 408 { 409 return SDL_sensors[device_index].type; 410 } 411 412 static int 413 SDL_WINDOWS_SensorGetDeviceNonPortableType(int device_index) 414 { 415 return -1; 416 } 417 418 static SDL_SensorID 419 SDL_WINDOWS_SensorGetDeviceInstanceID(int device_index) 420 { 421 return SDL_sensors[device_index].id; 422 } 423 424 static int 425 SDL_WINDOWS_SensorOpen(SDL_Sensor *sensor, int device_index) 426 { 427 SDL_sensors[device_index].sensor_opened = sensor; 428 return 0; 429 } 430 431 static void 432 SDL_WINDOWS_SensorUpdate(SDL_Sensor *sensor) 433 { 434 } 435 436 static void 437 SDL_WINDOWS_SensorClose(SDL_Sensor *sensor) 438 { 439 int i; 440 441 for (i = 0; i < SDL_num_sensors; ++i) { 442 if (sensor == SDL_sensors[i].sensor_opened) { 443 SDL_sensors[i].sensor_opened = NULL; 444 break; 445 } 446 } 447 } 448 449 static void 450 SDL_WINDOWS_SensorQuit(void) 451 { 452 while (SDL_num_sensors > 0) { 453 DisconnectSensor(SDL_sensors[0].sensor); 454 } 455 456 if (SDL_sensor_manager) { 457 ISensorManager_SetEventSink(SDL_sensor_manager, NULL); 458 ISensorManager_Release(SDL_sensor_manager); 459 SDL_sensor_manager = NULL; 460 } 461 462 if (SDL_windowscoinit) { 463 WIN_CoUninitialize(); 464 } 465 } 466 467 SDL_SensorDriver SDL_WINDOWS_SensorDriver = 468 { 469 SDL_WINDOWS_SensorInit, 470 SDL_WINDOWS_SensorGetCount, 471 SDL_WINDOWS_SensorDetect, 472 SDL_WINDOWS_SensorGetDeviceName, 473 SDL_WINDOWS_SensorGetDeviceType, 474 SDL_WINDOWS_SensorGetDeviceNonPortableType, 475 SDL_WINDOWS_SensorGetDeviceInstanceID, 476 SDL_WINDOWS_SensorOpen, 477 SDL_WINDOWS_SensorUpdate, 478 SDL_WINDOWS_SensorClose, 479 SDL_WINDOWS_SensorQuit, 480 }; 481 482 #endif /* SDL_SENSOR_WINDOWS */ 483 484 /* vi: set ts=4 sw=4 expandtab: */