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

Signed-off-by: Rémi Bernon <rbernon@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2021-09-28 09:30:12 +02:00 committed by Alexandre Julliard
parent 3886634c82
commit 9646873d63
2 changed files with 47 additions and 26 deletions

View File

@ -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;

View File

@ -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] );