Aric Stewart : winebus.sys: Implement SDL Haptic for controller vibration.

Alexandre Julliard julliard at winehq.org
Wed Feb 21 18:39:41 CST 2018


Module: wine
Branch: master
Commit: 249db7e49e29dd5995a47e3cb5d2875a288bc63d
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=249db7e49e29dd5995a47e3cb5d2875a288bc63d

Author: Aric Stewart <aric at codeweavers.com>
Date:   Wed Feb 21 06:57:18 2018 -0600

winebus.sys: Implement SDL Haptic for controller vibration.

Signed-off-by: Aric Stewart <aric at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/winebus.sys/bus_sdl.c | 134 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 131 insertions(+), 3 deletions(-)

diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c
index ea60d67..3a98fa7 100644
--- a/dlls/winebus.sys/bus_sdl.c
+++ b/dlls/winebus.sys/bus_sdl.c
@@ -110,6 +110,18 @@ MAKE_FUNCPTR(SDL_GameControllerGetAxis);
 MAKE_FUNCPTR(SDL_GameControllerName);
 MAKE_FUNCPTR(SDL_GameControllerOpen);
 MAKE_FUNCPTR(SDL_GameControllerEventState);
+MAKE_FUNCPTR(SDL_HapticClose);
+MAKE_FUNCPTR(SDL_HapticDestroyEffect);
+MAKE_FUNCPTR(SDL_HapticNewEffect);
+MAKE_FUNCPTR(SDL_HapticOpenFromJoystick);
+MAKE_FUNCPTR(SDL_HapticQuery);
+MAKE_FUNCPTR(SDL_HapticRumbleInit);
+MAKE_FUNCPTR(SDL_HapticRumblePlay);
+MAKE_FUNCPTR(SDL_HapticRumbleSupported);
+MAKE_FUNCPTR(SDL_HapticRunEffect);
+MAKE_FUNCPTR(SDL_HapticStopAll);
+MAKE_FUNCPTR(SDL_JoystickIsHaptic);
+MAKE_FUNCPTR(SDL_memset);
 #endif
 static Uint16 (*pSDL_JoystickGetProduct)(SDL_Joystick * joystick);
 static Uint16 (*pSDL_JoystickGetProductVersion)(SDL_Joystick * joystick);
@@ -130,6 +142,9 @@ struct platform_private
 
     int buffer_length;
     BYTE *report_buffer;
+
+    SDL_Haptic *sdl_haptic;
+    int haptic_effect_id;
 };
 
 static inline struct platform_private *impl_from_DEVICE_OBJECT(DEVICE_OBJECT *device)
@@ -193,6 +208,28 @@ static const BYTE CONTROLLER_TRIGGERS [] = {
     0x81, 0x02,         /* INPUT (Data,Var,Abs) */
 };
 
+static const BYTE HAPTIC_RUMBLE[] = {
+    0x06, 0x00, 0xff,   /* USAGE PAGE (vendor-defined) */
+    0x09, 0x01,         /* USAGE (1) */
+    0x85, 0x00,         /* REPORT_ID (0) */
+    /* padding */
+    0x95, 0x02,         /* REPORT_COUNT (2) */
+    0x75, 0x08,         /* REPORT_SIZE (8) */
+    0x91, 0x02,         /* OUTPUT (Data,Var,Abs) */
+    /* actuators */
+    0x15, 0x00,         /* LOGICAL MINIMUM (0) */
+    0x25, 0xff,         /* LOGICAL MAXIMUM (255) */
+    0x35, 0x00,         /* PHYSICAL MINIMUM (0) */
+    0x45, 0xff,         /* PHYSICAL MAXIMUM (255) */
+    0x75, 0x08,         /* REPORT_SIZE (8) */
+    0x95, 0x02,         /* REPORT_COUNT (2) */
+    0x91, 0x02,         /* OUTPUT (Data,Var,Abs) */
+    /* padding */
+    0x95, 0x02,         /* REPORT_COUNT (3) */
+    0x75, 0x08,         /* REPORT_SIZE (8) */
+    0x91, 0x02,         /* OUTPUT (Data,Var,Abs) */
+};
+
 static BYTE *add_axis_block(BYTE *report_ptr, BYTE count, BYTE page, const BYTE *usages, BOOL absolute)
 {
     int i;
@@ -257,6 +294,40 @@ static void set_hat_value(struct platform_private *ext, int index, int value)
     }
 }
 
