[PATCH 6/8] dinput: Implement HID joystick DIPROP_(DEADZONE|SATURATION|GRANULARITY).
Rémi Bernon
rbernon at codeweavers.com
Tue Sep 28 02:30:13 CDT 2021
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/dinput/joystick_hid.c | 119 +++++++++++++++++++++++++++++++++++--
dlls/dinput8/tests/hid.c | 30 ----------
2 files changed, 113 insertions(+), 36 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
index 3dc0776a1ec..4ce60e67faf 100644
--- a/dlls/dinput/joystick_hid.c
+++ b/dlls/dinput/joystick_hid.c
@@ -137,6 +137,12 @@ static inline const char *debugstr_hid_caps( struct hid_caps *caps )
return "(unknown type)";
}
+struct extra_caps
+{
+ LONG deadzone;
+ LONG saturation;
+};
+
#define DEVICE_STATE_MAX_SIZE 1024
struct hid_joystick
@@ -156,6 +162,7 @@ struct hid_joystick
HIDP_LINK_COLLECTION_NODE *collection_nodes;
HIDP_BUTTON_CAPS *input_button_caps;
HIDP_VALUE_CAPS *input_value_caps;
+ struct extra_caps *input_extra_caps;
char *input_report_buf;
USAGE_AND_PAGE *usages_buf;
@@ -424,6 +431,7 @@ static ULONG WINAPI hid_joystick_Release( IDirectInputDevice8W *iface )
{
HeapFree( GetProcessHeap(), 0, tmp.usages_buf );
HeapFree( GetProcessHeap(), 0, tmp.input_report_buf );
+ HeapFree( GetProcessHeap(), 0, tmp.input_extra_caps );
HeapFree( GetProcessHeap(), 0, tmp.input_value_caps );
HeapFree( GetProcessHeap(), 0, tmp.input_button_caps );
HeapFree( GetProcessHeap(), 0, tmp.collection_nodes );
@@ -519,6 +527,34 @@ static BOOL get_property_prop_range( struct hid_joystick *impl, struct hid_caps
return DIENUM_STOP;
}
+static BOOL get_property_prop_deadzone( struct hid_joystick *impl, struct hid_caps *caps,
+ DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+ struct extra_caps *extra;
+ DIPROPDWORD *deadzone = data;
+ extra = impl->input_extra_caps + (caps->value - impl->input_value_caps);
+ deadzone->dwData = extra->deadzone;
+ return DIENUM_STOP;
+}
+
+static BOOL get_property_prop_saturation( struct hid_joystick *impl, struct hid_caps *caps,
+ DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+ struct extra_caps *extra;
+ DIPROPDWORD *saturation = data;
+ extra = impl->input_extra_caps + (caps->value - impl->input_value_caps);
+ saturation->dwData = extra->saturation;
+ return DIENUM_STOP;
+}
+
+static BOOL get_property_prop_granularity( struct hid_joystick *impl, struct hid_caps *caps,
+ DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+ DIPROPDWORD *granularity = data;
+ granularity->dwData = 1;
+ return DIENUM_STOP;
+}
+
static HRESULT WINAPI hid_joystick_GetProperty( IDirectInputDevice8W *iface, const GUID *guid,
DIPROPHEADER *header )
{
@@ -538,6 +574,24 @@ static HRESULT WINAPI hid_joystick_GetProperty( IDirectInputDevice8W *iface, con
if (enum_objects( impl, header, DIDFT_AXIS, get_property_prop_range, header ) == DIENUM_STOP)
return DI_OK;
return DIERR_NOTFOUND;
+ case (DWORD_PTR)DIPROP_DEADZONE:
+ if (header->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
+ if (header->dwHow == DIPH_DEVICE) return DIERR_UNSUPPORTED;
+ if (enum_objects( impl, header, DIDFT_AXIS, get_property_prop_deadzone, header ) == DIENUM_STOP)
+ return DI_OK;
+ return DIERR_NOTFOUND;
+ case (DWORD_PTR)DIPROP_SATURATION:
+ if (header->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
+ if (header->dwHow == DIPH_DEVICE) return DIERR_UNSUPPORTED;
+ if (enum_objects( impl, header, DIDFT_AXIS, get_property_prop_saturation, header ) == DIENUM_STOP)
+ return DI_OK;
+ return DIERR_NOTFOUND;
+ case (DWORD_PTR)DIPROP_GRANULARITY:
+ if (header->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
+ if (header->dwHow == DIPH_DEVICE) return DIERR_UNSUPPORTED;
+ if (enum_objects( impl, header, DIDFT_AXIS, get_property_prop_granularity, header ) == DIENUM_STOP)
+ return DI_OK;
+ return DIERR_NOTFOUND;
case (DWORD_PTR)DIPROP_PRODUCTNAME:
{
DIPROPSTRING *value = (DIPROPSTRING *)header;
@@ -606,6 +660,26 @@ static BOOL set_property_prop_range( struct hid_joystick *impl, struct hid_caps
return DIENUM_CONTINUE;
}
+static BOOL set_property_prop_deadzone( struct hid_joystick *impl, struct hid_caps *caps,
+ DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+ struct extra_caps *extra;
+ DIPROPDWORD *deadzone = data;
+ extra = impl->input_extra_caps + (caps->value - impl->input_value_caps);
+ extra->deadzone = deadzone->dwData;
+ return DIENUM_CONTINUE;
+}
+
+static BOOL set_property_prop_saturation( struct hid_joystick *impl, struct hid_caps *caps,
+ DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+ struct extra_caps *extra;
+ DIPROPDWORD *saturation = data;
+ extra = impl->input_extra_caps + (caps->value - impl->input_value_caps);
+ extra->saturation = saturation->dwData;
+ return DIENUM_CONTINUE;
+}
+
static HRESULT WINAPI hid_joystick_SetProperty( IDirectInputDevice8W *iface, const GUID *guid,
const DIPROPHEADER *header )
{
@@ -627,6 +701,22 @@ static HRESULT WINAPI hid_joystick_SetProperty( IDirectInputDevice8W *iface, con
enum_objects( impl, header, DIDFT_AXIS, set_property_prop_range, (void *)header );
return DI_OK;
}
+ case (DWORD_PTR)DIPROP_DEADZONE:
+ {
+ DIPROPDWORD *value = (DIPROPDWORD *)header;
+ if (header->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
+ if (value->dwData > 10000) return DIERR_INVALIDPARAM;
+ enum_objects( impl, header, DIDFT_AXIS, set_property_prop_deadzone, (void *)header );
+ return DI_OK;
+ }
+ case (DWORD_PTR)DIPROP_SATURATION:
+ {
+ DIPROPDWORD *value = (DIPROPDWORD *)header;
+ if (header->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
+ if (value->dwData > 10000) return DIERR_INVALIDPARAM;
+ enum_objects( impl, header, DIDFT_AXIS, set_property_prop_saturation, (void *)header );
+ return DI_OK;
+ }
case (DWORD_PTR)DIPROP_FFLOAD:
case (DWORD_PTR)DIPROP_GRANULARITY:
case (DWORD_PTR)DIPROP_VIDPID:
@@ -859,7 +949,7 @@ static LONG scale_value( ULONG value, const HIDP_VALUE_CAPS *caps, LONG min, LON
return min + MulDiv( tmp - caps->LogicalMin, max - min, caps->LogicalMax - caps->LogicalMin );
}
-static LONG scale_axis_value( ULONG value, const HIDP_VALUE_CAPS *caps )
+static LONG scale_axis_value( ULONG value, const HIDP_VALUE_CAPS *caps, struct extra_caps *extra )
{
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;
@@ -879,14 +969,14 @@ static LONG scale_axis_value( ULONG value, const HIDP_VALUE_CAPS *caps )
tmp -= log_ctr;
if (tmp <= 0)
{
- log_max = 0;
- log_min -= log_ctr;
+ log_max = MulDiv( log_min - log_ctr, extra->deadzone, 10000 );
+ log_min = MulDiv( log_min - log_ctr, extra->saturation, 10000 );
phy_max = phy_ctr;
}
else
{
- log_min = 0;
- log_max -= log_ctr;
+ log_min = MulDiv( log_max - log_ctr, extra->deadzone, 10000 );
+ log_max = MulDiv( log_max - log_ctr, extra->saturation, 10000 );
phy_min = phy_ctr;
}
@@ -903,14 +993,16 @@ static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_caps
struct parse_device_state_params *params = data;
char *report_buf = impl->input_report_buf;
HIDP_VALUE_CAPS *value_caps = caps->value;
+ struct extra_caps *extra;
LONG old_value, value;
NTSTATUS status;
+ extra = impl->input_extra_caps + (value_caps - impl->input_value_caps);
status = HidP_GetUsageValue( HidP_Input, instance->wUsagePage, 0, instance->wUsage,
&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 );
- if (instance->dwType & DIDFT_AXIS) value = scale_axis_value( logical_value, value_caps );
+ if (instance->dwType & DIDFT_AXIS) value = scale_axis_value( logical_value, value_caps, extra );
else value = scale_value( logical_value, value_caps, value_caps->PhysicalMin, value_caps->PhysicalMax );
old_value = *(LONG *)(params->old_state + instance->dwOfs);
@@ -1305,9 +1397,19 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
.dwHow = DIPH_DEVICE,
},
};
+ DIPROPDWORD saturation =
+ {
+ .diph =
+ {
+ .dwSize = sizeof(DIPROPDWORD),
+ .dwHeaderSize = sizeof(DIPROPHEADER),
+ .dwHow = DIPH_DEVICE,
+ },
+ };
HIDD_ATTRIBUTES attrs = {.Size = sizeof(attrs)};
HIDP_LINK_COLLECTION_NODE *nodes;
struct hid_joystick *impl = NULL;
+ struct extra_caps *extra;
DIDATAFORMAT *format = NULL;
HIDP_BUTTON_CAPS *buttons;
HIDP_VALUE_CAPS *values;
@@ -1356,6 +1458,9 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
size = impl->caps.NumberInputValueCaps * sizeof(HIDP_VALUE_CAPS);
if (!(values = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed;
impl->input_value_caps = values;
+ size = impl->caps.NumberInputValueCaps * sizeof(struct extra_caps);
+ if (!(extra = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) goto failed;
+ impl->input_extra_caps = extra;
size = impl->caps.InputReportByteLength;
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed;
@@ -1400,6 +1505,8 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
enum_objects( impl, &range.diph, DIDFT_AXIS, set_property_prop_range, &range );
range.lMax = 36000;
enum_objects( impl, &range.diph, DIDFT_POV, set_property_prop_range, &range );
+ saturation.dwData = 10000;
+ enum_objects( impl, &range.diph, DIDFT_AXIS, set_property_prop_saturation, &saturation );
*out = &impl->base.IDirectInputDevice8W_iface;
return DI_OK;
diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c
index ec5dffe70f5..07505797eb1 100644
--- a/dlls/dinput8/tests/hid.c
+++ b/dlls/dinput8/tests/hid.c
@@ -3867,16 +3867,13 @@ static void test_simple_joystick(void)
todo_wine
ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_AUTOCENTER returned %#x\n", hr );
hr = IDirectInputDevice8_GetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
- todo_wine
ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_DEADZONE returned %#x\n", hr );
hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph );
todo_wine
ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_FFLOAD returned %#x\n", hr );
hr = IDirectInputDevice8_GetProperty( device, DIPROP_GRANULARITY, &prop_dword.diph );
- todo_wine
ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_GRANULARITY returned %#x\n", hr );
hr = IDirectInputDevice8_GetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
- todo_wine
ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_SATURATION returned %#x\n", hr );
hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph );
ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_RANGE returned %#x\n", hr );
@@ -3885,21 +3882,15 @@ static void test_simple_joystick(void)
prop_dword.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC );
prop_dword.dwData = 0xdeadbeef;
hr = IDirectInputDevice8_GetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
- todo_wine
ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_DEADZONE returned %#x\n", hr );
- todo_wine
ok( prop_dword.dwData == 0, "got %u expected %u\n", prop_dword.dwData, 0 );
prop_dword.dwData = 0xdeadbeef;
hr = IDirectInputDevice8_GetProperty( device, DIPROP_GRANULARITY, &prop_dword.diph );
- todo_wine
ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_GRANULARITY returned %#x\n", hr );
- todo_wine
ok( prop_dword.dwData == 1, "got %u expected %u\n", prop_dword.dwData, 1 );
prop_dword.dwData = 0xdeadbeef;
hr = IDirectInputDevice8_GetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
- todo_wine
ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_SATURATION returned %#x\n", hr );
- todo_wine
ok( prop_dword.dwData == 10000, "got %u expected %u\n", prop_dword.dwData, 10000 );
prop_range.diph.dwHow = DIPH_BYUSAGE;
@@ -4368,67 +4359,51 @@ static void test_simple_joystick(void)
prop_dword.diph.dwObj = 0;
prop_dword.dwData = 10001;
hr = IDirectInputDevice8_SetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
- todo_wine
ok( hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_SetProperty DIPROP_DEADZONE returned %#x\n", hr );
hr = IDirectInputDevice8_SetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
- todo_wine
ok( hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_SetProperty DIPROP_SATURATION returned %#x\n", hr );
prop_dword.dwData = 1000;
hr = IDirectInputDevice8_SetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
- todo_wine
ok( hr == DI_OK, "IDirectInputDevice8_SetProperty DIPROP_DEADZONE returned %#x\n", hr );
prop_dword.dwData = 6000;
hr = IDirectInputDevice8_SetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
- todo_wine
ok( hr == DI_OK, "IDirectInputDevice8_SetProperty DIPROP_SATURATION returned %#x\n", hr );
hr = IDirectInputDevice8_GetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
- todo_wine
ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_DEADZONE returned %#x\n", hr );
hr = IDirectInputDevice8_GetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
- todo_wine
ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetProperty DIPROP_SATURATION returned %#x\n", hr );
prop_dword.diph.dwHow = DIPH_BYUSAGE;
prop_dword.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC );
prop_dword.dwData = 2000;
hr = IDirectInputDevice8_SetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
- todo_wine
ok( hr == DI_OK, "IDirectInputDevice8_SetProperty DIPROP_DEADZONE returned %#x\n", hr );
ok( prop_dword.dwData == 2000, "got %u expected %u\n", prop_dword.dwData, 2000 );
prop_dword.dwData = 7000;
hr = IDirectInputDevice8_SetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
- todo_wine
ok( hr == DI_OK, "IDirectInputDevice8_SetProperty DIPROP_SATURATION returned %#x\n", hr );
prop_dword.diph.dwHow = DIPH_BYUSAGE;
prop_dword.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC );
prop_dword.dwData = 0xdeadbeef;
hr = IDirectInputDevice8_GetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
- todo_wine
ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_DEADZONE returned %#x\n", hr );
- todo_wine
ok( prop_dword.dwData == 2000, "got %u expected %u\n", prop_dword.dwData, 2000 );
prop_dword.dwData = 0xdeadbeef;
hr = IDirectInputDevice8_GetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
- todo_wine
ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_SATURATION returned %#x\n", hr );
- todo_wine
ok( prop_dword.dwData == 7000, "got %u expected %u\n", prop_dword.dwData, 7000 );
prop_dword.diph.dwHow = DIPH_BYUSAGE;
prop_dword.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_Y, HID_USAGE_PAGE_GENERIC );
prop_dword.dwData = 0xdeadbeef;
hr = IDirectInputDevice8_GetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
- todo_wine
ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_DEADZONE returned %#x\n", hr );
- todo_wine
ok( prop_dword.dwData == 1000, "got %u expected %u\n", prop_dword.dwData, 1000 );
prop_dword.dwData = 0xdeadbeef;
hr = IDirectInputDevice8_GetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
- todo_wine
ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_SATURATION returned %#x\n", hr );
- todo_wine
ok( prop_dword.dwData == 6000, "got %u expected %u\n", prop_dword.dwData, 6000 );
for (i = 0; i < ARRAY_SIZE(injected_input); ++i)
@@ -4439,9 +4414,7 @@ static void test_simple_joystick(void)
if (broken( state.lX == -10750 )) win_skip( "Ignoring 32-bit rounding\n" );
else
{
- todo_wine_if( i == 3 || i == 4 )
check_member( state, expect_state_abs[i], "%d", lX );
- todo_wine_if( i == 3 || i == 4 )
check_member( state, expect_state_abs[i], "%d", lY );
}
check_member( state, expect_state_abs[i], "%d", lZ );
@@ -4465,7 +4438,6 @@ static void test_simple_joystick(void)
ok( hr == DI_OK, "IDirectInputDevice8_GetDeviceState returned: %#x\n", hr );
winetest_push_context( "state[%d]", i );
check_member( state, expect_state_abs[i], "%d", lX );
- todo_wine
check_member( state, expect_state_abs[i], "%d", lY );
check_member( state, expect_state_abs[i], "%d", lZ );
check_member( state, expect_state_abs[i], "%d", lRx );
@@ -4547,11 +4519,9 @@ static void test_simple_joystick(void)
ok( hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_SetProperty DIPROP_CALIBRATION returned %#x\n", hr );
prop_dword.dwData = 0xdeadbeef;
hr = IDirectInputDevice8_SetProperty( device, DIPROP_DEADZONE, &prop_dword.diph );
- todo_wine
ok( hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_SetProperty DIPROP_DEADZONE returned %#x\n", hr );
prop_dword.dwData = 0xdeadbeef;
hr = IDirectInputDevice8_SetProperty( device, DIPROP_SATURATION, &prop_dword.diph );
- todo_wine
ok( hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_SetProperty DIPROP_SATURATION returned %#x\n", hr );
for (i = 0; i < ARRAY_SIZE(injected_input); ++i)
--
2.33.0
More information about the wine-devel
mailing list