src/sensor/windows/SDL_windowssensor.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 20 May 2020 16:59:35 -0400
changeset 13839 52dbeb97b294
parent 13838 02e41b30186f
child 13841 b89df0d683ad
permissions -rw-r--r--
sensor: Fix build on various Windows compilers with various predefinitions.
     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 #ifndef CLSID_SensorManager
    40 DEFINE_GUID(CLSID_SensorManager, 0x77A1C827, 0xFCD2, 0x4689, 0x89, 0x15, 0x9D, 0x61, 0x3C, 0xC5, 0xFA, 0x3E);
    41 #endif
    42 
    43 DEFINE_GUID(IID_SensorManager, 0xBD77DB67, 0x45A8, 0x42DC, 0x8D, 0x00, 0x6D, 0xCF, 0x15, 0xF8, 0x37, 0x7A);
    44 DEFINE_GUID(IID_SensorManagerEvents, 0x9B3B0B86, 0x266A, 0x4AAD, 0xB2, 0x1F, 0xFD, 0xE5, 0x50, 0x10, 0x01, 0xB7);
    45 DEFINE_GUID(IID_SensorEvents, 0x5D8DCC91, 0x4641, 0x47E7, 0xB7, 0xC3, 0xB7, 0x4F, 0x48, 0xA6, 0xC3, 0x91);
    46 
    47 /* These constants aren't available in Visual Studio 2015 or earlier Windows SDK  */
    48 #ifndef SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND
    49 DEFINE_PROPERTYKEY(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND, 0X3F8A69A2, 0X7C5, 0X4E48, 0XA9, 0X65, 0XCD, 0X79, 0X7A, 0XAB, 0X56, 0XD5, 10); //[VT_R8]
    50 DEFINE_PROPERTYKEY(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND, 0X3F8A69A2, 0X7C5, 0X4E48, 0XA9, 0X65, 0XCD, 0X79, 0X7A, 0XAB, 0X56, 0XD5, 11); //[VT_R8]
    51 DEFINE_PROPERTYKEY(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND, 0X3F8A69A2, 0X7C5, 0X4E48, 0XA9, 0X65, 0XCD, 0X79, 0X7A, 0XAB, 0X56, 0XD5, 12); //[VT_R8]
    52 #endif
    53 
    54 typedef struct
    55 {
    56     SDL_SensorID id;
    57     ISensor *sensor;
    58     SENSOR_ID sensor_id;
    59     char *name;
    60     SDL_SensorType type;
    61     SDL_Sensor *sensor_opened;
    62 
    63 } SDL_Windows_Sensor;
    64 
    65 static SDL_bool SDL_windowscoinit;
    66 static ISensorManager *SDL_sensor_manager;
    67 static int SDL_num_sensors;
    68 static SDL_Windows_Sensor *SDL_sensors;
    69 
    70 static int ConnectSensor(ISensor *sensor);
    71 static int DisconnectSensor(ISensor *sensor);
    72 
    73 static HRESULT STDMETHODCALLTYPE ISensorManagerEventsVtbl_QueryInterface(ISensorManagerEvents * This, REFIID riid, void **ppvObject)
    74 {
    75     if (!ppvObject) {
    76         return E_INVALIDARG;
    77     }
    78 
    79     *ppvObject = NULL;
    80     if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &IID_SensorManagerEvents)) {
    81         *ppvObject = This;
    82         return S_OK;
    83     }
    84     return E_NOINTERFACE;
    85 }
    86 
    87 static ULONG STDMETHODCALLTYPE ISensorManagerEventsVtbl_AddRef(ISensorManagerEvents * This)
    88 {
    89     return 1;
    90 }
    91 
    92 static ULONG STDMETHODCALLTYPE ISensorManagerEventsVtbl_Release(ISensorManagerEvents * This)
    93 {
    94     return 1;
    95 }
    96 
    97 static HRESULT STDMETHODCALLTYPE ISensorManagerEventsVtbl_OnSensorEnter(ISensorManagerEvents * This, ISensor *pSensor, SensorState state)
    98 {
    99     ConnectSensor(pSensor);
   100     return S_OK;
   101 }
   102 
   103 static ISensorManagerEventsVtbl sensor_manager_events_vtbl = {
   104     ISensorManagerEventsVtbl_QueryInterface,
   105     ISensorManagerEventsVtbl_AddRef,
   106     ISensorManagerEventsVtbl_Release,
   107     ISensorManagerEventsVtbl_OnSensorEnter
   108 };
   109 static ISensorManagerEvents sensor_manager_events = {
   110     &sensor_manager_events_vtbl
   111 };
   112 
   113 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_QueryInterface(ISensorEvents * This, REFIID riid, void **ppvObject)
   114 {
   115     if (!ppvObject) {
   116         return E_INVALIDARG;
   117     }
   118 
   119     *ppvObject = NULL;
   120     if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &IID_SensorEvents)) {
   121         *ppvObject = This;
   122         return S_OK;
   123     }
   124     return E_NOINTERFACE;
   125 }
   126 
   127 static ULONG STDMETHODCALLTYPE ISensorEventsVtbl_AddRef(ISensorEvents * This)
   128 {
   129     return 1;
   130 }
   131 
   132 static ULONG STDMETHODCALLTYPE ISensorEventsVtbl_Release(ISensorEvents * This)
   133 {
   134     return 1;
   135 }
   136 
   137 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnStateChanged(ISensorEvents * This, ISensor *pSensor, SensorState state)
   138 {
   139 #ifdef DEBUG_SENSORS
   140     int i;
   141 
   142     SDL_LockSensors();
   143     for (i = 0; i < SDL_num_sensors; ++i) {
   144         if (pSensor == SDL_sensors[i].sensor) {
   145             SDL_Log("Sensor %s state changed to %d\n", SDL_sensors[i].name, state);
   146         }
   147     }
   148     SDL_UnlockSensors();
   149 #endif
   150     return S_OK;
   151 }
   152 
   153 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnDataUpdated(ISensorEvents * This, ISensor *pSensor, ISensorDataReport *pNewData)
   154 {
   155     int i;
   156 
   157     SDL_LockSensors();
   158     for (i = 0; i < SDL_num_sensors; ++i) {
   159         if (pSensor == SDL_sensors[i].sensor) {
   160             if (SDL_sensors[i].sensor_opened) {
   161                 HRESULT hrX, hrY, hrZ;
   162                 PROPVARIANT valueX, valueY, valueZ;
   163 
   164 #ifdef DEBUG_SENSORS
   165                 SDL_Log("Sensor %s data updated\n", SDL_sensors[i].name);
   166 #endif
   167                 switch (SDL_sensors[i].type) {
   168                 case SDL_SENSOR_ACCEL:
   169                     hrX = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_X_G, &valueX);
   170                     hrY = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_Y_G, &valueY);
   171                     hrZ = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ACCELERATION_Z_G, &valueZ);
   172                     if (SUCCEEDED(hrX) && SUCCEEDED(hrY) && SUCCEEDED(hrZ) &&
   173                         valueX.vt == VT_R8 && valueY.vt == VT_R8 && valueZ.vt == VT_R8) {
   174                         float values[3];
   175 
   176                         values[0] = (float)valueX.dblVal * SDL_STANDARD_GRAVITY;
   177                         values[1] = (float)valueY.dblVal * SDL_STANDARD_GRAVITY;
   178                         values[2] = (float)valueZ.dblVal * SDL_STANDARD_GRAVITY;
   179                         SDL_PrivateSensorUpdate(SDL_sensors[i].sensor_opened, values, 3);
   180                     }
   181                     break;
   182                 case SDL_SENSOR_GYRO:
   183                     hrX = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND, &valueX);
   184                     hrY = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND, &valueY);
   185                     hrZ = ISensorDataReport_GetSensorValue(pNewData, &SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND, &valueZ);
   186                     if (SUCCEEDED(hrX) && SUCCEEDED(hrY) && SUCCEEDED(hrZ) &&
   187                         valueX.vt == VT_R8 && valueY.vt == VT_R8 && valueZ.vt == VT_R8) {
   188                         const float DEGREES_TO_RADIANS = (float)(M_PI / 180.0f);
   189                         float values[3];
   190 
   191                         values[0] = (float)valueX.dblVal * DEGREES_TO_RADIANS;
   192                         values[1] = (float)valueY.dblVal * DEGREES_TO_RADIANS;
   193                         values[2] = (float)valueZ.dblVal * DEGREES_TO_RADIANS;
   194                         SDL_PrivateSensorUpdate(SDL_sensors[i].sensor_opened, values, 3);
   195                     }
   196                     break;
   197                 default:
   198                     /* FIXME: Need to know how to interpret the data for this sensor */
   199                     break;
   200                 }
   201             }
   202             break;
   203         }
   204     }
   205     SDL_UnlockSensors();
   206 
   207     return S_OK;
   208 }
   209 
   210 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnEvent(ISensorEvents * This, ISensor *pSensor, REFGUID eventID, IPortableDeviceValues *pEventData)
   211 {
   212 #ifdef DEBUG_SENSORS
   213     int i;
   214 
   215     SDL_LockSensors();
   216     for (i = 0; i < SDL_num_sensors; ++i) {
   217         if (pSensor == SDL_sensors[i].sensor) {
   218             SDL_Log("Sensor %s event occurred\n", SDL_sensors[i].name);
   219         }
   220     }
   221     SDL_UnlockSensors();
   222 #endif
   223     return S_OK;
   224 }
   225 
   226 static HRESULT STDMETHODCALLTYPE ISensorEventsVtbl_OnLeave(ISensorEvents * This, REFSENSOR_ID ID)
   227 {
   228     int i;
   229 
   230     SDL_LockSensors();
   231     for (i = 0; i < SDL_num_sensors; ++i) {
   232         if (WIN_IsEqualIID(ID, &SDL_sensors[i].sensor_id)) {
   233 #ifdef DEBUG_SENSORS
   234             SDL_Log("Sensor %s disconnected\n", SDL_sensors[i].name);
   235 #endif
   236             DisconnectSensor(SDL_sensors[i].sensor);
   237         }
   238     }
   239     SDL_UnlockSensors();
   240 
   241     return S_OK;
   242 }
   243 
   244 static ISensorEventsVtbl sensor_events_vtbl = {
   245     ISensorEventsVtbl_QueryInterface,
   246     ISensorEventsVtbl_AddRef,
   247     ISensorEventsVtbl_Release,
   248     ISensorEventsVtbl_OnStateChanged,
   249     ISensorEventsVtbl_OnDataUpdated,
   250     ISensorEventsVtbl_OnEvent,
   251     ISensorEventsVtbl_OnLeave
   252 };
   253 static ISensorEvents sensor_events = {
   254     &sensor_events_vtbl
   255 };
   256 
   257 static int ConnectSensor(ISensor *sensor)
   258 {
   259     SDL_Windows_Sensor *new_sensor, *new_sensors;
   260     HRESULT hr;
   261     SENSOR_ID sensor_id;
   262     SENSOR_TYPE_ID type_id;
   263     SDL_SensorType type;
   264     BSTR bstr_name = NULL;
   265     char *name;
   266 
   267     hr = ISensor_GetID(sensor, &sensor_id);
   268     if (FAILED(hr)) {
   269         return SDL_SetError("Couldn't get sensor ID: 0x%.4x", hr);
   270     }
   271 
   272     hr = ISensor_GetType(sensor, &type_id);
   273     if (FAILED(hr)) {
   274         return SDL_SetError("Couldn't get sensor type: 0x%.4x", hr);
   275     }
   276 
   277     if (WIN_IsEqualIID(&type_id, &SENSOR_TYPE_ACCELEROMETER_3D)) {
   278         type = SDL_SENSOR_ACCEL;
   279     } else if (WIN_IsEqualIID(&type_id, &SENSOR_TYPE_GYROMETER_3D)) {
   280         type = SDL_SENSOR_GYRO;
   281     } else {
   282         return SDL_SetError("Unknown sensor type");
   283     }
   284 
   285     hr = ISensor_GetFriendlyName(sensor, &bstr_name);
   286     if (SUCCEEDED(hr) && bstr_name) {
   287         name = WIN_StringToUTF8(bstr_name);
   288     } else {
   289         name = SDL_strdup("Unknown Sensor");
   290     }
   291     if (bstr_name != NULL) {
   292         SysFreeString(bstr_name);
   293     }
   294     if (!name) {
   295         return SDL_OutOfMemory();
   296     }
   297 
   298     SDL_LockSensors();
   299     new_sensors = (SDL_Windows_Sensor *)SDL_realloc(SDL_sensors, (SDL_num_sensors + 1) * sizeof(SDL_Windows_Sensor));
   300     if (new_sensors == NULL) {
   301         SDL_UnlockSensors();
   302         return SDL_OutOfMemory();
   303     }
   304 
   305     ISensor_AddRef(sensor);
   306     ISensor_SetEventSink(sensor, &sensor_events);
   307 
   308     SDL_sensors = new_sensors;
   309     new_sensor = &SDL_sensors[SDL_num_sensors];
   310     ++SDL_num_sensors;
   311 
   312     SDL_zerop(new_sensor);
   313     new_sensor->id = SDL_GetNextSensorInstanceID();
   314     new_sensor->sensor = sensor;
   315     new_sensor->type = type;
   316     new_sensor->name = name;
   317 
   318     SDL_UnlockSensors();
   319 
   320     return 0;
   321 }
   322 
   323 static int DisconnectSensor(ISensor *sensor)
   324 {
   325     SDL_Windows_Sensor *old_sensor;
   326     int i;
   327 
   328     SDL_LockSensors();
   329     for (i = 0; i < SDL_num_sensors; ++i) {
   330         old_sensor = &SDL_sensors[i];
   331         if (sensor == old_sensor->sensor) {
   332             ISensor_SetEventSink(sensor, NULL);
   333             ISensor_Release(sensor);
   334             SDL_free(old_sensor->name);
   335             --SDL_num_sensors;
   336             if (i < SDL_num_sensors) {
   337                 SDL_memmove(&SDL_sensors[i], &SDL_sensors[i + 1], (SDL_num_sensors - i) * sizeof(SDL_sensors[i]));
   338             }
   339             break;
   340         }
   341     }
   342     SDL_UnlockSensors();
   343 
   344     return 0;
   345 }
   346 
   347 static int
   348 SDL_WINDOWS_SensorInit(void)
   349 {
   350     HRESULT hr;
   351     ISensorCollection *sensor_collection = NULL;
   352 
   353     if (WIN_CoInitialize() == S_OK) {
   354         SDL_windowscoinit = SDL_TRUE;
   355     }
   356 
   357     hr = CoCreateInstance(&CLSID_SensorManager, NULL, CLSCTX_INPROC_SERVER, &IID_SensorManager, (LPVOID *) &SDL_sensor_manager);
   358     if (FAILED(hr)) {
   359         return SDL_SetError("Couldn't create the sensor manager: 0x%.4x", hr);
   360     }
   361 
   362     hr = ISensorManager_SetEventSink(SDL_sensor_manager, &sensor_manager_events);
   363     if (FAILED(hr)) {
   364         ISensorManager_Release(SDL_sensor_manager);
   365         return SDL_SetError("Couldn't set the sensor manager event sink: 0x%.4x", hr);
   366     }
   367 
   368     hr = ISensorManager_GetSensorsByCategory(SDL_sensor_manager, &SENSOR_CATEGORY_ALL, &sensor_collection);
   369     if (SUCCEEDED(hr)) {
   370         ULONG i, count;
   371 
   372         hr = ISensorCollection_GetCount(sensor_collection, &count);
   373         if (SUCCEEDED(hr)) {
   374             for (i = 0; i < count; ++i) {
   375                 ISensor *sensor;
   376 
   377                 hr = ISensorCollection_GetAt(sensor_collection, i, &sensor);
   378                 if (SUCCEEDED(hr)) {
   379                     SensorState state;
   380 
   381                     hr = ISensor_GetState(sensor, &state);
   382                     if (SUCCEEDED(hr)) {
   383                         ISensorManagerEventsVtbl_OnSensorEnter(&sensor_manager_events, sensor, state);
   384                     }
   385                     ISensorManager_Release(sensor);
   386                 }
   387             }
   388         }
   389         ISensorCollection_Release(sensor_collection);
   390     }
   391     return 0;
   392 }
   393 
   394 static int
   395 SDL_WINDOWS_SensorGetCount(void)
   396 {
   397     return SDL_num_sensors;
   398 }
   399 
   400 static void
   401 SDL_WINDOWS_SensorDetect(void)
   402 {
   403 }
   404 
   405 static const char *
   406 SDL_WINDOWS_SensorGetDeviceName(int device_index)
   407 {
   408     return SDL_sensors[device_index].name;
   409 }
   410 
   411 static SDL_SensorType
   412 SDL_WINDOWS_SensorGetDeviceType(int device_index)
   413 {
   414     return SDL_sensors[device_index].type;
   415 }
   416 
   417 static int
   418 SDL_WINDOWS_SensorGetDeviceNonPortableType(int device_index)
   419 {
   420     return -1;
   421 }
   422 
   423 static SDL_SensorID
   424 SDL_WINDOWS_SensorGetDeviceInstanceID(int device_index)
   425 {
   426     return SDL_sensors[device_index].id;
   427 }
   428 
   429 static int
   430 SDL_WINDOWS_SensorOpen(SDL_Sensor *sensor, int device_index)
   431 {
   432     SDL_sensors[device_index].sensor_opened = sensor;
   433     return 0;
   434 }
   435 
   436 static void
   437 SDL_WINDOWS_SensorUpdate(SDL_Sensor *sensor)
   438 {
   439 }
   440 
   441 static void
   442 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 
   454 static void
   455 SDL_WINDOWS_SensorQuit(void)
   456 {
   457     while (SDL_num_sensors > 0) {
   458         DisconnectSensor(SDL_sensors[0].sensor);
   459     }
   460 
   461     if (SDL_sensor_manager) {
   462         ISensorManager_SetEventSink(SDL_sensor_manager, NULL);
   463         ISensorManager_Release(SDL_sensor_manager);
   464         SDL_sensor_manager = NULL;
   465     }
   466 
   467     if (SDL_windowscoinit) {
   468         WIN_CoUninitialize();
   469     }
   470 }
   471 
   472 SDL_SensorDriver SDL_WINDOWS_SensorDriver =
   473 {
   474     SDL_WINDOWS_SensorInit,
   475     SDL_WINDOWS_SensorGetCount,
   476     SDL_WINDOWS_SensorDetect,
   477     SDL_WINDOWS_SensorGetDeviceName,
   478     SDL_WINDOWS_SensorGetDeviceType,
   479     SDL_WINDOWS_SensorGetDeviceNonPortableType,
   480     SDL_WINDOWS_SensorGetDeviceInstanceID,
   481     SDL_WINDOWS_SensorOpen,
   482     SDL_WINDOWS_SensorUpdate,
   483     SDL_WINDOWS_SensorClose,
   484     SDL_WINDOWS_SensorQuit,
   485 };
   486 
   487 #endif /* SDL_SENSOR_WINDOWS */
   488 
   489 /* vi: set ts=4 sw=4 expandtab: */