+static int test_haptic(struct platform_private *ext)
+{
+    int rc = 0;
+    if (pSDL_JoystickIsHaptic(ext->sdl_joystick))
+    {
+        ext->sdl_haptic = pSDL_HapticOpenFromJoystick(ext->sdl_joystick);
+        if (ext->sdl_haptic &&
+            ((pSDL_HapticQuery(ext->sdl_haptic) & SDL_HAPTIC_LEFTRIGHT) != 0 ||
+             pSDL_HapticRumbleSupported(ext->sdl_haptic)))
+        {
+            pSDL_HapticStopAll(ext->sdl_haptic);
+            pSDL_HapticRumbleInit(ext->sdl_haptic);
+            rc = sizeof(HAPTIC_RUMBLE);
+            ext->haptic_effect_id = -1;
+        }
+        else
+        {
+            pSDL_HapticClose(ext->sdl_haptic);
+            ext->sdl_haptic = NULL;
+        }
+    }
+    return rc;
+}
+
+static int build_haptic(struct platform_private *ext, BYTE *report_ptr)
+{
+    if (ext->sdl_haptic)
+    {
+        memcpy(report_ptr, HAPTIC_RUMBLE, sizeof(HAPTIC_RUMBLE));
+        return (sizeof(HAPTIC_RUMBLE));
+    }
+    return 0;
+}
+
 static BOOL build_report_descriptor(struct platform_private *ext)
 {
     BYTE *report_ptr;
@@ -338,6 +409,8 @@ static BOOL build_report_descriptor(struct platform_private *ext)
             report_size++;
     }
 
+    descript_size += test_haptic(ext);
+
     TRACE("Report Descriptor will be %i bytes\n", descript_size);
     TRACE("Report will be %i bytes\n", report_size);
 
@@ -377,6 +450,7 @@ static BOOL build_report_descriptor(struct platform_private *ext)
     if (hat_count)
         report_ptr = add_hatswitch(report_ptr, hat_count);
 
+    report_ptr += build_haptic(ext, report_ptr);
     memcpy(report_ptr, REPORT_TAIL, sizeof(REPORT_TAIL));
 
     ext->report_descriptor_size = descript_size;
@@ -407,6 +481,7 @@ static BOOL build_mapped_report_descriptor(struct platform_private *ext)
     descript_size += sizeof(CONTROLLER_BUTTONS);
     descript_size += sizeof(CONTROLLER_AXIS);
     descript_size += sizeof(CONTROLLER_TRIGGERS);
+    descript_size += test_haptic(ext);
 
     ext->axis_start = 2;
     ext->buffer_length = 14;
@@ -432,6 +507,7 @@ static BOOL build_mapped_report_descriptor(struct platform_private *ext)
     report_ptr += sizeof(CONTROLLER_AXIS);
     memcpy(report_ptr, CONTROLLER_TRIGGERS, sizeof(CONTROLLER_TRIGGERS));
     report_ptr += sizeof(CONTROLLER_TRIGGERS);
+    report_ptr += build_haptic(ext, report_ptr);
     memcpy(report_ptr, REPORT_TAIL, sizeof(REPORT_TAIL));
 
     ext->report_descriptor_size = descript_size;
