dinput: Use a custom HID joystick state instead of DIJOYSTATE2.

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-27 09:43:03 +02:00 committed by Alexandre Julliard
parent 2d47d9fecd
commit d682b3a9d3
1 changed files with 32 additions and 53 deletions

View File

@ -136,10 +136,11 @@ static inline const char *debugstr_hid_caps( struct hid_caps *caps )
return "(unknown type)"; return "(unknown type)";
} }
#define DEVICE_STATE_MAX_SIZE 1024
struct hid_joystick struct hid_joystick
{ {
IDirectInputDeviceImpl base; IDirectInputDeviceImpl base;
DIJOYSTATE2 state;
HANDLE device; HANDLE device;
OVERLAPPED read_ovl; OVERLAPPED read_ovl;
@ -160,6 +161,7 @@ struct hid_joystick
ULONG usages_count; ULONG usages_count;
BYTE device_state_report_id; BYTE device_state_report_id;
BYTE device_state[DEVICE_STATE_MAX_SIZE];
}; };
static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface ) static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface )
@ -660,7 +662,7 @@ static HRESULT WINAPI hid_joystick_GetDeviceState( IDirectInputDevice8W *iface,
EnterCriticalSection( &impl->base.crit ); EnterCriticalSection( &impl->base.crit );
if (!impl->base.acquired) hr = DIERR_NOTACQUIRED; if (!impl->base.acquired) hr = DIERR_NOTACQUIRED;
else fill_DataFormat( ptr, len, &impl->state, &impl->base.data_format ); else fill_DataFormat( ptr, len, impl->device_state, &impl->base.data_format );
LeaveCriticalSection( &impl->base.crit ); LeaveCriticalSection( &impl->base.crit );
return hr; return hr;
@ -796,7 +798,8 @@ static const IDirectInputDevice8WVtbl hid_joystick_vtbl =
struct parse_device_state_params struct parse_device_state_params
{ {
DIJOYSTATE2 old_state; BYTE old_state[DEVICE_STATE_MAX_SIZE];
BYTE buttons[128];
DWORD time; DWORD time;
DWORD seq; DWORD seq;
}; };
@ -806,12 +809,18 @@ static BOOL check_device_state_button( struct hid_joystick *impl, struct hid_cap
{ {
IDirectInputDevice8W *iface = &impl->base.IDirectInputDevice8W_iface; IDirectInputDevice8W *iface = &impl->base.IDirectInputDevice8W_iface;
struct parse_device_state_params *params = data; struct parse_device_state_params *params = data;
DWORD i = DIDFT_GETINSTANCE( instance->dwType ); BYTE old_value, value;
if (!(instance->dwType & DIDFT_BUTTON)) if (!(instance->dwType & DIDFT_BUTTON))
FIXME( "unexpected object type %#x, expected DIDFT_BUTTON\n", instance->dwType ); FIXME( "unexpected object type %#x, expected DIDFT_BUTTON\n", instance->dwType );
else if (params->old_state.rgbButtons[i] != impl->state.rgbButtons[i]) else
queue_event( iface, instance->dwType, impl->state.rgbButtons[i], params->time, params->seq ); {
value = params->buttons[instance->wUsage - 1];
old_value = params->old_state[instance->dwOfs];
impl->device_state[instance->dwOfs] = value;
if (old_value != value)
queue_event( iface, instance->dwType, value, params->time, params->seq );
}
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
@ -842,8 +851,8 @@ static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_caps
struct parse_device_state_params *params = data; struct parse_device_state_params *params = data;
char *report_buf = impl->input_report_buf; char *report_buf = impl->input_report_buf;
HIDP_VALUE_CAPS *value_caps = caps->value; HIDP_VALUE_CAPS *value_caps = caps->value;
LONG old_value, value;
NTSTATUS status; NTSTATUS status;
LONG value;
if (!(instance->dwType & (DIDFT_POV | DIDFT_AXIS))) if (!(instance->dwType & (DIDFT_POV | DIDFT_AXIS)))
FIXME( "unexpected object type %#x, expected DIDFT_POV | DIDFT_AXIS\n", instance->dwType ); FIXME( "unexpected object type %#x, expected DIDFT_POV | DIDFT_AXIS\n", instance->dwType );
@ -855,47 +864,10 @@ static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_caps
instance->wUsagePage, instance->wUsage, status ); instance->wUsagePage, instance->wUsage, status );
value = scale_value( logical_value, value_caps, value_caps->PhysicalMin, value_caps->PhysicalMax ); value = scale_value( logical_value, value_caps, value_caps->PhysicalMin, value_caps->PhysicalMax );
switch (instance->dwOfs) old_value = *(LONG *)(params->old_state + instance->dwOfs);
{ *(LONG *)(impl->device_state + instance->dwOfs) = value;
case DIJOFS_X: if (old_value != value)
if (impl->state.lX == value) break;
impl->state.lX = value;
queue_event( iface, instance->dwType, value, params->time, params->seq ); queue_event( iface, instance->dwType, value, params->time, params->seq );
break;
case DIJOFS_Y:
if (impl->state.lY == value) break;
impl->state.lY = value;
queue_event( iface, instance->dwType, value, params->time, params->seq );
break;
case DIJOFS_Z:
if (impl->state.lZ == value) break;
impl->state.lZ = value;
queue_event( iface, instance->dwType, value, params->time, params->seq );
break;
case DIJOFS_RX:
if (impl->state.lRx == value) break;
impl->state.lRx = value;
queue_event( iface, instance->dwType, value, params->time, params->seq );
break;
case DIJOFS_RY:
if (impl->state.lRy == value) break;
impl->state.lRy = value;
queue_event( iface, instance->dwType, value, params->time, params->seq );
break;
case DIJOFS_RZ:
if (impl->state.lRz == value) break;
impl->state.lRz = value;
queue_event( iface, instance->dwType, value, params->time, params->seq );
break;
case DIJOFS_POV( 0 ):
if (impl->state.rgdwPOV[0] == value) break;
impl->state.rgdwPOV[0] = value;
queue_event( iface, instance->dwType, value, params->time, params->seq );
break;
default:
FIXME( "unimplemented offset %#x.\n", instance->dwOfs );
break;
}
} }
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
@ -911,7 +883,8 @@ static HRESULT hid_joystick_read_state( IDirectInputDevice8W *iface )
}; };
struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface );
ULONG i, count, report_len = impl->caps.InputReportByteLength; ULONG i, count, report_len = impl->caps.InputReportByteLength;
struct parse_device_state_params params = {0}; DIDATAFORMAT *format = impl->base.data_format.wine_df;
struct parse_device_state_params params = {{0}};
char *report_buf = impl->input_report_buf; char *report_buf = impl->input_report_buf;
USAGE_AND_PAGE *usages; USAGE_AND_PAGE *usages;
NTSTATUS status; NTSTATUS status;
@ -944,11 +917,11 @@ static HRESULT hid_joystick_read_state( IDirectInputDevice8W *iface )
if (report_buf[0] == impl->device_state_report_id) if (report_buf[0] == impl->device_state_report_id)
{ {
params.old_state = impl->state;
params.time = GetCurrentTime(); params.time = GetCurrentTime();
params.seq = impl->base.dinput->evsequence++; params.seq = impl->base.dinput->evsequence++;
memcpy( params.old_state, impl->device_state, format->dwDataSize );
memset( impl->device_state, 0, format->dwDataSize );
memset( impl->state.rgbButtons, 0, sizeof(impl->state.rgbButtons) );
while (count--) while (count--)
{ {
usages = impl->usages_buf + count; usages = impl->usages_buf + count;
@ -957,12 +930,12 @@ static HRESULT hid_joystick_read_state( IDirectInputDevice8W *iface )
else if (usages->Usage >= 128) else if (usages->Usage >= 128)
FIXME( "ignoring extraneous button %d.\n", usages->Usage ); FIXME( "ignoring extraneous button %d.\n", usages->Usage );
else else
impl->state.rgbButtons[usages->Usage - 1] = 0x80; params.buttons[usages->Usage - 1] = 0x80;
} }
enum_value_objects( impl, &filter, DIDFT_ALL, read_device_state_value, &params ); enum_value_objects( impl, &filter, DIDFT_ALL, read_device_state_value, &params );
enum_button_objects( impl, &filter, DIDFT_ALL, check_device_state_button, &params ); enum_button_objects( impl, &filter, DIDFT_ALL, check_device_state_button, &params );
if (memcmp( &params.old_state, &impl->state, sizeof(impl->state) ) && impl->base.hEvent) if (impl->base.hEvent && memcmp( &params.old_state, impl->device_state, format->dwDataSize ))
SetEvent( impl->base.hEvent ); SetEvent( impl->base.hEvent );
} }
@ -1231,6 +1204,7 @@ static BOOL init_objects( struct hid_joystick *impl, struct hid_caps *caps,
DIDATAFORMAT *format = impl->base.data_format.wine_df; DIDATAFORMAT *format = impl->base.data_format.wine_df;
format->dwNumObjs++; format->dwNumObjs++;
format->dwDataSize = max( format->dwDataSize, instance->dwOfs + sizeof(LONG) );
if (instance->dwType & DIDFT_BUTTON) impl->dev_caps.dwButtons++; if (instance->dwType & DIDFT_BUTTON) impl->dev_caps.dwButtons++;
if (instance->dwType & DIDFT_AXIS) impl->dev_caps.dwAxes++; if (instance->dwType & DIDFT_AXIS) impl->dev_caps.dwAxes++;
if (instance->dwType & DIDFT_POV) impl->dev_caps.dwPOVs++; if (instance->dwType & DIDFT_POV) impl->dev_caps.dwPOVs++;
@ -1360,12 +1334,17 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
enum_button_objects( impl, &filter, DIDFT_ALL, init_objects, NULL ); enum_button_objects( impl, &filter, DIDFT_ALL, init_objects, NULL );
format = impl->base.data_format.wine_df; format = impl->base.data_format.wine_df;
if (format->dwDataSize > DEVICE_STATE_MAX_SIZE)
{
FIXME( "unable to create device, state is too large\n" );
goto failed;
}
size = format->dwNumObjs * sizeof(*format->rgodf); size = format->dwNumObjs * sizeof(*format->rgodf);
if (!(format->rgodf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) goto failed; if (!(format->rgodf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) goto failed;
format->dwSize = sizeof(*format); format->dwSize = sizeof(*format);
format->dwObjSize = sizeof(*format->rgodf); format->dwObjSize = sizeof(*format->rgodf);
format->dwFlags = DIDF_ABSAXIS; format->dwFlags = DIDF_ABSAXIS;
format->dwDataSize = sizeof(impl->state);
index = 0; index = 0;
enum_value_objects( impl, &filter, DIDFT_ALL, init_data_format, &index ); enum_value_objects( impl, &filter, DIDFT_ALL, init_data_format, &index );