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