@@ -509,8 +585,48 @@ static NTSTATUS begin_report_processing(DEVICE_OBJECT *device)
 
 static NTSTATUS set_output_report(DEVICE_OBJECT *device, UCHAR id, BYTE *report, DWORD length, ULONG_PTR *written)
 {
-    *written = 0;
-    return STATUS_NOT_IMPLEMENTED;
+    struct platform_private *ext = impl_from_DEVICE_OBJECT(device);
+
+    if (ext->sdl_haptic && id == 0)
+    {
+        WORD left = report[2] * 128;
+        WORD right = report[3] * 128;
+
+        if (ext->haptic_effect_id >= 0)
+        {
+            pSDL_HapticDestroyEffect(ext->sdl_haptic, ext->haptic_effect_id);
+            ext->haptic_effect_id = -1;
+        }
+        pSDL_HapticStopAll(ext->sdl_haptic);
+        if (left != 0 || right != 0)
+        {
+            SDL_HapticEffect effect;
+
+            pSDL_memset( &effect, 0, sizeof(SDL_HapticEffect) );
+            effect.type = SDL_HAPTIC_LEFTRIGHT;
+            effect.leftright.length = -1;
+            effect.leftright.large_magnitude = left;
+            effect.leftright.small_magnitude = right;
+
+            ext->haptic_effect_id = pSDL_HapticNewEffect(ext->sdl_haptic, &effect);
+            if (ext->haptic_effect_id >= 0)
+            {
+                pSDL_HapticRunEffect(ext->sdl_haptic, ext->haptic_effect_id, 1);
+            }
+            else
+            {
+                float i = (float)((left + right)/2.0) / 32767.0;
+                pSDL_HapticRumblePlay(ext->sdl_haptic, i, -1);
+            }
+        }
+        *written = length;
+        return STATUS_SUCCESS;
+    }
+    else
+    {
+        *written = 0;
+        return STATUS_NOT_IMPLEMENTED;
+    }
 }
 
 static NTSTATUS get_feature_report(DEVICE_OBJECT *device, UCHAR id, BYTE *report, DWORD length, ULONG_PTR *read)
@@ -790,7 +906,7 @@ static DWORD CALLBACK deviceloop_thread(void *args)
     HANDLE init_done = args;
     SDL_Event event;
 
-    if (pSDL_Init(SDL_INIT_GAMECONTROLLER) < 0)
+    if (pSDL_Init(SDL_INIT_GAMECONTROLLER|SDL_INIT_HAPTIC) < 0)
     {
         ERR("Can't Init SDL\n");
         return STATUS_UNSUCCESSFUL;
@@ -847,6 +963,18 @@ NTSTATUS WINAPI sdl_driver_init(DRIVER_OBJECT *driver, UNICODE_STRING *registry_
         LOAD_FUNCPTR(SDL_GameControllerName);
         LOAD_FUNCPTR(SDL_GameControllerOpen);
         LOAD_FUNCPTR(SDL_GameControllerEventState);
+        LOAD_FUNCPTR(SDL_HapticClose);
+        LOAD_FUNCPTR(SDL_HapticDestroyEffect);
+        LOAD_FUNCPTR(SDL_HapticNewEffect);
+        LOAD_FUNCPTR(SDL_HapticOpenFromJoystick);
+        LOAD_FUNCPTR(SDL_HapticQuery);
+        LOAD_FUNCPTR(SDL_HapticRumbleInit);
+        LOAD_FUNCPTR(SDL_HapticRumblePlay);
+        LOAD_FUNCPTR(SDL_HapticRumbleSupported);
+        LOAD_FUNCPTR(SDL_HapticRunEffect);
+        LOAD_FUNCPTR(SDL_HapticStopAll);
+        LOAD_FUNCPTR(SDL_JoystickIsHaptic);
+        LOAD_FUNCPTR(SDL_memset);
 #undef LOAD_FUNCPTR
         pSDL_JoystickGetProduct = wine_dlsym(sdl_handle, "SDL_JoystickGetProduct", NULL, 0);
         pSDL_JoystickGetProductVersion = wine_dlsym(sdl_handle, "SDL_JoystickGetProductVersion", NULL, 0);




More information about the wine-cvs mailing list