src/sensor/windows/SDL_windowssensor.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 18 Apr 2020 21:41:37 -0700
changeset 13768 5e7c6765ceda
parent 13716 d2647d9e93c7
child 13776 74f7ed12a32b
permissions -rw-r--r--
Added a Windows Gaming Input joystick driver

This driver supports the Razer Atrox Arcade Stick

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