Rémi Bernon : dinput: Scale HID joystick axis values according to their center point.

Alexandre Julliard julliard at winehq.org
Tue Sep 28 16:01:56 CDT 2021


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

Author: Rémi Bernon <rbernon at codeweavers.com>
Date:   Tue Sep 28 09:30:12 2021 +0200

dinput: Scale HID joystick axis values according to their center point.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/dinput/joystick_hid.c | 43 ++++++++++++++++++++++++++++++++++++++-----
 dlls/dinput8/tests/hid.c   | 30 +++++++++---------------------
 2 files changed, 47 insertions(+), 26 deletions(-)

diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
index e20d02224fe..3dc0776a1ec 100644
--- a/dlls/dinput/joystick_hid.c
+++ b/dlls/dinput/joystick_hid.c
@@ -854,15 +854,47 @@ static LONG sign_extend( ULONG value, const HIDP_VALUE_CAPS *caps )
 
 static LONG scale_value( ULONG value, const HIDP_VALUE_CAPS *caps, LONG min, LONG max )
 {
-    ULONG bit_max = (1 << caps->BitSize) - 1;
     LONG tmp = sign_extend( value, caps );
-
-    /* xinput HID gamepad have bogus logical value range, let's use the bit range instead */
-    if (caps->LogicalMin == 0 && caps->LogicalMax == -1) return min + MulDiv( tmp, max - min, bit_max );
     if (caps->LogicalMin > tmp || caps->LogicalMax < tmp) return -1; /* invalid / null value */
     return min + MulDiv( tmp - caps->LogicalMin, max - min, caps->LogicalMax - caps->LogicalMin );
 }
 
+static LONG scale_axis_value( ULONG value, const HIDP_VALUE_CAPS *caps )
+{
+    LONG tmp = sign_extend( value, caps ), log_ctr, log_min, log_max, phy_ctr, phy_min, phy_max;
+    ULONG bit_max = (1 << caps->BitSize) - 1;
+
+    log_min = caps->LogicalMin;
+    log_max = caps->LogicalMax;
+    phy_min = caps->PhysicalMin;
+    phy_max = caps->PhysicalMax;
+    /* xinput HID gamepad have bogus logical value range, let's use the bit range instead */
+    if (log_min == 0 && log_max == -1) log_max = bit_max;
+
+    if (phy_min == 0) phy_ctr = phy_max >> 1;
+    else phy_ctr = round( (phy_min + phy_max) / 2.0 );
+    if (log_min == 0) log_ctr = log_max >> 1;
+    else log_ctr = round( (log_min + log_max) / 2.0 );
+
+    tmp -= log_ctr;
+    if (tmp <= 0)
+    {
+        log_max = 0;
+        log_min -= log_ctr;
+        phy_max = phy_ctr;
+    }
+    else
+    {
+        log_min = 0;
+        log_max -= log_ctr;
+        phy_min = phy_ctr;
+    }
+
+    if (tmp <= log_min) return phy_min;
+    if (tmp >= log_max) return phy_max;
+    return phy_min + MulDiv( tmp - log_min, phy_max - phy_min, log_max - log_min );
+}
+
 static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_caps *caps,
                                      DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
@@ -878,7 +910,8 @@ static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_caps
                                  &logical_value, impl->preparsed, report_buf, report_len );
     if (status != HIDP_STATUS_SUCCESS) WARN( "HidP_GetUsageValue %04x:%04x returned %#x\n",
                                              instance->wUsagePage, instance->wUsage, status );
-    value = scale_value( logical_value, value_caps, value_caps->PhysicalMin, value_caps->PhysicalMax );
+    if (instance->dwType & DIDFT_AXIS) value = scale_axis_value( logical_value, value_caps );
+    else value = scale_value( logical_value, value_caps, value_caps->PhysicalMin, value_caps->PhysicalMax );
 
     old_value = *(LONG *)(params->old_state + instance->dwOfs);
     *(LONG *)(impl->device_state + instance->dwOfs) = value;
diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c
index ae758837d36..ec5dffe70f5 100644
--- a/dlls/dinput8/tests/hid.c
+++ b/dlls/dinput8/tests/hid.c
@@ -4098,11 +4098,8 @@ static void test_simple_joystick(void)
         winetest_push_context( "state[%d]", i );
         hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state );
         ok( hr == DI_OK, "IDirectInputDevice8_GetDeviceState returned: %#x\n", hr );
-        todo_wine_if( i != 0 && i != 2 )
         check_member( state, expect_state[i], "%d", lX );
