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