Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 2 + dlls/dinput8/tests/device.c | 18 +++ dlls/dinput8/tests/driver_hid.c | 83 +++++++++++ dlls/dinput8/tests/driver_hid.h | 3 +- dlls/dinput8/tests/hid.c | 244 ++++++++++++++++++++++++-------- 5 files changed, 289 insertions(+), 61 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 4af7da6654d..57e08025650 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -322,6 +322,8 @@ static const WCHAR *object_usage_to_string( DIDEVICEOBJECTINSTANCEW *instance ) case MAKELONG(PID_USAGE_DC_ENABLE_ACTUATORS, HID_USAGE_PAGE_PID): return L"DC Enable Actuators"; case MAKELONG(PID_USAGE_DC_STOP_ALL_EFFECTS, HID_USAGE_PAGE_PID): return L"DC Stop All Effects";
+ case MAKELONG(PID_USAGE_DEVICE_GAIN, HID_USAGE_PAGE_PID): return L"Device Gain"; + case MAKELONG(PID_USAGE_DEVICE_GAIN_REPORT, HID_USAGE_PAGE_PID): return L"Device Gain Report"; case MAKELONG(PID_USAGE_CP_OFFSET, HID_USAGE_PAGE_PID): return L"CP Offset"; case MAKELONG(PID_USAGE_DEAD_BAND, HID_USAGE_PAGE_PID): return L"Dead Band"; case MAKELONG(PID_USAGE_DEVICE_CONTROL, HID_USAGE_PAGE_PID): return L"PID Device Control"; diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c index 5ae9e225dc9..019f63ad825 100644 --- a/dlls/dinput8/tests/device.c +++ b/dlls/dinput8/tests/device.c @@ -1414,6 +1414,15 @@ static void test_mouse_info(void) ok( prop_range.lMin == DIPROPRANGE_NOMIN, "got %d expected %d\n", prop_range.lMin, DIPROPRANGE_NOMIN ); ok( prop_range.lMax == DIPROPRANGE_NOMAX, "got %d expected %d\n", prop_range.lMax, DIPROPRANGE_NOMAX );
+ prop_range.diph.dwHow = DIPH_DEVICE; + prop_range.diph.dwObj = 0; + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_FFGAIN returned %#x\n", hr ); + prop_dword.dwData = 1000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_FFGAIN returned %#x\n", hr ); + res = 0; hr = IDirectInputDevice8_EnumObjects( device, check_object_count, &res, DIDFT_AXIS | DIDFT_PSHBUTTON ); ok( hr == DI_OK, "EnumObjects returned %#x\n", hr ); @@ -1732,6 +1741,15 @@ static void test_keyboard_info(void) hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_RANGE returned %#x\n", hr );
+ prop_range.diph.dwHow = DIPH_DEVICE; + prop_range.diph.dwObj = 0; + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_FFGAIN returned %#x\n", hr ); + prop_dword.dwData = 1000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_FFGAIN returned %#x\n", hr ); + res = 0; hr = IDirectInputDevice8_EnumObjects( device, check_object_count, &res, DIDFT_AXIS | DIDFT_PSHBUTTON ); ok( hr == DI_OK, "EnumObjects returned %#x\n", hr ); diff --git a/dlls/dinput8/tests/driver_hid.c b/dlls/dinput8/tests/driver_hid.c index d6f085e4f30..2201fd07080 100644 --- a/dlls/dinput8/tests/driver_hid.c +++ b/dlls/dinput8/tests/driver_hid.c @@ -55,6 +55,7 @@ struct expect_queue struct hid_expect *end; struct hid_expect spurious; struct hid_expect *buffer; + IRP *pending_wait; };
static void expect_queue_init( struct expect_queue *queue ) @@ -68,6 +69,24 @@ static void expect_queue_init( struct expect_queue *queue )
static void expect_queue_cleanup( struct expect_queue *queue ) { + KIRQL irql; + IRP *irp; + + KeAcquireSpinLock( &queue->lock, &irql ); + if ((irp = queue->pending_wait)) + { + queue->pending_wait = NULL; + if (!IoSetCancelRoutine( irp, NULL )) irp = NULL; + } + KeReleaseSpinLock( &queue->lock, irql ); + + if (irp) + { + irp->IoStatus.Information = 0; + irp->IoStatus.Status = STATUS_DELETE_PENDING; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + } + ExFreePool( queue->buffer ); }
@@ -112,6 +131,54 @@ static void expect_queue_reset( struct expect_queue *queue, void *buffer, unsign ExFreePool( missing ); }
+static void WINAPI wait_cancel_routine( DEVICE_OBJECT *device, IRP *irp ) +{ + struct expect_queue *queue = irp->Tail.Overlay.DriverContext[0]; + KIRQL irql; + + IoReleaseCancelSpinLock( irp->CancelIrql ); + + KeAcquireSpinLock( &queue->lock, &irql ); + queue->pending_wait = NULL; + KeReleaseSpinLock( &queue->lock, irql ); + + irp->IoStatus.Information = 0; + irp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest( irp, IO_NO_INCREMENT ); +} + +static NTSTATUS expect_queue_wait( struct expect_queue *queue, IRP *irp ) +{ + NTSTATUS status; + KIRQL irql; + + KeAcquireSpinLock( &queue->lock, &irql ); + if (queue->pos == queue->end) + status = STATUS_SUCCESS; + else + { + IoSetCancelRoutine( irp, wait_cancel_routine ); + if (irp->Cancel && !IoSetCancelRoutine( irp, NULL )) + status = STATUS_CANCELLED; + else + { + irp->Tail.Overlay.DriverContext[0] = queue; + IoMarkIrpPending( irp ); + queue->pending_wait = irp; + status = STATUS_PENDING; + } + } + KeReleaseSpinLock( &queue->lock, irql ); + + if (status == STATUS_SUCCESS) + { + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + } + + return status; +} + static void expect_queue_next( struct expect_queue *queue, ULONG code, HID_XFER_PACKET *packet, LONG *index, struct hid_expect *expect, BOOL compare_buf ) { @@ -119,6 +186,7 @@ static void expect_queue_next( struct expect_queue *queue, ULONG code, HID_XFER_ ULONG len = packet->reportBufferLen; BYTE *buf = packet->reportBuffer; BYTE id = packet->reportId; + IRP *irp = NULL; KIRQL irql;
missing = ExAllocatePool( PagedPool, EXPECT_QUEUE_BUFFER_SIZE ); @@ -140,8 +208,21 @@ static void expect_queue_next( struct expect_queue *queue, ULONG code, HID_XFER_ if (tmp < queue->end) queue->pos = tmp + 1; else tmp = &queue->spurious; *expect = *tmp; + + if (queue->pos == queue->end && (irp = queue->pending_wait)) + { + queue->pending_wait = NULL; + if (!IoSetCancelRoutine( irp, NULL )) irp = NULL; + } KeReleaseSpinLock( &queue->lock, irql );
+ if (irp) + { + irp->IoStatus.Information = 0; + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + } + ok( tmp != &queue->spurious, "got spurious packet\n" );
winetest_push_context( "%s expect[%d]", tmp->context, tmp - queue->buffer ); @@ -624,6 +705,8 @@ static NTSTATUS WINAPI driver_ioctl( DEVICE_OBJECT *device, IRP *irp ) irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest( irp, IO_NO_INCREMENT ); return STATUS_SUCCESS; + case IOCTL_WINETEST_HID_WAIT_EXPECT: + return expect_queue_wait( &expect_queue, irp ); case IOCTL_WINETEST_HID_SEND_INPUT: input_queue_reset( &input_queue, irp->AssociatedIrp.SystemBuffer, in_size ); irp->IoStatus.Status = STATUS_SUCCESS; diff --git a/dlls/dinput8/tests/driver_hid.h b/dlls/dinput8/tests/driver_hid.h index 6c355760171..ffd45bd2e35 100644 --- a/dlls/dinput8/tests/driver_hid.h +++ b/dlls/dinput8/tests/driver_hid.h @@ -40,7 +40,8 @@ DEFINE_GUID(control_class,0xdeadbeef,0x29ef,0x4538,0xa5,0xfd,0xb6,0x95,0x73,0xa3,0x62,0xc0);
#define IOCTL_WINETEST_HID_SET_EXPECT CTL_CODE(FILE_DEVICE_KEYBOARD, 0x800, METHOD_IN_DIRECT, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_HID_SEND_INPUT CTL_CODE(FILE_DEVICE_KEYBOARD, 0x801, METHOD_IN_DIRECT, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_HID_WAIT_EXPECT CTL_CODE(FILE_DEVICE_KEYBOARD, 0x801, METHOD_NEITHER, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_HID_SEND_INPUT CTL_CODE(FILE_DEVICE_KEYBOARD, 0x802, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
struct hid_expect { diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index 38bdfb7455e..26b60fc21c6 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -743,7 +743,7 @@ 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 ) +static BOOL sync_ioctl( HANDLE file, DWORD code, void *in_buf, DWORD in_len, void *out_buf, DWORD *ret_len, DWORD timeout ) { OVERLAPPED ovl = {0}; DWORD out_len = ret_len ? *ret_len : 0; @@ -752,7 +752,18 @@ static BOOL sync_ioctl( HANDLE file, DWORD code, void *in_buf, DWORD in_len, voi 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 = GetOverlappedResult( file, &ovl, &out_len, TRUE ); + { + ret = GetOverlappedResultEx( file, &ovl, &out_len, timeout, TRUE ); + todo_wine_if( timeout != INFINITE ) + ok( ret, "GetOverlappedResultEx returned %u\n", GetLastError() ); + if (!ret) + { + ret = CancelIoEx( file, &ovl ); + ok( ret, "CancelIoEx returned %u\n", GetLastError() ); + ret = WaitForSingleObject( ovl.hEvent, INFINITE ); + ok( ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + } + } CloseHandle( ovl.hEvent );
if (ret_len) *ret_len = out_len; @@ -774,10 +785,20 @@ 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 ); + 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() ); }
+#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 ); + todo_wine + ok( ret, "IOCTL_WINETEST_HID_WAIT_EXPECT failed, last error %u\n", GetLastError() ); + + set_hid_expect( file, NULL, 0 ); +} + #define send_hid_input( a, b, c ) send_hid_input_( __LINE__, a, b, c ) static void send_hid_input_( int line, HANDLE file, struct hid_expect *expect, DWORD expect_size ) { @@ -793,7 +814,7 @@ static void send_hid_input_( 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_SEND_INPUT, expect, expect_size, NULL, 0 ); + ret = sync_ioctl( file, IOCTL_WINETEST_HID_SEND_INPUT, expect, expect_size, NULL, 0, INFINITE ); ok( ret, "IOCTL_WINETEST_HID_SEND_INPUT failed, last error %u\n", GetLastError() ); }
@@ -883,7 +904,7 @@ static void test_hidp_get_input( HANDLE file, int report_id, ULONG report_len, P
SetLastError( 0xdeadbeef ); length = report_len * 2; - ret = sync_ioctl( file, IOCTL_HID_GET_INPUT_REPORT, NULL, 0, report, &length ); + ret = sync_ioctl( file, IOCTL_HID_GET_INPUT_REPORT, NULL, 0, report, &length, INFINITE ); ok( ret, "IOCTL_HID_GET_INPUT_REPORT failed, last error %u\n", GetLastError() ); ok( length == 3, "got length %u, expected 3\n", length ); ok( report[0] == report_id, "got report[0] %02x, expected %02x\n", report[0], report_id ); @@ -977,7 +998,7 @@ static void test_hidp_get_feature( HANDLE file, int report_id, ULONG report_len,
length = report_len * 2; SetLastError( 0xdeadbeef ); - ret = sync_ioctl( file, IOCTL_HID_GET_FEATURE, NULL, 0, report, &length ); + ret = sync_ioctl( file, IOCTL_HID_GET_FEATURE, NULL, 0, report, &length, INFINITE ); ok( ret, "IOCTL_HID_GET_FEATURE failed, last error %u\n", GetLastError() ); ok( length == 3, "got length %u, expected 3\n", length ); ok( report[0] == report_id, "got report[0] %02x, expected %02x\n", report[0], report_id ); @@ -1073,13 +1094,13 @@ static void test_hidp_set_feature( HANDLE file, int report_id, ULONG report_len,
length = report_len * 2; SetLastError( 0xdeadbeef ); - ret = sync_ioctl( file, IOCTL_HID_SET_FEATURE, NULL, 0, report, &length ); + ret = sync_ioctl( file, IOCTL_HID_SET_FEATURE, NULL, 0, report, &length, INFINITE ); ok( !ret, "IOCTL_HID_SET_FEATURE succeeded\n" ); ok( GetLastError() == ERROR_INVALID_USER_BUFFER, "IOCTL_HID_SET_FEATURE returned error %u\n", GetLastError() ); length = 0; SetLastError( 0xdeadbeef ); - ret = sync_ioctl( file, IOCTL_HID_SET_FEATURE, report, report_len * 2, NULL, &length ); + ret = sync_ioctl( file, IOCTL_HID_SET_FEATURE, report, report_len * 2, NULL, &length, INFINITE ); ok( ret, "IOCTL_HID_SET_FEATURE failed, last error %u\n", GetLastError() ); ok( length == 3, "got length %u, expected 3\n", length );
@@ -1168,13 +1189,13 @@ static void test_hidp_set_output( HANDLE file, int report_id, ULONG report_len,
length = report_len * 2; SetLastError( 0xdeadbeef ); - ret = sync_ioctl( file, IOCTL_HID_SET_OUTPUT_REPORT, NULL, 0, report, &length ); + ret = sync_ioctl( file, IOCTL_HID_SET_OUTPUT_REPORT, NULL, 0, report, &length, INFINITE ); ok( !ret, "IOCTL_HID_SET_OUTPUT_REPORT succeeded\n" ); ok( GetLastError() == ERROR_INVALID_USER_BUFFER, "IOCTL_HID_SET_OUTPUT_REPORT returned error %u\n", GetLastError() ); length = 0; SetLastError( 0xdeadbeef ); - ret = sync_ioctl( file, IOCTL_HID_SET_OUTPUT_REPORT, report, report_len * 2, NULL, &length ); + ret = sync_ioctl( file, IOCTL_HID_SET_OUTPUT_REPORT, report, report_len * 2, NULL, &length, INFINITE ); ok( ret, "IOCTL_HID_SET_OUTPUT_REPORT failed, last error %u\n", GetLastError() ); ok( length == 3, "got length %u, expected 3\n", length );
@@ -2173,7 +2194,7 @@ static void test_hidp( HANDLE file, HANDLE async_file, int report_id, BOOL polle
value = 10; SetLastError( 0xdeadbeef ); - ret = sync_ioctl( file, IOCTL_HID_SET_POLL_FREQUENCY_MSEC, &value, sizeof(ULONG), NULL, NULL ); + ret = sync_ioctl( file, IOCTL_HID_SET_POLL_FREQUENCY_MSEC, &value, sizeof(ULONG), NULL, NULL, INFINITE ); ok( ret, "IOCTL_HID_SET_POLL_FREQUENCY_MSEC failed last error %u\n", GetLastError() );
Sleep( 600 ); @@ -2392,7 +2413,7 @@ static void test_hid_device( DWORD report_id, DWORD polled, const HIDP_CAPS *exp { out_len = sizeof(ULONG); SetLastError( 0xdeadbeef ); - ret = sync_ioctl( file, IOCTL_HID_GET_POLL_FREQUENCY_MSEC, NULL, 0, &poll_freq, &out_len ); + ret = sync_ioctl( file, IOCTL_HID_GET_POLL_FREQUENCY_MSEC, NULL, 0, &poll_freq, &out_len, INFINITE ); ok( ret, "IOCTL_HID_GET_POLL_FREQUENCY_MSEC failed last error %u\n", GetLastError() ); ok( out_len == sizeof(ULONG), "got out_len %u, expected sizeof(ULONG)\n", out_len ); todo_wine @@ -2401,27 +2422,27 @@ static void test_hid_device( DWORD report_id, DWORD polled, const HIDP_CAPS *exp out_len = 0; poll_freq = 500; SetLastError( 0xdeadbeef ); - ret = sync_ioctl( file, IOCTL_HID_SET_POLL_FREQUENCY_MSEC, &poll_freq, sizeof(ULONG), NULL, &out_len ); + ret = sync_ioctl( file, IOCTL_HID_SET_POLL_FREQUENCY_MSEC, &poll_freq, sizeof(ULONG), NULL, &out_len, INFINITE ); ok( ret, "IOCTL_HID_SET_POLL_FREQUENCY_MSEC failed last error %u\n", GetLastError() ); ok( out_len == 0, "got out_len %u, expected 0\n", out_len );
out_len = 0; poll_freq = 10001; SetLastError( 0xdeadbeef ); - ret = sync_ioctl( file, IOCTL_HID_SET_POLL_FREQUENCY_MSEC, &poll_freq, sizeof(ULONG), NULL, &out_len ); + ret = sync_ioctl( file, IOCTL_HID_SET_POLL_FREQUENCY_MSEC, &poll_freq, sizeof(ULONG), NULL, &out_len, INFINITE ); ok( ret, "IOCTL_HID_SET_POLL_FREQUENCY_MSEC failed last error %u\n", GetLastError() ); ok( out_len == 0, "got out_len %u, expected 0\n", out_len );
out_len = 0; poll_freq = 0; SetLastError( 0xdeadbeef ); - ret = sync_ioctl( file, IOCTL_HID_SET_POLL_FREQUENCY_MSEC, &poll_freq, sizeof(ULONG), NULL, &out_len ); + ret = sync_ioctl( file, IOCTL_HID_SET_POLL_FREQUENCY_MSEC, &poll_freq, sizeof(ULONG), NULL, &out_len, INFINITE ); ok( ret, "IOCTL_HID_SET_POLL_FREQUENCY_MSEC failed last error %u\n", GetLastError() ); ok( out_len == 0, "got out_len %u, expected 0\n", out_len );
out_len = sizeof(ULONG); SetLastError( 0xdeadbeef ); - ret = sync_ioctl( file, IOCTL_HID_GET_POLL_FREQUENCY_MSEC, NULL, 0, &poll_freq, &out_len ); + ret = sync_ioctl( file, IOCTL_HID_GET_POLL_FREQUENCY_MSEC, NULL, 0, &poll_freq, &out_len, INFINITE ); ok( ret, "IOCTL_HID_GET_POLL_FREQUENCY_MSEC failed last error %u\n", GetLastError() ); ok( out_len == sizeof(ULONG), "got out_len %u, expected sizeof(ULONG)\n", out_len ); ok( poll_freq == 10000, "got poll_freq %u, expected 10000\n", poll_freq ); @@ -2429,13 +2450,13 @@ static void test_hid_device( DWORD report_id, DWORD polled, const HIDP_CAPS *exp out_len = 0; poll_freq = 500; SetLastError( 0xdeadbeef ); - ret = sync_ioctl( file, IOCTL_HID_SET_POLL_FREQUENCY_MSEC, &poll_freq, sizeof(ULONG), NULL, &out_len ); + ret = sync_ioctl( file, IOCTL_HID_SET_POLL_FREQUENCY_MSEC, &poll_freq, sizeof(ULONG), NULL, &out_len, INFINITE ); ok( ret, "IOCTL_HID_SET_POLL_FREQUENCY_MSEC failed last error %u\n", GetLastError() ); ok( out_len == 0, "got out_len %u, expected 0\n", out_len );
out_len = sizeof(ULONG); SetLastError( 0xdeadbeef ); - ret = sync_ioctl( async_file, IOCTL_HID_GET_POLL_FREQUENCY_MSEC, NULL, 0, &poll_freq, &out_len ); + ret = sync_ioctl( async_file, IOCTL_HID_GET_POLL_FREQUENCY_MSEC, NULL, 0, &poll_freq, &out_len, INFINITE ); ok( ret, "IOCTL_HID_GET_POLL_FREQUENCY_MSEC failed last error %u\n", GetLastError() ); ok( out_len == sizeof(ULONG), "got out_len %u, expected sizeof(ULONG)\n", out_len ); ok( poll_freq == 500, "got poll_freq %u, expected 500\n", poll_freq ); @@ -4358,7 +4379,8 @@ static void test_simple_joystick(void) ok( hr == DI_OK, "SetEventNotification returned: %#x\n", hr );
file = CreateFileW( prop_guid_path.wszPath, FILE_READ_ACCESS | FILE_WRITE_ACCESS, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL ); ok( file != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError() );
hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, 0 ); @@ -5551,12 +5573,30 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO .report_buf = {1,0x01}, }, }; - struct hid_expect expect_dc_reset = + struct hid_expect expect_acquire[] = { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, - .report_len = 2, - .report_buf = {1, 0x01}, + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x01}, + }, + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 8, + .report_len = 2, + .report_buf = {8, 0x19}, + .todo = TRUE, + }, + }; + struct hid_expect expect_reset[] = + { + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x01}, + }, }; static const DWORD expect_axes_init[2] = {0}; const DIEFFECT expect_desc_init = @@ -5689,16 +5729,16 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO hr = IDirectInputEffect_GetParameters( effect, &desc, 0 ); ok( hr == DI_OK, "GetParameters returned %#x\n", hr );
- set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); + set_hid_expect( file, expect_reset, sizeof(expect_reset) ); hr = IDirectInputDevice8_Unacquire( device ); ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); set_hid_expect( file, NULL, 0 ); hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DURATION ); ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); + set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); hr = IDirectInputDevice8_Acquire( device ); ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */
desc.dwDuration = 0xdeadbeef; hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DURATION ); @@ -5810,16 +5850,16 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO if (version >= 0x700) check_member( desc, expect_desc_init, "%u", dwStartDelay ); else ok( desc.dwStartDelay == 0xcdcdcdcd, "got dwStartDelay %#x\n", desc.dwStartDelay );
- set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); + set_hid_expect( file, expect_reset, sizeof(expect_reset) ); hr = IDirectInputDevice8_Unacquire( device ); ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); set_hid_expect( file, NULL, 0 ); hr = IDirectInputEffect_Download( effect ); ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "Download returned %#x\n", hr ); - set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); + set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); hr = IDirectInputDevice8_Acquire( device ); ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */
hr = IDirectInputEffect_Download( effect ); ok( hr == DIERR_INCOMPLETEEFFECT, "Download returned %#x\n", hr ); @@ -5835,16 +5875,16 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_NODOWNLOAD ); ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr );
- set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); + set_hid_expect( file, expect_reset, sizeof(expect_reset) ); hr = IDirectInputDevice8_Unacquire( device ); ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); set_hid_expect( file, NULL, 0 ); hr = IDirectInputEffect_SetParameters( effect, &expect_desc, DIEP_DURATION ); ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); + set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); hr = IDirectInputDevice8_Acquire( device ); ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */
hr = IDirectInputEffect_SetParameters( effect, &expect_desc, DIEP_DURATION | DIEP_NODOWNLOAD ); ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); @@ -6111,10 +6151,10 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO hr = IDirectInputEffect_Stop( effect ); ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "Stop returned %#x\n", hr );
- set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); + set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); hr = IDirectInputDevice8_Acquire( device ); ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */
hr = IDirectInputEffect_Unload( effect ); ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); @@ -6291,7 +6331,7 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO winetest_pop_context(); }
- set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); + set_hid_expect( file, expect_reset, sizeof(expect_reset) ); hr = IDirectInputDevice8_Unacquire( device ); ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); set_hid_expect( file, NULL, 0 ); @@ -6299,10 +6339,10 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); ref = IDirectInputEffect_Release( effect ); ok( ref == 0, "Release returned %d\n", ref ); - set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); + set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); hr = IDirectInputDevice8_Acquire( device ); ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ }
static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file, DWORD version ) @@ -6858,6 +6898,21 @@ static void test_force_feedback_joystick( DWORD version ) REPORT_COUNT(1, 1), OUTPUT(1, Data|Var|Abs), END_COLLECTION, + + + USAGE(1, PID_USAGE_DEVICE_GAIN_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 8), + + USAGE(1, PID_USAGE_DEVICE_GAIN), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, END_COLLECTION, }; #undef REPORT_ID_OR_USAGE_PAGE @@ -6881,12 +6936,46 @@ static void test_force_feedback_joystick( DWORD version ) .dwHardwareRevision = 1, .dwFFDriverVersion = 1, }; - struct hid_expect expect_dc_reset = + struct hid_expect expect_acquire[] = + { + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x01}, + }, + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 8, + .report_len = 2, + .report_buf = {8, 0x19}, + .todo = TRUE, + }, + }; + struct hid_expect expect_reset[] = + { + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x01}, + }, + }; + struct hid_expect expect_set_device_gain_1 = { .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, + .report_id = 8, .report_len = 2, - .report_buf = {1, 0x01}, + .report_buf = {8, 0x19}, + .todo = TRUE, + }; + struct hid_expect expect_set_device_gain_2 = + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 8, + .report_len = 2, + .report_buf = {8, 0x33}, + .todo = TRUE, };
const DIDEVICEINSTANCEW expect_devinst = @@ -7004,7 +7093,7 @@ static void test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Button, - .dwOfs = version >= 0x800 ? 0x64 : 0x10, + .dwOfs = version >= 0x800 ? 0x68 : 0x10, .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(0)|DIDFT_FFEFFECTTRIGGER, .dwFlags = DIDOI_FFEFFECTTRIGGER, .tszName = L"Button 0", @@ -7016,7 +7105,7 @@ static void test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Button, - .dwOfs = version >= 0x800 ? 0x65 : 0x11, + .dwOfs = version >= 0x800 ? 0x69 : 0x11, .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(1)|DIDFT_FFEFFECTTRIGGER, .dwFlags = DIDOI_FFEFFECTTRIGGER, .tszName = L"Button 1", @@ -7028,7 +7117,7 @@ static void test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x6c : 0, + .dwOfs = version >= 0x800 ? 0x70 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(12)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"DC Device Reset", @@ -7052,7 +7141,7 @@ static void test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x6d : 0, + .dwOfs = version >= 0x800 ? 0x71 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(14)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Op Effect Start", @@ -7064,7 +7153,7 @@ static void test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x6e : 0, + .dwOfs = version >= 0x800 ? 0x72 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(15)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Op Effect Start Solo", @@ -7076,7 +7165,7 @@ static void test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x6f : 0, + .dwOfs = version >= 0x800 ? 0x73 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(16)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Op Effect Stop", @@ -7112,7 +7201,7 @@ static void test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x70 : 0, + .dwOfs = version >= 0x800 ? 0x74 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(19)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"ET Square", @@ -7124,7 +7213,7 @@ static void test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x71 : 0, + .dwOfs = version >= 0x800 ? 0x75 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(20)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"ET Sine", @@ -7136,7 +7225,7 @@ static void test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x72 : 0, + .dwOfs = version >= 0x800 ? 0x76 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(21)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"ET Spring", @@ -7148,7 +7237,7 @@ static void test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x73 : 0, + .dwOfs = version >= 0x800 ? 0x77 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(22)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Z Axis", @@ -7160,7 +7249,7 @@ static void test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x74 : 0, + .dwOfs = version >= 0x800 ? 0x78 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(23)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Y Axis", @@ -7172,7 +7261,7 @@ static void test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x75 : 0, + .dwOfs = version >= 0x800 ? 0x79 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(24)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"X Axis", @@ -7184,7 +7273,7 @@ static void test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x76 : 0, + .dwOfs = version >= 0x800 ? 0x7a : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(25)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Direction Enable", @@ -7419,6 +7508,18 @@ static void test_force_feedback_joystick( DWORD version ) .wUsage = PID_USAGE_DEAD_BAND, .wReportId = 7, }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x64 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(44)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Device Gain", + .wCollectionNumber = 15, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_DEVICE_GAIN, + .wReportId = 8, + }, { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, @@ -7545,6 +7646,14 @@ static void test_force_feedback_joystick( DWORD version ) .wUsagePage = HID_USAGE_PAGE_PID, .wUsage = PID_USAGE_TYPE_SPECIFIC_BLOCK_OFFSET, }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(15), + .tszName = L"Collection 15 - Device Gain Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_DEVICE_GAIN_REPORT, + }, }; const DIEFFECTINFOW expect_effects[] = { @@ -7713,7 +7822,8 @@ static void test_force_feedback_joystick( DWORD version ) ok( hr == DI_OK, "GetProperty DIPROP_GUIDANDPATH returned %#x\n", hr );
file = CreateFileW( prop_guid_path.wszPath, FILE_READ_ACCESS | FILE_WRITE_ACCESS, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL ); ok( file != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError() );
hwnd = CreateWindowW( L"static", L"dinput", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 10, 10, 200, 200, @@ -7771,10 +7881,24 @@ static void test_force_feedback_joystick( DWORD version ) hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr );
- set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); + set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); hr = IDirectInputDevice8_Acquire( device ); ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ + + set_hid_expect( file, &expect_set_device_gain_2, sizeof(expect_set_device_gain_2) ); + prop_dword.dwData = 2000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + todo_wine + ok( hr == DI_OK, "SetProperty DIPROP_FFGAIN returned %#x\n", hr ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ + + set_hid_expect( file, &expect_set_device_gain_1, sizeof(expect_set_device_gain_1) ); + prop_dword.dwData = 1000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + todo_wine + ok( hr == DI_OK, "SetProperty DIPROP_FFGAIN returned %#x\n", hr ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */
hr = IDirectInputDevice8_Escape( device, &escape ); todo_wine @@ -7792,10 +7916,10 @@ static void test_force_feedback_joystick( DWORD version ) hr = IDirectInputDevice8_SendForceFeedbackCommand( device, 0xdeadbeef ); ok( hr == DIERR_INVALIDPARAM, "SendForceFeedbackCommand returned %#x\n", hr );
- set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); + set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); ok( hr == DI_OK, "SendForceFeedbackCommand returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */
hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_STOPALL ); ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#x\n", hr ); @@ -7818,7 +7942,7 @@ static void test_force_feedback_joystick( DWORD version ) test_periodic_effect( device, file, version ); test_condition_effect( device, file, version );
- set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); + set_hid_expect( file, expect_reset, sizeof(expect_reset) ); hr = IDirectInputDevice8_Unacquire( device ); ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); set_hid_expect( file, NULL, 0 );