-        todo_wine_if( i != 0 && i != 2 )
         check_member( state, expect_state[i], "%d", lY );
-        todo_wine_if( i != 0 )
         check_member( state, expect_state[i], "%d", lZ );
         check_member( state, expect_state[i], "%d", lRx );
         check_member( state, expect_state[i], "%#x", rgdwPOV[0] );
@@ -4114,20 +4111,17 @@ static void test_simple_joystick(void)
         send_hid_input( file, &injected_input[i], sizeof(*injected_input) );
 
         res = WaitForSingleObject( event, 100 );
-        if (i == 0 || i == 3) todo_wine_if( i == 0 )
-        ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" );
-        else ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event );
+        if (i == 0 || i == 3) ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" );
+        else ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
+        ResetEvent( event );
         winetest_pop_context();
     }
 
     hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state );
     ok( hr == DI_OK, "IDirectInputDevice8_GetDeviceState returned: %#x\n", hr );
     winetest_push_context( "state[%d]", i );
-    todo_wine
     check_member( state, expect_state[i], "%d", lX );
-    todo_wine
     check_member( state, expect_state[i], "%d", lY );
-    todo_wine
     check_member( state, expect_state[i], "%d", lZ );
     check_member( state, expect_state[i], "%d", lRx );
     check_member( state, expect_state[i], "%#x", rgdwPOV[0] );
@@ -4237,7 +4231,7 @@ static void test_simple_joystick(void)
         winetest_push_context( "objdata[%d]", i );
         todo_wine
         check_member( objdata[i], expect_objdata[6 + i], "%#x", dwOfs );
-        todo_wine_if( i != 3 && i != 4 && i != 7 )
+        todo_wine_if( i == 1 || i == 2 || i == 6 )
         check_member( objdata[i], expect_objdata[6 + i], "%#x", dwData );
         ok( objdata[i].uAppData == -1, "got %p, expected %p\n", (void *)objdata[i].uAppData, (void *)-1 );
         winetest_pop_context();
@@ -4250,11 +4244,8 @@ static void test_simple_joystick(void)
 
     hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state );
     ok( hr == DI_OK, "IDirectInputDevice8_GetDeviceState returned: %#x\n", hr );
-    todo_wine
     check_member( state, expect_state[3], "%d", lX );
-    todo_wine
     check_member( state, expect_state[3], "%d", lY );
-    todo_wine
     check_member( state, expect_state[3], "%d", lZ );
     check_member( state, expect_state[3], "%d", lRx );
     check_member( state, expect_state[3], "%d", rgdwPOV[0] );
@@ -4448,12 +4439,11 @@ static void test_simple_joystick(void)
         if (broken( state.lX == -10750 )) win_skip( "Ignoring 32-bit rounding\n" );
         else
         {
-            todo_wine_if( i != 0 && i != 2 )
+            todo_wine_if( i == 3 || i == 4 )
             check_member( state, expect_state_abs[i], "%d", lX );
-            todo_wine_if( i != 0 && i != 2 )
+            todo_wine_if( i == 3 || i == 4 )
             check_member( state, expect_state_abs[i], "%d", lY );
         }
-        todo_wine_if( i != 0 )
         check_member( state, expect_state_abs[i], "%d", lZ );
         check_member( state, expect_state_abs[i], "%d", lRx );
         check_member( state, expect_state_abs[i], "%d", rgdwPOV[0] );
@@ -4465,20 +4455,18 @@ static void test_simple_joystick(void)
         send_hid_input( file, &injected_input[i], sizeof(*injected_input) );
 
         res = WaitForSingleObject( event, 100 );
-        if (i == 0 || i == 3) todo_wine_if( i == 0 )
-        ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" );
-        else ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event );
+        if (i == 0 || i == 3) ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" );
+        else ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
+        ResetEvent( event );
         winetest_pop_context();
     }
 
     hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state );
     ok( hr == DI_OK, "IDirectInputDevice8_GetDeviceState returned: %#x\n", hr );
     winetest_push_context( "state[%d]", i );
-    todo_wine
     check_member( state, expect_state_abs[i], "%d", lX );
     todo_wine
     check_member( state, expect_state_abs[i], "%d", lY );
-    todo_wine
     check_member( state, expect_state_abs[i], "%d", lZ );
     check_member( state, expect_state_abs[i], "%d", lRx );
     check_member( state, expect_state_abs[i], "%d", rgdwPOV[0] );




More information about the wine-cvs mailing list