Fixes a regression from e9c3c494fd2f388acd046c95ac6b121c0830bb46 where although we use the last report length, it was only initialized after the first corresponding report was received. Calling HidD_GetInputReport before that could cause a buffer overlow and report invalid data.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52068 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/main.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index d805f887a6f..111953c3bae 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -444,8 +444,6 @@ static void process_hid_report(DEVICE_OBJECT *device, BYTE *report_buf, DWORD re
if (!ext->collection_desc.ReportIDs[0].ReportID) last_report = ext->last_reports[0]; else last_report = ext->last_reports[report_buf[0]]; - - last_report->length = report_len; memcpy(last_report->buffer, report_buf, report_len);
if ((irp = pop_pending_read(ext))) @@ -861,7 +859,13 @@ static NTSTATUS pdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp) { if (!(size = reports[i].InputLength)) continue; size = offsetof( struct hid_report, buffer[size] ); - if (!(ext->last_reports[reports[i].ReportID] = RtlAllocateHeap(GetProcessHeap(), 0, size))) status = STATUS_NO_MEMORY; + if (!(report = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, size))) status = STATUS_NO_MEMORY; + else + { + report->length = reports[i].InputLength; + report->buffer[0] = reports[i].ReportID; + ext->last_reports[reports[i].ReportID] = report; + } } if (!status) ext->state = DEVICE_STATE_STARTED; }
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52075 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput8/tests/hid.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index cbb202530ac..f1342c5714d 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -745,16 +745,18 @@ static inline void check_hidp_value_caps_( int line, HIDP_VALUE_CAPS *caps, cons
static BOOL sync_ioctl( HANDLE file, DWORD code, void *in_buf, DWORD in_len, void *out_buf, DWORD *ret_len, DWORD timeout ) { + DWORD res, out_len = ret_len ? *ret_len : 0; OVERLAPPED ovl = {0}; - DWORD out_len = ret_len ? *ret_len : 0; BOOL ret;
ovl.hEvent = CreateEventW( NULL, TRUE, FALSE, NULL ); ret = DeviceIoControl( file, code, in_buf, in_len, out_buf, out_len, &out_len, &ovl ); if (!ret && GetLastError() == ERROR_IO_PENDING) { - ret = GetOverlappedResultEx( file, &ovl, &out_len, timeout, TRUE ); - ok( ret, "GetOverlappedResultEx returned %u\n", GetLastError() ); + res = WaitForSingleObject( ovl.hEvent, timeout ); + ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", res ); + ret = GetOverlappedResult( file, &ovl, &out_len, FALSE ); + ok( ret, "GetOverlappedResult returned %u\n", GetLastError() ); } CloseHandle( ovl.hEvent );
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52061 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput8/tests/driver_hid.c | 13 ++- dlls/dinput8/tests/driver_hid.h | 1 + dlls/dinput8/tests/hid.c | 135 ++++++++++++++++++++++++++++++-- 3 files changed, 137 insertions(+), 12 deletions(-)
diff --git a/dlls/dinput8/tests/driver_hid.c b/dlls/dinput8/tests/driver_hid.c index 2201fd07080..db7b3185906 100644 --- a/dlls/dinput8/tests/driver_hid.c +++ b/dlls/dinput8/tests/driver_hid.c @@ -122,7 +122,7 @@ static void expect_queue_reset( struct expect_queue *queue, void *buffer, unsign else { todo_wine_if( tmp->todo ) - ok( 0, "missing (code %#x id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len ); + ok( tmp->wine_only, "missing (code %#x id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len ); } winetest_pop_context(); tmp++; @@ -198,7 +198,7 @@ static void expect_queue_next( struct expect_queue *queue, ULONG code, HID_XFER_ while (tmp < queue->end) { if (running_under_wine && !tmp->todo) break; - if (!running_under_wine && !tmp->broken) break; + if (!running_under_wine && !tmp->broken && !tmp->wine_only) break; if (tmp->code == code && tmp->report_id == id && tmp->report_len == len && (!compare_buf || RtlCompareMemory( tmp->report_buf, buf, len ) == len)) break; @@ -209,6 +209,11 @@ static void expect_queue_next( struct expect_queue *queue, ULONG code, HID_XFER_ else tmp = &queue->spurious; *expect = *tmp;
+ while (queue->pos < queue->end) + { + if (running_under_wine || !queue->pos->wine_only) break; + queue->pos++; + } if (queue->pos == queue->end && (irp = queue->pending_wait)) { queue->pending_wait = NULL; @@ -227,7 +232,7 @@ static void expect_queue_next( struct expect_queue *queue, ULONG code, HID_XFER_
winetest_push_context( "%s expect[%d]", tmp->context, tmp - queue->buffer ); todo_wine_if( tmp->todo ) - ok( 1, "found code %#x id %u len %u\n", tmp->code, tmp->report_id, tmp->report_len ); + ok( !tmp->wine_only, "found code %#x id %u len %u\n", tmp->code, tmp->report_id, tmp->report_len ); winetest_pop_context();
tmp = missing; @@ -242,7 +247,7 @@ static void expect_queue_next( struct expect_queue *queue, ULONG code, HID_XFER_ else { todo_wine_if( tmp->todo ) - ok( 0, "missing (code %#x id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len ); + ok( tmp->wine_only, "missing (code %#x id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len ); } winetest_pop_context(); tmp++; diff --git a/dlls/dinput8/tests/driver_hid.h b/dlls/dinput8/tests/driver_hid.h index ffd45bd2e35..191c0c7bae2 100644 --- a/dlls/dinput8/tests/driver_hid.h +++ b/dlls/dinput8/tests/driver_hid.h @@ -50,6 +50,7 @@ struct hid_expect DWORD ret_status; BYTE todo; /* missing on wine */ BYTE broken; /* missing on some win versions */ + BYTE wine_only; BYTE report_id; BYTE report_len; BYTE report_buf[128]; diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index f1342c5714d..884a0100abe 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -743,7 +743,8 @@ static inline void check_hidp_value_caps_( int line, HIDP_VALUE_CAPS *caps, cons } }
-static BOOL sync_ioctl( HANDLE file, DWORD code, void *in_buf, DWORD in_len, void *out_buf, DWORD *ret_len, DWORD timeout ) +#define sync_ioctl( a, b, c, d, e, f, g ) sync_ioctl_( __LINE__, a, b, c, d, e, f, g ) +static BOOL sync_ioctl_( int line, HANDLE file, DWORD code, void *in_buf, DWORD in_len, void *out_buf, DWORD *ret_len, DWORD timeout ) { DWORD res, out_len = ret_len ? *ret_len : 0; OVERLAPPED ovl = {0}; @@ -754,9 +755,9 @@ static BOOL sync_ioctl( HANDLE file, DWORD code, void *in_buf, DWORD in_len, voi if (!ret && GetLastError() == ERROR_IO_PENDING) { res = WaitForSingleObject( ovl.hEvent, timeout ); - ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", res ); + ok_(__FILE__, line)( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", res ); ret = GetOverlappedResult( file, &ovl, &out_len, FALSE ); - ok( ret, "GetOverlappedResult returned %u\n", GetLastError() ); + ok_(__FILE__, line)( ret, "GetOverlappedResult returned %u\n", GetLastError() ); } CloseHandle( ovl.hEvent );
@@ -779,17 +780,17 @@ static void set_hid_expect_( int line, HANDLE file, struct hid_expect *expect, D for (i = 0; i < expect_size / sizeof(struct hid_expect); ++i) snprintf( expect[i].context, ARRAY_SIZE(expect[i].context), "%s:%d", source_file, line );
- ret = sync_ioctl( file, IOCTL_WINETEST_HID_SET_EXPECT, expect, expect_size, NULL, 0, INFINITE ); - ok( ret, "IOCTL_WINETEST_HID_SET_EXPECT failed, last error %u\n", GetLastError() ); + ret = sync_ioctl_( line, file, IOCTL_WINETEST_HID_SET_EXPECT, expect, expect_size, NULL, 0, INFINITE ); + ok_(__FILE__, line)( ret, "IOCTL_WINETEST_HID_SET_EXPECT failed, last error %u\n", GetLastError() ); }
#define wait_hid_expect( a, b ) wait_hid_expect_( __LINE__, a, b ) static void wait_hid_expect_( int line, HANDLE file, DWORD timeout ) { - BOOL ret = sync_ioctl( file, IOCTL_WINETEST_HID_WAIT_EXPECT, NULL, 0, NULL, 0, timeout ); - ok( ret, "IOCTL_WINETEST_HID_WAIT_EXPECT failed, last error %u\n", GetLastError() ); + BOOL ret = sync_ioctl_( line, file, IOCTL_WINETEST_HID_WAIT_EXPECT, NULL, 0, NULL, 0, timeout ); + ok_(__FILE__, line)( ret, "IOCTL_WINETEST_HID_WAIT_EXPECT failed, last error %u\n", GetLastError() );
- set_hid_expect( file, NULL, 0 ); + set_hid_expect_( line, file, NULL, 0 ); }
#define send_hid_input( a, b, c ) send_hid_input_( __LINE__, a, b, c ) @@ -5601,6 +5602,91 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO .report_buf = {0x02,0x01,0x01,0x01}, }, }; + struct hid_expect expect_download_2[] = + { + /* set periodic */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 5, + .report_len = 2, + .report_buf = {0x05,0x19}, + }, + /* set envelope */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 6, + .report_len = 7, + .report_buf = {0x06,0x19,0x4c,0x02,0x00,0x04,0x00}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x02,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0xd5}, + }, + }; + struct hid_expect expect_update[] = + { + /* set periodic */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 5, + .report_len = 2, + .report_buf = {0x05,0x19}, + .wine_only = TRUE, .todo = TRUE, + }, + /* set envelope */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 6, + .report_len = 7, + .report_buf = {0x06,0x19,0x4c,0x02,0x00,0x04,0x00}, + .wine_only = TRUE, .todo = TRUE, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x02,0x08,0xff,0xff,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0xd5}, + .todo = TRUE, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x02,0x08,0x00,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0xd5}, + .wine_only = TRUE, .todo = TRUE, + }, + }; + struct hid_expect expect_set_envelope[] = + { + /* set periodic */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 5, + .report_len = 2, + .report_buf = {0x05,0x19}, + .wine_only = TRUE, .todo = TRUE, + }, + /* set envelope */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 6, + .report_len = 7, + .report_buf = {0x06,0x19,0x4c,0x01,0x00,0x04,0x00}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x02,0x08,0x00,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0xd5}, + .wine_only = TRUE, .todo = TRUE, + }, + }; struct hid_expect expect_start = { .code = IOCTL_HID_WRITE_REPORT, @@ -6409,6 +6495,39 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO winetest_pop_context(); }
+ hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); + + set_hid_expect( file, expect_download_2, sizeof(expect_download_2) ); + flags = version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5; + hr = IDirectInputEffect_SetParameters( effect, &expect_desc, flags ); + ok( hr == DI_OK, "SetParameters returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + desc = expect_desc; + desc.dwDuration = INFINITE; + desc.dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER, + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_NODOWNLOAD|DIEP_DURATION|DIEP_TRIGGERBUTTON ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + set_hid_expect( file, expect_update, sizeof(expect_update) ); + hr = IDirectInputEffect_SetParameters( effect, &expect_desc, 0 ); + ok( hr == DI_OK, "SetParameters returned %#x\n", hr ); + wait_hid_expect( file, 100 ); /* these updates are sent asynchronously */ + + desc = expect_desc; + desc.lpEnvelope = &envelope; + desc.lpEnvelope->dwAttackTime = 1000; + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_NODOWNLOAD|DIEP_ENVELOPE ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + set_hid_expect( file, expect_set_envelope, sizeof(expect_set_envelope) ); + hr = IDirectInputEffect_SetParameters( effect, &expect_desc, 0 ); + ok( hr == DI_OK, "SetParameters returned %#x\n", hr ); + wait_hid_expect( file, 100 ); /* these updates are sent asynchronously */ + + set_hid_expect( file, &expect_stop, sizeof(expect_stop) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %d\n", ref ); + set_hid_expect( file, NULL, 0 ); + set_hid_expect( file, expect_reset, sizeof(expect_reset) ); hr = IDirectInputDevice8_Unacquire( device ); ok( hr == DI_OK, "Acquire returned: %#x\n", hr );
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52061 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 3 ++- dlls/dinput8/tests/hid.c | 11 +---------- 2 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 3d90e721fb6..5ecf54e2281 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -2728,7 +2728,8 @@ static void set_parameter_value_us( struct hid_joystick_effect *impl, char *repo LONG exp; if (!caps) return; exp = caps->units_exp; - if (caps->units != 0x1003) WARN( "unknown time unit caps %x\n", caps->units ); + if (value == INFINITE) value = caps->physical_min - 1; + else if (caps->units != 0x1003) WARN( "unknown time unit caps %x\n", caps->units ); else if (exp < -6) while (exp++ < -6) value *= 10; else if (exp > -6) while (exp-- > -6) value /= 10; set_parameter_value( impl, report_buf, caps, value ); diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index 884a0100abe..26a5406fa57 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -5650,15 +5650,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO .report_id = 3, .report_len = 11, .report_buf = {0x03,0x01,0x02,0x08,0xff,0xff,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0xd5}, - .todo = TRUE, - }, - /* update effect */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 3, - .report_len = 11, - .report_buf = {0x03,0x01,0x02,0x08,0x00,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0xd5}, - .wine_only = TRUE, .todo = TRUE, }, }; struct hid_expect expect_set_envelope[] = @@ -5683,7 +5674,7 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO .code = IOCTL_HID_WRITE_REPORT, .report_id = 3, .report_len = 11, - .report_buf = {0x03,0x01,0x02,0x08,0x00,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0xd5}, + .report_buf = {0x03,0x01,0x02,0x08,0xff,0xff,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0xd5}, .wine_only = TRUE, .todo = TRUE, }, };
From: Ivo Ivanov logos128@gmail.com
DInput will only send the output reports that have been modified, we need to support sparse effect updates.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52061 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/bus_sdl.c | 1 + dlls/winebus.sys/bus_udev.c | 1 + dlls/winebus.sys/hid.c | 21 ++++++++++++++++++--- 3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index e3932e31ff5..003f6652f05 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -569,6 +569,7 @@ static NTSTATUS sdl_device_physical_effect_update(struct unix_device *iface, BYT
TRACE("iface %p, index %u, params %p.\n", iface, index, params);
+ if (params->effect_type == PID_USAGE_UNDEFINED) return STATUS_SUCCESS; if ((status = set_effect_type_from_usage(&effect, params->effect_type))) return status;
switch (params->effect_type) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 3a7a5db723d..521ae4192b5 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1024,6 +1024,7 @@ static NTSTATUS lnxev_device_physical_effect_update(struct unix_device *iface, B
TRACE("iface %p, index %u, params %p.\n", iface, index, params);
+ if (params->effect_type == PID_USAGE_UNDEFINED) return STATUS_SUCCESS; if ((status = set_effect_type_from_usage(&effect, params->effect_type))) return status;
effect.replay.length = params->duration; diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index 56f30338481..beb2ebe8ad9 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -1033,7 +1033,11 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC else if (!(control = pid_device_control_usages[report->control_index])) io->Status = STATUS_INVALID_PARAMETER; else + { io->Status = iface->hid_vtbl->physical_device_control(iface, control); + if (control == PID_USAGE_DC_DEVICE_RESET && io->Status == STATUS_SUCCESS) + memset(physical->effect_params, 0, sizeof(physical->effect_params)); + } } else if (packet->reportId == physical->device_gain_report) { @@ -1088,8 +1092,6 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC params->direction[1] = report->direction[1];
io->Status = iface->hid_vtbl->physical_effect_update(iface, report->index, params); - - params->condition_count = 0; } } else if (packet->reportId == physical->set_periodic_report) @@ -1106,6 +1108,8 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC params->periodic.offset = report->offset; params->periodic.phase = report->phase; params->periodic.period = report->period; + + io->Status = iface->hid_vtbl->physical_effect_update(iface, report->index, params); } } else if (packet->reportId == physical->set_envelope_report) @@ -1122,6 +1126,8 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC params->envelope.fade_level = report->fade_level; params->envelope.attack_time = report->attack_time; params->envelope.fade_time = report->fade_time; + + io->Status = iface->hid_vtbl->physical_effect_update(iface, report->index, params); } } else if (packet->reportId == physical->set_condition_report) @@ -1134,10 +1140,11 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC io->Information = sizeof(*report) + 1; if (packet->reportBufferLen < io->Information) io->Status = STATUS_BUFFER_TOO_SMALL; - else if ((index = params->condition_count++) >= ARRAY_SIZE(params->condition)) + else if ((index = report->condition_index) >= ARRAY_SIZE(params->condition)) io->Status = STATUS_INVALID_PARAMETER; else { + if (params->condition_count <= index) params->condition_count = index + 1; condition = params->condition + index; condition->center_point_offset = report->center_point_offset; condition->positive_coefficient = report->positive_coefficient; @@ -1145,6 +1152,8 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC condition->positive_saturation = report->positive_saturation; condition->negative_saturation = report->negative_saturation; condition->dead_band = report->dead_band; + + io->Status = iface->hid_vtbl->physical_effect_update(iface, report->index, params); } } else if (packet->reportId == physical->set_constant_force_report) @@ -1156,7 +1165,11 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC if (packet->reportBufferLen < io->Information) io->Status = STATUS_BUFFER_TOO_SMALL; else + { params->constant_force.magnitude = report->magnitude; + + io->Status = iface->hid_vtbl->physical_effect_update(iface, report->index, params); + } } else if (packet->reportId == physical->set_ramp_force_report) { @@ -1170,6 +1183,8 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC { params->ramp_force.ramp_start = report->ramp_start; params->ramp_force.ramp_end = report->ramp_end; + + io->Status = iface->hid_vtbl->physical_effect_update(iface, report->index, params); } } else
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52061 From: Ivo Ivanov logos128@gmail.com Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 71 +++++++++++++++++++++++--------------- dlls/dinput8/tests/hid.c | 32 ----------------- 2 files changed, 44 insertions(+), 59 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 5ecf54e2281..62856cefa44 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -219,7 +219,7 @@ struct hid_joystick_effect DIENVELOPE envelope; DIPERIODIC periodic; DIEFFECT params; - BOOL modified; + DWORD modified; DWORD flags;
char *effect_control_buf; @@ -2470,7 +2470,7 @@ static HRESULT WINAPI hid_joystick_effect_SetParameters( IDirectInputEffect *ifa if (ret != DIENUM_STOP) impl->params.rgdwAxes[i] = 0; }
- impl->modified = TRUE; + impl->modified |= DIEP_AXES; }
if (flags & DIEP_DIRECTION) @@ -2486,7 +2486,7 @@ static HRESULT WINAPI hid_joystick_effect_SetParameters( IDirectInputEffect *ifa impl->params.dwFlags &= ~(DIEFF_CARTESIAN | DIEFF_POLAR | DIEFF_SPHERICAL); impl->params.dwFlags |= direction_flags; if (memcmp( impl->params.rglDirection, params->rglDirection, count * sizeof(LONG) )) - impl->modified = TRUE; + impl->modified |= DIEP_DIRECTION; memcpy( impl->params.rglDirection, params->rglDirection, count * sizeof(LONG) ); }
@@ -2502,7 +2502,7 @@ static HRESULT WINAPI hid_joystick_effect_SetParameters( IDirectInputEffect *ifa if (!params->lpvTypeSpecificParams) return E_POINTER; if (params->cbTypeSpecificParams != sizeof(DIPERIODIC)) return DIERR_INVALIDPARAM; if (memcmp( &impl->periodic, params->lpvTypeSpecificParams, sizeof(DIPERIODIC) )) - impl->modified = TRUE; + impl->modified |= DIEP_TYPESPECIFICPARAMS; memcpy( &impl->periodic, params->lpvTypeSpecificParams, sizeof(DIPERIODIC) ); impl->params.cbTypeSpecificParams = sizeof(DIPERIODIC); break; @@ -2516,6 +2516,8 @@ static HRESULT WINAPI hid_joystick_effect_SetParameters( IDirectInputEffect *ifa if (params->cbTypeSpecificParams != count * sizeof(DICONDITION) && params->cbTypeSpecificParams != sizeof(DICONDITION)) return DIERR_INVALIDPARAM; + if (memcmp( impl->condition, params->lpvTypeSpecificParams, params->cbTypeSpecificParams )) + impl->modified |= DIEP_TYPESPECIFICPARAMS; memcpy( impl->condition, params->lpvTypeSpecificParams, params->cbTypeSpecificParams ); impl->params.cbTypeSpecificParams = params->cbTypeSpecificParams; } @@ -2524,7 +2526,7 @@ static HRESULT WINAPI hid_joystick_effect_SetParameters( IDirectInputEffect *ifa if (!params->lpvTypeSpecificParams) return E_POINTER; if (params->cbTypeSpecificParams != sizeof(DICONSTANTFORCE)) return DIERR_INVALIDPARAM; if (memcmp( &impl->constant_force, params->lpvTypeSpecificParams, sizeof(DICONSTANTFORCE) )) - impl->modified = TRUE; + impl->modified |= DIEP_TYPESPECIFICPARAMS; memcpy( &impl->constant_force, params->lpvTypeSpecificParams, sizeof(DICONSTANTFORCE) ); impl->params.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); break; @@ -2532,7 +2534,7 @@ static HRESULT WINAPI hid_joystick_effect_SetParameters( IDirectInputEffect *ifa if (!params->lpvTypeSpecificParams) return E_POINTER; if (params->cbTypeSpecificParams != sizeof(DIRAMPFORCE)) return DIERR_INVALIDPARAM; if (memcmp( &impl->constant_force, params->lpvTypeSpecificParams, sizeof(DIRAMPFORCE) )) - impl->modified = TRUE; + impl->modified |= DIEP_TYPESPECIFICPARAMS; memcpy( &impl->constant_force, params->lpvTypeSpecificParams, sizeof(DIRAMPFORCE) ); impl->params.cbTypeSpecificParams = sizeof(DIRAMPFORCE); break; @@ -2546,35 +2548,35 @@ static HRESULT WINAPI hid_joystick_effect_SetParameters( IDirectInputEffect *ifa { if (params->lpEnvelope->dwSize != sizeof(DIENVELOPE)) return DIERR_INVALIDPARAM; if (memcmp( &impl->envelope, params->lpEnvelope, sizeof(DIENVELOPE) )) - impl->modified = TRUE; + impl->modified |= DIEP_ENVELOPE; memcpy( &impl->envelope, params->lpEnvelope, sizeof(DIENVELOPE) ); }
if (flags & DIEP_DURATION) { - if (impl->params.dwDuration != params->dwDuration) impl->modified = TRUE; + if (impl->params.dwDuration != params->dwDuration) impl->modified |= DIEP_DURATION; impl->params.dwDuration = params->dwDuration; } if (flags & DIEP_GAIN) { - if (impl->params.dwGain != params->dwGain) impl->modified = TRUE; + if (impl->params.dwGain != params->dwGain) impl->modified |= DIEP_GAIN; impl->params.dwGain = params->dwGain; } if (flags & DIEP_SAMPLEPERIOD) { - if (impl->params.dwSamplePeriod != params->dwSamplePeriod) impl->modified = TRUE; + if (impl->params.dwSamplePeriod != params->dwSamplePeriod) impl->modified |= DIEP_SAMPLEPERIOD; impl->params.dwSamplePeriod = params->dwSamplePeriod; } if (flags & DIEP_STARTDELAY) { if (params->dwSize != sizeof(DIEFFECT_DX6)) return DIERR_INVALIDPARAM; - if (impl->params.dwStartDelay != params->dwStartDelay) impl->modified = TRUE; + if (impl->params.dwStartDelay != params->dwStartDelay) impl->modified |= DIEP_STARTDELAY; impl->params.dwStartDelay = params->dwStartDelay; } if (flags & DIEP_TRIGGERREPEATINTERVAL) { if (impl->params.dwTriggerRepeatInterval != params->dwTriggerRepeatInterval) - impl->modified = TRUE; + impl->modified |= DIEP_TRIGGERREPEATINTERVAL; impl->params.dwTriggerRepeatInterval = params->dwTriggerRepeatInterval; }
@@ -2587,7 +2589,7 @@ static HRESULT WINAPI hid_joystick_effect_SetParameters( IDirectInputEffect *ifa ret = enum_objects( impl->joystick, &filter, DIDFT_BUTTON, set_parameters_object, &impl->params.dwTriggerButton ); if (ret != DIENUM_STOP) impl->params.dwTriggerButton = -1; - if (impl->params.dwTriggerButton != old_value) impl->modified = TRUE; + if (impl->params.dwTriggerButton != old_value) impl->modified |= DIEP_TRIGGERBUTTON; }
impl->flags |= flags; @@ -2792,6 +2794,8 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) case PID_USAGE_ET_TRIANGLE: case PID_USAGE_ET_SAWTOOTH_UP: case PID_USAGE_ET_SAWTOOTH_DOWN: + if (!(impl->modified & DIEP_TYPESPECIFICPARAMS)) break; + set_parameter_value( impl, impl->type_specific_buf, set_periodic->magnitude_caps, impl->periodic.dwMagnitude ); set_parameter_value_us( impl, impl->type_specific_buf, set_periodic->period_caps, @@ -2801,13 +2805,15 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) set_parameter_value( impl, impl->type_specific_buf, set_periodic->offset_caps, impl->periodic.lOffset );
- if (WriteFile( device, impl->type_specific_buf, report_len, NULL, NULL )) hr = DI_OK; - else hr = DIERR_INPUTLOST; + if (!WriteFile( device, impl->type_specific_buf, report_len, NULL, NULL )) hr = DIERR_INPUTLOST; + else impl->modified &= ~DIEP_TYPESPECIFICPARAMS; break; case PID_USAGE_ET_SPRING: case PID_USAGE_ET_DAMPER: case PID_USAGE_ET_INERTIA: case PID_USAGE_ET_FRICTION: + if (!(impl->modified & DIEP_TYPESPECIFICPARAMS)) break; + for (i = 0; i < impl->params.cbTypeSpecificParams / sizeof(DICONDITION); ++i) { status = HidP_SetUsageValue( HidP_Output, HID_USAGE_PAGE_PID, 0, PID_USAGE_PARAMETER_BLOCK_OFFSET, @@ -2827,28 +2833,35 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) set_parameter_value( impl, impl->type_specific_buf, set_condition->dead_band_caps, impl->condition[i].lDeadBand );
- if (WriteFile( device, impl->type_specific_buf, report_len, NULL, NULL )) hr = DI_OK; - else hr = DIERR_INPUTLOST; + if (!WriteFile( device, impl->type_specific_buf, report_len, NULL, NULL )) hr = DIERR_INPUTLOST; + else impl->modified &= ~DIEP_TYPESPECIFICPARAMS; } break; case PID_USAGE_ET_CONSTANT_FORCE: + if (!(impl->modified & DIEP_TYPESPECIFICPARAMS)) break; + set_parameter_value( impl, impl->type_specific_buf, set_constant_force->magnitude_caps, impl->constant_force.lMagnitude );
- if (WriteFile( device, impl->type_specific_buf, report_len, NULL, NULL )) hr = DI_OK; - else hr = DIERR_INPUTLOST; + if (!WriteFile( device, impl->type_specific_buf, report_len, NULL, NULL )) hr = DIERR_INPUTLOST; + else impl->modified &= ~DIEP_TYPESPECIFICPARAMS; break; case PID_USAGE_ET_RAMP: + if (!(impl->modified & DIEP_TYPESPECIFICPARAMS)) break; + set_parameter_value( impl, impl->type_specific_buf, set_ramp_force->start_caps, impl->ramp_force.lStart ); set_parameter_value( impl, impl->type_specific_buf, set_ramp_force->end_caps, impl->ramp_force.lEnd );
- if (WriteFile( device, impl->type_specific_buf, report_len, NULL, NULL )) hr = DI_OK; - else hr = DIERR_INPUTLOST; + if (!WriteFile( device, impl->type_specific_buf, report_len, NULL, NULL )) hr = DIERR_INPUTLOST; + else impl->modified &= ~DIEP_TYPESPECIFICPARAMS; break; } + }
+ if (hr == DI_OK) + { switch (impl->type) { case PID_USAGE_ET_SQUARE: @@ -2858,6 +2871,8 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) case PID_USAGE_ET_SAWTOOTH_DOWN: case PID_USAGE_ET_CONSTANT_FORCE: case PID_USAGE_ET_RAMP: + if (!(impl->modified & DIEP_ENVELOPE)) break; + set_parameter_value( impl, impl->set_envelope_buf, set_envelope->attack_level_caps, impl->envelope.dwAttackLevel ); set_parameter_value_us( impl, impl->set_envelope_buf, set_envelope->attack_time_caps, @@ -2867,11 +2882,14 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) set_parameter_value_us( impl, impl->set_envelope_buf, set_envelope->fade_time_caps, impl->envelope.dwFadeTime );
- if (WriteFile( device, impl->set_envelope_buf, report_len, NULL, NULL )) hr = DI_OK; - else hr = DIERR_INPUTLOST; + if (!WriteFile( device, impl->set_envelope_buf, report_len, NULL, NULL )) hr = DIERR_INPUTLOST; + else impl->modified &= ~DIEP_ENVELOPE; break; } + }
+ if (hr == DI_OK && impl->modified) + { set_parameter_value_us( impl, impl->effect_update_buf, effect_update->duration_caps, impl->params.dwDuration ); set_parameter_value( impl, impl->effect_update_buf, effect_update->gain_caps, @@ -2904,10 +2922,8 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) impl->effect_update_buf, report_len ); if (status != HIDP_STATUS_SUCCESS) WARN( "HidP_SetUsageValue returned %#x\n", status );
- if (WriteFile( device, impl->effect_update_buf, report_len, NULL, NULL )) hr = DI_OK; - else hr = DIERR_INPUTLOST; - - impl->modified = FALSE; + if (!WriteFile( device, impl->effect_update_buf, report_len, NULL, NULL )) hr = DIERR_INPUTLOST; + else impl->modified = 0; } LeaveCriticalSection( &impl->joystick->base.crit );
@@ -2947,6 +2963,7 @@ static HRESULT WINAPI hid_joystick_effect_Unload( IDirectInputEffect *iface ) else hr = DIERR_INPUTLOST; }
+ impl->modified = impl->flags; impl->index = 0; } LeaveCriticalSection( &joystick->base.crit ); diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index 26a5406fa57..4159c3edd90 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -5628,22 +5628,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO }; struct hid_expect expect_update[] = { - /* set periodic */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 5, - .report_len = 2, - .report_buf = {0x05,0x19}, - .wine_only = TRUE, .todo = TRUE, - }, - /* set envelope */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 6, - .report_len = 7, - .report_buf = {0x06,0x19,0x4c,0x02,0x00,0x04,0x00}, - .wine_only = TRUE, .todo = TRUE, - }, /* update effect */ { .code = IOCTL_HID_WRITE_REPORT, @@ -5654,14 +5638,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO }; struct hid_expect expect_set_envelope[] = { - /* set periodic */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 5, - .report_len = 2, - .report_buf = {0x05,0x19}, - .wine_only = TRUE, .todo = TRUE, - }, /* set envelope */ { .code = IOCTL_HID_WRITE_REPORT, @@ -5669,14 +5645,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO .report_len = 7, .report_buf = {0x06,0x19,0x4c,0x01,0x00,0x04,0x00}, }, - /* update effect */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 3, - .report_len = 11, - .report_buf = {0x03,0x01,0x02,0x08,0xff,0xff,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0xd5}, - .wine_only = TRUE, .todo = TRUE, - }, }; struct hid_expect expect_start = {
Even if it doesn't actually change.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52061 From: Ivo Ivanov logos128@gmail.com Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 2 +- dlls/dinput8/tests/hid.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 62856cefa44..99436bd8b05 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -2554,7 +2554,7 @@ static HRESULT WINAPI hid_joystick_effect_SetParameters( IDirectInputEffect *ifa
if (flags & DIEP_DURATION) { - if (impl->params.dwDuration != params->dwDuration) impl->modified |= DIEP_DURATION; + impl->modified |= DIEP_DURATION; impl->params.dwDuration = params->dwDuration; } if (flags & DIEP_GAIN) diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index 4159c3edd90..0c63ed835e8 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -6471,6 +6471,15 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO hr = IDirectInputEffect_SetParameters( effect, &expect_desc, 0 ); ok( hr == DI_OK, "SetParameters returned %#x\n", hr ); wait_hid_expect( file, 100 ); /* these updates are sent asynchronously */ + desc = expect_desc; + desc.dwDuration = INFINITE; + desc.dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER, + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_NODOWNLOAD|DIEP_DURATION|DIEP_TRIGGERBUTTON ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + set_hid_expect( file, expect_update, sizeof(expect_update) ); + hr = IDirectInputEffect_SetParameters( effect, &expect_desc, 0 ); + ok( hr == DI_OK, "SetParameters returned %#x\n", hr ); + wait_hid_expect( file, 100 ); /* these updates are sent asynchronously */
desc = expect_desc; desc.lpEnvelope = &envelope;