src/sensor/windows/SDL_windowssensor.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 20 May 2020 17:22:52 -0400
changeset 13841 b89df0d683ad
parent 13839 52dbeb97b294
child 13842 a09f7d0800eb
permissions -rw-r--r--
sensor: Correct fix for redefinition of various symbols.
     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, &SDL_SENSOR_DATA_TYPE_ACCELERATION_X_G, &valueX);
   165                     hrY = ISensorDataReport_GetSensorValue(pNewData, &SDL_SENSOR_DATA_TYPE_ACCELERATION_Y_G, &valueY);
   166                     hrZ = ISensorDataReport_GetSensorValue(pNewData, &SDL_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 SDL_SetError("Couldn't get sensor ID: 0x%.4x", hr);
   265     }
   266 
   267     hr = ISensor_GetType(sensor, &type_id);
   268     if (FAILED(hr)) {
   269         return SDL_SetError("Couldn't get sensor type: 0x%.4x", 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 SDL_SetError("Couldn't create the sensor manager: 0x%.4x", 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 SDL_SetError("Couldn't set the sensor manager event sink: 0x%.4x", 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: */