Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/Makefile.in | 2 + dlls/dinput/tests/dinput_test.h | 100 + dlls/dinput/tests/driver_hid.c | 1 + dlls/dinput/tests/driver_hid.h | 2 - dlls/dinput/tests/force_feedback.c | 4337 ++++++++++++++++++ dlls/dinput/tests/hid.c | 6767 +--------------------------- dlls/dinput/tests/joystick8.c | 2594 +++++++++++ 7 files changed, 7125 insertions(+), 6678 deletions(-) create mode 100644 dlls/dinput/tests/dinput_test.h create mode 100644 dlls/dinput/tests/force_feedback.c create mode 100644 dlls/dinput/tests/joystick8.c
diff --git a/dlls/dinput/tests/Makefile.in b/dlls/dinput/tests/Makefile.in index 87a4dad2708..b6648008115 100644 --- a/dlls/dinput/tests/Makefile.in +++ b/dlls/dinput/tests/Makefile.in @@ -11,7 +11,9 @@ SOURCES = \ dinput8.c \ driver_hid.c \ driver_hid.spec \ + force_feedback.c \ hid.c \ joystick.c \ + joystick8.c \ keyboard.c \ mouse.c diff --git a/dlls/dinput/tests/dinput_test.h b/dlls/dinput/tests/dinput_test.h new file mode 100644 index 00000000000..0a4c9ba5fa4 --- /dev/null +++ b/dlls/dinput/tests/dinput_test.h @@ -0,0 +1,100 @@ +/* + * DInput driver-based testing framework + * + * Copyright 2015 Sebastian Lackner + * Copyright 2015 Michael Müller + * Copyright 2015 Christian Costa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_DINPUT_TEST_H +#define __WINE_DINPUT_TEST_H + +#include <stdarg.h> +#include <stddef.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winioctl.h" +#include "winternl.h" + +#include "dinput.h" + +#include "ddk/wdm.h" +#include "ddk/hidsdi.h" +#include "ddk/hidport.h" + +#include "wine/test.h" + +#include "driver_hid.h" + +#define EXPECT_VIDPID MAKELONG( 0x1209, 0x0001 ) +extern const WCHAR expect_vidpid_str[]; +extern const GUID expect_guid_product; +extern const WCHAR expect_path[]; +extern const WCHAR expect_path_end[]; + +extern HINSTANCE instance; +extern BOOL localized; /* object names get translated */ + +BOOL pnp_driver_start( const WCHAR *resource ); +void pnp_driver_stop(void); + +void cleanup_registry_keys(void); + +#define dinput_driver_start( a, b, c, d, e ) dinput_driver_start_( __FILE__, __LINE__, a, b, c, d, e ) +BOOL dinput_driver_start_( const char *file, int line, const BYTE *desc_buf, ULONG desc_len, + const HIDP_CAPS *caps, struct hid_expect *expect, ULONG expect_size ); + +#define dinput_test_init() dinput_test_init_( __FILE__, __LINE__ ) +BOOL dinput_test_init_( const char *file, int line ); +void dinput_test_exit(void); + +HRESULT dinput_test_create_device( DWORD version, DIDEVICEINSTANCEW *devinst, IDirectInputDevice8W **device ); + +#define check_member_( file, line, val, exp, fmt, member ) \ + ok_(file, line)( (val).member == (exp).member, "got " #member " " fmt "\n", (val).member ) +#define check_member( val, exp, fmt, member ) \ + check_member_( __FILE__, __LINE__, val, exp, fmt, member ) + +#define check_member_guid_( file, line, val, exp, member ) \ + ok_(file, line)( IsEqualGUID( &(val).member, &(exp).member ), "got " #member " %s\n", \ + debugstr_guid( &(val).member ) ) +#define check_member_guid( val, exp, member ) \ + check_member_guid_( __FILE__, __LINE__, val, exp, member ) + +#define check_member_wstr_( file, line, val, exp, member ) \ + ok_(file, line)( !wcscmp( (val).member, (exp).member ), "got " #member " %s\n", \ + debugstr_w((val).member) ) +#define check_member_wstr( val, exp, member ) \ + check_member_wstr_( __FILE__, __LINE__, val, exp, member ) + +#define sync_ioctl( a, b, c, d, e, f, g ) sync_ioctl_( __FILE__, __LINE__, a, b, c, d, e, f, g ) +BOOL sync_ioctl_( const char *file, int line, HANDLE device, DWORD code, void *in_buf, DWORD in_len, + void *out_buf, DWORD *ret_len, DWORD timeout ); + +#define set_hid_expect( a, b, c ) set_hid_expect_( __FILE__, __LINE__, a, b, c ) +void set_hid_expect_( const char *file, int line, HANDLE device, struct hid_expect *expect, DWORD expect_size ); + +#define wait_hid_expect( a, b ) wait_hid_expect_( __FILE__, __LINE__, a, b ) +void wait_hid_expect_( const char *file, int line, HANDLE device, DWORD timeout ); + +#define send_hid_input( a, b, c ) send_hid_input_( __FILE__, __LINE__, a, b, c ) +void send_hid_input_( const char *file, int line, HANDLE device, struct hid_expect *expect, DWORD expect_size ); + +#endif /* __WINE_DINPUT_TEST_H */ diff --git a/dlls/dinput/tests/driver_hid.c b/dlls/dinput/tests/driver_hid.c index 545dff0c2dc..84b84101592 100644 --- a/dlls/dinput/tests/driver_hid.c +++ b/dlls/dinput/tests/driver_hid.c @@ -34,6 +34,7 @@
#include "wine/list.h"
+#include "initguid.h" #include "driver_hid.h"
static UNICODE_STRING control_symlink; diff --git a/dlls/dinput/tests/driver_hid.h b/dlls/dinput/tests/driver_hid.h index 3d31b4ee824..963f7619b1f 100644 --- a/dlls/dinput/tests/driver_hid.h +++ b/dlls/dinput/tests/driver_hid.h @@ -35,8 +35,6 @@
#include "ddk/wdm.h"
-#include "initguid.h" - 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) diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c new file mode 100644 index 00000000000..bc5161a9b63 --- /dev/null +++ b/dlls/dinput/tests/force_feedback.c @@ -0,0 +1,4337 @@ +/* + * Copyright 2022 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define DIRECTINPUT_VERSION 0x0800 + +#include <stdarg.h> +#include <stddef.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" + +#define COBJMACROS +#include "dinput.h" +#include "dinputd.h" + +#include "wine/hid.h" + +#include "dinput_test.h" + +struct check_objects_todos +{ + BOOL type; + BOOL guid; + BOOL usage; + BOOL name; +}; + +struct check_objects_params +{ + DWORD version; + UINT index; + UINT expect_count; + const DIDEVICEOBJECTINSTANCEW *expect_objs; + const struct check_objects_todos *todo_objs; + BOOL todo_extra; +}; + +static BOOL CALLBACK check_objects( const DIDEVICEOBJECTINSTANCEW *obj, void *args ) +{ + static const DIDEVICEOBJECTINSTANCEW unexpected_obj = {0}; + static const struct check_objects_todos todo_none = {0}; + struct check_objects_params *params = args; + const DIDEVICEOBJECTINSTANCEW *exp = params->expect_objs + params->index; + const struct check_objects_todos *todo; + + if (!params->todo_objs) todo = &todo_none; + else todo = params->todo_objs + params->index; + + todo_wine_if( params->todo_extra && params->index >= params->expect_count ) + ok( params->index < params->expect_count, "unexpected extra object\n" ); + if (params->index >= params->expect_count) return DIENUM_STOP; + + winetest_push_context( "obj[%d]", params->index ); + + ok( params->index < params->expect_count, "unexpected extra object\n" ); + if (params->index >= params->expect_count) exp = &unexpected_obj; + + check_member( *obj, *exp, "%u", dwSize ); + todo_wine_if( todo->guid ) + check_member_guid( *obj, *exp, guidType ); + todo_wine_if( params->version < 0x700 && (obj->dwType & DIDFT_BUTTON) ) + check_member( *obj, *exp, "%#x", dwOfs ); + todo_wine_if( todo->type ) + check_member( *obj, *exp, "%#x", dwType ); + check_member( *obj, *exp, "%#x", dwFlags ); + if (!localized) todo_wine_if( todo->name ) check_member_wstr( *obj, *exp, tszName ); + check_member( *obj, *exp, "%u", dwFFMaxForce ); + check_member( *obj, *exp, "%u", dwFFForceResolution ); + check_member( *obj, *exp, "%u", wCollectionNumber ); + check_member( *obj, *exp, "%u", wDesignatorIndex ); + check_member( *obj, *exp, "%#04x", wUsagePage ); + todo_wine_if( todo->usage ) + check_member( *obj, *exp, "%#04x", wUsage ); + check_member( *obj, *exp, "%#04x", dwDimension ); + check_member( *obj, *exp, "%#04x", wExponent ); + check_member( *obj, *exp, "%u", wReportId ); + + winetest_pop_context(); + + params->index++; + return DIENUM_CONTINUE; +} + +struct check_effects_params +{ + UINT index; + UINT expect_count; + const DIEFFECTINFOW *expect_effects; +}; + +static BOOL CALLBACK check_effects( const DIEFFECTINFOW *effect, void *args ) +{ + static const DIEFFECTINFOW unexpected_effect = {0}; + struct check_effects_params *params = args; + const DIEFFECTINFOW *exp = params->expect_effects + params->index; + + winetest_push_context( "effect[%d]", params->index ); + + ok( params->index < params->expect_count, "unexpected extra object\n" ); + if (params->index >= params->expect_count) exp = &unexpected_effect; + + check_member( *effect, *exp, "%u", dwSize ); + check_member_guid( *effect, *exp, guid ); + check_member( *effect, *exp, "%#x", dwEffType ); + check_member( *effect, *exp, "%#x", dwStaticParams ); + check_member( *effect, *exp, "%#x", dwDynamicParams ); + check_member_wstr( *effect, *exp, tszName ); + + winetest_pop_context(); + params->index++; + + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK check_effect_count( const DIEFFECTINFOW *effect, void *args ) +{ + DWORD *count = args; + *count = *count + 1; + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK check_no_created_effect_objects( IDirectInputEffect *effect, void *context ) +{ + ok( 0, "unexpected effect %p\n", effect ); + return DIENUM_CONTINUE; +} + +struct check_created_effect_params +{ + IDirectInputEffect *expect_effect; + DWORD count; +}; + +static BOOL CALLBACK check_created_effect_objects( IDirectInputEffect *effect, void *context ) +{ + struct check_created_effect_params *params = context; + ULONG ref; + + ok( effect == params->expect_effect, "got effect %p, expected %p\n", effect, params->expect_effect ); + params->count++; + + IDirectInputEffect_AddRef( effect ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 1, "got ref %u, expected 1\n", ref ); + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK enum_device_count( const DIDEVICEINSTANCEW *devinst, void *context ) +{ + DWORD *count = context; + *count = *count + 1; + return DIENUM_CONTINUE; +} + +static void check_dinput_devices( DWORD version, DIDEVICEINSTANCEW *devinst ) +{ + IDirectInput8W *di8; + IDirectInputW *di; + ULONG count; + HRESULT hr; + + if (version >= 0x800) + { + hr = DirectInput8Create( instance, version, &IID_IDirectInput8W, (void **)&di8, NULL ); + ok( hr == DI_OK, "DirectInput8Create returned %#x\n", hr ); + + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_ALL, NULL, NULL, DIEDFL_ALLDEVICES ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_ALL, enum_device_count, &count, 0xdeadbeef ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + hr = IDirectInput8_EnumDevices( di8, 0xdeadbeef, enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + + count = 0; + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_ALL, enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 3, "got count %u, expected 0\n", count ); + count = 0; + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_DEVICE, enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 0, "got count %u, expected 0\n", count ); + count = 0; + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_POINTER, enum_device_count, &count, + DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + todo_wine + ok( count == 3, "got count %u, expected 3\n", count ); + count = 0; + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_KEYBOARD, enum_device_count, &count, + DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + todo_wine + ok( count == 3, "got count %u, expected 3\n", count ); + count = 0; + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_GAMECTRL, enum_device_count, &count, + DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 1, "got count %u, expected 1\n", count ); + + count = 0; + hr = IDirectInput8_EnumDevices( di8, (devinst->dwDevType & 0xff), enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 1, "got count %u, expected 1\n", count ); + + count = 0; + hr = IDirectInput8_EnumDevices( di8, (devinst->dwDevType & 0xff), enum_device_count, &count, DIEDFL_FORCEFEEDBACK ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + if (IsEqualGUID( &devinst->guidFFDriver, &GUID_NULL )) ok( count == 0, "got count %u, expected 0\n", count ); + else ok( count == 1, "got count %u, expected 1\n", count ); + + count = 0; + hr = IDirectInput8_EnumDevices( di8, (devinst->dwDevType & 0xff) + 1, enum_device_count, &count, DIEDFL_ALLDEVICES ); + if ((devinst->dwDevType & 0xff) != DI8DEVTYPE_SUPPLEMENTAL) ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + else ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + ok( count == 0, "got count %u, expected 0\n", count ); + } + else + { + hr = DirectInputCreateEx( instance, version, &IID_IDirectInput2W, (void **)&di, NULL ); + ok( hr == DI_OK, "DirectInputCreateEx returned %#x\n", hr ); + + hr = IDirectInput_EnumDevices( di, 0, NULL, NULL, DIEDFL_ALLDEVICES ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + hr = IDirectInput_EnumDevices( di, 0, enum_device_count, &count, 0xdeadbeef ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + hr = IDirectInput_EnumDevices( di, 0xdeadbeef, enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + hr = IDirectInput_EnumDevices( di, 0, enum_device_count, &count, DIEDFL_INCLUDEHIDDEN ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + + count = 0; + hr = IDirectInput_EnumDevices( di, 0, enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 3, "got count %u, expected 0\n", count ); + count = 0; + hr = IDirectInput_EnumDevices( di, DIDEVTYPE_DEVICE, enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 0, "got count %u, expected 0\n", count ); + count = 0; + hr = IDirectInput_EnumDevices( di, DIDEVTYPE_MOUSE, enum_device_count, &count, + DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + todo_wine + ok( count == 3, "got count %u, expected 3\n", count ); + count = 0; + hr = IDirectInput_EnumDevices( di, DIDEVTYPE_KEYBOARD, enum_device_count, &count, + DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + todo_wine + ok( count == 3, "got count %u, expected 3\n", count ); + count = 0; + hr = IDirectInput_EnumDevices( di, DIDEVTYPE_JOYSTICK, enum_device_count, &count, + DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 1, "got count %u, expected 1\n", count ); + + count = 0; + hr = IDirectInput_EnumDevices( di, (devinst->dwDevType & 0xff), enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 1, "got count %u, expected 1\n", count ); + + count = 0; + hr = IDirectInput_EnumDevices( di, (devinst->dwDevType & 0xff), enum_device_count, &count, DIEDFL_FORCEFEEDBACK ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + if (IsEqualGUID( &devinst->guidFFDriver, &GUID_NULL )) ok( count == 0, "got count %u, expected 0\n", count ); + else ok( count == 1, "got count %u, expected 1\n", count ); + + hr = IDirectInput_EnumDevices( di, 0x14, enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + } +} + +static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWORD version ) +{ + struct hid_expect expect_download[] = + { + /* 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,0x01,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0xd5}, + }, + /* start command when DIEP_START is set */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .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[] = + { + /* 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}, + }, + }; + struct hid_expect expect_set_envelope[] = + { + /* set envelope */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 6, + .report_len = 7, + .report_buf = {0x06, 0x19, 0x4c, 0x01, 0x00, 0x04, 0x00}, + }, + }; + struct hid_expect expect_start = + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {0x02, 0x01, 0x01, 0x01}, + }; + struct hid_expect expect_start_solo = + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {0x02, 0x01, 0x02, 0x01}, + }; + struct hid_expect expect_start_0 = + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {0x02, 0x01, 0x01, 0x00}, + }; + struct hid_expect expect_start_4 = + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {0x02, 0x01, 0x01, 0x04}, + }; + struct hid_expect expect_stop = + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {0x02, 0x01, 0x03, 0x00}, + }; + struct hid_expect expect_unload[] = + { + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {0x02,0x01,0x03,0x00}, + }, + /* device reset, when unloaded from Unacquire */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1,0x01}, + }, + }; + 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}, + }, + }; + 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 = + { + .dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5), + .dwTriggerButton = -1, + .rgdwAxes = (void *)expect_axes_init, + }; + static const DWORD expect_axes[3] = + { + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ) | DIDFT_FFACTUATOR, + }; + static const LONG expect_directions[3] = + { + +3000, + -6000, + 0, + }; + static const DIENVELOPE expect_envelope = + { + .dwSize = sizeof(DIENVELOPE), + .dwAttackLevel = 1000, + .dwAttackTime = 2000, + .dwFadeLevel = 3000, + .dwFadeTime = 4000, + }; + static const DIPERIODIC expect_periodic = + { + .dwMagnitude = 1000, + .lOffset = 2000, + .dwPhase = 3000, + .dwPeriod = 4000, + }; + const DIEFFECT expect_desc = + { + .dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5), + .dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS, + .dwDuration = 1000, + .dwSamplePeriod = 2000, + .dwGain = 3000, + .dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER, + .dwTriggerRepeatInterval = 5000, + .cAxes = 3, + .rgdwAxes = (void *)expect_axes, + .rglDirection = (void *)expect_directions, + .lpEnvelope = (void *)&expect_envelope, + .cbTypeSpecificParams = sizeof(DIPERIODIC), + .lpvTypeSpecificParams = (void *)&expect_periodic, + .dwStartDelay = 6000, + }; + struct check_created_effect_params check_params = {0}; + IDirectInputEffect *effect; + DIPERIODIC periodic = {0}; + DIENVELOPE envelope = {0}; + LONG directions[4] = {0}; + DIEFFECT desc = {0}; + DWORD axes[4] = {0}; + ULONG i, ref, flags; + HRESULT hr; + GUID guid; + + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, NULL, NULL ); + ok( hr == E_POINTER, "CreateEffect returned %#x\n", hr ); + hr = IDirectInputDevice8_CreateEffect( device, NULL, NULL, &effect, NULL ); + ok( hr == E_POINTER, "CreateEffect returned %#x\n", hr ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_NULL, NULL, &effect, NULL ); + ok( hr == DIERR_DEVICENOTREG, "CreateEffect returned %#x\n", hr ); + + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); + if (hr != DI_OK) return; + + hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, check_no_created_effect_objects, effect, 0xdeadbeef ); + ok( hr == DIERR_INVALIDPARAM, "EnumCreatedEffectObjects returned %#x\n", hr ); + check_params.expect_effect = effect; + hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, check_created_effect_objects, &check_params, 0 ); + ok( hr == DI_OK, "EnumCreatedEffectObjects returned %#x\n", hr ); + ok( check_params.count == 1, "got count %u, expected 1\n", check_params.count ); + + hr = IDirectInputEffect_Initialize( effect, NULL, version, &GUID_Sine ); + ok( hr == DIERR_INVALIDPARAM, "Initialize returned %#x\n", hr ); + hr = IDirectInputEffect_Initialize( effect, instance, 0x800 - (version - 0x700), &GUID_Sine ); + if (version == 0x800) + { + todo_wine + ok( hr == DIERR_BETADIRECTINPUTVERSION, "Initialize returned %#x\n", hr ); + } + else + { + todo_wine + ok( hr == DIERR_OLDDIRECTINPUTVERSION, "Initialize returned %#x\n", hr ); + } + hr = IDirectInputEffect_Initialize( effect, instance, 0, &GUID_Sine ); + todo_wine + ok( hr == DIERR_NOTINITIALIZED, "Initialize returned %#x\n", hr ); + hr = IDirectInputEffect_Initialize( effect, instance, version, NULL ); + ok( hr == E_POINTER, "Initialize returned %#x\n", hr ); + + hr = IDirectInputEffect_Initialize( effect, instance, version, &GUID_NULL ); + ok( hr == DIERR_DEVICENOTREG, "Initialize returned %#x\n", hr ); + hr = IDirectInputEffect_Initialize( effect, instance, version, &GUID_Sine ); + ok( hr == DI_OK, "Initialize returned %#x\n", hr ); + hr = IDirectInputEffect_Initialize( effect, instance, version, &GUID_Square ); + ok( hr == DI_OK, "Initialize returned %#x\n", hr ); + + hr = IDirectInputEffect_GetEffectGuid( effect, NULL ); + ok( hr == E_POINTER, "GetEffectGuid returned %#x\n", hr ); + hr = IDirectInputEffect_GetEffectGuid( effect, &guid ); + ok( hr == DI_OK, "GetEffectGuid returned %#x\n", hr ); + ok( IsEqualGUID( &guid, &GUID_Square ), "got guid %s, expected %s\n", debugstr_guid( &guid ), + debugstr_guid( &GUID_Square ) ); + + hr = IDirectInputEffect_GetParameters( effect, NULL, 0 ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + hr = IDirectInputEffect_GetParameters( effect, NULL, DIEP_DURATION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + hr = IDirectInputEffect_GetParameters( effect, &desc, 0 ); + ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); + desc.dwSize = sizeof(DIEFFECT_DX5) + 2; + hr = IDirectInputEffect_GetParameters( effect, &desc, 0 ); + ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); + desc.dwSize = sizeof(DIEFFECT_DX5); + hr = IDirectInputEffect_GetParameters( effect, &desc, 0 ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_STARTDELAY ); + ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); + desc.dwSize = sizeof(DIEFFECT_DX6); + hr = IDirectInputEffect_GetParameters( effect, &desc, 0 ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + + 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_acquire, sizeof(expect_acquire) ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ + + desc.dwDuration = 0xdeadbeef; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DURATION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc_init, "%u", dwDuration ); + memset( &desc, 0xcd, sizeof(desc) ); + desc.dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5); + desc.dwFlags = 0; + desc.dwStartDelay = 0xdeadbeef; + flags = DIEP_GAIN | DIEP_SAMPLEPERIOD | DIEP_TRIGGERREPEATINTERVAL | + (version >= 0x700 ? DIEP_STARTDELAY : 0); + hr = IDirectInputEffect_GetParameters( effect, &desc, flags ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc_init, "%u", dwSamplePeriod ); + check_member( desc, expect_desc_init, "%u", dwGain ); + if (version >= 0x700) check_member( desc, expect_desc_init, "%u", dwStartDelay ); + else ok( desc.dwStartDelay == 0xdeadbeef, "got dwStartDelay %#x\n", desc.dwStartDelay ); + check_member( desc, expect_desc_init, "%u", dwTriggerRepeatInterval ); + + memset( &desc, 0xcd, sizeof(desc) ); + desc.dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5); + desc.dwFlags = 0; + desc.lpEnvelope = NULL; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ENVELOPE ); + ok( hr == E_POINTER, "GetParameters returned %#x\n", hr ); + desc.lpEnvelope = &envelope; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ENVELOPE ); + ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); + envelope.dwSize = sizeof(DIENVELOPE); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ENVELOPE ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + + desc.dwFlags = 0; + desc.cAxes = 0; + desc.rgdwAxes = NULL; + desc.rglDirection = NULL; + desc.lpEnvelope = NULL; + desc.cbTypeSpecificParams = 0; + desc.lpvTypeSpecificParams = NULL; + hr = IDirectInputEffect_GetParameters( effect, &desc, version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5 ); + ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TRIGGERBUTTON ); + ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES ); + ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); + desc.dwFlags = DIEFF_OBJECTOFFSETS; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TRIGGERBUTTON ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc_init, "%#x", dwTriggerButton ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc_init, "%u", cAxes ); + desc.dwFlags = DIEFF_OBJECTIDS; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TRIGGERBUTTON ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc_init, "%#x", dwTriggerButton ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc_init, "%u", cAxes ); + desc.dwFlags |= DIEFF_CARTESIAN; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + ok( desc.dwFlags == DIEFF_OBJECTIDS, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_OBJECTIDS ); + desc.dwFlags |= DIEFF_POLAR; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); + ok( desc.dwFlags == DIEFF_OBJECTIDS, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_OBJECTIDS ); + desc.dwFlags |= DIEFF_SPHERICAL; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc_init, "%u", cAxes ); + ok( desc.dwFlags == DIEFF_OBJECTIDS, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_OBJECTIDS ); + + desc.dwFlags |= DIEFF_SPHERICAL; + desc.cAxes = 2; + desc.rgdwAxes = axes; + desc.rglDirection = directions; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES | DIEP_DIRECTION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc_init, "%u", cAxes ); + check_member( desc, expect_desc_init, "%u", rgdwAxes[0] ); + check_member( desc, expect_desc_init, "%u", rgdwAxes[1] ); + check_member( desc, expect_desc_init, "%p", rglDirection ); + ok( desc.dwFlags == DIEFF_OBJECTIDS, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_OBJECTIDS ); + + desc.dwFlags |= DIEFF_SPHERICAL; + desc.lpEnvelope = &envelope; + desc.cbTypeSpecificParams = sizeof(periodic); + desc.lpvTypeSpecificParams = &periodic; + hr = IDirectInputEffect_GetParameters( effect, &desc, version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5 ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc_init, "%u", dwDuration ); + check_member( desc, expect_desc_init, "%u", dwSamplePeriod ); + check_member( desc, expect_desc_init, "%u", dwGain ); + check_member( desc, expect_desc_init, "%#x", dwTriggerButton ); + check_member( desc, expect_desc_init, "%u", dwTriggerRepeatInterval ); + check_member( desc, expect_desc_init, "%u", cAxes ); + check_member( desc, expect_desc_init, "%u", rgdwAxes[0] ); + check_member( desc, expect_desc_init, "%u", rgdwAxes[1] ); + check_member( desc, expect_desc_init, "%p", rglDirection ); + check_member( desc, expect_desc_init, "%p", lpEnvelope ); + check_member( desc, expect_desc_init, "%u", cbTypeSpecificParams ); + 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_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_acquire, sizeof(expect_acquire) ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ + + hr = IDirectInputEffect_Download( effect ); + ok( hr == DIERR_INCOMPLETEEFFECT, "Download returned %#x\n", hr ); + hr = IDirectInputEffect_Unload( effect ); + ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); + + hr = IDirectInputEffect_SetParameters( effect, NULL, DIEP_NODOWNLOAD ); + ok( hr == E_POINTER, "SetParameters returned %#x\n", hr ); + memset( &desc, 0, sizeof(desc) ); + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_NODOWNLOAD ); + ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); + desc.dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5); + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_NODOWNLOAD ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + + 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_acquire, sizeof(expect_acquire) ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); + 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 ); + + desc.dwTriggerButton = -1; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DURATION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc, "%u", dwDuration ); + check_member( desc, expect_desc_init, "%u", dwSamplePeriod ); + check_member( desc, expect_desc_init, "%u", dwGain ); + check_member( desc, expect_desc_init, "%#x", dwTriggerButton ); + check_member( desc, expect_desc_init, "%u", dwTriggerRepeatInterval ); + check_member( desc, expect_desc_init, "%u", cAxes ); + check_member( desc, expect_desc_init, "%p", rglDirection ); + check_member( desc, expect_desc_init, "%p", lpEnvelope ); + check_member( desc, expect_desc_init, "%u", cbTypeSpecificParams ); + check_member( desc, expect_desc_init, "%u", dwStartDelay ); + + hr = IDirectInputEffect_Download( effect ); + ok( hr == DIERR_INCOMPLETEEFFECT, "Download returned %#x\n", hr ); + hr = IDirectInputEffect_Unload( effect ); + ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); + + flags = DIEP_GAIN | DIEP_SAMPLEPERIOD | DIEP_TRIGGERREPEATINTERVAL | DIEP_NODOWNLOAD; + if (version >= 0x700) flags |= DIEP_STARTDELAY; + hr = IDirectInputEffect_SetParameters( effect, &expect_desc, flags ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + desc.dwDuration = 0; + flags = DIEP_DURATION | DIEP_GAIN | DIEP_SAMPLEPERIOD | DIEP_TRIGGERREPEATINTERVAL; + if (version >= 0x700) flags |= DIEP_STARTDELAY; + hr = IDirectInputEffect_GetParameters( effect, &desc, flags ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc, "%u", dwDuration ); + check_member( desc, expect_desc, "%u", dwSamplePeriod ); + check_member( desc, expect_desc, "%u", dwGain ); + check_member( desc, expect_desc_init, "%#x", dwTriggerButton ); + check_member( desc, expect_desc, "%u", dwTriggerRepeatInterval ); + check_member( desc, expect_desc_init, "%u", cAxes ); + check_member( desc, expect_desc_init, "%p", rglDirection ); + check_member( desc, expect_desc_init, "%p", lpEnvelope ); + check_member( desc, expect_desc_init, "%u", cbTypeSpecificParams ); + if (version >= 0x700) check_member( desc, expect_desc, "%u", dwStartDelay ); + else ok( desc.dwStartDelay == 0, "got dwStartDelay %#x\n", desc.dwStartDelay ); + + hr = IDirectInputEffect_Download( effect ); + ok( hr == DIERR_INCOMPLETEEFFECT, "Download returned %#x\n", hr ); + hr = IDirectInputEffect_Unload( effect ); + ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); + + desc.lpEnvelope = NULL; + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_ENVELOPE | DIEP_NODOWNLOAD ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + desc.lpEnvelope = &envelope; + envelope.dwSize = 0; + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_ENVELOPE | DIEP_NODOWNLOAD ); + ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); + + hr = IDirectInputEffect_SetParameters( effect, &expect_desc, DIEP_ENVELOPE | DIEP_NODOWNLOAD ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + + desc.lpEnvelope = &envelope; + envelope.dwSize = sizeof(DIENVELOPE); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ENVELOPE ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( envelope, expect_envelope, "%u", dwAttackLevel ); + check_member( envelope, expect_envelope, "%u", dwAttackTime ); + check_member( envelope, expect_envelope, "%u", dwFadeLevel ); + check_member( envelope, expect_envelope, "%u", dwFadeTime ); + + hr = IDirectInputEffect_Download( effect ); + ok( hr == DIERR_INCOMPLETEEFFECT, "Download returned %#x\n", hr ); + hr = IDirectInputEffect_Unload( effect ); + ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); + + desc.dwFlags = 0; + desc.cAxes = 0; + desc.rgdwAxes = NULL; + desc.rglDirection = NULL; + desc.lpEnvelope = NULL; + desc.cbTypeSpecificParams = 0; + desc.lpvTypeSpecificParams = NULL; + flags = version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5; + hr = IDirectInputEffect_SetParameters( effect, &desc, flags | DIEP_NODOWNLOAD ); + ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_TRIGGERBUTTON | DIEP_NODOWNLOAD ); + ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_AXES | DIEP_NODOWNLOAD ); + ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); + + desc.dwFlags = DIEFF_OBJECTOFFSETS; + desc.cAxes = 1; + desc.rgdwAxes = axes; + desc.rgdwAxes[0] = DIJOFS_X; + desc.dwTriggerButton = DIJOFS_BUTTON( 1 ); + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_DIRECTION | DIEP_NODOWNLOAD ); + ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); + hr = IDirectInputEffect_SetParameters( effect, &expect_desc, DIEP_AXES | DIEP_TRIGGERBUTTON | DIEP_NODOWNLOAD ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_AXES | DIEP_TRIGGERBUTTON | DIEP_NODOWNLOAD ); + ok( hr == DIERR_ALREADYINITIALIZED, "SetParameters returned %#x\n", hr ); + + desc.cAxes = 0; + desc.dwFlags = DIEFF_OBJECTIDS; + desc.rgdwAxes = axes; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES | DIEP_TRIGGERBUTTON ); + ok( hr == DIERR_MOREDATA, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc, "%u", cAxes ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES | DIEP_TRIGGERBUTTON ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc, "%#x", dwTriggerButton ); + check_member( desc, expect_desc, "%u", cAxes ); + check_member( desc, expect_desc, "%u", rgdwAxes[0] ); + check_member( desc, expect_desc, "%u", rgdwAxes[1] ); + check_member( desc, expect_desc, "%u", rgdwAxes[2] ); + + desc.dwFlags = DIEFF_OBJECTOFFSETS; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES | DIEP_TRIGGERBUTTON ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + ok( desc.dwTriggerButton == 0x30, "got %#x expected %#x\n", desc.dwTriggerButton, 0x30 ); + ok( desc.rgdwAxes[0] == 8, "got %#x expected %#x\n", desc.rgdwAxes[0], 8 ); + ok( desc.rgdwAxes[1] == 0, "got %#x expected %#x\n", desc.rgdwAxes[1], 0 ); + ok( desc.rgdwAxes[2] == 4, "got %#x expected %#x\n", desc.rgdwAxes[2], 4 ); + + hr = IDirectInputEffect_Download( effect ); + ok( hr == DIERR_INCOMPLETEEFFECT, "Download returned %#x\n", hr ); + hr = IDirectInputEffect_Unload( effect ); + ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); + + desc.dwFlags = DIEFF_CARTESIAN; + desc.cAxes = 0; + desc.rglDirection = directions; + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_DIRECTION | DIEP_NODOWNLOAD ); + ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); + desc.cAxes = 3; + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_DIRECTION | DIEP_NODOWNLOAD ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + desc.dwFlags = DIEFF_POLAR; + desc.cAxes = 3; + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_DIRECTION | DIEP_NODOWNLOAD ); + ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); + + hr = IDirectInputEffect_SetParameters( effect, &expect_desc, DIEP_DIRECTION | DIEP_NODOWNLOAD ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + + desc.dwFlags = DIEFF_SPHERICAL; + desc.cAxes = 1; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DIERR_MOREDATA, "GetParameters returned %#x\n", hr ); + ok( desc.dwFlags == DIEFF_SPHERICAL, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_SPHERICAL ); + check_member( desc, expect_desc, "%u", cAxes ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc, "%u", cAxes ); + ok( desc.rglDirection[0] == 3000, "got rglDirection[0] %d expected %d\n", desc.rglDirection[0], 3000 ); + ok( desc.rglDirection[1] == 30000, "got rglDirection[1] %d expected %d\n", desc.rglDirection[1], 30000 ); + ok( desc.rglDirection[2] == 0, "got rglDirection[2] %d expected %d\n", desc.rglDirection[2], 0 ); + desc.dwFlags = DIEFF_CARTESIAN; + desc.cAxes = 2; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DIERR_MOREDATA, "GetParameters returned %#x\n", hr ); + ok( desc.dwFlags == DIEFF_CARTESIAN, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_CARTESIAN ); + check_member( desc, expect_desc, "%u", cAxes ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc, "%u", cAxes ); + ok( desc.rglDirection[0] == 4330, "got rglDirection[0] %d expected %d\n", desc.rglDirection[0], 4330 ); + ok( desc.rglDirection[1] == 2500, "got rglDirection[1] %d expected %d\n", desc.rglDirection[1], 2500 ); + ok( desc.rglDirection[2] == -8660, "got rglDirection[2] %d expected %d\n", desc.rglDirection[2], -8660 ); + desc.dwFlags = DIEFF_POLAR; + desc.cAxes = 3; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); + + hr = IDirectInputEffect_Download( effect ); + ok( hr == DIERR_INCOMPLETEEFFECT, "Download returned %#x\n", hr ); + hr = IDirectInputEffect_Unload( effect ); + ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); + + desc.cbTypeSpecificParams = 0; + desc.lpvTypeSpecificParams = &periodic; + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS | DIEP_NODOWNLOAD ); + ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); + desc.cbTypeSpecificParams = sizeof(DIPERIODIC); + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS | DIEP_NODOWNLOAD ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + hr = IDirectInputEffect_SetParameters( effect, &expect_desc, DIEP_TYPESPECIFICPARAMS | DIEP_NODOWNLOAD ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( periodic, expect_periodic, "%u", dwMagnitude ); + check_member( periodic, expect_periodic, "%d", lOffset ); + check_member( periodic, expect_periodic, "%u", dwPhase ); + check_member( periodic, expect_periodic, "%u", dwPeriod ); + + hr = IDirectInputEffect_Start( effect, 1, DIES_NODOWNLOAD ); + ok( hr == DIERR_NOTDOWNLOADED, "Start returned %#x\n", hr ); + hr = IDirectInputEffect_Stop( effect ); + ok( hr == DIERR_NOTDOWNLOADED, "Stop returned %#x\n", hr ); + + set_hid_expect( file, expect_download, 3 * sizeof(struct hid_expect) ); + hr = IDirectInputEffect_Download( effect ); + ok( hr == DI_OK, "Download returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + hr = IDirectInputEffect_Download( effect ); + ok( hr == DI_NOEFFECT, "Download returned %#x\n", hr ); + + hr = IDirectInputEffect_Start( effect, 1, 0xdeadbeef ); + ok( hr == DIERR_INVALIDPARAM, "Start returned %#x\n", hr ); + + set_hid_expect( file, &expect_start_solo, sizeof(expect_start_solo) ); + hr = IDirectInputEffect_Start( effect, 1, DIES_SOLO ); + ok( hr == DI_OK, "Start returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_stop, sizeof(expect_stop) ); + hr = IDirectInputEffect_Stop( effect ); + ok( hr == DI_OK, "Stop returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_start, sizeof(expect_start) ); + hr = IDirectInputEffect_Start( effect, 1, 0 ); + ok( hr == DI_OK, "Start returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_start_4, sizeof(expect_start_4) ); + hr = IDirectInputEffect_Start( effect, 4, 0 ); + ok( hr == DI_OK, "Start returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_start_0, sizeof(expect_start_4) ); + hr = IDirectInputEffect_Start( effect, 0, 0 ); + ok( hr == DI_OK, "Start returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_unload, sizeof(struct hid_expect) ); + hr = IDirectInputEffect_Unload( effect ); + ok( hr == DI_OK, "Unload returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_download, 4 * sizeof(struct hid_expect) ); + hr = IDirectInputEffect_SetParameters( effect, &expect_desc, DIEP_START ); + ok( hr == DI_OK, "SetParameters returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_unload, sizeof(struct hid_expect) ); + hr = IDirectInputEffect_Unload( effect ); + ok( hr == DI_OK, "Unload returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_download, 3 * sizeof(struct hid_expect) ); + hr = IDirectInputEffect_Download( effect ); + ok( hr == DI_OK, "Download returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_unload, 2 * sizeof(struct hid_expect) ); + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + hr = IDirectInputEffect_Start( effect, 1, DIES_NODOWNLOAD ); + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "Start returned %#x\n", hr ); + hr = IDirectInputEffect_Stop( effect ); + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "Stop returned %#x\n", hr ); + + set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ + + hr = IDirectInputEffect_Unload( effect ); + ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); + + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %d\n", ref ); + + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); + + desc.dwFlags = DIEFF_POLAR | DIEFF_OBJECTIDS; + desc.cAxes = 2; + desc.rgdwAxes[0] = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR; + desc.rgdwAxes[1] = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFACTUATOR; + desc.rglDirection[0] = 3000; + desc.rglDirection[1] = 0; + desc.rglDirection[2] = 0; + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_AXES | DIEP_DIRECTION | DIEP_NODOWNLOAD ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + desc.rglDirection[0] = 0; + + desc.dwFlags = DIEFF_SPHERICAL; + desc.cAxes = 1; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DIERR_MOREDATA, "GetParameters returned %#x\n", hr ); + ok( desc.dwFlags == DIEFF_SPHERICAL, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_SPHERICAL ); + ok( desc.cAxes == 2, "got cAxes %u expected 2\n", desc.cAxes ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + ok( desc.cAxes == 2, "got cAxes %u expected 2\n", desc.cAxes ); + ok( desc.rglDirection[0] == 30000, "got rglDirection[0] %d expected %d\n", desc.rglDirection[0], 30000 ); + ok( desc.rglDirection[1] == 0, "got rglDirection[1] %d expected %d\n", desc.rglDirection[1], 0 ); + ok( desc.rglDirection[2] == 0, "got rglDirection[2] %d expected %d\n", desc.rglDirection[2], 0 ); + + desc.dwFlags = DIEFF_CARTESIAN; + desc.cAxes = 1; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DIERR_MOREDATA, "GetParameters returned %#x\n", hr ); + ok( desc.dwFlags == DIEFF_CARTESIAN, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_CARTESIAN ); + ok( desc.cAxes == 2, "got cAxes %u expected 2\n", desc.cAxes ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + ok( desc.cAxes == 2, "got cAxes %u expected 2\n", desc.cAxes ); + ok( desc.rglDirection[0] == 5000, "got rglDirection[0] %d expected %d\n", desc.rglDirection[0], 5000 ); + ok( desc.rglDirection[1] == -8660, "got rglDirection[1] %d expected %d\n", desc.rglDirection[1], -8660 ); + ok( desc.rglDirection[2] == 0, "got rglDirection[2] %d expected %d\n", desc.rglDirection[2], 0 ); + + desc.dwFlags = DIEFF_POLAR; + desc.cAxes = 1; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DIERR_MOREDATA, "GetParameters returned %#x\n", hr ); + ok( desc.dwFlags == DIEFF_POLAR, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_POLAR ); + ok( desc.cAxes == 2, "got cAxes %u expected 2\n", desc.cAxes ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + ok( desc.cAxes == 2, "got cAxes %u expected 2\n", desc.cAxes ); + ok( desc.rglDirection[0] == 3000, "got rglDirection[0] %d expected %d\n", desc.rglDirection[0], 3000 ); + ok( desc.rglDirection[1] == 0, "got rglDirection[1] %d expected %d\n", desc.rglDirection[1], 0 ); + ok( desc.rglDirection[2] == 0, "got rglDirection[2] %d expected %d\n", desc.rglDirection[2], 0 ); + + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %d\n", ref ); + + for (i = 1; i < 4; i++) + { + struct hid_expect expect_directions[] = + { + /* 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 */ + {0}, + /* effect control */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {0x02,0x01,0x03,0x00}, + }, + }; + struct hid_expect expect_spherical = + { + .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, + i >= 2 ? 0x55 : 0, i >= 3 ? 0x1c : 0 }, + }; + struct hid_expect expect_cartesian = + { + .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, i >= 2 ? 0x63 : 0, i >= 3 ? 0x1d : 0}, + }; + struct hid_expect expect_polar = + { + .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, i >= 2 ? 0x3f : 0, i >= 3 ? 0x00 : 0}, + }; + + winetest_push_context( "%u axes", i ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); + + desc.dwFlags = DIEFF_OBJECTIDS; + desc.cAxes = i; + desc.rgdwAxes[0] = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR; + desc.rgdwAxes[1] = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFACTUATOR; + desc.rgdwAxes[2] = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ) | DIDFT_FFACTUATOR; + desc.rglDirection[0] = 0; + desc.rglDirection[1] = 0; + desc.rglDirection[2] = 0; + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_AXES | DIEP_NODOWNLOAD ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + + desc.dwFlags = DIEFF_CARTESIAN; + desc.cAxes = i == 3 ? 2 : 3; + desc.rglDirection[0] = 1000; + desc.rglDirection[1] = 2000; + desc.rglDirection[2] = 3000; + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_DIRECTION | DIEP_NODOWNLOAD ); + ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); + desc.cAxes = i; + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_DIRECTION | DIEP_NODOWNLOAD ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + + desc.dwFlags = DIEFF_SPHERICAL; + desc.cAxes = i; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + desc.cAxes = 3; + memset( desc.rglDirection, 0xcd, 3 * sizeof(LONG) ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + ok( desc.cAxes == i, "got cAxes %u expected 2\n", desc.cAxes ); + if (i == 1) + { + ok( desc.rglDirection[0] == 0, "got rglDirection[0] %d expected %d\n", desc.rglDirection[0], 0 ); + ok( desc.rglDirection[1] == 0xcdcdcdcd, "got rglDirection[1] %d expected %d\n", + desc.rglDirection[1], 0xcdcdcdcd ); + ok( desc.rglDirection[2] == 0xcdcdcdcd, "got rglDirection[2] %d expected %d\n", + desc.rglDirection[2], 0xcdcdcdcd ); + } + else + { + ok( desc.rglDirection[0] == 6343, "got rglDirection[0] %d expected %d\n", + desc.rglDirection[0], 6343 ); + if (i == 2) + { + ok( desc.rglDirection[1] == 0, "got rglDirection[1] %d expected %d\n", + desc.rglDirection[1], 0 ); + ok( desc.rglDirection[2] == 0xcdcdcdcd, "got rglDirection[2] %d expected %d\n", + desc.rglDirection[2], 0xcdcdcdcd ); + } + else + { + ok( desc.rglDirection[1] == 5330, "got rglDirection[1] %d expected %d\n", + desc.rglDirection[1], 5330 ); + ok( desc.rglDirection[2] == 0, "got rglDirection[2] %d expected %d\n", + desc.rglDirection[2], 0 ); + } + } + + desc.dwFlags = DIEFF_CARTESIAN; + desc.cAxes = i; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + desc.cAxes = 3; + memset( desc.rglDirection, 0xcd, 3 * sizeof(LONG) ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + ok( desc.cAxes == i, "got cAxes %u expected 2\n", desc.cAxes ); + ok( desc.rglDirection[0] == 1000, "got rglDirection[0] %d expected %d\n", desc.rglDirection[0], 1000 ); + if (i == 1) + ok( desc.rglDirection[1] == 0xcdcdcdcd, "got rglDirection[1] %d expected %d\n", + desc.rglDirection[1], 0xcdcdcdcd ); + else + ok( desc.rglDirection[1] == 2000, "got rglDirection[1] %d expected %d\n", + desc.rglDirection[1], 2000 ); + if (i <= 2) + ok( desc.rglDirection[2] == 0xcdcdcdcd, "got rglDirection[2] %d expected %d\n", + desc.rglDirection[2], 0xcdcdcdcd ); + else + ok( desc.rglDirection[2] == 3000, "got rglDirection[2] %d expected %d\n", + desc.rglDirection[2], 3000 ); + + desc.dwFlags = DIEFF_POLAR; + desc.cAxes = 1; + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + if (i != 2) ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); + else ok( hr == DIERR_MOREDATA, "GetParameters returned %#x\n", hr ); + desc.cAxes = 3; + memset( desc.rglDirection, 0xcd, 3 * sizeof(LONG) ); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); + if (i != 2) ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); + else + { + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + ok( desc.cAxes == i, "got cAxes %u expected 2\n", desc.cAxes ); + ok( desc.rglDirection[0] == 15343, "got rglDirection[0] %d expected %d\n", + desc.rglDirection[0], 15343 ); + ok( desc.rglDirection[1] == 0, "got rglDirection[1] %d expected %d\n", desc.rglDirection[1], 0 ); + ok( desc.rglDirection[2] == 0xcdcdcdcd, "got rglDirection[2] %d expected %d\n", + desc.rglDirection[2], 0xcdcdcdcd ); + } + + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %d\n", ref ); + + desc = expect_desc; + desc.dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS; + desc.cAxes = i; + desc.rgdwAxes = axes; + desc.rglDirection = directions; + desc.rglDirection[0] = 3000; + desc.rglDirection[1] = 4000; + desc.rglDirection[2] = 5000; + flags = version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5; + expect_directions[2] = expect_spherical; + set_hid_expect( file, expect_directions, sizeof(expect_directions) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, &desc, &effect, NULL ); + 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, NULL, 0 ); + + desc = expect_desc; + desc.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTIDS; + desc.cAxes = i; + desc.rgdwAxes = axes; + desc.rglDirection = directions; + desc.rglDirection[0] = 6000; + desc.rglDirection[1] = 7000; + desc.rglDirection[2] = 8000; + flags = version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5; + expect_directions[2] = expect_cartesian; + set_hid_expect( file, expect_directions, sizeof(expect_directions) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, &desc, &effect, NULL ); + 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, NULL, 0 ); + + if (i == 2) + { + desc = expect_desc; + desc.dwFlags = DIEFF_POLAR | DIEFF_OBJECTIDS; + desc.cAxes = i; + desc.rgdwAxes = axes; + desc.rglDirection = directions; + desc.rglDirection[0] = 9000; + desc.rglDirection[1] = 10000; + desc.rglDirection[2] = 11000; + flags = version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5; + expect_directions[2] = expect_polar; + set_hid_expect( file, expect_directions, sizeof(expect_directions) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, &desc, &effect, NULL ); + 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, NULL, 0 ); + } + + 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.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 ); + set_hid_expect( file, NULL, 0 ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, &expect_desc, &effect, NULL ); + 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_acquire, sizeof(expect_acquire) ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ +} + +static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file, DWORD version ) +{ + struct hid_expect expect_create[] = + { + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 8, + .report_buf = {0x07,0x00,0xf9,0x19,0xd9,0xff,0xff,0x99}, + }, + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 8, + .report_buf = {0x07,0x00,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0x00}, + }, + }; + struct hid_expect expect_create_1[] = + { + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 8, + .report_buf = {0x07,0x00,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x3f,0x00}, + }, + }; + struct hid_expect expect_create_2[] = + { + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 8, + .report_buf = {0x07,0x00,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0xf1}, + }, + }; + struct hid_expect expect_create_3[] = + { + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 8, + .report_buf = {0x07,0x00,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0x00}, + }, + }; + struct hid_expect expect_destroy = + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {0x02, 0x01, 0x03, 0x00}, + }; + static const DWORD expect_axes[3] = + { + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ) | DIDFT_FFACTUATOR, + }; + static const LONG expect_directions[3] = { + +3000, + 0, + 0, + }; + static const DIENVELOPE expect_envelope = + { + .dwSize = sizeof(DIENVELOPE), + .dwAttackLevel = 1000, + .dwAttackTime = 2000, + .dwFadeLevel = 3000, + .dwFadeTime = 4000, + }; + static const DICONDITION expect_condition[3] = + { + { + .lOffset = -500, + .lPositiveCoefficient = 2000, + .lNegativeCoefficient = -3000, + .dwPositiveSaturation = -4000, + .dwNegativeSaturation = -5000, + .lDeadBand = 6000, + }, + { + .lOffset = 6000, + .lPositiveCoefficient = 5000, + .lNegativeCoefficient = -4000, + .dwPositiveSaturation = 3000, + .dwNegativeSaturation = 2000, + .lDeadBand = 1000, + }, + { + .lOffset = -7000, + .lPositiveCoefficient = -8000, + .lNegativeCoefficient = 9000, + .dwPositiveSaturation = 10000, + .dwNegativeSaturation = 11000, + .lDeadBand = -12000, + }, + }; + const DIEFFECT expect_desc = + { + .dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5), + .dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS, + .dwDuration = 1000, + .dwSamplePeriod = 2000, + .dwGain = 3000, + .dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER, + .dwTriggerRepeatInterval = 5000, + .cAxes = 2, + .rgdwAxes = (void *)expect_axes, + .rglDirection = (void *)expect_directions, + .lpEnvelope = (void *)&expect_envelope, + .cbTypeSpecificParams = 2 * sizeof(DICONDITION), + .lpvTypeSpecificParams = (void *)expect_condition, + .dwStartDelay = 6000, + }; + struct check_created_effect_params check_params = {0}; + DIENVELOPE envelope = {.dwSize = sizeof(DIENVELOPE)}; + DICONDITION condition[2] = {0}; + IDirectInputEffect *effect; + LONG directions[4] = {0}; + DWORD axes[4] = {0}; + DIEFFECT desc = + { + .dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5), + .dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS, + .cAxes = 4, + .rgdwAxes = axes, + .rglDirection = directions, + .lpEnvelope = &envelope, + .cbTypeSpecificParams = 2 * sizeof(DICONDITION), + .lpvTypeSpecificParams = condition, + }; + HRESULT hr; + ULONG ref; + GUID guid; + + set_hid_expect( file, expect_create, sizeof(expect_create) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &expect_desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + check_params.expect_effect = effect; + hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, check_created_effect_objects, &check_params, 0 ); + ok( hr == DI_OK, "EnumCreatedEffectObjects returned %#x\n", hr ); + ok( check_params.count == 1, "got count %u, expected 1\n", check_params.count ); + + hr = IDirectInputEffect_GetEffectGuid( effect, &guid ); + ok( hr == DI_OK, "GetEffectGuid returned %#x\n", hr ); + ok( IsEqualGUID( &guid, &GUID_Spring ), "got guid %s, expected %s\n", debugstr_guid( &guid ), + debugstr_guid( &GUID_Spring ) ); + + hr = IDirectInputEffect_GetParameters( effect, &desc, version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5 ); + ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); + check_member( desc, expect_desc, "%u", dwDuration ); + check_member( desc, expect_desc, "%u", dwSamplePeriod ); + check_member( desc, expect_desc, "%u", dwGain ); + check_member( desc, expect_desc, "%#x", dwTriggerButton ); + check_member( desc, expect_desc, "%u", dwTriggerRepeatInterval ); + check_member( desc, expect_desc, "%u", cAxes ); + check_member( desc, expect_desc, "%#x", rgdwAxes[0] ); + check_member( desc, expect_desc, "%#x", rgdwAxes[1] ); + check_member( desc, expect_desc, "%d", rglDirection[0] ); + check_member( desc, expect_desc, "%d", rglDirection[1] ); + check_member( desc, expect_desc, "%u", cbTypeSpecificParams ); + if (version >= 0x700) check_member( desc, expect_desc, "%u", dwStartDelay ); + else ok( desc.dwStartDelay == 0, "got dwStartDelay %#x\n", desc.dwStartDelay ); + check_member( envelope, expect_envelope, "%u", dwAttackLevel ); + check_member( envelope, expect_envelope, "%u", dwAttackTime ); + check_member( envelope, expect_envelope, "%u", dwFadeLevel ); + check_member( envelope, expect_envelope, "%u", dwFadeTime ); + check_member( condition[0], expect_condition[0], "%d", lOffset ); + check_member( condition[0], expect_condition[0], "%d", lPositiveCoefficient ); + check_member( condition[0], expect_condition[0], "%d", lNegativeCoefficient ); + check_member( condition[0], expect_condition[0], "%u", dwPositiveSaturation ); + check_member( condition[0], expect_condition[0], "%u", dwNegativeSaturation ); + check_member( condition[0], expect_condition[0], "%d", lDeadBand ); + check_member( condition[1], expect_condition[1], "%d", lOffset ); + check_member( condition[1], expect_condition[1], "%d", lPositiveCoefficient ); + check_member( condition[1], expect_condition[1], "%d", lNegativeCoefficient ); + check_member( condition[1], expect_condition[1], "%u", dwPositiveSaturation ); + check_member( condition[1], expect_condition[1], "%u", dwNegativeSaturation ); + check_member( condition[1], expect_condition[1], "%d", lDeadBand ); + + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %d\n", ref ); + set_hid_expect( file, NULL, 0 ); + + desc = expect_desc; + desc.cAxes = 1; + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); + ok( hr == DIERR_INVALIDPARAM, "CreateEffect returned %#x\n", hr ); + desc.cbTypeSpecificParams = 1 * sizeof(DICONDITION); + desc.lpvTypeSpecificParams = (void *)&expect_condition[1]; + set_hid_expect( file, expect_create_1, sizeof(expect_create_1) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %d\n", ref ); + set_hid_expect( file, NULL, 0 ); + + desc = expect_desc; + desc.cAxes = 3; + desc.rglDirection = directions; + desc.rglDirection[0] = +3000; + desc.rglDirection[1] = -2000; + desc.rglDirection[2] = +1000; + desc.cbTypeSpecificParams = 1 * sizeof(DICONDITION); + desc.lpvTypeSpecificParams = (void *)&expect_condition[1]; + set_hid_expect( file, expect_create_2, sizeof(expect_create_2) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %d\n", ref ); + set_hid_expect( file, NULL, 0 ); + + desc = expect_desc; + desc.cAxes = 2; + desc.rgdwAxes = axes; + desc.rgdwAxes[0] = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ) | DIDFT_FFACTUATOR; + desc.rgdwAxes[1] = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR; + desc.rglDirection = directions; + desc.rglDirection[0] = +3000; + desc.rglDirection[1] = -2000; + desc.cbTypeSpecificParams = 1 * sizeof(DICONDITION); + desc.lpvTypeSpecificParams = (void *)&expect_condition[1]; + set_hid_expect( file, expect_create_3, sizeof(expect_create_3) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %d\n", ref ); + set_hid_expect( file, NULL, 0 ); + + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, NULL, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); + desc = expect_desc; + desc.cAxes = 0; + desc.cbTypeSpecificParams = 1 * sizeof(DICONDITION); + desc.lpvTypeSpecificParams = (void *)&expect_condition[0]; + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS | DIEP_NODOWNLOAD ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + desc.cbTypeSpecificParams = 0 * sizeof(DICONDITION); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS ); + ok( hr == DIERR_MOREDATA, "SetParameters returned %#x\n", hr ); + ok( desc.cbTypeSpecificParams == 1 * sizeof(DICONDITION), "got %u\n", desc.cbTypeSpecificParams ); + desc.cbTypeSpecificParams = 0 * sizeof(DICONDITION); + hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS | DIEP_NODOWNLOAD ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + desc.cbTypeSpecificParams = 0 * sizeof(DICONDITION); + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS ); + ok( hr == DI_OK, "SetParameters returned %#x\n", hr ); + ok( desc.cbTypeSpecificParams == 0 * sizeof(DICONDITION), "got %u\n", desc.cbTypeSpecificParams ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %d\n", ref ); +} + +static BOOL test_force_feedback_joystick( DWORD version ) +{ +#include "psh_hid_macros.h" + const unsigned char report_descriptor[] = { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Report), + REPORT_ID(1, 1), + + USAGE(1, HID_USAGE_GENERIC_X), + USAGE(1, HID_USAGE_GENERIC_Y), + USAGE(1, HID_USAGE_GENERIC_Z), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 3), + INPUT(1, Data|Var|Abs), + + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 2), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 2), + INPUT(1, Data|Var|Abs), + REPORT_COUNT(1, 6), + INPUT(1, Cnst|Var|Abs), + END_COLLECTION, + + USAGE_PAGE(1, HID_USAGE_PAGE_PID), + USAGE(1, PID_USAGE_STATE_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 2), + + USAGE(1, PID_USAGE_DEVICE_PAUSED), + USAGE(1, PID_USAGE_ACTUATORS_ENABLED), + USAGE(1, PID_USAGE_SAFETY_SWITCH), + USAGE(1, PID_USAGE_ACTUATOR_OVERRIDE_SWITCH), + USAGE(1, PID_USAGE_ACTUATOR_POWER), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 5), + INPUT(1, Data|Var|Abs), + REPORT_COUNT(1, 3), + INPUT(1, Cnst|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_PLAYING), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MAXIMUM(1, 0x7f), + LOGICAL_MINIMUM(1, 0x00), + REPORT_SIZE(1, 7), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE_PAGE(1, HID_USAGE_PAGE_PID), + USAGE(1, PID_USAGE_DEVICE_CONTROL_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 1), + + USAGE(1, PID_USAGE_DEVICE_CONTROL), + COLLECTION(1, Logical), + USAGE(1, PID_USAGE_DC_DEVICE_RESET), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 2), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 2), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + END_COLLECTION, + + USAGE(1, PID_USAGE_EFFECT_OPERATION_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 2), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_OPERATION), + COLLECTION(1, NamedArray), + USAGE(1, PID_USAGE_OP_EFFECT_START), + USAGE(1, PID_USAGE_OP_EFFECT_START_SOLO), + USAGE(1, PID_USAGE_OP_EFFECT_STOP), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 3), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 3), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_LOOP_COUNT), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_SET_EFFECT_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 3), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_TYPE), + COLLECTION(1, NamedArray), + USAGE(1, PID_USAGE_ET_SQUARE), + USAGE(1, PID_USAGE_ET_SINE), + USAGE(1, PID_USAGE_ET_SPRING), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 3), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 3), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_AXES_ENABLE), + COLLECTION(1, Logical), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_X), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_Y), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_Z), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 3), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + USAGE(1, PID_USAGE_DIRECTION_ENABLE), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + REPORT_COUNT(1, 4), + OUTPUT(1, Cnst|Var|Abs), + + USAGE(1, PID_USAGE_DURATION), + USAGE(1, PID_USAGE_START_DELAY), + UNIT(2, 0x1003), /* Eng Lin:Time */ + UNIT_EXPONENT(1, -3), /* 10^-3 */ + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x7fff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x7fff), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + UNIT(1, 0), + UNIT_EXPONENT(1, 0), + + USAGE(1, PID_USAGE_TRIGGER_BUTTON), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 0x08), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 0x08), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_DIRECTION), + COLLECTION(1, Logical), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|1), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|2), + UNIT(1, 0x14), /* Eng Rot:Angular Pos */ + UNIT_EXPONENT(1, -2), /* 10^-2 */ + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(4, 0x00008ca0), + UNIT(1, 0), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + UNIT_EXPONENT(1, 0), + UNIT(1, 0), + END_COLLECTION, + END_COLLECTION, + + USAGE(1, PID_USAGE_SET_PERIODIC_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 5), + + USAGE(1, PID_USAGE_MAGNITUDE), + 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, + + USAGE(1, PID_USAGE_SET_ENVELOPE_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 6), + + USAGE(1, PID_USAGE_ATTACK_LEVEL), + USAGE(1, PID_USAGE_FADE_LEVEL), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_ATTACK_TIME), + USAGE(1, PID_USAGE_FADE_TIME), + UNIT(2, 0x1003), /* Eng Lin:Time */ + UNIT_EXPONENT(1, -3), /* 10^-3 */ + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x7fff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x7fff), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + PHYSICAL_MAXIMUM(1, 0), + UNIT_EXPONENT(1, 0), + UNIT(1, 0), + END_COLLECTION, + + + USAGE(1, PID_USAGE_SET_CONDITION_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 7), + + USAGE(1, PID_USAGE_TYPE_SPECIFIC_BLOCK_OFFSET), + COLLECTION(1, Logical), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|1), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|2), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 2), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + REPORT_SIZE(1, 4), + REPORT_COUNT(1, 1), + OUTPUT(1, Cnst|Var|Abs), + + USAGE(1, PID_USAGE_CP_OFFSET), + LOGICAL_MINIMUM(1, 0x80), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(2, 0xd8f0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_POSITIVE_COEFFICIENT), + USAGE(1, PID_USAGE_NEGATIVE_COEFFICIENT), + LOGICAL_MINIMUM(1, 0x80), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(2, 0xd8f0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_POSITIVE_SATURATION), + USAGE(1, PID_USAGE_NEGATIVE_SATURATION), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_DEAD_BAND), + 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, + + + 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 +#include "pop_hid_macros.h" + + static const HIDP_CAPS hid_caps = + { + .InputReportByteLength = 5, + }; + const DIDEVCAPS expect_caps = + { + .dwSize = sizeof(DIDEVCAPS), + .dwFlags = DIDC_FORCEFEEDBACK | DIDC_ATTACHED | DIDC_EMULATED | DIDC_STARTDELAY | + DIDC_FFFADE | DIDC_FFATTACK | DIDC_DEADBAND | DIDC_SATURATION, + .dwDevType = version >= 0x800 ? DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK + : DIDEVTYPE_HID | (DIDEVTYPEJOYSTICK_UNKNOWN << 8) | DIDEVTYPE_JOYSTICK, + .dwAxes = 3, + .dwButtons = 2, + .dwFFSamplePeriod = 1000000, + .dwFFMinTimeResolution = 1000000, + .dwHardwareRevision = 1, + .dwFFDriverVersion = 1, + }; + 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}, + }, + }; + 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 = 8, + .report_len = 2, + .report_buf = {8, 0x19}, + }; + struct hid_expect expect_set_device_gain_2 = + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 8, + .report_len = 2, + .report_buf = {8, 0x33}, + }; + + const DIDEVICEINSTANCEW expect_devinst = + { + .dwSize = sizeof(DIDEVICEINSTANCEW), + .guidInstance = expect_guid_product, + .guidProduct = expect_guid_product, + .dwDevType = version >= 0x800 ? DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK + : DIDEVTYPE_HID | (DIDEVTYPEJOYSTICK_UNKNOWN << 8) | DIDEVTYPE_JOYSTICK, + .tszInstanceName = L"Wine test root driver", + .tszProductName = L"Wine test root driver", + .guidFFDriver = IID_IDirectInputPIDDriver, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }; + const DIDEVICEOBJECTINSTANCEW expect_objects_5[] = + { + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_XAxis, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(0)|DIDFT_FFACTUATOR, + .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, + .tszName = L"X Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_X, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_YAxis, + .dwOfs = 0x4, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(1)|DIDFT_FFACTUATOR, + .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, + .tszName = L"Y Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_Y, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_ZAxis, + .dwOfs = 0x8, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(2)|DIDFT_FFACTUATOR, + .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, + .tszName = L"Z Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_Z, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Button, + .dwOfs = 0x30, + .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(0)|DIDFT_FFEFFECTTRIGGER, + .dwFlags = DIDOI_FFEFFECTTRIGGER, + .tszName = L"Button 0", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_BUTTON, + .wUsage = 0x1, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Button, + .dwOfs = 0x31, + .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(1)|DIDFT_FFEFFECTTRIGGER, + .dwFlags = DIDOI_FFEFFECTTRIGGER, + .tszName = L"Button 1", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_BUTTON, + .wUsage = 0x2, + .wReportId = 1, + }, + }; + const DIDEVICEOBJECTINSTANCEW expect_objects[] = + { + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_ZAxis, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(2)|DIDFT_FFACTUATOR, + .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, + .tszName = L"Z Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_Z, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_YAxis, + .dwOfs = 0x4, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(1)|DIDFT_FFACTUATOR, + .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, + .tszName = L"Y Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_Y, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_XAxis, + .dwOfs = 0x8, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(0)|DIDFT_FFACTUATOR, + .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, + .tszName = L"X Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_X, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Button, + .dwOfs = version >= 0x800 ? 0x68 : 0x10, + .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(0)|DIDFT_FFEFFECTTRIGGER, + .dwFlags = DIDOI_FFEFFECTTRIGGER, + .tszName = L"Button 0", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_BUTTON, + .wUsage = 0x1, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Button, + .dwOfs = version >= 0x800 ? 0x69 : 0x11, + .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(1)|DIDFT_FFEFFECTTRIGGER, + .dwFlags = DIDOI_FFEFFECTTRIGGER, + .tszName = L"Button 1", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_BUTTON, + .wUsage = 0x2, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x70 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(12)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"DC Device Reset", + .wCollectionNumber = 4, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_DC_DEVICE_RESET, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x10 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(13)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Effect Block Index", + .wCollectionNumber = 5, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_EFFECT_BLOCK_INDEX, + .wReportId = 2, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x71 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(14)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Op Effect Start", + .wCollectionNumber = 6, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_OP_EFFECT_START, + .wReportId = 2, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x72 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(15)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Op Effect Start Solo", + .wCollectionNumber = 6, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_OP_EFFECT_START_SOLO, + .wReportId = 2, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x73 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(16)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Op Effect Stop", + .wCollectionNumber = 6, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_OP_EFFECT_STOP, + .wReportId = 2, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x14 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(17)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Loop Count", + .wCollectionNumber = 5, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_LOOP_COUNT, + .wReportId = 2, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x18 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(18)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Effect Block Index", + .wCollectionNumber = 7, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_EFFECT_BLOCK_INDEX, + .wReportId = 3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x74 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(19)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"ET Square", + .wCollectionNumber = 8, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_ET_SQUARE, + .wReportId = 3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x75 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(20)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"ET Sine", + .wCollectionNumber = 8, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_ET_SINE, + .wReportId = 3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x76 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(21)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"ET Spring", + .wCollectionNumber = 8, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_ET_SPRING, + .wReportId = 3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x77 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(22)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Z Axis", + .wCollectionNumber = 9, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_Z, + .wReportId = 3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x78 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(23)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Y Axis", + .wCollectionNumber = 9, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_Y, + .wReportId = 3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x79 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(24)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"X Axis", + .wCollectionNumber = 9, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_X, + .wReportId = 3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x7a : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(25)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Direction Enable", + .wCollectionNumber = 7, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_DIRECTION_ENABLE, + .wReportId = 3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x1c : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(26)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Start Delay", + .wCollectionNumber = 7, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_START_DELAY, + .wReportId = 3, + .dwDimension = 0x1003, + .wExponent = -3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x20 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(27)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Duration", + .wCollectionNumber = 7, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_DURATION, + .wReportId = 3, + .dwDimension = 0x1003, + .wExponent = -3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x24 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(28)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Trigger Button", + .wCollectionNumber = 7, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_TRIGGER_BUTTON, + .wReportId = 3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x28 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(29)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Unknown 29", + .wCollectionNumber = 10, + .wUsagePage = HID_USAGE_PAGE_ORDINAL, + .wUsage = 2, + .wReportId = 3, + .wExponent = -2, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x2c : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(30)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Unknown 30", + .wCollectionNumber = 10, + .wUsagePage = HID_USAGE_PAGE_ORDINAL, + .wUsage = 1, + .wReportId = 3, + .wExponent = -2, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x30 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(31)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Magnitude", + .wCollectionNumber = 11, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_MAGNITUDE, + .wReportId = 5, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x34 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(32)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Fade Level", + .wCollectionNumber = 12, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_FADE_LEVEL, + .wReportId = 6, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x38 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(33)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Attack Level", + .wCollectionNumber = 12, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_ATTACK_LEVEL, + .wReportId = 6, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x3c : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(34)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Fade Time", + .wCollectionNumber = 12, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_FADE_TIME, + .wReportId = 6, + .dwDimension = 0x1003, + .wExponent = -3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x40 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(35)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Attack Time", + .wCollectionNumber = 12, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_ATTACK_TIME, + .wReportId = 6, + .dwDimension = 0x1003, + .wExponent = -3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x44 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(36)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Unknown 36", + .wCollectionNumber = 14, + .wUsagePage = HID_USAGE_PAGE_ORDINAL, + .wUsage = 2, + .wReportId = 7, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x48 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(37)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Unknown 37", + .wCollectionNumber = 14, + .wUsagePage = HID_USAGE_PAGE_ORDINAL, + .wUsage = 1, + .wReportId = 7, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x4c : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(38)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"CP Offset", + .wCollectionNumber = 13, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_CP_OFFSET, + .wReportId = 7, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x50 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(39)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Negative Coefficient", + .wCollectionNumber = 13, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_NEGATIVE_COEFFICIENT, + .wReportId = 7, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x54 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(40)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Positive Coefficient", + .wCollectionNumber = 13, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_POSITIVE_COEFFICIENT, + .wReportId = 7, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x58 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(41)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Negative Saturation", + .wCollectionNumber = 13, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_NEGATIVE_SATURATION, + .wReportId = 7, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x5c : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(42)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Positive Saturation", + .wCollectionNumber = 13, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_POSITIVE_SATURATION, + .wReportId = 7, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x60 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(43)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Dead Band", + .wCollectionNumber = 13, + .wUsagePage = HID_USAGE_PAGE_PID, + .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, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(0), + .tszName = L"Collection 0 - Joystick", + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(1), + .tszName = L"Collection 1 - Joystick", + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(2), + .tszName = L"Collection 2 - PID State Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_STATE_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(3), + .tszName = L"Collection 3 - PID Device Control Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_DEVICE_CONTROL_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(4), + .tszName = L"Collection 4 - PID Device Control", + .wCollectionNumber = 3, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_DEVICE_CONTROL, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(5), + .tszName = L"Collection 5 - Effect Operation Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_EFFECT_OPERATION_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(6), + .tszName = L"Collection 6 - Effect Operation", + .wCollectionNumber = 5, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_EFFECT_OPERATION, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(7), + .tszName = L"Collection 7 - Set Effect Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_SET_EFFECT_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(8), + .tszName = L"Collection 8 - Effect Type", + .wCollectionNumber = 7, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_EFFECT_TYPE, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(9), + .tszName = L"Collection 9 - Axes Enable", + .wCollectionNumber = 7, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_AXES_ENABLE, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(10), + .tszName = L"Collection 10 - Direction", + .wCollectionNumber = 7, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_DIRECTION, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(11), + .tszName = L"Collection 11 - Set Periodic Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_SET_PERIODIC_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(12), + .tszName = L"Collection 12 - Set Envelope Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_SET_ENVELOPE_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(13), + .tszName = L"Collection 13 - Set Condition Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_SET_CONDITION_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(14), + .tszName = L"Collection 14 - Type Specific Block Offset", + .wCollectionNumber = 13, + .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[] = + { + { + .dwSize = sizeof(DIEFFECTINFOW), + .guid = GUID_Square, + .dwEffType = DIEFT_PERIODIC | DIEFT_STARTDELAY | DIEFT_FFFADE | DIEFT_FFATTACK, + .dwStaticParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, + .dwDynamicParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, + .tszName = L"GUID_Square", + }, + { + .dwSize = sizeof(DIEFFECTINFOW), + .guid = GUID_Sine, + .dwEffType = DIEFT_PERIODIC | DIEFT_STARTDELAY | DIEFT_FFFADE | DIEFT_FFATTACK, + .dwStaticParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, + .dwDynamicParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, + .tszName = L"GUID_Sine", + }, + { + .dwSize = sizeof(DIEFFECTINFOW), + .guid = GUID_Spring, + .dwEffType = DIEFT_CONDITION | DIEFT_STARTDELAY | DIEFT_DEADBAND | DIEFT_SATURATION, + .dwStaticParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION, + .dwDynamicParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION, + .tszName = L"GUID_Spring", + } + }; + + struct check_objects_todos todo_objects_5[ARRAY_SIZE(expect_objects_5)] = + { + {.guid = TRUE, .type = TRUE, .usage = TRUE, .name = TRUE}, + {0}, + {.guid = TRUE, .type = TRUE, .usage = TRUE, .name = TRUE}, + }; + struct check_objects_params check_objects_params = + { + .version = version, + .expect_count = version < 0x700 ? ARRAY_SIZE(expect_objects_5) : ARRAY_SIZE(expect_objects), + .expect_objs = version < 0x700 ? expect_objects_5 : expect_objects, + .todo_objs = version < 0x700 ? todo_objects_5 : NULL, + .todo_extra = version < 0x700 ? TRUE : FALSE, + }; + struct check_effects_params check_effects_params = + { + .expect_count = ARRAY_SIZE(expect_effects), + .expect_effects = expect_effects, + }; + DIPROPDWORD prop_dword = + { + .diph = + { + .dwSize = sizeof(DIPROPDWORD), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + DIPROPGUIDANDPATH prop_guid_path = + { + .diph = + { + .dwSize = sizeof(DIPROPGUIDANDPATH), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; + WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; + IDirectInputDevice8W *device = NULL; + DIDEVICEOBJECTDATA objdata = {0}; + DIEFFECTINFOW effectinfo = {0}; + DIEFFESCAPE escape = {0}; + DIDEVCAPS caps = {0}; + char buffer[1024]; + ULONG res, ref; + HANDLE file; + HRESULT hr; + HWND hwnd; + + winetest_push_context( "%#x", version ); + + GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); + GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); + SetCurrentDirectoryW( tempdir ); + + cleanup_registry_keys(); + if (!dinput_driver_start( report_descriptor, sizeof(report_descriptor), &hid_caps, NULL, 0 )) goto done; + if (FAILED(hr = dinput_test_create_device( version, &devinst, &device ))) goto done; + + check_dinput_devices( version, &devinst ); + + hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); + ok( hr == DI_OK, "GetDeviceInfo returned %#x\n", hr ); + check_member( devinst, expect_devinst, "%d", dwSize ); + todo_wine + check_member_guid( devinst, expect_devinst, guidInstance ); + check_member_guid( devinst, expect_devinst, guidProduct ); + check_member( devinst, expect_devinst, "%#x", dwDevType ); + todo_wine + check_member_wstr( devinst, expect_devinst, tszInstanceName ); + todo_wine + check_member_wstr( devinst, expect_devinst, tszProductName ); + check_member_guid( devinst, expect_devinst, guidFFDriver ); + check_member( devinst, expect_devinst, "%04x", wUsagePage ); + check_member( devinst, expect_devinst, "%04x", wUsage ); + + caps.dwSize = sizeof(DIDEVCAPS); + hr = IDirectInputDevice8_GetCapabilities( device, &caps ); + ok( hr == DI_OK, "GetCapabilities returned %#x\n", hr ); + check_member( caps, expect_caps, "%d", dwSize ); + check_member( caps, expect_caps, "%#x", dwFlags ); + check_member( caps, expect_caps, "%#x", dwDevType ); + check_member( caps, expect_caps, "%d", dwAxes ); + check_member( caps, expect_caps, "%d", dwButtons ); + check_member( caps, expect_caps, "%d", dwPOVs ); + check_member( caps, expect_caps, "%d", dwFFSamplePeriod ); + check_member( caps, expect_caps, "%d", dwFFMinTimeResolution ); + check_member( caps, expect_caps, "%d", dwFirmwareRevision ); + check_member( caps, expect_caps, "%d", dwHardwareRevision ); + check_member( caps, expect_caps, "%d", dwFFDriverVersion ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_FFGAIN returned %#x\n", hr ); + ok( prop_dword.dwData == 10000, "got %u expected %u\n", prop_dword.dwData, 10000 ); + + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); + + hr = IDirectInputDevice8_EnumObjects( device, check_objects, &check_objects_params, DIDFT_ALL ); + ok( hr == DI_OK, "EnumObjects returned %#x\n", hr ); + ok( check_objects_params.index >= check_objects_params.expect_count, "missing %u objects\n", + check_objects_params.expect_count - check_objects_params.index ); + + res = 0; + hr = IDirectInputDevice8_EnumEffects( device, check_effect_count, &res, 0xfe ); + ok( hr == DI_OK, "EnumEffects returned %#x\n", hr ); + ok( res == 0, "got %u expected %u\n", res, 0 ); + res = 0; + hr = IDirectInputDevice8_EnumEffects( device, check_effect_count, &res, DIEFT_PERIODIC ); + ok( hr == DI_OK, "EnumEffects returned %#x\n", hr ); + ok( res == 2, "got %u expected %u\n", res, 2 ); + hr = IDirectInputDevice8_EnumEffects( device, check_effects, &check_effects_params, DIEFT_ALL ); + ok( hr == DI_OK, "EnumEffects returned %#x\n", hr ); + ok( check_effects_params.index >= check_effects_params.expect_count, "missing %u effects\n", + check_effects_params.expect_count - check_effects_params.index ); + + effectinfo.dwSize = sizeof(DIEFFECTINFOW); + hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_Sine ); + ok( hr == DI_OK, "GetEffectInfo returned %#x\n", hr ); + check_member_guid( effectinfo, expect_effects[1], guid ); + check_member( effectinfo, expect_effects[1], "%#x", dwEffType ); + check_member( effectinfo, expect_effects[1], "%#x", dwStaticParams ); + check_member( effectinfo, expect_effects[1], "%#x", dwDynamicParams ); + check_member_wstr( effectinfo, expect_effects[1], tszName ); + + hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); + ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); + + hr = IDirectInputDevice8_GetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph ); + 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, + 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, + NULL, NULL, NULL, NULL ); + + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE ); + ok( hr == DI_OK, "SetCooperativeLevel 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 = DIPROPAUTOCENTER_ON; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_AUTOCENTER returned %#x\n", hr ); + prop_dword.diph.dwHow = DIPH_DEVICE; + prop_dword.diph.dwObj = 0; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_AUTOCENTER returned %#x\n", hr ); + + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_FFGAIN returned %#x\n", hr ); + prop_dword.dwData = 1000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_FFGAIN returned %#x\n", hr ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + ok( hr == DIERR_READONLY, "SetProperty DIPROP_FFLOAD returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetForceFeedbackState returned %#x\n", hr ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "SendForceFeedbackCommand returned %#x\n", hr ); + + escape.dwSize = sizeof(DIEFFESCAPE); + escape.dwCommand = 0; + escape.lpvInBuffer = buffer; + escape.cbInBuffer = 10; + escape.lpvOutBuffer = buffer + 10; + escape.cbOutBuffer = 10; + hr = IDirectInputDevice8_Escape( device, &escape ); + todo_wine + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "Escape returned: %#x\n", hr ); + + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); + ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr ); + + set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); + 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 ); + 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 ); + 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 + ok( hr == DIERR_UNSUPPORTED, "Escape returned: %#x\n", hr ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + todo_wine + ok( hr == 0x80040301, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + todo_wine + ok( hr == 0x80040301, "GetForceFeedbackState returned %#x\n", hr ); + + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, 0xdeadbeef ); + ok( hr == DIERR_INVALIDPARAM, "SendForceFeedbackCommand returned %#x\n", hr ); + + set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); + ok( hr == DI_OK, "SendForceFeedbackCommand returned %#x\n", hr ); + 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 ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_PAUSE ); + ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#x\n", hr ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_CONTINUE ); + ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#x\n", hr ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSON ); + ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#x\n", hr ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSOFF ); + ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#x\n", hr ); + + objdata.dwOfs = 0x1e; + objdata.dwData = 0x80; + res = 1; + hr = IDirectInputDevice8_SendDeviceData( device, sizeof(DIDEVICEOBJECTDATA), &objdata, &res, 0 ); + if (version < 0x800) ok( hr == DI_OK, "SendDeviceData returned %#x\n", hr ); + else todo_wine ok( hr == DIERR_INVALIDPARAM, "SendDeviceData returned %#x\n", hr ); + + test_periodic_effect( device, file, version ); + test_condition_effect( device, file, version ); + + 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 ); + + ref = IDirectInputDevice8_Release( device ); + ok( ref == 0, "Release returned %d\n", ref ); + + DestroyWindow( hwnd ); + CloseHandle( file ); + +done: + pnp_driver_stop(); + cleanup_registry_keys(); + SetCurrentDirectoryW( cwd ); + winetest_pop_context(); + + return device != NULL; +} + +static void test_device_managed_effect(void) +{ +#include "psh_hid_macros.h" + const unsigned char report_descriptor[] = { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Report), + REPORT_ID(1, 1), + + USAGE(1, HID_USAGE_GENERIC_X), + USAGE(1, HID_USAGE_GENERIC_Y), + USAGE(1, HID_USAGE_GENERIC_Z), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 3), + INPUT(1, Data|Var|Abs), + + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 2), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 2), + INPUT(1, Data|Var|Abs), + REPORT_COUNT(1, 6), + INPUT(1, Cnst|Var|Abs), + END_COLLECTION, + + USAGE_PAGE(1, HID_USAGE_PAGE_PID), + USAGE(1, PID_USAGE_STATE_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 2), + + USAGE(1, PID_USAGE_DEVICE_PAUSED), + USAGE(1, PID_USAGE_ACTUATORS_ENABLED), + USAGE(1, PID_USAGE_SAFETY_SWITCH), + USAGE(1, PID_USAGE_ACTUATOR_OVERRIDE_SWITCH), + USAGE(1, PID_USAGE_ACTUATOR_POWER), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 5), + INPUT(1, Data|Var|Abs), + REPORT_COUNT(1, 3), + INPUT(1, Cnst|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_PLAYING), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 8), + INPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE_PAGE(1, HID_USAGE_PAGE_PID), + USAGE(1, PID_USAGE_DEVICE_CONTROL_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 1), + + USAGE(1, PID_USAGE_DEVICE_CONTROL), + COLLECTION(1, Logical), + USAGE(1, PID_USAGE_DC_DEVICE_RESET), + USAGE(1, PID_USAGE_DC_DEVICE_PAUSE), + USAGE(1, PID_USAGE_DC_DEVICE_CONTINUE), + USAGE(1, PID_USAGE_DC_ENABLE_ACTUATORS), + USAGE(1, PID_USAGE_DC_DISABLE_ACTUATORS), + USAGE(1, PID_USAGE_DC_STOP_ALL_EFFECTS), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 6), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 6), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + END_COLLECTION, + + USAGE(1, PID_USAGE_EFFECT_OPERATION_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 2), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_OPERATION), + COLLECTION(1, NamedArray), + USAGE(1, PID_USAGE_OP_EFFECT_START), + USAGE(1, PID_USAGE_OP_EFFECT_START_SOLO), + USAGE(1, PID_USAGE_OP_EFFECT_STOP), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 3), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 3), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_LOOP_COUNT), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_SET_EFFECT_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 3), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_TYPE), + COLLECTION(1, NamedArray), + USAGE(1, PID_USAGE_ET_SQUARE), + USAGE(1, PID_USAGE_ET_SINE), + USAGE(1, PID_USAGE_ET_SPRING), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 3), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 3), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_AXES_ENABLE), + COLLECTION(1, Logical), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_X), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_Y), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_Z), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 3), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + USAGE(1, PID_USAGE_DIRECTION_ENABLE), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + REPORT_COUNT(1, 4), + OUTPUT(1, Cnst|Var|Abs), + + USAGE(1, PID_USAGE_DURATION), + USAGE(1, PID_USAGE_START_DELAY), + UNIT(2, 0x1003), /* Eng Lin:Time */ + UNIT_EXPONENT(1, -3), /* 10^-3 */ + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x7fff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x7fff), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + UNIT(1, 0), + UNIT_EXPONENT(1, 0), + + USAGE(1, PID_USAGE_TRIGGER_BUTTON), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 0x08), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 0x08), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_DIRECTION), + COLLECTION(1, Logical), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|1), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|2), + UNIT(1, 0x14), /* Eng Rot:Angular Pos */ + UNIT_EXPONENT(1, -2), /* 10^-2 */ + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(4, 0x00008ca0), + UNIT(1, 0), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + UNIT_EXPONENT(1, 0), + UNIT(1, 0), + END_COLLECTION, + END_COLLECTION, + + USAGE(1, PID_USAGE_SET_CONDITION_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 4), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_PARAMETER_BLOCK_OFFSET), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 4), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_TYPE_SPECIFIC_BLOCK_OFFSET), + COLLECTION(1, Logical), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|1), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|2), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 2), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_CP_OFFSET), + LOGICAL_MINIMUM(1, 0x80), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(2, 0xd8f0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_POSITIVE_COEFFICIENT), + USAGE(1, PID_USAGE_NEGATIVE_COEFFICIENT), + LOGICAL_MINIMUM(1, 0x80), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(2, 0xd8f0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_POSITIVE_SATURATION), + USAGE(1, PID_USAGE_NEGATIVE_SATURATION), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_DEAD_BAND), + 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, + + USAGE(1, PID_USAGE_BLOCK_FREE_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 5), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_DEVICE_GAIN_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 6), + + 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, + + USAGE(1, PID_USAGE_POOL_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 1), + + USAGE(1, PID_USAGE_RAM_POOL_SIZE), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(4, 0xffff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(4, 0xffff), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 1), + FEATURE(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_SIMULTANEOUS_EFFECTS_MAX), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + FEATURE(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_DEVICE_MANAGED_POOL), + USAGE(1, PID_USAGE_SHARED_PARAMETER_BLOCKS), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 8), + FEATURE(1, Data|Var|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_CREATE_NEW_EFFECT_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 2), + + USAGE(1, PID_USAGE_EFFECT_TYPE), + COLLECTION(1, NamedArray), + USAGE(1, PID_USAGE_ET_SQUARE), + USAGE(1, PID_USAGE_ET_SINE), + USAGE(1, PID_USAGE_ET_SPRING), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 3), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 3), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + FEATURE(1, Data|Ary|Abs), + END_COLLECTION, + END_COLLECTION, + + USAGE(1, PID_USAGE_BLOCK_LOAD_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 3), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + FEATURE(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_BLOCK_LOAD_STATUS), + COLLECTION(1, NamedArray), + USAGE(1, PID_USAGE_BLOCK_LOAD_SUCCESS), + USAGE(1, PID_USAGE_BLOCK_LOAD_FULL), + USAGE(1, PID_USAGE_BLOCK_LOAD_ERROR), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 3), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 3), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + FEATURE(1, Data|Ary|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_RAM_POOL_AVAILABLE), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(4, 0xffff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(4, 0xffff), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 1), + FEATURE(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, + }; +#include "pop_hid_macros.h" + + static const HIDP_CAPS hid_caps = + { + .InputReportByteLength = 5, + }; + struct hid_expect expect_acquire[] = + { + /* device control */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x01}, + }, + /* device gain */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 6, + .report_len = 2, + .report_buf = {6, 0xff}, + }, + }; + struct hid_expect expect_reset[] = + { + /* device control */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x01}, + }, + }; + struct hid_expect expect_enable_actuators[] = + { + /* device control */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x04}, + }, + }; + struct hid_expect expect_disable_actuators[] = + { + /* device control */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x05}, + }, + }; + struct hid_expect expect_stop_all[] = + { + /* device control */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x06}, + }, + }; + struct hid_expect expect_device_pause[] = + { + /* device control */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x02}, + }, + }; + struct hid_expect expect_device_continue[] = + { + /* device control */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x03}, + }, + }; + struct hid_expect expect_create[] = + { + /* create new effect */ + { + .code = IOCTL_HID_SET_FEATURE, + .report_id = 2, + .report_len = 2, + .report_buf = {2,0x03}, + }, + /* block load */ + { + .code = IOCTL_HID_GET_FEATURE, + .report_id = 3, + .report_len = 5, + .report_buf = {3,0x01,0x01,0x00,0x00}, + }, + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 4, + .report_len = 9, + .report_buf = {4,0x01,0x00,0xf9,0x19,0xd9,0xff,0xff,0x99}, + }, + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 4, + .report_len = 9, + .report_buf = {4,0x01,0x01,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {3,0x01,0x03,0x08,0x01,0x00,0x06,0x00,0x01,0x55,0x00}, + }, + }; + struct hid_expect expect_create_2[] = + { + /* create new effect */ + { + .code = IOCTL_HID_SET_FEATURE, + .report_id = 2, + .report_len = 2, + .report_buf = {2,0x03}, + }, + /* block load */ + { + .code = IOCTL_HID_GET_FEATURE, + .report_id = 3, + .report_len = 5, + .report_buf = {3,0x02,0x01,0x00,0x00}, + }, + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 4, + .report_len = 9, + .report_buf = {4,0x02,0x00,0xf9,0x19,0xd9,0xff,0xff,0x99}, + }, + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 4, + .report_len = 9, + .report_buf = {4,0x02,0x01,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {3,0x02,0x03,0x08,0x01,0x00,0x06,0x00,0x01,0x55,0x00}, + }, + }; + struct hid_expect expect_create_delay[] = + { + /* create new effect */ + { + .code = IOCTL_HID_SET_FEATURE, + .report_id = 2, + .report_len = 2, + .report_buf = {2,0x03}, + }, + /* block load */ + { + .code = IOCTL_HID_GET_FEATURE, + .report_id = 3, + .report_len = 5, + .report_buf = {3,0x01,0x01,0x00,0x00}, + }, + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 4, + .report_len = 9, + .report_buf = {4,0x01,0x00,0xf9,0x19,0xd9,0xff,0xff,0x99}, + }, + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 4, + .report_len = 9, + .report_buf = {4,0x01,0x01,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {3,0x01,0x03,0x08,0x01,0x00,0xff,0x7f,0x01,0x55,0x00}, + }, + }; + struct hid_expect expect_create_duration[] = + { + /* create new effect */ + { + .code = IOCTL_HID_SET_FEATURE, + .report_id = 2, + .report_len = 2, + .report_buf = {2,0x03}, + }, + /* block load */ + { + .code = IOCTL_HID_GET_FEATURE, + .report_id = 3, + .report_len = 5, + .report_buf = {3,0x01,0x01,0x00,0x00}, + }, + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 4, + .report_len = 9, + .report_buf = {4,0x01,0x00,0xf9,0x19,0xd9,0xff,0xff,0x99}, + }, + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 4, + .report_len = 9, + .report_buf = {4,0x01,0x01,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {3,0x01,0x03,0x08,0x00,0x00,0x00,0x00,0x01,0x55,0x00}, + }, + }; + struct hid_expect expect_start = + { + /* effect control */ + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {2, 0x01, 0x01, 0x01}, + }; + struct hid_expect expect_start_2 = + { + /* effect control */ + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {2, 0x02, 0x02, 0x01}, + }; + struct hid_expect expect_stop = + { + /* effect control */ + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {2, 0x01, 0x03, 0x00}, + }; + struct hid_expect expect_stop_2 = + { + /* effect control */ + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {2, 0x02, 0x03, 0x00}, + }; + struct hid_expect expect_destroy[] = + { + /* effect operation */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {2,0x01,0x03,0x00}, + }, + /* block free */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 5, + .report_len = 2, + .report_buf = {5,0x01}, + }, + }; + struct hid_expect expect_destroy_2[] = + { + /* effect operation */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {2,0x02,0x03,0x00}, + }, + /* block free */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 5, + .report_len = 2, + .report_buf = {5,0x02}, + }, + }; + struct hid_expect device_state_input[] = + { + /* effect state */ + { + .code = IOCTL_HID_READ_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {2,0xff,0x00,0xff}, + }, + /* device state */ + { + .code = IOCTL_HID_READ_REPORT, + .report_id = 1, + .report_len = 5, + .report_buf = {1,0x12,0x34,0x56,0xff}, + }, + }; + struct hid_expect device_state_input_0[] = + { + /* effect state */ + { + .code = IOCTL_HID_READ_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {2,0xff,0x00,0xff}, + }, + /* device state */ + { + .code = IOCTL_HID_READ_REPORT, + .report_id = 1, + .report_len = 5, + .report_buf = {1,0x56,0x12,0x34,0xff}, + }, + }; + struct hid_expect device_state_input_1[] = + { + /* effect state */ + { + .code = IOCTL_HID_READ_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {2,0x00,0x01,0x01}, + }, + /* device state */ + { + .code = IOCTL_HID_READ_REPORT, + .report_id = 1, + .report_len = 5, + .report_buf = {1,0x65,0x43,0x21,0x00}, + }, + }; + struct hid_expect device_state_input_2[] = + { + /* effect state */ + { + .code = IOCTL_HID_READ_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {2,0x03,0x00,0x01}, + }, + /* device state */ + { + .code = IOCTL_HID_READ_REPORT, + .report_id = 1, + .report_len = 5, + .report_buf = {1,0x12,0x34,0x56,0xff}, + }, + }; + struct hid_expect expect_pool[] = + { + /* device pool */ + { + .code = IOCTL_HID_GET_FEATURE, + .report_id = 1, + .report_len = 5, + .report_buf = {1,0x10,0x00,0x04,0x03}, + .todo = TRUE, + }, + /* device pool */ + { + .code = IOCTL_HID_GET_FEATURE, + .report_id = 1, + .report_len = 5, + .report_buf = {1,0x10,0x00,0x04,0x03}, + .todo = TRUE, + }, + }; + static const DWORD expect_axes[3] = + { + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ) | DIDFT_FFACTUATOR, + }; + static const LONG expect_directions[3] = { + +3000, + 0, + 0, + }; + static const DIENVELOPE expect_envelope = + { + .dwSize = sizeof(DIENVELOPE), + .dwAttackLevel = 1000, + .dwAttackTime = 2000, + .dwFadeLevel = 3000, + .dwFadeTime = 4000, + }; + static const DICONDITION expect_condition[3] = + { + { + .lOffset = -500, + .lPositiveCoefficient = 2000, + .lNegativeCoefficient = -3000, + .dwPositiveSaturation = -4000, + .dwNegativeSaturation = -5000, + .lDeadBand = 6000, + }, + { + .lOffset = 6000, + .lPositiveCoefficient = 5000, + .lNegativeCoefficient = -4000, + .dwPositiveSaturation = 3000, + .dwNegativeSaturation = 2000, + .lDeadBand = 1000, + }, + { + .lOffset = -7000, + .lPositiveCoefficient = -8000, + .lNegativeCoefficient = 9000, + .dwPositiveSaturation = 10000, + .dwNegativeSaturation = 11000, + .lDeadBand = -12000, + }, + }; + const DIEFFECT expect_desc = + { + .dwSize = sizeof(DIEFFECT_DX6), + .dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS, + .dwDuration = 1000, + .dwSamplePeriod = 2000, + .dwGain = 3000, + .dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER, + .dwTriggerRepeatInterval = 5000, + .cAxes = 2, + .rgdwAxes = (void *)expect_axes, + .rglDirection = (void *)expect_directions, + .lpEnvelope = (void *)&expect_envelope, + .cbTypeSpecificParams = 2 * sizeof(DICONDITION), + .lpvTypeSpecificParams = (void *)expect_condition, + .dwStartDelay = 6000, + }; + DIPROPGUIDANDPATH prop_guid_path = + { + .diph = + { + .dwSize = sizeof(DIPROPGUIDANDPATH), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + DIPROPDWORD prop_dword = + { + .diph = + { + .dwSize = sizeof(DIPROPDWORD), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; + WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; + IDirectInputDevice8W *device; + IDirectInputEffect *effect, *effect2; + HANDLE file, event; + ULONG res, ref; + DIEFFECT desc; + DWORD flags; + HRESULT hr; + HWND hwnd; + + GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); + GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); + SetCurrentDirectoryW( tempdir ); + + cleanup_registry_keys(); + if (!dinput_driver_start( report_descriptor, sizeof(report_descriptor), &hid_caps, + expect_pool, sizeof(expect_pool) )) goto done; + if (FAILED(hr = dinput_test_create_device( DIRECTINPUT_VERSION, &devinst, &device ))) goto done; + + hr = IDirectInputDevice8_GetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph ); + 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, + 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, + NULL, NULL, NULL, NULL ); + + event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( event != NULL, "CreateEventW failed, last error %u\n", GetLastError() ); + hr = IDirectInputDevice8_SetEventNotification( device, event ); + ok( hr == DI_OK, "SetEventNotification returned: %#x\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); + ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr ); + hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); + ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); + + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetForceFeedbackState returned %#x\n", hr ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "SendForceFeedbackCommand returned %#x\n", hr ); + + set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); + wait_hid_expect( file, 100 ); + + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); + ok( prop_dword.dwData == 0, "got DIPROP_FFLOAD %#x\n", prop_dword.dwData ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_STOPPED | DIGFFS_EMPTY; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); + ok( prop_dword.dwData == 0, "got DIPROP_FFLOAD %#x\n", prop_dword.dwData ); + set_hid_expect( file, NULL, 0 ); + + send_hid_input( file, device_state_input, sizeof(struct hid_expect) ); + res = WaitForSingleObject( event, 100 ); + ok( res == WAIT_TIMEOUT, "WaitForSingleObject returned %#x\n", res ); + send_hid_input( file, device_state_input, sizeof(device_state_input) ); + res = WaitForSingleObject( event, 100 ); + ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", res ); + + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_PAUSED | DIGFFS_EMPTY | DIGFFS_ACTUATORSON | DIGFFS_POWERON | + DIGFFS_SAFETYSWITCHON | DIGFFS_USERFFSWITCHON; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, NULL, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); + + hr = IDirectInputEffect_GetEffectStatus( effect, NULL ); + ok( hr == E_POINTER, "GetEffectStatus returned %#x\n", hr ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DIERR_NOTDOWNLOADED, "GetEffectStatus returned %#x\n", hr ); + ok( res == 0, "got status %#x\n", res ); + + flags = DIEP_ALLPARAMS; + hr = IDirectInputEffect_SetParameters( effect, &expect_desc, flags | DIEP_NODOWNLOAD ); + ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); + + set_hid_expect( file, expect_reset, sizeof(struct hid_expect) ); + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetEffectStatus returned %#x\n", hr ); + + set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); + wait_hid_expect( file, 100 ); + + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DIERR_NOTDOWNLOADED, "GetEffectStatus returned %#x\n", hr ); + ok( res == 0, "got status %#x\n", res ); + + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_STOPPED | DIGFFS_EMPTY; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_create, sizeof(expect_create) ); + hr = IDirectInputEffect_Download( effect ); + ok( hr == DI_OK, "Download returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == 0, "got status %#x\n", res ); + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_STOPPED; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); + ok( prop_dword.dwData == 0, "got DIPROP_FFLOAD %#x\n", prop_dword.dwData ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_start, sizeof(expect_start) ); + hr = IDirectInputEffect_Start( effect, 1, DIES_NODOWNLOAD ); + ok( hr == DI_OK, "Start returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_create_2, sizeof(expect_create_2) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &expect_desc, &effect2, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + set_hid_expect( file, &expect_start_2, sizeof(expect_start_2) ); + hr = IDirectInputEffect_Start( effect2, 1, DIES_SOLO ); + ok( hr == DI_OK, "Start returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect2, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == DIEGES_PLAYING, "got status %#x\n", res ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == DIEGES_PLAYING, "got status %#x\n", res ); + set_hid_expect( file, &expect_stop_2, sizeof(expect_stop_2) ); + hr = IDirectInputEffect_Stop( effect2 ); + ok( hr == DI_OK, "Stop returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect2, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == 0, "got status %#x\n", res ); + set_hid_expect( file, expect_destroy_2, sizeof(expect_destroy_2) ); + ref = IDirectInputEffect_Release( effect2 ); + ok( ref == 0, "Release returned %d\n", ref ); + set_hid_expect( file, NULL, 0 ); + + /* sending commands has no direct effect on status */ + set_hid_expect( file, expect_stop_all, sizeof(expect_stop_all) ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_STOPALL ); + ok( hr == DI_OK, "SendForceFeedbackCommand returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == DIEGES_PLAYING, "got status %#x\n", res ); + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_STOPPED; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_device_pause, sizeof(expect_device_pause) ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_PAUSE ); + ok( hr == DI_OK, "SendForceFeedbackCommand returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == DIEGES_PLAYING, "got status %#x\n", res ); + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_STOPPED; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_device_continue, sizeof(expect_device_continue) ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_CONTINUE ); + ok( hr == DI_OK, "SendForceFeedbackCommand returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == DIEGES_PLAYING, "got status %#x\n", res ); + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_STOPPED; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_disable_actuators, sizeof(expect_disable_actuators) ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSOFF ); + ok( hr == DI_OK, "SendForceFeedbackCommand returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == DIEGES_PLAYING, "got status %#x\n", res ); + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_STOPPED; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_enable_actuators, sizeof(expect_enable_actuators) ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSON ); + ok( hr == DI_OK, "SendForceFeedbackCommand returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == DIEGES_PLAYING, "got status %#x\n", res ); + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_STOPPED; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_stop, sizeof(expect_stop) ); + hr = IDirectInputEffect_Stop( effect ); + ok( hr == DI_OK, "Stop returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == 0, "got status %#x\n", res ); + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_STOPPED; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + send_hid_input( file, device_state_input_0, sizeof(device_state_input_0) ); + res = WaitForSingleObject( event, 100 ); + ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", res ); + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_PAUSED | DIGFFS_ACTUATORSON | DIGFFS_POWERON | DIGFFS_SAFETYSWITCHON | DIGFFS_USERFFSWITCHON; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + send_hid_input( file, device_state_input_1, sizeof(device_state_input_1) ); + res = WaitForSingleObject( event, 100 ); + ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", res ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == DIEGES_PLAYING, "got status %#x\n", res ); + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_ACTUATORSOFF | DIGFFS_POWEROFF | DIGFFS_SAFETYSWITCHOFF | DIGFFS_USERFFSWITCHOFF; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + send_hid_input( file, device_state_input_2, sizeof(device_state_input_2) ); + res = WaitForSingleObject( event, 100 ); + ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", res ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == 0, "got status %#x\n", res ); + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_PAUSED | DIGFFS_ACTUATORSON | DIGFFS_POWEROFF | DIGFFS_SAFETYSWITCHOFF | DIGFFS_USERFFSWITCHOFF; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_stop, sizeof(expect_stop) ); + hr = IDirectInputEffect_Stop( effect ); + ok( hr == DI_OK, "Stop returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == 0, "got status %#x\n", res ); + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_PAUSED | DIGFFS_ACTUATORSON | DIGFFS_POWEROFF | DIGFFS_SAFETYSWITCHOFF | DIGFFS_USERFFSWITCHOFF; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, expect_destroy, sizeof(expect_destroy) ); + hr = IDirectInputEffect_Unload( effect ); + ok( hr == DI_OK, "Unload returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DIERR_NOTDOWNLOADED, "GetEffectStatus returned %#x\n", hr ); + ok( res == 0, "got status %#x\n", res ); + set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); + flags = DIGFFS_EMPTY | DIGFFS_PAUSED | DIGFFS_ACTUATORSON | DIGFFS_POWEROFF | + DIGFFS_SAFETYSWITCHOFF | DIGFFS_USERFFSWITCHOFF; + ok( res == flags, "got state %#x\n", res ); + set_hid_expect( file, NULL, 0 ); + + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %d\n", ref ); + + /* start delay has no direct effect on effect status */ + desc = expect_desc; + desc.dwStartDelay = 32767000; + set_hid_expect( file, expect_create_delay, sizeof(expect_create_delay) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == 0, "got status %#x\n", res ); + set_hid_expect( file, &expect_start, sizeof(expect_start) ); + hr = IDirectInputEffect_Start( effect, 1, 0 ); + ok( hr == DI_OK, "Start returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == DIEGES_PLAYING, "got status %#x\n", res ); + set_hid_expect( file, expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %d\n", ref ); + set_hid_expect( file, NULL, 0 ); + + /* duration has no direct effect on effect status */ + desc = expect_desc; + desc.dwDuration = 100; + desc.dwStartDelay = 0; + set_hid_expect( file, expect_create_duration, sizeof(expect_create_duration) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == 0, "got status %#x\n", res ); + set_hid_expect( file, &expect_start, sizeof(expect_start) ); + hr = IDirectInputEffect_Start( effect, 1, 0 ); + ok( hr == DI_OK, "Start returned %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + Sleep( 100 ); + res = 0xdeadbeef; + hr = IDirectInputEffect_GetEffectStatus( effect, &res ); + ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); + ok( res == DIEGES_PLAYING, "got status %#x\n", res ); + set_hid_expect( file, expect_destroy, sizeof(expect_destroy) ); + 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(struct hid_expect) ); + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + set_hid_expect( file, NULL, 0 ); + + ref = IDirectInputDevice8_Release( device ); + ok( ref == 0, "Release returned %d\n", ref ); + + DestroyWindow( hwnd ); + CloseHandle( event ); + CloseHandle( file ); + +done: + pnp_driver_stop(); + cleanup_registry_keys(); + SetCurrentDirectoryW( cwd ); + winetest_pop_context(); +} + +START_TEST( force_feedback ) +{ + if (!dinput_test_init()) return; + + CoInitialize( NULL ); + if (test_force_feedback_joystick( 0x800 )) + { + test_force_feedback_joystick( 0x500 ); + test_force_feedback_joystick( 0x700 ); + test_device_managed_effect(); + } + CoUninitialize(); + + dinput_test_exit(); +} diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index 82657c2e235..f8e8a275b09 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -43,10 +43,7 @@ #include "objbase.h"
#define COBJMACROS -#include "wingdi.h" #include "dinput.h" -#include "dinputd.h" -#include "mmsystem.h"
#include "initguid.h" #include "ddk/wdm.h" @@ -57,22 +54,20 @@ #include "hidusage.h" #include "devguid.h"
-#include "wine/test.h" #include "wine/mssign.h" -#include "wine/hid.h"
-#include "driver_hid.h" +#include "dinput_test.h"
-static HINSTANCE instance; -static BOOL localized; /* object names get translated */ +HINSTANCE instance; +BOOL localized; /* object names get translated */
-#define EXPECT_VIDPID MAKELONG( 0x1209, 0x0001 ) -static const WCHAR expect_vidpid_str[] = L"VID_1209&PID_0001"; -static const GUID expect_guid_product = {EXPECT_VIDPID,0x0000,0x0000,{0x00,0x00,'P','I','D','V','I','D'}}; -static const WCHAR expect_path[] = L"\\?\hid#winetest#1&2fafeb0&"; -static const WCHAR expect_path_end[] = L"&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"; +const WCHAR expect_vidpid_str[] = L"VID_1209&PID_0001"; +const GUID expect_guid_product = {EXPECT_VIDPID, 0x0000, 0x0000, {0x00, 0x00, 'P', 'I', 'D', 'V', 'I', 'D'}}; +const WCHAR expect_path[] = L"\\?\hid#winetest#1&2fafeb0&"; +const WCHAR expect_path_end[] = L"&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}";
static struct winetest_shared_data *test_data; +static HANDLE test_data_mapping; static HANDLE okfile;
static HRESULT (WINAPI *pSignerSign)( SIGNER_SUBJECT_INFO *subject, SIGNER_CERT *cert, @@ -420,7 +415,7 @@ static void unload_driver( SC_HANDLE service ) CloseServiceHandle( service ); }
-static void pnp_driver_stop(void) +void pnp_driver_stop(void) { SP_DEVINFO_DATA device = {sizeof(SP_DEVINFO_DATA)}; WCHAR path[MAX_PATH], dest[MAX_PATH], *filepart; @@ -493,7 +488,7 @@ static void pnp_driver_stop(void) ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %u\n", GetLastError() ); }
-static BOOL pnp_driver_start( const WCHAR *resource ) +BOOL pnp_driver_start( const WCHAR *resource ) { static const WCHAR hardware_id[] = L"test_hardware_id\0"; SP_DEVINFO_DATA device = {sizeof(SP_DEVINFO_DATA)}; @@ -595,21 +590,6 @@ static BOOL pnp_driver_start( const WCHAR *resource ) return ret || GetLastError() == ERROR_SERVICE_ALREADY_RUNNING; }
-#define check_member_( file, line, val, exp, fmt, member ) \ - ok_(file, line)( (val).member == (exp).member, "got " #member " " fmt "\n", (val).member ) -#define check_member( val, exp, fmt, member ) \ - check_member_( __FILE__, __LINE__, val, exp, fmt, member ) - -#define check_member_guid_( file, line, val, exp, member ) \ - ok_(file, line)( IsEqualGUID( &(val).member, &(exp).member ), "got " #member " %s\n", debugstr_guid(&(val).member) ) -#define check_member_guid( val, exp, member ) \ - check_member_guid_( __FILE__, __LINE__, val, exp, member ) - -#define check_member_wstr_( file, line, val, exp, member ) \ - ok_(file, line)( !wcscmp( (val).member, (exp).member ), "got " #member " %s\n", debugstr_w((val).member) ) -#define check_member_wstr( val, exp, member ) \ - check_member_wstr_( __FILE__, __LINE__, val, exp, member ) - #define check_hidp_caps( a, b ) check_hidp_caps_( __LINE__, a, b ) static inline void check_hidp_caps_( int line, HIDP_CAPS *caps, const HIDP_CAPS *exp ) { @@ -744,21 +724,21 @@ static inline void check_hidp_value_caps_( int line, HIDP_VALUE_CAPS *caps, cons } }
-#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 ) +BOOL sync_ioctl_( const char *file, int line, HANDLE device, 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}; BOOL ret;
ovl.hEvent = CreateEventW( NULL, TRUE, FALSE, NULL ); - ret = DeviceIoControl( file, code, in_buf, in_len, out_buf, out_len, &out_len, &ovl ); + ret = DeviceIoControl( device, code, in_buf, in_len, out_buf, out_len, &out_len, &ovl ); if (!ret && GetLastError() == ERROR_IO_PENDING) { res = WaitForSingleObject( ovl.hEvent, timeout ); - ok_(__FILE__, line)( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", res ); - ret = GetOverlappedResult( file, &ovl, &out_len, FALSE ); - ok_(__FILE__, line)( ret, "GetOverlappedResult returned %u\n", GetLastError() ); + ok_(file, line)( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", res ); + ret = GetOverlappedResult( device, &ovl, &out_len, FALSE ); + ok_(file, line)( ret, "GetOverlappedResult returned %u\n", GetLastError() ); } CloseHandle( ovl.hEvent );
@@ -776,39 +756,36 @@ static BOOL sync_ioctl_( int line, HANDLE file, DWORD code, void *in_buf, DWORD snprintf( a, b, "%s:%d", source_file, line ); \ } while (0)
-#define set_hid_expect( a, b, c ) set_hid_expect_( __LINE__, a, b, c ) -static void set_hid_expect_( int line, HANDLE file, struct hid_expect *expect, DWORD expect_size ) +void set_hid_expect_( const char *file, int line, HANDLE device, struct hid_expect *expect, DWORD expect_size ) { char context[64]; BOOL ret;
fill_context( line, context, ARRAY_SIZE(context) ); - ret = sync_ioctl_( line, file, IOCTL_WINETEST_HID_SET_CONTEXT, context, ARRAY_SIZE(context), NULL, 0, INFINITE ); - ok_(__FILE__, line)( ret, "IOCTL_WINETEST_HID_SET_CONTEXT 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() ); + ret = sync_ioctl_( file, line, device, IOCTL_WINETEST_HID_SET_CONTEXT, context, ARRAY_SIZE(context), NULL, 0, INFINITE ); + ok_(file, line)( ret, "IOCTL_WINETEST_HID_SET_CONTEXT failed, last error %u\n", GetLastError() ); + ret = sync_ioctl_( file, line, device, 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 ) +void wait_hid_expect_( const char *file, int line, HANDLE device, DWORD timeout ) { - 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() ); + BOOL ret = sync_ioctl_( file, line, device, 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_( line, file, NULL, 0 ); + set_hid_expect_( file, line, device, 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 ) +void send_hid_input_( const char *file, int line, HANDLE device, struct hid_expect *expect, DWORD expect_size ) { char context[64]; BOOL ret;
fill_context( line, context, ARRAY_SIZE(context) ); - ret = sync_ioctl_( line, file, IOCTL_WINETEST_HID_SET_CONTEXT, context, ARRAY_SIZE(context), NULL, 0, INFINITE ); - ok_(__FILE__, line)( ret, "IOCTL_WINETEST_HID_SET_CONTEXT failed, last error %u\n", GetLastError() ); - 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() ); + ret = sync_ioctl_( file, line, device, IOCTL_WINETEST_HID_SET_CONTEXT, context, ARRAY_SIZE(context), NULL, 0, INFINITE ); + ok_(file, line)( ret, "IOCTL_WINETEST_HID_SET_CONTEXT failed, last error %u\n", GetLastError() ); + ret = sync_ioctl_( file, line, device, IOCTL_WINETEST_HID_SEND_INPUT, expect, expect_size, NULL, 0, INFINITE ); + ok_(file, line)( ret, "IOCTL_WINETEST_HID_SEND_INPUT failed, last error %u\n", GetLastError() ); }
static void test_hidp_get_input( HANDLE file, int report_id, ULONG report_len, PHIDP_PREPARSED_DATA preparsed ) @@ -3266,7 +3243,7 @@ done: SetCurrentDirectoryW( cwd ); }
-static void cleanup_registry_keys(void) +void cleanup_registry_keys(void) { static const WCHAR joystick_oem_path[] = L"System\CurrentControlSet\Control\MediaProperties\" "PrivateProperties\Joystick\OEM"; @@ -3299,9 +3276,8 @@ static void cleanup_registry_keys(void) RegCloseKey( root_key ); }
-#define dinput_driver_start( a, b, c, d, e ) dinput_driver_start_( __LINE__, a, b, c, d, e ) -static BOOL dinput_driver_start_( int line, const BYTE *desc_buf, ULONG desc_len, const HIDP_CAPS *caps, - struct hid_expect *expect, ULONG expect_size ) +BOOL dinput_driver_start_( const char *file, int line, const BYTE *desc_buf, ULONG desc_len, + const HIDP_CAPS *caps, struct hid_expect *expect, ULONG expect_size ) { static const HID_DEVICE_ATTRIBUTES attributes = { @@ -3318,192 +3294,85 @@ static BOOL dinput_driver_start_( int line, const BYTE *desc_buf, ULONG desc_len
status = RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"System\CurrentControlSet\Services\winetest", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ); - ok_(__FILE__, line)( !status, "RegCreateKeyExW returned %#x\n", status ); + ok_(file, line)( !status, "RegCreateKeyExW returned %#x\n", status ); status = RegSetValueExW( hkey, L"ReportID", 0, REG_DWORD, (void *)&report_id, sizeof(report_id) ); - ok_(__FILE__, line)( !status, "RegSetValueExW returned %#x\n", status ); + ok_(file, line)( !status, "RegSetValueExW returned %#x\n", status ); status = RegSetValueExW( hkey, L"PolledMode", 0, REG_DWORD, (void *)&polled, sizeof(polled) ); - ok_(__FILE__, line)( !status, "RegSetValueExW returned %#x\n", status ); + ok_(file, line)( !status, "RegSetValueExW returned %#x\n", status ); status = RegSetValueExW( hkey, L"Descriptor", 0, REG_BINARY, (void *)desc_buf, desc_len ); - ok_(__FILE__, line)( !status, "RegSetValueExW returned %#x\n", status ); + ok_(file, line)( !status, "RegSetValueExW returned %#x\n", status ); status = RegSetValueExW( hkey, L"Attributes", 0, REG_BINARY, (void *)&attributes, sizeof(attributes) ); - ok_(__FILE__, line)( !status, "RegSetValueExW returned %#x\n", status ); + ok_(file, line)( !status, "RegSetValueExW returned %#x\n", status ); status = RegSetValueExW( hkey, L"Caps", 0, REG_BINARY, (void *)caps, sizeof(*caps) ); - ok_(__FILE__, line)( !status, "RegSetValueExW returned %#x\n", status ); + ok_(file, line)( !status, "RegSetValueExW returned %#x\n", status ); status = RegSetValueExW( hkey, L"Expect", 0, REG_BINARY, (void *)expect, expect_size ); - ok_(__FILE__, line)( !status, "RegSetValueExW returned %#x\n", status ); + ok_(file, line)( !status, "RegSetValueExW returned %#x\n", status ); status = RegSetValueExW( hkey, L"Input", 0, REG_BINARY, NULL, 0 ); - ok_(__FILE__, line)( !status, "RegSetValueExW returned %#x\n", status ); + ok_(file, line)( !status, "RegSetValueExW returned %#x\n", status ); fill_context( line, context, ARRAY_SIZE(context) ); status = RegSetValueExW( hkey, L"Context", 0, REG_BINARY, (void *)context, sizeof(context) ); - ok_(__FILE__, line)( !status, "RegSetValueExW returned %#x\n", status ); + ok_(file, line)( !status, "RegSetValueExW returned %#x\n", status );
return pnp_driver_start( L"driver_hid.dll" ); }
-static BOOL CALLBACK find_test_device( const DIDEVICEINSTANCEW *devinst, void *context ) +BOOL dinput_test_init_( const char *file, int line ) +{ + BOOL is_wow64; + + subtest_(file, line)( "hid" ); + instance = GetModuleHandleW( NULL ); + localized = GetUserDefaultLCID() != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); + pSignerSign = (void *)GetProcAddress( LoadLibraryW( L"mssign32" ), "SignerSign" ); + + if (IsWow64Process( GetCurrentProcess(), &is_wow64 ) && is_wow64) + { + skip( "Running in WoW64.\n" ); + return FALSE; + } + + test_data_mapping = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, + sizeof(*test_data), L"Global\winetest_dinput_section" ); + if (!test_data_mapping && GetLastError() == ERROR_ACCESS_DENIED) + { + win_skip( "Failed to create test data mapping.\n" ); + return FALSE; + } + ok( !!test_data_mapping, "got error %u\n", GetLastError() ); + test_data = MapViewOfFile( test_data_mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024 ); + test_data->running_under_wine = !strcmp( winetest_platform, "wine" ); + test_data->winetest_report_success = winetest_report_success; + test_data->winetest_debug = winetest_debug; + + okfile = CreateFileW( L"C:\windows\winetest_dinput_okfile", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL ); + ok( okfile != INVALID_HANDLE_VALUE, "failed to create file, error %u\n", GetLastError() ); + + subtest( "driver_hid" ); + return TRUE; +} + +void dinput_test_exit(void) +{ + UnmapViewOfFile( test_data ); + CloseHandle( test_data_mapping ); + CloseHandle( okfile ); + DeleteFileW( L"C:\windows\winetest_dinput_okfile" ); +} + +BOOL CALLBACK find_test_device( const DIDEVICEINSTANCEW *devinst, void *context ) { if (IsEqualGUID( &devinst->guidProduct, &expect_guid_product )) *(DIDEVICEINSTANCEW *)context = *devinst; return DIENUM_CONTINUE; }
-struct check_objects_todos +HRESULT dinput_test_create_device( DWORD version, DIDEVICEINSTANCEW *devinst, IDirectInputDevice8W **device ) { - BOOL type; - BOOL guid; - BOOL usage; - BOOL name; -}; - -struct check_objects_params -{ - DWORD version; - UINT index; - UINT expect_count; - const DIDEVICEOBJECTINSTANCEW *expect_objs; - const struct check_objects_todos *todo_objs; - BOOL todo_extra; -}; - -static BOOL CALLBACK check_objects( const DIDEVICEOBJECTINSTANCEW *obj, void *args ) -{ - static const DIDEVICEOBJECTINSTANCEW unexpected_obj = {0}; - static const struct check_objects_todos todo_none = {0}; - struct check_objects_params *params = args; - const DIDEVICEOBJECTINSTANCEW *exp = params->expect_objs + params->index; - const struct check_objects_todos *todo; - - if (!params->todo_objs) todo = &todo_none; - else todo = params->todo_objs + params->index; - - todo_wine_if( params->todo_extra && params->index >= params->expect_count ) - ok( params->index < params->expect_count, "unexpected extra object\n" ); - if (params->index >= params->expect_count) return DIENUM_STOP; - - winetest_push_context( "obj[%d]", params->index ); - - ok( params->index < params->expect_count, "unexpected extra object\n" ); - if (params->index >= params->expect_count) exp = &unexpected_obj; - - check_member( *obj, *exp, "%u", dwSize ); - todo_wine_if( todo->guid ) - check_member_guid( *obj, *exp, guidType ); - todo_wine_if( params->version < 0x700 && (obj->dwType & DIDFT_BUTTON) ) - check_member( *obj, *exp, "%#x", dwOfs ); - todo_wine_if( todo->type ) - check_member( *obj, *exp, "%#x", dwType ); - check_member( *obj, *exp, "%#x", dwFlags ); - if (!localized) todo_wine_if( todo->name )check_member_wstr( *obj, *exp, tszName ); - check_member( *obj, *exp, "%u", dwFFMaxForce ); - check_member( *obj, *exp, "%u", dwFFForceResolution ); - check_member( *obj, *exp, "%u", wCollectionNumber ); - check_member( *obj, *exp, "%u", wDesignatorIndex ); - check_member( *obj, *exp, "%#04x", wUsagePage ); - todo_wine_if( todo->usage ) - check_member( *obj, *exp, "%#04x", wUsage ); - check_member( *obj, *exp, "%#04x", dwDimension ); - check_member( *obj, *exp, "%#04x", wExponent ); - check_member( *obj, *exp, "%u", wReportId ); - - winetest_pop_context(); - - params->index++; - return DIENUM_CONTINUE; -} - -static BOOL CALLBACK check_object_count( const DIDEVICEOBJECTINSTANCEW *obj, void *args ) -{ - DWORD *count = args; - *count = *count + 1; - return DIENUM_CONTINUE; -} - -struct check_effects_params -{ - UINT index; - UINT expect_count; - const DIEFFECTINFOW *expect_effects; -}; - -static BOOL CALLBACK check_effects( const DIEFFECTINFOW *effect, void *args ) -{ - static const DIEFFECTINFOW unexpected_effect = {0}; - struct check_effects_params *params = args; - const DIEFFECTINFOW *exp = params->expect_effects + params->index; - - winetest_push_context( "effect[%d]", params->index ); - - ok( params->index < params->expect_count, "unexpected extra object\n" ); - if (params->index >= params->expect_count) exp = &unexpected_effect; - - check_member( *effect, *exp, "%u", dwSize ); - check_member_guid( *effect, *exp, guid ); - check_member( *effect, *exp, "%#x", dwEffType ); - check_member( *effect, *exp, "%#x", dwStaticParams ); - check_member( *effect, *exp, "%#x", dwDynamicParams ); - check_member_wstr( *effect, *exp, tszName ); - - winetest_pop_context(); - params->index++; - - return DIENUM_CONTINUE; -} - -static BOOL CALLBACK check_effect_count( const DIEFFECTINFOW *effect, void *args ) -{ - DWORD *count = args; - *count = *count + 1; - return DIENUM_CONTINUE; -} - -static BOOL CALLBACK check_no_created_effect_objects( IDirectInputEffect *effect, void *context ) -{ - ok( 0, "unexpected effect %p\n", effect ); - return DIENUM_CONTINUE; -} - -struct check_created_effect_params -{ - IDirectInputEffect *expect_effect; - DWORD count; -}; - -static BOOL CALLBACK check_created_effect_objects( IDirectInputEffect *effect, void *context ) -{ - struct check_created_effect_params *params = context; - ULONG ref; - - ok( effect == params->expect_effect, "got effect %p, expected %p\n", effect, params->expect_effect ); - params->count++; - - IDirectInputEffect_AddRef( effect ); - ref = IDirectInputEffect_Release( effect ); - ok( ref == 1, "got ref %u, expected 1\n", ref ); - return DIENUM_CONTINUE; -} - -static BOOL CALLBACK enum_device_count( const DIDEVICEINSTANCEW *devinst, void *context ) -{ - DWORD *count = context; - *count = *count + 1; - return DIENUM_CONTINUE; -} - -static HRESULT create_dinput_device( DWORD version, DIDEVICEINSTANCEW *devinst, IDirectInputDevice8W **device ) -{ - DIPROPDWORD prop_dword = - { - .diph = - { - .dwSize = sizeof(DIPROPDWORD), - .dwHeaderSize = sizeof(DIPROPHEADER), - .dwHow = DIPH_DEVICE, - }, - }; IDirectInput8W *di8; IDirectInputW *di; - ULONG ref, count; HRESULT hr; + ULONG ref;
if (version >= 0x800) { @@ -3524,76 +3393,6 @@ static HRESULT create_dinput_device( DWORD version, DIDEVICEINSTANCEW *devinst, return DIERR_DEVICENOTREG; }
- hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_ALL, NULL, NULL, DIEDFL_ALLDEVICES ); - ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); - hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_ALL, enum_device_count, &count, 0xdeadbeef ); - ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); - hr = IDirectInput8_EnumDevices( di8, 0xdeadbeef, enum_device_count, &count, DIEDFL_ALLDEVICES ); - ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); - - count = 0; - hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_ALL, enum_device_count, &count, DIEDFL_ALLDEVICES ); - ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - ok( count == 3, "got count %u, expected 0\n", count ); - count = 0; - hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_DEVICE, enum_device_count, &count, DIEDFL_ALLDEVICES ); - ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - ok( count == 0, "got count %u, expected 0\n", count ); - count = 0; - hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_POINTER, enum_device_count, &count, - DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN ); - ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - todo_wine - ok( count == 3, "got count %u, expected 3\n", count ); - count = 0; - hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_KEYBOARD, enum_device_count, &count, - DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN ); - ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - todo_wine - ok( count == 3, "got count %u, expected 3\n", count ); - count = 0; - hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_GAMECTRL, enum_device_count, &count, - DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN ); - ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - ok( count == 1, "got count %u, expected 1\n", count ); - - count = 0; - hr = IDirectInput8_EnumDevices( di8, (devinst->dwDevType & 0xff), enum_device_count, &count, DIEDFL_ALLDEVICES ); - ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - ok( count == 1, "got count %u, expected 1\n", count ); - - count = 0; - hr = IDirectInput8_EnumDevices( di8, (devinst->dwDevType & 0xff), enum_device_count, &count, DIEDFL_FORCEFEEDBACK ); - ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - if (IsEqualGUID( &devinst->guidFFDriver, &GUID_NULL )) ok( count == 0, "got count %u, expected 0\n", count ); - else ok( count == 1, "got count %u, expected 1\n", count ); - - count = 0; - hr = IDirectInput8_EnumDevices( di8, (devinst->dwDevType & 0xff) + 1, enum_device_count, &count, DIEDFL_ALLDEVICES ); - if ((devinst->dwDevType & 0xff) != DI8DEVTYPE_SUPPLEMENTAL) ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - else ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); - ok( count == 0, "got count %u, expected 0\n", count ); - - hr = IDirectInput8_CreateDevice( di8, &devinst->guidInstance, NULL, NULL ); - ok( hr == E_POINTER, "CreateDevice returned %#x\n", hr ); - hr = IDirectInput8_CreateDevice( di8, NULL, device, NULL ); - ok( hr == E_POINTER, "CreateDevice returned %#x\n", hr ); - hr = IDirectInput8_CreateDevice( di8, &GUID_NULL, device, NULL ); - ok( hr == DIERR_DEVICENOTREG, "CreateDevice returned %#x\n", hr ); - hr = IDirectInput8_CreateDevice( di8, &devinst->guidInstance, device, NULL ); - ok( hr == DI_OK, "CreateDevice returned %#x\n", hr ); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( *device, DIPROP_VIDPID, &prop_dword.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_VIDPID returned %#x\n", hr ); - /* Wine may get the wrong device here, because the test driver creates another instance of - hidclass.sys, and gets duplicate rawinput handles, which we use in the guidInstance */ - todo_wine_if( prop_dword.dwData != EXPECT_VIDPID ) - ok( prop_dword.dwData == EXPECT_VIDPID, "got %#x expected %#x\n", prop_dword.dwData, EXPECT_VIDPID ); - - ref = IDirectInputDevice8_Release( *device ); - ok( ref == 0, "Release returned %d\n", ref ); - hr = IDirectInput8_CreateDevice( di8, &expect_guid_product, device, NULL ); ok( hr == DI_OK, "CreateDevice returned %#x\n", hr );
@@ -3621,55 +3420,6 @@ static HRESULT create_dinput_device( DWORD version, DIDEVICEINSTANCEW *devinst, return DIERR_DEVICENOTREG; }
- hr = IDirectInput_EnumDevices( di, 0, NULL, NULL, DIEDFL_ALLDEVICES ); - ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); - hr = IDirectInput_EnumDevices( di, 0, enum_device_count, &count, 0xdeadbeef ); - ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); - hr = IDirectInput_EnumDevices( di, 0xdeadbeef, enum_device_count, &count, DIEDFL_ALLDEVICES ); - ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); - hr = IDirectInput_EnumDevices( di, 0, enum_device_count, &count, DIEDFL_INCLUDEHIDDEN ); - ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); - - count = 0; - hr = IDirectInput_EnumDevices( di, 0, enum_device_count, &count, DIEDFL_ALLDEVICES ); - ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - ok( count == 3, "got count %u, expected 0\n", count ); - count = 0; - hr = IDirectInput_EnumDevices( di, DIDEVTYPE_DEVICE, enum_device_count, &count, DIEDFL_ALLDEVICES ); - ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - ok( count == 0, "got count %u, expected 0\n", count ); - count = 0; - hr = IDirectInput_EnumDevices( di, DIDEVTYPE_MOUSE, enum_device_count, &count, - DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS ); - ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - todo_wine - ok( count == 3, "got count %u, expected 3\n", count ); - count = 0; - hr = IDirectInput_EnumDevices( di, DIDEVTYPE_KEYBOARD, enum_device_count, &count, - DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS ); - ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - todo_wine - ok( count == 3, "got count %u, expected 3\n", count ); - count = 0; - hr = IDirectInput_EnumDevices( di, DIDEVTYPE_JOYSTICK, enum_device_count, &count, - DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS ); - ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - ok( count == 1, "got count %u, expected 1\n", count ); - - count = 0; - hr = IDirectInput_EnumDevices( di, (devinst->dwDevType & 0xff), enum_device_count, &count, DIEDFL_ALLDEVICES ); - ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - ok( count == 1, "got count %u, expected 1\n", count ); - - count = 0; - hr = IDirectInput_EnumDevices( di, (devinst->dwDevType & 0xff), enum_device_count, &count, DIEDFL_FORCEFEEDBACK ); - ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); - if (IsEqualGUID( &devinst->guidFFDriver, &GUID_NULL )) ok( count == 0, "got count %u, expected 0\n", count ); - else ok( count == 1, "got count %u, expected 1\n", count ); - - hr = IDirectInput_EnumDevices( di, 0x14, enum_device_count, &count, DIEDFL_ALLDEVICES ); - ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); - hr = IDirectInput_CreateDevice( di, &expect_guid_product, (IDirectInputDeviceW **)device, NULL ); ok( hr == DI_OK, "CreateDevice returned %#x\n", hr );
@@ -3681,6350 +3431,15 @@ static HRESULT create_dinput_device( DWORD version, DIDEVICEINSTANCEW *devinst, return DI_OK; }
-static void test_simple_joystick(void) -{ -#include "psh_hid_macros.h" - static const unsigned char report_desc[] = - { - USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Application), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Report), - REPORT_ID(1, 1), - - USAGE(1, HID_USAGE_GENERIC_WHEEL), - USAGE(4, (0xff01u<<16)|(0x1234)), - USAGE(1, HID_USAGE_GENERIC_X), - USAGE(1, HID_USAGE_GENERIC_Y), - USAGE(4, (HID_USAGE_PAGE_SIMULATION<<16)|HID_USAGE_SIMULATION_RUDDER), - USAGE(4, (HID_USAGE_PAGE_DIGITIZER<<16)|HID_USAGE_DIGITIZER_TIP_PRESSURE), - USAGE(4, (HID_USAGE_PAGE_CONSUMER<<16)|HID_USAGE_CONSUMER_VOLUME), - LOGICAL_MINIMUM(1, 0xe7), - LOGICAL_MAXIMUM(1, 0x38), - PHYSICAL_MINIMUM(1, 0xe7), - PHYSICAL_MAXIMUM(1, 0x38), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 7), - INPUT(1, Data|Var|Abs), - - USAGE(1, HID_USAGE_GENERIC_HATSWITCH), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 8), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 8), - REPORT_SIZE(1, 4), - REPORT_COUNT(1, 1), - INPUT(1, Data|Var|Abs|Null), - - USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), - USAGE_MINIMUM(1, 1), - USAGE_MAXIMUM(1, 2), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 4), - INPUT(1, Data|Var|Abs), - END_COLLECTION, - END_COLLECTION, - }; -#undef REPORT_ID_OR_USAGE_PAGE -#include "pop_hid_macros.h" - - static const HIDP_CAPS hid_caps = - { - .InputReportByteLength = 9, - }; - static const DIDEVCAPS expect_caps = - { - .dwSize = sizeof(DIDEVCAPS), - .dwFlags = DIDC_ATTACHED | DIDC_EMULATED, - .dwDevType = DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK, - .dwAxes = 6, - .dwPOVs = 1, - .dwButtons = 2, - }; - struct hid_expect injected_input[] = - { - { - .code = IOCTL_HID_READ_REPORT, - .report_buf = {1,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0}, - }, - { - .code = IOCTL_HID_READ_REPORT, - .report_buf = {1,0x10,0x10,0x38,0x38,0x10,0x10,0x10,0xf8}, - }, - { - .code = IOCTL_HID_READ_REPORT, - .report_buf = {1,0x10,0x10,0x01,0x01,0x10,0x10,0x10,0x00}, - }, - { - .code = IOCTL_HID_READ_REPORT, - .report_buf = {1,0x10,0x10,0x01,0x01,0x10,0x10,0x10,0x00}, - }, - { - .code = IOCTL_HID_READ_REPORT, - .report_buf = {1,0x10,0x10,0x80,0x80,0x10,0x10,0x10,0xff}, - }, - { - .code = IOCTL_HID_READ_REPORT, - .report_buf = {1,0x10,0x10,0x10,0xee,0x10,0x10,0x10,0x54}, - }, - }; - static const struct DIJOYSTATE2 expect_state[] = - { - {.lX = 32767, .lY = 32767, .lZ = 32767, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, - {.lX = 32767, .lY = 32767, .lZ = 32767, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, - {.lX = 65535, .lY = 65535, .lZ = 32767, .rgdwPOV = {31500, -1, -1, -1}, .rgbButtons = {0x80, 0x80}}, - {.lX = 20779, .lY = 20779, .lZ = 32767, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, - {.lX = 20779, .lY = 20779, .lZ = 32767, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, - {.lX = 0, .lY = 0, .lZ = 32767, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0x80, 0x80}}, - {.lX = 32767, .lY = 5594, .lZ = 32767, .rgdwPOV = {13500, -1, -1, -1}, .rgbButtons = {0x80}}, - }; - static const struct DIJOYSTATE2 expect_state_abs[] = - { - {.lX = -9000, .lY = 26000, .lZ = 26000, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, - {.lX = -9000, .lY = 26000, .lZ = 26000, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, - {.lX = -4000, .lY = 51000, .lZ = 26000, .rgdwPOV = {31500, -1, -1, -1}, .rgbButtons = {0x80, 0x80}}, - {.lX = -10667, .lY = 12905, .lZ = 26000, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, - {.lX = -10667, .lY = 12905, .lZ = 26000, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, - {.lX = -14000, .lY = 1000, .lZ = 26000, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0x80, 0x80}}, - {.lX = -9000, .lY = 1000, .lZ = 26000, .rgdwPOV = {13500, -1, -1, -1}, .rgbButtons = {0x80}}, - }; - static const struct DIJOYSTATE2 expect_state_rel[] = - { - {.lX = 0, .lY = 0, .rgdwPOV = {13500, -1, -1, -1}, .rgbButtons = {0x80, 0}}, - {.lX = 9016, .lY = -984, .lZ = -25984, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, - {.lX = 40, .lY = 40, .rgdwPOV = {31500, -1, -1, -1}, .rgbButtons = {0x80, 0x80}}, - {.lX = -55, .lY = -55, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, - {.lX = 0, .lY = 0, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, - {.lX = -129, .lY = -129, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0x80, 0x80}}, - {.lX = 144, .lY = 110, .rgdwPOV = {13500, -1, -1, -1}, .rgbButtons = {0x80}}, - }; - static const DIDEVICEOBJECTDATA expect_objdata[] = - { - {.dwOfs = 0x4, .dwData = 0xffff, .dwSequence = 0xa}, - {.dwOfs = 0x4, .dwData = 0xffff, .dwSequence = 0xa}, - {.dwOfs = 0, .dwData = 0xffff, .dwSequence = 0xa}, - {.dwOfs = 0x20, .dwData = 31500, .dwSequence = 0xa}, - {.dwOfs = 0x30, .dwData = 0x80, .dwSequence = 0xa}, - {.dwOfs = 0x4, .dwData = 0x512b, .dwSequence = 0xd}, - {.dwOfs = 0, .dwData = 0x512b, .dwSequence = 0xd}, - {.dwOfs = 0x20, .dwData = -1, .dwSequence = 0xd}, - {.dwOfs = 0x30, .dwData = 0, .dwSequence = 0xd}, - {.dwOfs = 0x31, .dwData = 0, .dwSequence = 0xd}, - {.dwOfs = 0x4, .dwData = 0, .dwSequence = 0xf}, - {.dwOfs = 0, .dwData = 0, .dwSequence = 0xf}, - {.dwOfs = 0x30, .dwData = 0x80, .dwSequence = 0xf}, - {.dwOfs = 0x31, .dwData = 0x80, .dwSequence = 0xf}, - }; - - const DIDEVICEINSTANCEW expect_devinst = - { - .dwSize = sizeof(DIDEVICEINSTANCEW), - .guidInstance = expect_guid_product, - .guidProduct = expect_guid_product, - .dwDevType = DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", - .guidFFDriver = GUID_NULL, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_JOYSTICK, - }; - const DIDEVICEOBJECTINSTANCEW expect_objects[] = - { - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(6), - .tszName = L"Volume", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_CONSUMER, - .wUsage = HID_USAGE_CONSUMER_VOLUME, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = 0x4, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(7), - .tszName = L"Tip Pressure", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_DIGITIZER, - .wUsage = HID_USAGE_DIGITIZER_TIP_PRESSURE, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_RzAxis, - .dwOfs = 0x8, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(5), - .dwFlags = DIDOI_ASPECTPOSITION, - .tszName = L"Rudder", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_SIMULATION, - .wUsage = HID_USAGE_SIMULATION_RUDDER, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_YAxis, - .dwOfs = 0xc, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(1), - .dwFlags = DIDOI_ASPECTPOSITION, - .tszName = L"Y Axis", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_Y, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_XAxis, - .dwOfs = 0x10, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(0), - .dwFlags = DIDOI_ASPECTPOSITION, - .tszName = L"X Axis", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_X, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_ZAxis, - .dwOfs = 0x18, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(2), - .dwFlags = DIDOI_ASPECTPOSITION, - .tszName = L"Wheel", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_WHEEL, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_POV, - .dwOfs = 0x1c, - .dwType = DIDFT_POV|DIDFT_MAKEINSTANCE(0), - .tszName = L"Hat Switch", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_HATSWITCH, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Button, - .dwOfs = 0x20, - .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(0), - .tszName = L"Button 0", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_BUTTON, - .wUsage = 0x1, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Button, - .dwOfs = 0x21, - .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(1), - .tszName = L"Button 1", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_BUTTON, - .wUsage = 0x2, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(0), - .tszName = L"Collection 0 - Joystick", - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_JOYSTICK, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(1), - .tszName = L"Collection 1 - Joystick", - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_JOYSTICK, - }, - }; - const DIEFFECTINFOW expect_effects[] = {}; - - struct check_objects_params check_objects_params = - { - .version = DIRECTINPUT_VERSION, - .expect_count = ARRAY_SIZE(expect_objects), - .expect_objs = expect_objects, - }; - struct check_effects_params check_effects_params = - { - .expect_count = ARRAY_SIZE(expect_effects), - .expect_effects = expect_effects, - }; - DIPROPGUIDANDPATH prop_guid_path = - { - .diph = - { - .dwSize = sizeof(DIPROPGUIDANDPATH), - .dwHeaderSize = sizeof(DIPROPHEADER), - .dwHow = DIPH_DEVICE, - }, - }; - DIPROPSTRING prop_string = - { - .diph = - { - .dwSize = sizeof(DIPROPSTRING), - .dwHeaderSize = sizeof(DIPROPHEADER), - .dwHow = DIPH_DEVICE, - }, - }; - DIPROPDWORD prop_dword = - { - .diph = - { - .dwSize = sizeof(DIPROPDWORD), - .dwHeaderSize = sizeof(DIPROPHEADER), - .dwHow = DIPH_DEVICE, - }, - }; - DIPROPRANGE prop_range = - { - .diph = - { - .dwSize = sizeof(DIPROPRANGE), - .dwHeaderSize = sizeof(DIPROPHEADER), - .dwHow = DIPH_DEVICE, - }, - }; - DIPROPPOINTER prop_pointer = - { - .diph = - { - .dwSize = sizeof(DIPROPPOINTER), - .dwHeaderSize = sizeof(DIPROPHEADER), - }, - }; - DIOBJECTDATAFORMAT objdataformat[32] = {{0}}; - WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; - DIDEVICEOBJECTDATA objdata[32] = {{0}}; - DIDEVICEOBJECTINSTANCEW objinst = {0}; - DIDEVICEINSTANCEW devinst = {0}; - DIEFFECTINFOW effectinfo = {0}; - DIDATAFORMAT dataformat = {0}; - IDirectInputDevice8W *device; - IDirectInputEffect *effect; - DIEFFESCAPE escape = {0}; - DIDEVCAPS caps = {0}; - HANDLE event, file; - char buffer[1024]; - DIJOYSTATE2 state; - ULONG i, res, ref; - HRESULT hr; - WCHAR *tmp; - GUID guid; - HWND hwnd; - - GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - - cleanup_registry_keys(); - if (!dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 )) goto done; - if (FAILED(hr = create_dinput_device( DIRECTINPUT_VERSION, &devinst, &device ))) goto done; - - hr = IDirectInputDevice8_Initialize( device, instance, 0x0700, &GUID_NULL ); - todo_wine - ok( hr == DIERR_BETADIRECTINPUTVERSION, "Initialize returned %#x\n", hr ); - hr = IDirectInputDevice8_Initialize( device, instance, DIRECTINPUT_VERSION, NULL ); - todo_wine - ok( hr == E_POINTER, "Initialize returned %#x\n", hr ); - hr = IDirectInputDevice8_Initialize( device, NULL, DIRECTINPUT_VERSION, &GUID_NULL ); - todo_wine - ok( hr == DIERR_INVALIDPARAM, "Initialize returned %#x\n", hr ); - hr = IDirectInputDevice8_Initialize( device, instance, DIRECTINPUT_VERSION, &GUID_NULL ); - todo_wine - ok( hr == REGDB_E_CLASSNOTREG, "Initialize returned %#x\n", hr ); - - hr = IDirectInputDevice8_Initialize( device, instance, DIRECTINPUT_VERSION, &devinst.guidInstance ); - ok( hr == DI_OK, "Initialize returned %#x\n", hr ); - guid = devinst.guidInstance; - memset( &devinst, 0, sizeof(devinst) ); - devinst.dwSize = sizeof(DIDEVICEINSTANCEW); - hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); - ok( hr == DI_OK, "GetDeviceInfo returned %#x\n", hr ); - ok( IsEqualGUID( &guid, &devinst.guidInstance ), "got %s expected %s\n", debugstr_guid( &guid ), - debugstr_guid( &devinst.guidInstance ) ); - hr = IDirectInputDevice8_Initialize( device, instance, DIRECTINPUT_VERSION, &devinst.guidProduct ); - ok( hr == DI_OK, "Initialize returned %#x\n", hr ); - - hr = IDirectInputDevice8_GetDeviceInfo( device, NULL ); - ok( hr == E_POINTER, "GetDeviceInfo returned %#x\n", hr ); - devinst.dwSize = sizeof(DIDEVICEINSTANCEW) + 1; - hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); - ok( hr == DIERR_INVALIDPARAM, "GetDeviceInfo returned %#x\n", hr ); - - devinst.dwSize = sizeof(DIDEVICEINSTANCE_DX3W); - hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); - ok( hr == DI_OK, "GetDeviceInfo returned %#x\n", hr ); - todo_wine - check_member_guid( devinst, expect_devinst, guidInstance ); - check_member_guid( devinst, expect_devinst, guidProduct ); - check_member( devinst, expect_devinst, "%#x", dwDevType ); - todo_wine - check_member_wstr( devinst, expect_devinst, tszInstanceName ); - todo_wine - check_member_wstr( devinst, expect_devinst, tszProductName ); - - memset( &devinst, 0, sizeof(devinst) ); - devinst.dwSize = sizeof(DIDEVICEINSTANCEW); - hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); - ok( hr == DI_OK, "GetDeviceInfo returned %#x\n", hr ); - check_member( devinst, expect_devinst, "%d", dwSize ); - todo_wine - check_member_guid( devinst, expect_devinst, guidInstance ); - check_member_guid( devinst, expect_devinst, guidProduct ); - check_member( devinst, expect_devinst, "%#x", dwDevType ); - todo_wine - check_member_wstr( devinst, expect_devinst, tszInstanceName ); - todo_wine - check_member_wstr( devinst, expect_devinst, tszProductName ); - check_member_guid( devinst, expect_devinst, guidFFDriver ); - check_member( devinst, expect_devinst, "%04x", wUsagePage ); - check_member( devinst, expect_devinst, "%04x", wUsage ); - - hr = IDirectInputDevice8_GetCapabilities( device, NULL ); - ok( hr == E_POINTER, "GetCapabilities returned %#x\n", hr ); - hr = IDirectInputDevice8_GetCapabilities( device, &caps ); - ok( hr == DIERR_INVALIDPARAM, "GetCapabilities returned %#x\n", hr ); - caps.dwSize = sizeof(DIDEVCAPS); - hr = IDirectInputDevice8_GetCapabilities( device, &caps ); - ok( hr == DI_OK, "GetCapabilities returned %#x\n", hr ); - check_member( caps, expect_caps, "%d", dwSize ); - check_member( caps, expect_caps, "%#x", dwFlags ); - check_member( caps, expect_caps, "%#x", dwDevType ); - check_member( caps, expect_caps, "%d", dwAxes ); - check_member( caps, expect_caps, "%d", dwButtons ); - check_member( caps, expect_caps, "%d", dwPOVs ); - check_member( caps, expect_caps, "%d", dwFFSamplePeriod ); - check_member( caps, expect_caps, "%d", dwFFMinTimeResolution ); - check_member( caps, expect_caps, "%d", dwFirmwareRevision ); - check_member( caps, expect_caps, "%d", dwHardwareRevision ); - check_member( caps, expect_caps, "%d", dwFFDriverVersion ); - - hr = IDirectInputDevice8_GetProperty( device, NULL, NULL ); - ok( hr == DIERR_INVALIDPARAM, "GetProperty returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, &GUID_NULL, NULL ); - ok( hr == DIERR_INVALIDPARAM, "GetProperty returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_VIDPID, NULL ); - ok( hr == DIERR_INVALIDPARAM, "GetProperty returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_VIDPID, &prop_string.diph ); - ok( hr == DIERR_INVALIDPARAM, "GetProperty returned %#x\n", hr ); - prop_dword.diph.dwHeaderSize = sizeof(DIPROPHEADER) - 1; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_VIDPID, &prop_dword.diph ); - ok( hr == DIERR_INVALIDPARAM, "GetProperty returned %#x\n", hr ); - prop_dword.diph.dwHeaderSize = sizeof(DIPROPHEADER); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_VIDPID, &prop_dword.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_VIDPID returned %#x\n", hr ); - ok( prop_dword.dwData == EXPECT_VIDPID, "got %#x expected %#x\n", prop_dword.dwData, EXPECT_VIDPID ); - - hr = IDirectInputDevice8_GetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_GUIDANDPATH returned %#x\n", hr ); - todo_wine - ok( IsEqualGUID( &prop_guid_path.guidClass, &GUID_DEVCLASS_HIDCLASS ), "got guid %s\n", - debugstr_guid( &prop_guid_path.guidClass ) ); - todo_wine - ok( !wcsncmp( prop_guid_path.wszPath, expect_path, wcslen( expect_path ) ), "got path %s\n", - debugstr_w(prop_guid_path.wszPath) ); - if (!(tmp = wcsrchr( prop_guid_path.wszPath, '&' ))) - todo_wine ok( 0, "got path %s\n", debugstr_w(prop_guid_path.wszPath) ); - else - { - ok( !wcscmp( wcsrchr( prop_guid_path.wszPath, '&' ), expect_path_end ), "got path %s\n", - debugstr_w(prop_guid_path.wszPath) ); - } - - hr = IDirectInputDevice8_GetProperty( device, DIPROP_INSTANCENAME, &prop_string.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_INSTANCENAME returned %#x\n", hr ); - todo_wine - ok( !wcscmp( prop_string.wsz, expect_devinst.tszInstanceName ), "got instance %s\n", - debugstr_w(prop_string.wsz) ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_PRODUCTNAME, &prop_string.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_PRODUCTNAME returned %#x\n", hr ); - todo_wine - ok( !wcscmp( prop_string.wsz, expect_devinst.tszProductName ), "got product %s\n", - debugstr_w(prop_string.wsz) ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_TYPENAME, &prop_string.diph ); - todo_wine - ok( hr == DI_OK, "GetProperty DIPROP_TYPENAME returned %#x\n", hr ); - todo_wine - ok( !wcscmp( prop_string.wsz, expect_vidpid_str ), "got type %s\n", debugstr_w(prop_string.wsz) ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_USERNAME, &prop_string.diph ); - ok( hr == S_FALSE, "GetProperty DIPROP_USERNAME returned %#x\n", hr ); - todo_wine - ok( !wcscmp( prop_string.wsz, L"" ), "got user %s\n", debugstr_w(prop_string.wsz) ); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_JOYSTICKID, &prop_dword.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_JOYSTICKID returned %#x\n", hr ); - todo_wine - ok( prop_dword.dwData == 0, "got %#x expected %#x\n", prop_dword.dwData, 0 ); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_AXISMODE, &prop_dword.diph ); - todo_wine - ok( hr == DI_OK, "GetProperty DIPROP_AXISMODE returned %#x\n", hr ); - todo_wine - ok( prop_dword.dwData == DIPROPAXISMODE_ABS, "got %u expected %u\n", prop_dword.dwData, DIPROPAXISMODE_ABS ); - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_BUFFERSIZE returned %#x\n", hr ); - ok( prop_dword.dwData == 0, "got %#x expected %#x\n", prop_dword.dwData, 0 ); - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_FFGAIN returned %#x\n", hr ); - ok( prop_dword.dwData == 10000, "got %u expected %u\n", prop_dword.dwData, 10000 ); - - hr = IDirectInputDevice8_GetProperty( device, DIPROP_CALIBRATION, &prop_dword.diph ); - ok( hr == DIERR_INVALIDPARAM, "GetProperty DIPROP_CALIBRATION returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); - ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_AUTOCENTER returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_DEADZONE, &prop_dword.diph ); - ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_DEADZONE returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); - ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_GRANULARITY, &prop_dword.diph ); - ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_GRANULARITY returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_SATURATION, &prop_dword.diph ); - ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_SATURATION returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); - ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_CALIBRATIONMODE returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); - ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_RANGE returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_KEYNAME, &prop_string.diph ); - ok( hr == DIERR_INVALIDPARAM, "GetProperty DIPROP_KEYNAME returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_LOGICALRANGE, &prop_range.diph ); - ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_LOGICALRANGE returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_PHYSICALRANGE, &prop_range.diph ); - ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_PHYSICALRANGE 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 ); - ok( hr == DI_OK, "GetProperty DIPROP_DEADZONE returned %#x\n", hr ); - 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 ); - ok( hr == DI_OK, "GetProperty DIPROP_GRANULARITY returned %#x\n", hr ); - 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 ); - ok( hr == DI_OK, "GetProperty DIPROP_SATURATION returned %#x\n", hr ); - ok( prop_dword.dwData == 10000, "got %u expected %u\n", prop_dword.dwData, 10000 ); - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_CALIBRATIONMODE returned %#x\n", hr ); - ok( prop_dword.dwData == DIPROPCALIBRATIONMODE_COOKED, "got %u expected %u\n", prop_dword.dwData, DIPROPCALIBRATIONMODE_COOKED ); - - prop_string.diph.dwHow = DIPH_BYUSAGE; - prop_string.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_KEYNAME, &prop_string.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_KEYNAME returned %#x\n", hr ); - ok( !wcscmp( prop_string.wsz, expect_objects[4].tszName ), "got DIPROP_KEYNAME %s\n", - debugstr_w( prop_string.wsz ) ); - prop_string.diph.dwObj = MAKELONG( 0x1, HID_USAGE_PAGE_BUTTON ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_KEYNAME, &prop_string.diph ); - todo_wine - ok( hr == DIERR_NOTFOUND, "GetProperty DIPROP_KEYNAME returned %#x\n", hr ); - prop_string.diph.dwHow = DIPH_BYUSAGE; - prop_string.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_KEYNAME, &prop_string.diph ); - ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_KEYNAME returned %#x\n", hr ); - - prop_range.diph.dwHow = DIPH_BYUSAGE; - prop_range.diph.dwObj = MAKELONG( 0, 0 ); - prop_range.lMin = 0xdeadbeef; - prop_range.lMax = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); - ok( hr == DIERR_NOTFOUND, "GetProperty DIPROP_RANGE returned %#x\n", hr ); - prop_range.diph.dwObj = MAKELONG( 0, HID_USAGE_PAGE_GENERIC ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); - ok( hr == DIERR_NOTFOUND, "GetProperty DIPROP_RANGE returned %#x\n", hr ); - prop_range.diph.dwObj = MAKELONG( HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_X ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); - ok( hr == DIERR_NOTFOUND, "GetProperty DIPROP_RANGE returned %#x\n", hr ); - prop_range.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); - prop_range.lMin = 0xdeadbeef; - prop_range.lMax = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_RANGE returned %#x\n", hr ); - ok( prop_range.lMin == 0, "got %d expected %d\n", prop_range.lMin, 0 ); - ok( prop_range.lMax == 65535, "got %d expected %d\n", prop_range.lMax, 65535 ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_LOGICALRANGE, &prop_range.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_LOGICALRANGE returned %#x\n", hr ); - ok( prop_range.lMin == -25, "got %d expected %d\n", prop_range.lMin, -25 ); - ok( prop_range.lMax == 56, "got %d expected %d\n", prop_range.lMax, 56 ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_PHYSICALRANGE, &prop_range.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_PHYSICALRANGE returned %#x\n", hr ); - ok( prop_range.lMin == -25, "got %d expected %d\n", prop_range.lMin, -25 ); - ok( prop_range.lMax == 56, "got %d expected %d\n", prop_range.lMax, 56 ); - - prop_pointer.diph.dwHow = DIPH_BYUSAGE; - prop_pointer.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); - todo_wine - ok( hr == DIERR_NOTINITIALIZED, "GetProperty DIPROP_APPDATA returned %#x\n", hr ); - - hr = IDirectInputDevice8_EnumObjects( device, NULL, NULL, DIDFT_ALL ); - ok( hr == DIERR_INVALIDPARAM, "EnumObjects returned %#x\n", hr ); - hr = IDirectInputDevice8_EnumObjects( device, check_object_count, &res, 0x20 ); - ok( hr == DIERR_INVALIDPARAM, "EnumObjects 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 ); - ok( res == 8, "got %u expected %u\n", res, 8 ); - hr = IDirectInputDevice8_EnumObjects( device, check_objects, &check_objects_params, DIDFT_ALL ); - ok( hr == DI_OK, "EnumObjects returned %#x\n", hr ); - ok( check_objects_params.index >= check_objects_params.expect_count, "missing %u objects\n", - check_objects_params.expect_count - check_objects_params.index ); - - hr = IDirectInputDevice8_GetObjectInfo( device, NULL, 0, DIPH_DEVICE ); - ok( hr == E_POINTER, "GetObjectInfo returned: %#x\n", hr ); - hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, 0, DIPH_DEVICE ); - ok( hr == DIERR_INVALIDPARAM, "GetObjectInfo returned: %#x\n", hr ); - objinst.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW); - hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, 0, DIPH_DEVICE ); - ok( hr == DIERR_INVALIDPARAM, "GetObjectInfo returned: %#x\n", hr ); - - res = MAKELONG( HID_USAGE_GENERIC_Z, HID_USAGE_PAGE_GENERIC ); - hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, res, DIPH_BYUSAGE ); - ok( hr == DIERR_NOTFOUND, "GetObjectInfo returned: %#x\n", hr ); - res = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); - hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, res, DIPH_BYUSAGE ); - ok( hr == DI_OK, "GetObjectInfo returned: %#x\n", hr ); - - check_member( objinst, expect_objects[4], "%u", dwSize ); - check_member_guid( objinst, expect_objects[4], guidType ); - check_member( objinst, expect_objects[4], "%#x", dwOfs ); - check_member( objinst, expect_objects[4], "%#x", dwType ); - check_member( objinst, expect_objects[4], "%#x", dwFlags ); - if (!localized) check_member_wstr( objinst, expect_objects[4], tszName ); - check_member( objinst, expect_objects[4], "%u", dwFFMaxForce ); - check_member( objinst, expect_objects[4], "%u", dwFFForceResolution ); - check_member( objinst, expect_objects[4], "%u", wCollectionNumber ); - check_member( objinst, expect_objects[4], "%u", wDesignatorIndex ); - check_member( objinst, expect_objects[4], "%#04x", wUsagePage ); - check_member( objinst, expect_objects[4], "%#04x", wUsage ); - check_member( objinst, expect_objects[4], "%#04x", dwDimension ); - check_member( objinst, expect_objects[4], "%#04x", wExponent ); - check_member( objinst, expect_objects[4], "%u", wReportId ); - - hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, 0x14, DIPH_BYOFFSET ); - ok( hr == DIERR_NOTFOUND, "GetObjectInfo returned: %#x\n", hr ); - hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, 0, DIPH_BYOFFSET ); - ok( hr == DIERR_NOTFOUND, "GetObjectInfo returned: %#x\n", hr ); - res = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 3 ); - hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, res, DIPH_BYID ); - ok( hr == DIERR_NOTFOUND, "GetObjectInfo returned: %#x\n", hr ); - res = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 1 ); - hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, res, DIPH_BYID ); - ok( hr == DI_OK, "GetObjectInfo returned: %#x\n", hr ); - - check_member( objinst, expect_objects[8], "%u", dwSize ); - check_member_guid( objinst, expect_objects[8], guidType ); - check_member( objinst, expect_objects[8], "%#x", dwOfs ); - check_member( objinst, expect_objects[8], "%#x", dwType ); - check_member( objinst, expect_objects[8], "%#x", dwFlags ); - if (!localized) check_member_wstr( objinst, expect_objects[8], tszName ); - check_member( objinst, expect_objects[8], "%u", dwFFMaxForce ); - check_member( objinst, expect_objects[8], "%u", dwFFForceResolution ); - check_member( objinst, expect_objects[8], "%u", wCollectionNumber ); - check_member( objinst, expect_objects[8], "%u", wDesignatorIndex ); - check_member( objinst, expect_objects[8], "%#04x", wUsagePage ); - check_member( objinst, expect_objects[8], "%#04x", wUsage ); - check_member( objinst, expect_objects[8], "%#04x", dwDimension ); - check_member( objinst, expect_objects[8], "%#04x", wExponent ); - check_member( objinst, expect_objects[8], "%u", wReportId ); - - hr = IDirectInputDevice8_EnumEffects( device, NULL, NULL, DIEFT_ALL ); - ok( hr == DIERR_INVALIDPARAM, "EnumEffects returned %#x\n", hr ); - res = 0; - hr = IDirectInputDevice8_EnumEffects( device, check_effect_count, &res, 0xfe ); - ok( hr == DI_OK, "EnumEffects returned %#x\n", hr ); - ok( res == 0, "got %u expected %u\n", res, 0 ); - res = 0; - hr = IDirectInputDevice8_EnumEffects( device, check_effect_count, &res, DIEFT_PERIODIC ); - ok( hr == DI_OK, "EnumEffects returned %#x\n", hr ); - ok( res == 0, "got %u expected %u\n", res, 0 ); - hr = IDirectInputDevice8_EnumEffects( device, check_effects, &check_effects_params, DIEFT_ALL ); - ok( hr == DI_OK, "EnumEffects returned %#x\n", hr ); - ok( check_effects_params.index >= check_effects_params.expect_count, "missing %u effects\n", - check_effects_params.expect_count - check_effects_params.index ); - - hr = IDirectInputDevice8_GetEffectInfo( device, NULL, &GUID_Sine ); - ok( hr == E_POINTER, "GetEffectInfo returned %#x\n", hr ); - effectinfo.dwSize = sizeof(DIEFFECTINFOW) + 1; - hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_Sine ); - ok( hr == DIERR_INVALIDPARAM, "GetEffectInfo returned %#x\n", hr ); - effectinfo.dwSize = sizeof(DIEFFECTINFOW); - hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_NULL ); - ok( hr == DIERR_DEVICENOTREG, "GetEffectInfo returned %#x\n", hr ); - hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_Sine ); - ok( hr == DIERR_DEVICENOTREG, "GetEffectInfo returned %#x\n", hr ); - - hr = IDirectInputDevice8_SetDataFormat( device, NULL ); - ok( hr == E_POINTER, "SetDataFormat returned: %#x\n", hr ); - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); - dataformat.dwSize = sizeof(DIDATAFORMAT); - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); - dataformat.dwObjSize = sizeof(DIOBJECTDATAFORMAT); - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); - hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); - ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); - - hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, DIJOFS_Y, DIPH_BYOFFSET ); - ok( hr == DI_OK, "GetObjectInfo returned: %#x\n", hr ); - - check_member( objinst, expect_objects[3], "%u", dwSize ); - check_member_guid( objinst, expect_objects[3], guidType ); - check_member( objinst, expect_objects[3], "%#x", dwOfs ); - check_member( objinst, expect_objects[3], "%#x", dwType ); - check_member( objinst, expect_objects[3], "%#x", dwFlags ); - if (!localized) check_member_wstr( objinst, expect_objects[3], tszName ); - check_member( objinst, expect_objects[3], "%u", dwFFMaxForce ); - check_member( objinst, expect_objects[3], "%u", dwFFForceResolution ); - check_member( objinst, expect_objects[3], "%u", wCollectionNumber ); - check_member( objinst, expect_objects[3], "%u", wDesignatorIndex ); - check_member( objinst, expect_objects[3], "%#04x", wUsagePage ); - check_member( objinst, expect_objects[3], "%#04x", wUsage ); - check_member( objinst, expect_objects[3], "%#04x", dwDimension ); - check_member( objinst, expect_objects[3], "%#04x", wExponent ); - check_member( objinst, expect_objects[3], "%u", wReportId ); - - hr = IDirectInputDevice8_SetEventNotification( device, (HANDLE)0xdeadbeef ); - todo_wine - ok( hr == E_HANDLE, "SetEventNotification returned: %#x\n", hr ); - event = CreateEventW( NULL, FALSE, FALSE, NULL ); - ok( event != NULL, "CreateEventW failed, last error %u\n", GetLastError() ); - hr = IDirectInputDevice8_SetEventNotification( device, event ); - 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, - FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL ); - ok( file != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError() ); - - hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, 0 ); - ok( hr == DIERR_INVALIDPARAM, "SetCooperativeLevel returned: %#x\n", hr ); - hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_BACKGROUND ); - ok( hr == DIERR_INVALIDPARAM, "SetCooperativeLevel returned: %#x\n", hr ); - hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE ); - ok( hr == E_HANDLE, "SetCooperativeLevel returned: %#x\n", hr ); - hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); - ok( hr == E_HANDLE, "SetCooperativeLevel returned: %#x\n", hr ); - hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_FOREGROUND | DISCL_EXCLUSIVE ); - ok( hr == E_HANDLE, "SetCooperativeLevel returned: %#x\n", hr ); - - hwnd = CreateWindowW( L"static", L"dinput", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 10, 10, 200, 200, - NULL, NULL, NULL, NULL ); - SetForegroundWindow( hwnd ); - - hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE ); - ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr ); - hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); - ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr ); - hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE ); - ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr ); - - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_NOEFFECT, "Unacquire returned: %#x\n", hr ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE ); - ok( hr == DIERR_ACQUIRED, "SetCooperativeLevel returned: %#x\n", hr ); - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - - DestroyWindow( hwnd ); - - hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE ); - ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr ); - - hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); - ok( hr == DIERR_NOTACQUIRED, "GetDeviceState returned: %#x\n", hr ); - - hr = IDirectInputDevice8_Poll( device ); - ok( hr == DIERR_NOTACQUIRED, "Poll returned: %#x\n", hr ); - - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - - hr = IDirectInputDevice8_Poll( device ); - ok( hr == DI_NOEFFECT, "Poll returned: %#x\n", hr ); - - hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2) + 1, &state ); - ok( hr == DIERR_INVALIDPARAM, "GetDeviceState returned: %#x\n", hr ); - - for (i = 0; i < ARRAY_SIZE(injected_input); ++i) - { - winetest_push_context( "state[%d]", i ); - hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); - ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); - check_member( state, expect_state[i], "%d", lX ); - check_member( state, expect_state[i], "%d", lY ); - check_member( state, expect_state[i], "%d", lZ ); - check_member( state, expect_state[i], "%d", lRx ); - check_member( state, expect_state[i], "%#x", rgdwPOV[0] ); - check_member( state, expect_state[i], "%#x", rgdwPOV[1] ); - check_member( state, expect_state[i], "%#x", rgbButtons[0] ); - check_member( state, expect_state[i], "%#x", rgbButtons[1] ); - check_member( state, expect_state[i], "%#x", rgbButtons[2] ); - - send_hid_input( file, &injected_input[i], sizeof(*injected_input) ); - - res = WaitForSingleObject( event, 100 ); - if (i == 0 || i == 3) ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" ); - else ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); - ResetEvent( event ); - winetest_pop_context(); - } - - hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); - ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); - winetest_push_context( "state[%d]", i ); - check_member( state, expect_state[i], "%d", lX ); - check_member( state, expect_state[i], "%d", lY ); - check_member( state, expect_state[i], "%d", lZ ); - check_member( state, expect_state[i], "%d", lRx ); - check_member( state, expect_state[i], "%#x", rgdwPOV[0] ); - check_member( state, expect_state[i], "%#x", rgdwPOV[1] ); - check_member( state, expect_state[i], "%#x", rgbButtons[0] ); - check_member( state, expect_state[i], "%#x", rgbButtons[1] ); - check_member( state, expect_state[i], "%#x", rgbButtons[2] ); - winetest_pop_context(); - - res = 1; - hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA) - 1, objdata, &res, DIGDD_PEEK ); - todo_wine - ok( hr == DIERR_INVALIDPARAM, "GetDeviceData returned %#x\n", hr ); - res = 1; - hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, DIGDD_PEEK ); - ok( hr == DIERR_NOTBUFFERED, "GetDeviceData returned %#x\n", hr ); - - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire 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 = 1; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); - ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_BUFFERSIZE returned %#x\n", hr ); - prop_dword.diph.dwHow = DIPH_DEVICE; - prop_dword.diph.dwObj = 0; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_BUFFERSIZE returned %#x\n", hr ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - - res = 1; - hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, DIGDD_PEEK ); - ok( hr == DI_OK, "GetDeviceData returned %#x\n", hr ); - ok( res == 0, "got %u expected %u\n", res, 0 ); - - send_hid_input( file, &injected_input[0], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); - ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); - ResetEvent( event ); - - res = 1; - hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, DIGDD_PEEK ); - ok( hr == DI_BUFFEROVERFLOW, "GetDeviceData returned %#x\n", hr ); - ok( res == 0, "got %u expected %u\n", res, 0 ); - res = 1; - hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, 0 ); - todo_wine - ok( hr == DI_OK, "GetDeviceData returned %#x\n", hr ); - ok( res == 0, "got %u expected %u\n", res, 0 ); - - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - prop_dword.diph.dwHow = DIPH_DEVICE; - prop_dword.diph.dwObj = 0; - prop_dword.dwData = 10; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_BUFFERSIZE returned %#x\n", hr ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - - send_hid_input( file, &injected_input[1], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); - ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); - ResetEvent( event ); - - res = 1; - hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, DIGDD_PEEK ); - ok( hr == DI_OK, "GetDeviceData returned %#x\n", hr ); - ok( res == 1, "got %u expected %u\n", res, 1 ); - check_member( objdata[0], expect_objdata[0], "%#x", dwOfs ); - check_member( objdata[0], expect_objdata[0], "%#x", dwData ); - ok( objdata[0].uAppData == -1, "got %p, expected %p\n", (void *)objdata[0].uAppData, (void *)-1 ); - res = 4; - hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, 0 ); - ok( hr == DI_OK, "GetDeviceData returned %#x\n", hr ); - ok( res == 4, "got %u expected %u\n", res, 4 ); - for (i = 0; i < 4; ++i) - { - winetest_push_context( "objdata[%d]", i ); - check_member( objdata[i], expect_objdata[1 + i], "%#x", dwOfs ); - check_member( objdata[i], expect_objdata[1 + i], "%#x", dwData ); - ok( objdata[i].uAppData == -1, "got %p, expected %p\n", (void *)objdata[i].uAppData, (void *)-1 ); - winetest_pop_context(); - } - - send_hid_input( file, &injected_input[2], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); - ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); - ResetEvent( event ); - send_hid_input( file, &injected_input[4], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); - ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); - ResetEvent( event ); - - res = 1; - hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, 0 ); - ok( hr == DI_BUFFEROVERFLOW, "GetDeviceData returned %#x\n", hr ); - ok( res == 1, "got %u expected %u\n", res, 1 ); - todo_wine - check_member( objdata[0], expect_objdata[5], "%#x", dwOfs ); - todo_wine - check_member( objdata[0], expect_objdata[5], "%#x", dwData ); - ok( objdata[0].uAppData == -1, "got %p, expected %p\n", (void *)objdata[0].uAppData, (void *)-1 ); - res = ARRAY_SIZE(objdata); - hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, 0 ); - ok( hr == DI_OK, "GetDeviceData returned %#x\n", hr ); - ok( res == 8, "got %u expected %u\n", res, 8 ); - for (i = 0; i < 8; ++i) - { - winetest_push_context( "objdata[%d]", i ); - todo_wine - check_member( objdata[i], expect_objdata[6 + i], "%#x", dwOfs ); - todo_wine_if( i == 1 || i == 2 || i == 6 ) - check_member( objdata[i], expect_objdata[6 + i], "%#x", dwData ); - ok( objdata[i].uAppData == -1, "got %p, expected %p\n", (void *)objdata[i].uAppData, (void *)-1 ); - winetest_pop_context(); - } - - send_hid_input( file, &injected_input[3], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); - ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); - ResetEvent( event ); - - hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); - ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); - check_member( state, expect_state[3], "%d", lX ); - check_member( state, expect_state[3], "%d", lY ); - check_member( state, expect_state[3], "%d", lZ ); - check_member( state, expect_state[3], "%d", lRx ); - check_member( state, expect_state[3], "%d", rgdwPOV[0] ); - check_member( state, expect_state[3], "%d", rgdwPOV[1] ); - check_member( state, expect_state[3], "%#x", rgbButtons[0] ); - check_member( state, expect_state[3], "%#x", rgbButtons[1] ); - check_member( state, expect_state[3], "%#x", rgbButtons[2] ); - - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - - dataformat.dwSize = sizeof(DIDATAFORMAT); - dataformat.dwObjSize = sizeof(DIOBJECTDATAFORMAT); - dataformat.dwFlags = DIDF_ABSAXIS; - dataformat.dwDataSize = sizeof(buffer); - dataformat.dwNumObjs = 0; - dataformat.rgodf = objdataformat; - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); - - dataformat.dwNumObjs = 1; - dataformat.dwDataSize = 8; - objdataformat[0].pguid = NULL; - objdataformat[0].dwOfs = 2; - objdataformat[0].dwType = DIDFT_AXIS|DIDFT_ANYINSTANCE; - objdataformat[0].dwFlags = 0; - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - todo_wine - ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); - objdataformat[0].dwOfs = 4; - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); - dataformat.dwDataSize = 10; - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - todo_wine - ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); - dataformat.dwDataSize = 8; - objdataformat[0].dwOfs = 2; - objdataformat[0].dwType = DIDFT_OPTIONAL|0xff|DIDFT_ANYINSTANCE; - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - todo_wine - ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); - - dataformat.dwNumObjs = 2; - dataformat.dwDataSize = 5; - objdataformat[0].pguid = NULL; - objdataformat[0].dwOfs = 4; - objdataformat[0].dwType = DIDFT_BUTTON|DIDFT_ANYINSTANCE; - objdataformat[0].dwFlags = 0; - objdataformat[1].pguid = NULL; - objdataformat[1].dwOfs = 0; - objdataformat[1].dwType = DIDFT_AXIS|DIDFT_MAKEINSTANCE( 0 ); - objdataformat[1].dwFlags = 0; - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - todo_wine - ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); - dataformat.dwDataSize = 8; - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); - - dataformat.dwNumObjs = 4; - dataformat.dwDataSize = 12; - objdataformat[0].pguid = NULL; - objdataformat[0].dwOfs = 0; - objdataformat[0].dwType = DIDFT_AXIS|DIDFT_MAKEINSTANCE( 0 ); - objdataformat[0].dwFlags = 0; - objdataformat[1].pguid = NULL; - objdataformat[1].dwOfs = 0; - objdataformat[1].dwType = DIDFT_AXIS|DIDFT_MAKEINSTANCE( 0 ); - objdataformat[1].dwFlags = 0; - objdataformat[2].pguid = &GUID_ZAxis; - objdataformat[2].dwOfs = 8; - objdataformat[2].dwType = 0xff|DIDFT_ANYINSTANCE; - objdataformat[2].dwFlags = 0; - objdataformat[3].pguid = &GUID_POV; - objdataformat[3].dwOfs = 0; - objdataformat[3].dwType = 0xff|DIDFT_ANYINSTANCE; - objdataformat[3].dwFlags = 0; - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); - objdataformat[1].dwType = DIDFT_AXIS|DIDFT_MAKEINSTANCE( 12 ); - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); - objdataformat[1].dwType = DIDFT_AXIS|DIDFT_MAKEINSTANCE( 0xff ); - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); - objdataformat[1].dwType = DIDFT_AXIS|DIDFT_MAKEINSTANCE( 1 ); - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); - objdataformat[1].pguid = &GUID_RzAxis; - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); - objdataformat[1].pguid = &GUID_Unknown; - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); - objdataformat[1].pguid = &GUID_YAxis; - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); - objdataformat[1].pguid = NULL; - objdataformat[1].dwType = DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_MAKEINSTANCE( 0 ); - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); - - dataformat.dwNumObjs = 0; - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - - send_hid_input( file, &injected_input[4], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); - todo_wine - ok( res == WAIT_TIMEOUT, "WaitForSingleObject failed\n" ); - ResetEvent( event ); - - hr = IDirectInputDevice8_GetDeviceState( device, dataformat.dwDataSize, buffer ); - ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - - dataformat.dwNumObjs = 4; - hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); - ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - - send_hid_input( file, &injected_input[4], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); - todo_wine - ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); - ResetEvent( event ); - send_hid_input( file, &injected_input[3], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); - ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); - ResetEvent( event ); - - hr = IDirectInputDevice8_GetDeviceState( device, dataformat.dwDataSize, buffer ); - ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); - ok( ((ULONG *)buffer)[0] == 0x512b, "got %#x, expected %#x\n", ((ULONG *)buffer)[0], 0x512b ); - ok( ((ULONG *)buffer)[1] == 0, "got %#x, expected %#x\n", ((ULONG *)buffer)[1], 0 ); - ok( ((ULONG *)buffer)[2] == 0x7fff, "got %#x, expected %#x\n", ((ULONG *)buffer)[2], 0x7fff ); - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - - hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); - ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - - send_hid_input( file, &injected_input[4], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); - ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); - ResetEvent( event ); - send_hid_input( file, &injected_input[3], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); - ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); - ResetEvent( event ); - - hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); - ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); - check_member( state, expect_state[3], "%d", lX ); - check_member( state, expect_state[3], "%d", lY ); - check_member( state, expect_state[3], "%d", lZ ); - check_member( state, expect_state[3], "%d", lRx ); - check_member( state, expect_state[3], "%d", rgdwPOV[0] ); - check_member( state, expect_state[3], "%d", rgdwPOV[1] ); - check_member( state, expect_state[3], "%#x", rgbButtons[0] ); - check_member( state, expect_state[3], "%#x", rgbButtons[1] ); - check_member( state, expect_state[3], "%#x", rgbButtons[2] ); - - prop_range.diph.dwHow = DIPH_DEVICE; - prop_range.diph.dwObj = 0; - prop_range.lMin = 1000; - prop_range.lMax = 51000; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_RANGE, &prop_range.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_RANGE returned %#x\n", hr ); - prop_range.diph.dwHow = DIPH_BYUSAGE; - prop_range.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); - prop_range.lMin = -4000; - prop_range.lMax = -14000; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_RANGE, &prop_range.diph ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_RANGE returned %#x\n", hr ); - prop_range.lMin = -14000; - prop_range.lMax = -4000; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_RANGE, &prop_range.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_RANGE returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_LOGICALRANGE, &prop_range.diph ); - ok( hr == DIERR_ACQUIRED, "SetProperty DIPROP_LOGICALRANGE returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_PHYSICALRANGE, &prop_range.diph ); - ok( hr == DIERR_ACQUIRED, "SetProperty DIPROP_PHYSICALRANGE returned %#x\n", hr ); - - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_LOGICALRANGE, &prop_range.diph ); - ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_LOGICALRANGE returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_PHYSICALRANGE, &prop_range.diph ); - ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_PHYSICALRANGE returned %#x\n", hr ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - - prop_range.diph.dwHow = DIPH_DEVICE; - prop_range.diph.dwObj = 0; - prop_range.lMin = 0xdeadbeef; - prop_range.lMax = 0xdeadbeef; - 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_BYUSAGE; - prop_range.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); - prop_range.lMin = 0xdeadbeef; - prop_range.lMax = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_RANGE returned %#x\n", hr ); - ok( prop_range.lMin == -14000, "got %d expected %d\n", prop_range.lMin, -14000 ); - ok( prop_range.lMax == -4000, "got %d expected %d\n", prop_range.lMax, -4000 ); - prop_range.diph.dwHow = DIPH_BYUSAGE; - prop_range.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_Y, HID_USAGE_PAGE_GENERIC ); - prop_range.lMin = 0xdeadbeef; - prop_range.lMax = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_RANGE returned %#x\n", hr ); - ok( prop_range.lMin == 1000, "got %d expected %d\n", prop_range.lMin, 1000 ); - ok( prop_range.lMax == 51000, "got %d expected %d\n", prop_range.lMax, 51000 ); - - hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); - ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); - check_member( state, expect_state_abs[1], "%d", lX ); - check_member( state, expect_state_abs[1], "%d", lY ); - check_member( state, expect_state_abs[1], "%d", lZ ); - check_member( state, expect_state_abs[1], "%d", lRx ); - check_member( state, expect_state_abs[1], "%d", rgdwPOV[0] ); - check_member( state, expect_state_abs[1], "%d", rgdwPOV[1] ); - check_member( state, expect_state_abs[1], "%#x", rgbButtons[0] ); - check_member( state, expect_state_abs[1], "%#x", rgbButtons[1] ); - check_member( state, expect_state_abs[1], "%#x", rgbButtons[2] ); - - hr = IDirectInputDevice8_SetProperty( device, NULL, NULL ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, &GUID_NULL, NULL ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_VIDPID, NULL ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_VIDPID, &prop_string.diph ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty returned %#x\n", hr ); - - prop_dword.diph.dwHow = DIPH_DEVICE; - prop_dword.diph.dwObj = 0; - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_VIDPID, &prop_dword.diph ); - ok( hr == DIERR_READONLY, "SetProperty DIPROP_VIDPID returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph ); - ok( hr == DIERR_READONLY, "SetProperty DIPROP_GUIDANDPATH returned %#x\n", hr ); - - prop_string.diph.dwHow = DIPH_DEVICE; - prop_string.diph.dwObj = 0; - wcscpy( prop_string.wsz, L"instance name" ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_INSTANCENAME, &prop_string.diph ); - ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_INSTANCENAME returned %#x\n", hr ); - - wcscpy( prop_string.wsz, L"product name" ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_PRODUCTNAME, &prop_string.diph ); - todo_wine - ok( hr == DI_OK, "SetProperty DIPROP_PRODUCTNAME returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_PRODUCTNAME, &prop_string.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_PRODUCTNAME returned %#x\n", hr ); - todo_wine - ok( !wcscmp( prop_string.wsz, expect_devinst.tszProductName ), "got product %s\n", - debugstr_w(prop_string.wsz) ); - - hr = IDirectInputDevice8_SetProperty( device, DIPROP_TYPENAME, &prop_string.diph ); - ok( hr == DIERR_READONLY, "SetProperty DIPROP_TYPENAME returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_USERNAME, &prop_string.diph ); - ok( hr == DIERR_READONLY, "SetProperty DIPROP_USERNAME returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); - ok( hr == DIERR_READONLY, "SetProperty DIPROP_FFLOAD returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_GRANULARITY, &prop_dword.diph ); - ok( hr == DIERR_READONLY, "SetProperty DIPROP_GRANULARITY returned %#x\n", hr ); - - hr = IDirectInputDevice8_SetProperty( device, DIPROP_JOYSTICKID, &prop_dword.diph ); - todo_wine - ok( hr == DIERR_ACQUIRED, "SetProperty DIPROP_JOYSTICKID returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_AXISMODE, &prop_dword.diph ); - ok( hr == DIERR_ACQUIRED, "SetProperty DIPROP_AXISMODE returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); - ok( hr == DIERR_ACQUIRED, "SetProperty DIPROP_BUFFERSIZE returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); - ok( hr == DIERR_ACQUIRED, "SetProperty DIPROP_AUTOCENTER returned %#x\n", hr ); - prop_pointer.diph.dwHow = DIPH_BYUSAGE; - prop_pointer.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); - todo_wine - ok( hr == DIERR_ACQUIRED, "SetProperty DIPROP_APPDATA returned %#x\n", hr ); - - prop_dword.diph.dwHow = DIPH_DEVICE; - prop_dword.diph.dwObj = 0; - prop_dword.dwData = 10001; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_DEADZONE, &prop_dword.diph ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_DEADZONE returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_SATURATION, &prop_dword.diph ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_SATURATION returned %#x\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_CALIBRATIONMODE returned %#x\n", hr ); - prop_dword.dwData = 1000; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_DEADZONE, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_DEADZONE returned %#x\n", hr ); - prop_dword.dwData = 6000; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_SATURATION, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_SATURATION returned %#x\n", hr ); - prop_dword.dwData = DIPROPCALIBRATIONMODE_COOKED; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_CALIBRATIONMODE returned %#x\n", hr ); - - hr = IDirectInputDevice8_GetProperty( device, DIPROP_DEADZONE, &prop_dword.diph ); - ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_DEADZONE returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_SATURATION, &prop_dword.diph ); - ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_SATURATION returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); - ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_CALIBRATIONMODE 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 ); - ok( hr == DI_OK, "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 ); - ok( hr == DI_OK, "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 ); - ok( hr == DI_OK, "GetProperty DIPROP_DEADZONE returned %#x\n", hr ); - 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 ); - ok( hr == DI_OK, "GetProperty DIPROP_SATURATION returned %#x\n", hr ); - 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 ); - ok( hr == DI_OK, "GetProperty DIPROP_DEADZONE returned %#x\n", hr ); - 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 ); - ok( hr == DI_OK, "GetProperty DIPROP_SATURATION returned %#x\n", hr ); - ok( prop_dword.dwData == 6000, "got %u expected %u\n", prop_dword.dwData, 6000 ); - - for (i = 0; i < ARRAY_SIZE(injected_input); ++i) - { - winetest_push_context( "state[%d]", i ); - hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); - ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); - if (broken( state.lX == -10750 )) win_skip( "Ignoring 32-bit rounding\n" ); - else - { - check_member( state, expect_state_abs[i], "%d", lX ); - 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 ); - check_member( state, expect_state_abs[i], "%d", rgdwPOV[0] ); - check_member( state, expect_state_abs[i], "%d", rgdwPOV[1] ); - check_member( state, expect_state_abs[i], "%#x", rgbButtons[0] ); - check_member( state, expect_state_abs[i], "%#x", rgbButtons[1] ); - check_member( state, expect_state_abs[i], "%#x", rgbButtons[2] ); - - send_hid_input( file, &injected_input[i], sizeof(*injected_input) ); - - res = WaitForSingleObject( event, 100 ); - if (i == 0 || i == 3) ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" ); - else ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); - ResetEvent( event ); - winetest_pop_context(); - } - - hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); - ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); - winetest_push_context( "state[%d]", i ); - check_member( state, expect_state_abs[i], "%d", lX ); - 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 ); - check_member( state, expect_state_abs[i], "%d", rgdwPOV[0] ); - check_member( state, expect_state_abs[i], "%d", rgdwPOV[1] ); - check_member( state, expect_state_abs[i], "%#x", rgbButtons[0] ); - check_member( state, expect_state_abs[i], "%#x", rgbButtons[1] ); - check_member( state, expect_state_abs[i], "%#x", rgbButtons[2] ); - winetest_pop_context(); - - prop_dword.diph.dwHow = DIPH_BYUSAGE; - prop_dword.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); - prop_dword.dwData = DIPROPCALIBRATIONMODE_RAW; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_CALIBRATIONMODE returned %#x\n", hr ); - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_CALIBRATIONMODE returned %#x\n", hr ); - ok( prop_dword.dwData == DIPROPCALIBRATIONMODE_RAW, "got %u expected %u\n", prop_dword.dwData, DIPROPCALIBRATIONMODE_RAW ); - - hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); - ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); - winetest_push_context( "state[%d]", i ); - todo_wine - ok( state.lX == 15, "got lX %d, expected %d\n" , state.lX, 15 ); - check_member( state, expect_state_abs[0], "%d", lY ); - check_member( state, expect_state_abs[0], "%d", lZ ); - check_member( state, expect_state_abs[0], "%d", lRx ); - check_member( state, expect_state_abs[0], "%d", rgdwPOV[0] ); - check_member( state, expect_state_abs[0], "%d", rgdwPOV[1] ); - winetest_pop_context(); - - prop_dword.dwData = DIPROPCALIBRATIONMODE_COOKED; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_CALIBRATIONMODE returned %#x\n", hr ); - - send_hid_input( file, &injected_input[ARRAY_SIZE(injected_input) - 1], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); - ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); - - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - - prop_dword.diph.dwHow = DIPH_DEVICE; - prop_dword.diph.dwObj = 0; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_JOYSTICKID, &prop_dword.diph ); - ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_JOYSTICKID returned %#x\n", hr ); - prop_dword.dwData = 0x1000; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_BUFFERSIZE returned %#x\n", hr ); - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_AUTOCENTER returned %#x\n", hr ); - prop_dword.dwData = DIPROPAUTOCENTER_ON; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); - ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_AUTOCENTER returned %#x\n", hr ); - prop_pointer.diph.dwHow = DIPH_BYUSAGE; - prop_pointer.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); - prop_pointer.uData = 0xfeedcafe; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_APPDATA returned %#x\n", hr ); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_AXISMODE, &prop_dword.diph ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_AXISMODE returned %#x\n", hr ); - prop_dword.dwData = DIPROPAXISMODE_REL; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_AXISMODE, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_AXISMODE returned %#x\n", hr ); - - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_AXISMODE, &prop_dword.diph ); - todo_wine - ok( hr == DI_OK, "GetProperty DIPROP_AXISMODE returned %#x\n", hr ); - todo_wine - ok( prop_dword.dwData == DIPROPAXISMODE_REL, "got %u expected %u\n", prop_dword.dwData, DIPROPAXISMODE_REL ); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_BUFFERSIZE returned %#x\n", hr ); - ok( prop_dword.dwData == 0x1000, "got %#x expected %#x\n", prop_dword.dwData, 0x1000 ); - - prop_pointer.diph.dwHow = DIPH_BYUSAGE; - prop_pointer.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); - todo_wine - ok( hr == DI_OK, "GetProperty DIPROP_APPDATA returned %#x\n", hr ); - ok( prop_pointer.uData == 0xfeedcafe, "got %p expected %p\n", (void *)prop_pointer.uData, (void *)0xfeedcafe ); - - prop_dword.diph.dwHow = DIPH_DEVICE; - prop_dword.diph.dwObj = 0; - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_FFGAIN returned %#x\n", hr ); - prop_dword.dwData = 1000; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_FFGAIN returned %#x\n", hr ); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_CALIBRATION, &prop_dword.diph ); - todo_wine - ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_CALIBRATION returned %#x\n", hr ); - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_DEADZONE, &prop_dword.diph ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_DEADZONE returned %#x\n", hr ); - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_SATURATION, &prop_dword.diph ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_SATURATION returned %#x\n", hr ); - - for (i = 0; i < ARRAY_SIZE(injected_input); ++i) - { - winetest_push_context( "state[%d]", i ); - hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); - ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); - todo_wine - check_member( state, expect_state_rel[i], "%d", lX ); - todo_wine - check_member( state, expect_state_rel[i], "%d", lY ); - todo_wine - check_member( state, expect_state_rel[i], "%d", lZ ); - check_member( state, expect_state_rel[i], "%d", lRx ); - check_member( state, expect_state_rel[i], "%d", rgdwPOV[0] ); - check_member( state, expect_state_rel[i], "%d", rgdwPOV[1] ); - check_member( state, expect_state_rel[i], "%#x", rgbButtons[0] ); - check_member( state, expect_state_rel[i], "%#x", rgbButtons[1] ); - check_member( state, expect_state_rel[i], "%#x", rgbButtons[2] ); - - send_hid_input( file, &injected_input[i], sizeof(*injected_input) ); - - res = WaitForSingleObject( event, 100 ); - if (i == 3) ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" ); - else ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); - ResetEvent( event ); - winetest_pop_context(); - } - - hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); - ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); - winetest_push_context( "state[%d]", i ); - todo_wine - check_member( state, expect_state_rel[i], "%d", lX ); - todo_wine - check_member( state, expect_state_rel[i], "%d", lY ); - todo_wine - check_member( state, expect_state_rel[i], "%d", lZ ); - check_member( state, expect_state_rel[i], "%d", lRx ); - check_member( state, expect_state_rel[i], "%d", rgdwPOV[0] ); - check_member( state, expect_state_rel[i], "%d", rgdwPOV[1] ); - check_member( state, expect_state_rel[i], "%#x", rgbButtons[0] ); - check_member( state, expect_state_rel[i], "%#x", rgbButtons[1] ); - check_member( state, expect_state_rel[i], "%#x", rgbButtons[2] ); - winetest_pop_context(); - - hr = IDirectInputDevice8_GetForceFeedbackState( device, NULL ); - ok( hr == E_POINTER, "GetForceFeedbackState returned %#x\n", hr ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DIERR_UNSUPPORTED, "GetForceFeedbackState returned %#x\n", hr ); - - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, 0xdeadbeef ); - ok( hr == DIERR_INVALIDPARAM, "SendForceFeedbackCommand returned %#x\n", hr ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); - ok( hr == DIERR_UNSUPPORTED, "SendForceFeedbackCommand returned %#x\n", hr ); - - objdata[0].dwOfs = 0xd; - objdata[0].dwData = 0x80; - res = 1; - hr = IDirectInputDevice8_SendDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, 0xdeadbeef ); - todo_wine - ok( hr == DIERR_INVALIDPARAM, "SendDeviceData returned %#x\n", hr ); - res = 1; - hr = IDirectInputDevice8_SendDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, 1 /*DISDD_CONTINUE*/ ); - todo_wine - ok( hr == DIERR_INVALIDPARAM, "SendDeviceData returned %#x\n", hr ); - res = 1; - hr = IDirectInputDevice8_SendDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, 0 ); - todo_wine - ok( hr == DIERR_INVALIDPARAM, "SendDeviceData returned %#x\n", hr ); - - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, NULL, NULL ); - ok( hr == E_POINTER, "CreateEffect returned %#x\n", hr ); - hr = IDirectInputDevice8_CreateEffect( device, NULL, NULL, &effect, NULL ); - ok( hr == DIERR_UNSUPPORTED, "CreateEffect returned %#x\n", hr ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_NULL, NULL, &effect, NULL ); - ok( hr == DIERR_UNSUPPORTED, "CreateEffect returned %#x\n", hr ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, &effect, NULL ); - ok( hr == DIERR_UNSUPPORTED, "CreateEffect returned %#x\n", hr ); - - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, &effect, NULL ); - ok( hr == DIERR_UNSUPPORTED, "CreateEffect returned %#x\n", hr ); - - hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, NULL, effect, 0 ); - ok( hr == DIERR_INVALIDPARAM, "EnumCreatedEffectObjects returned %#x\n", hr ); - hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, check_no_created_effect_objects, effect, 0xdeadbeef ); - ok( hr == DIERR_INVALIDPARAM, "EnumCreatedEffectObjects returned %#x\n", hr ); - hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, check_no_created_effect_objects, (void *)0xdeadbeef, 0 ); - ok( hr == DI_OK, "EnumCreatedEffectObjects returned %#x\n", hr ); - - hr = IDirectInputDevice8_Escape( device, NULL ); - todo_wine - ok( hr == E_POINTER, "Escape returned: %#x\n", hr ); - hr = IDirectInputDevice8_Escape( device, &escape ); - todo_wine - ok( hr == DIERR_INVALIDPARAM, "Escape returned: %#x\n", hr ); - escape.dwSize = sizeof(DIEFFESCAPE) + 1; - hr = IDirectInputDevice8_Escape( device, &escape ); - todo_wine - ok( hr == DIERR_INVALIDPARAM, "Escape returned: %#x\n", hr ); - escape.dwSize = sizeof(DIEFFESCAPE); - escape.dwCommand = 0; - escape.lpvInBuffer = buffer; - escape.cbInBuffer = 10; - escape.lpvOutBuffer = buffer + 10; - escape.cbOutBuffer = 10; - hr = IDirectInputDevice8_Escape( device, &escape ); - todo_wine - ok( hr == DIERR_UNSUPPORTED, "Escape returned: %#x\n", hr ); - - ref = IDirectInputDevice8_Release( device ); - ok( ref == 0, "Release returned %d\n", ref ); - - CloseHandle( event ); - CloseHandle( file ); - -done: - pnp_driver_stop(); - cleanup_registry_keys(); - SetCurrentDirectoryW( cwd ); -} - -struct device_desc -{ - const BYTE *report_desc_buf; - ULONG report_desc_len; - HIDP_CAPS hid_caps; -}; - -static BOOL test_device_types( DWORD version ) -{ -#include "psh_hid_macros.h" - static const unsigned char unknown_desc[] = - { - USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Application), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Physical), - USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), - USAGE_MINIMUM(1, 1), - USAGE_MAXIMUM(1, 6), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 8), - INPUT(1, Data|Var|Abs), - END_COLLECTION, - END_COLLECTION, - }; - static const unsigned char limited_desc[] = - { - USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Application), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Physical), - USAGE(1, HID_USAGE_GENERIC_X), - USAGE(1, HID_USAGE_GENERIC_Y), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 127), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 127), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 2), - INPUT(1, Data|Var|Abs), - - USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), - USAGE_MINIMUM(1, 1), - USAGE_MAXIMUM(1, 6), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 8), - INPUT(1, Data|Var|Abs), - END_COLLECTION, - END_COLLECTION, - }; - static const unsigned char gamepad_desc[] = - { - USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), - USAGE(1, HID_USAGE_GENERIC_GAMEPAD), - COLLECTION(1, Application), - USAGE(1, HID_USAGE_GENERIC_GAMEPAD), - COLLECTION(1, Physical), - USAGE(1, HID_USAGE_GENERIC_X), - USAGE(1, HID_USAGE_GENERIC_Y), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 127), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 127), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 2), - INPUT(1, Data|Var|Abs), - - USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), - USAGE_MINIMUM(1, 1), - USAGE_MAXIMUM(1, 6), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 8), - INPUT(1, Data|Var|Abs), - END_COLLECTION, - END_COLLECTION, - }; - static const unsigned char joystick_desc[] = - { - USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Application), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Physical), - USAGE(1, HID_USAGE_GENERIC_X), - USAGE(1, HID_USAGE_GENERIC_Y), - USAGE(1, HID_USAGE_GENERIC_Z), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 127), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 127), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 3), - INPUT(1, Data|Var|Abs), - - USAGE(1, HID_USAGE_GENERIC_HATSWITCH), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 8), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 8), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - INPUT(1, Data|Var|Abs|Null), - - USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), - USAGE_MINIMUM(1, 1), - USAGE_MAXIMUM(1, 5), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 8), - INPUT(1, Data|Var|Abs), - END_COLLECTION, - END_COLLECTION, - }; -#include "pop_hid_macros.h" - - static struct device_desc device_desc[] = - { - { - .report_desc_buf = unknown_desc, - .report_desc_len = sizeof(unknown_desc), - .hid_caps = - { - .InputReportByteLength = 1, - }, - }, - { - .report_desc_buf = limited_desc, - .report_desc_len = sizeof(limited_desc), - .hid_caps = - { - .InputReportByteLength = 3, - }, - }, - { - .report_desc_buf = gamepad_desc, - .report_desc_len = sizeof(gamepad_desc), - .hid_caps = - { - .InputReportByteLength = 3, - }, - }, - { - .report_desc_buf = joystick_desc, - .report_desc_len = sizeof(joystick_desc), - .hid_caps = - { - .InputReportByteLength = 5, - }, - }, - }; - const DIDEVCAPS expect_caps[] = - { - { - .dwSize = sizeof(DIDEVCAPS), - .dwFlags = DIDC_ATTACHED|DIDC_EMULATED, - .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPESUPPLEMENTAL_UNKNOWN << 8)|DI8DEVTYPE_SUPPLEMENTAL - : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, - .dwButtons = 6, - }, - { - .dwSize = sizeof(DIDEVCAPS), - .dwFlags = DIDC_ATTACHED|DIDC_EMULATED, - .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEJOYSTICK_LIMITED << 8)|DI8DEVTYPE_JOYSTICK - : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, - .dwAxes = 2, - .dwButtons = 6, - }, - { - .dwSize = sizeof(DIDEVCAPS), - .dwFlags = DIDC_ATTACHED|DIDC_EMULATED, - .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEGAMEPAD_STANDARD << 8)|DI8DEVTYPE_GAMEPAD - : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_GAMEPAD << 8)|DIDEVTYPE_JOYSTICK, - .dwAxes = 2, - .dwButtons = 6, - }, - { - .dwSize = sizeof(DIDEVCAPS), - .dwFlags = DIDC_ATTACHED|DIDC_EMULATED, - .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEJOYSTICK_STANDARD << 8)|DI8DEVTYPE_JOYSTICK - : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, - .dwAxes = 3, - .dwPOVs = 1, - .dwButtons = 5, - }, - }; - - const DIDEVICEINSTANCEW expect_devinst[] = - { - { - .dwSize = sizeof(DIDEVICEINSTANCEW), - .guidInstance = expect_guid_product, - .guidProduct = expect_guid_product, - .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPESUPPLEMENTAL_UNKNOWN << 8)|DI8DEVTYPE_SUPPLEMENTAL - : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", - .guidFFDriver = GUID_NULL, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_JOYSTICK, - }, - { - .dwSize = sizeof(DIDEVICEINSTANCEW), - .guidInstance = expect_guid_product, - .guidProduct = expect_guid_product, - .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEJOYSTICK_LIMITED << 8)|DI8DEVTYPE_JOYSTICK - : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", - .guidFFDriver = GUID_NULL, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_JOYSTICK, - }, - { - .dwSize = sizeof(DIDEVICEINSTANCEW), - .guidInstance = expect_guid_product, - .guidProduct = expect_guid_product, - .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEGAMEPAD_STANDARD << 8)|DI8DEVTYPE_GAMEPAD - : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_GAMEPAD << 8)|DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", - .guidFFDriver = GUID_NULL, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_GAMEPAD, - }, - { - .dwSize = sizeof(DIDEVICEINSTANCEW), - .guidInstance = expect_guid_product, - .guidProduct = expect_guid_product, - .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEJOYSTICK_STANDARD << 8)|DI8DEVTYPE_JOYSTICK - : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", - .guidFFDriver = GUID_NULL, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_JOYSTICK, - }, - }; - - DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; - DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; - WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; - IDirectInputDevice8W *device; - BOOL success = TRUE; - ULONG i, ref; - HRESULT hr; - - winetest_push_context( "version %#x", version ); - - for (i = 0; i < ARRAY_SIZE(device_desc) && success; ++i) - { - winetest_push_context( "desc[%d]", i ); - GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - - cleanup_registry_keys(); - if (!dinput_driver_start( device_desc[i].report_desc_buf, device_desc[i].report_desc_len, - &device_desc[i].hid_caps, NULL, 0 )) - { - success = FALSE; - goto done; - } - - if (FAILED(hr = create_dinput_device( version, &devinst, &device ))) - { - success = FALSE; - goto done; - } - - hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); - ok( hr == DI_OK, "GetDeviceInfo returned %#x\n", hr ); - check_member( devinst, expect_devinst[i], "%d", dwSize ); - todo_wine - check_member_guid( devinst, expect_devinst[i], guidInstance ); - check_member_guid( devinst, expect_devinst[i], guidProduct ); - todo_wine_if( version <= 0x700 && i == 3 ) - check_member( devinst, expect_devinst[i], "%#x", dwDevType ); - todo_wine - check_member_wstr( devinst, expect_devinst[i], tszInstanceName ); - todo_wine - check_member_wstr( devinst, expect_devinst[i], tszProductName ); - check_member_guid( devinst, expect_devinst[i], guidFFDriver ); - check_member( devinst, expect_devinst[i], "%04x", wUsagePage ); - check_member( devinst, expect_devinst[i], "%04x", wUsage ); - - hr = IDirectInputDevice8_GetCapabilities( device, &caps ); - ok( hr == DI_OK, "GetCapabilities returned %#x\n", hr ); - check_member( caps, expect_caps[i], "%d", dwSize ); - check_member( caps, expect_caps[i], "%#x", dwFlags ); - todo_wine_if( version <= 0x700 && i == 3 ) - check_member( caps, expect_caps[i], "%#x", dwDevType ); - check_member( caps, expect_caps[i], "%d", dwAxes ); - check_member( caps, expect_caps[i], "%d", dwButtons ); - check_member( caps, expect_caps[i], "%d", dwPOVs ); - check_member( caps, expect_caps[i], "%d", dwFFSamplePeriod ); - check_member( caps, expect_caps[i], "%d", dwFFMinTimeResolution ); - check_member( caps, expect_caps[i], "%d", dwFirmwareRevision ); - check_member( caps, expect_caps[i], "%d", dwHardwareRevision ); - check_member( caps, expect_caps[i], "%d", dwFFDriverVersion ); - - ref = IDirectInputDevice8_Release( device ); - ok( ref == 0, "Release returned %d\n", ref ); - - done: - pnp_driver_stop(); - cleanup_registry_keys(); - SetCurrentDirectoryW( cwd ); - winetest_pop_context(); - } - - winetest_pop_context(); - - return success; -} - -static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWORD version ) -{ - struct hid_expect expect_download[] = - { - /* 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,0x01,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0xd5}, - }, - /* start command when DIEP_START is set */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .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[] = - { - /* 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}, - }, - }; - struct hid_expect expect_set_envelope[] = - { - /* set envelope */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 6, - .report_len = 7, - .report_buf = {0x06,0x19,0x4c,0x01,0x00,0x04,0x00}, - }, - }; - struct hid_expect expect_start = - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {0x02, 0x01, 0x01, 0x01}, - }; - struct hid_expect expect_start_solo = - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {0x02, 0x01, 0x02, 0x01}, - }; - struct hid_expect expect_start_0 = - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {0x02, 0x01, 0x01, 0x00}, - }; - struct hid_expect expect_start_4 = - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {0x02, 0x01, 0x01, 0x04}, - }; - struct hid_expect expect_stop = - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {0x02, 0x01, 0x03, 0x00}, - }; - struct hid_expect expect_unload[] = - { - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {0x02,0x01,0x03,0x00}, - }, - /* device reset, when unloaded from Unacquire */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, - .report_len = 2, - .report_buf = {1,0x01}, - }, - }; - 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}, - }, - }; - 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 = - { - .dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5), - .dwTriggerButton = -1, - .rgdwAxes = (void *)expect_axes_init, - }; - static const DWORD expect_axes[3] = - { - DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR, - DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFACTUATOR, - DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ) | DIDFT_FFACTUATOR, - }; - static const LONG expect_directions[3] = - { - +3000, - -6000, - 0, - }; - static const DIENVELOPE expect_envelope = - { - .dwSize = sizeof(DIENVELOPE), - .dwAttackLevel = 1000, - .dwAttackTime = 2000, - .dwFadeLevel = 3000, - .dwFadeTime = 4000, - }; - static const DIPERIODIC expect_periodic = - { - .dwMagnitude = 1000, - .lOffset = 2000, - .dwPhase = 3000, - .dwPeriod = 4000, - }; - const DIEFFECT expect_desc = - { - .dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5), - .dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS, - .dwDuration = 1000, - .dwSamplePeriod = 2000, - .dwGain = 3000, - .dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER, - .dwTriggerRepeatInterval = 5000, - .cAxes = 3, - .rgdwAxes = (void *)expect_axes, - .rglDirection = (void *)expect_directions, - .lpEnvelope = (void *)&expect_envelope, - .cbTypeSpecificParams = sizeof(DIPERIODIC), - .lpvTypeSpecificParams = (void *)&expect_periodic, - .dwStartDelay = 6000, - }; - struct check_created_effect_params check_params = {0}; - IDirectInputEffect *effect; - DIPERIODIC periodic = {0}; - DIENVELOPE envelope = {0}; - LONG directions[4] = {0}; - DIEFFECT desc = {0}; - DWORD axes[4] = {0}; - ULONG i, ref, flags; - HRESULT hr; - GUID guid; - - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, NULL, NULL ); - ok( hr == E_POINTER, "CreateEffect returned %#x\n", hr ); - hr = IDirectInputDevice8_CreateEffect( device, NULL, NULL, &effect, NULL ); - ok( hr == E_POINTER, "CreateEffect returned %#x\n", hr ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_NULL, NULL, &effect, NULL ); - ok( hr == DIERR_DEVICENOTREG, "CreateEffect returned %#x\n", hr ); - - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, &effect, NULL ); - ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); - if (hr != DI_OK) return; - - hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, check_no_created_effect_objects, effect, 0xdeadbeef ); - ok( hr == DIERR_INVALIDPARAM, "EnumCreatedEffectObjects returned %#x\n", hr ); - check_params.expect_effect = effect; - hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, check_created_effect_objects, &check_params, 0 ); - ok( hr == DI_OK, "EnumCreatedEffectObjects returned %#x\n", hr ); - ok( check_params.count == 1, "got count %u, expected 1\n", check_params.count ); - - hr = IDirectInputEffect_Initialize( effect, NULL, version, &GUID_Sine ); - ok( hr == DIERR_INVALIDPARAM, "Initialize returned %#x\n", hr ); - hr = IDirectInputEffect_Initialize( effect, instance, 0x800 - (version - 0x700), &GUID_Sine ); - if (version == 0x800) - { - todo_wine - ok( hr == DIERR_BETADIRECTINPUTVERSION, "Initialize returned %#x\n", hr ); - } - else - { - todo_wine - ok( hr == DIERR_OLDDIRECTINPUTVERSION, "Initialize returned %#x\n", hr ); - } - hr = IDirectInputEffect_Initialize( effect, instance, 0, &GUID_Sine ); - todo_wine - ok( hr == DIERR_NOTINITIALIZED, "Initialize returned %#x\n", hr ); - hr = IDirectInputEffect_Initialize( effect, instance, version, NULL ); - ok( hr == E_POINTER, "Initialize returned %#x\n", hr ); - - hr = IDirectInputEffect_Initialize( effect, instance, version, &GUID_NULL ); - ok( hr == DIERR_DEVICENOTREG, "Initialize returned %#x\n", hr ); - hr = IDirectInputEffect_Initialize( effect, instance, version, &GUID_Sine ); - ok( hr == DI_OK, "Initialize returned %#x\n", hr ); - hr = IDirectInputEffect_Initialize( effect, instance, version, &GUID_Square ); - ok( hr == DI_OK, "Initialize returned %#x\n", hr ); - - hr = IDirectInputEffect_GetEffectGuid( effect, NULL ); - ok( hr == E_POINTER, "GetEffectGuid returned %#x\n", hr ); - hr = IDirectInputEffect_GetEffectGuid( effect, &guid ); - ok( hr == DI_OK, "GetEffectGuid returned %#x\n", hr ); - ok( IsEqualGUID( &guid, &GUID_Square ), "got guid %s, expected %s\n", debugstr_guid( &guid ), - debugstr_guid( &GUID_Square ) ); - - hr = IDirectInputEffect_GetParameters( effect, NULL, 0 ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - hr = IDirectInputEffect_GetParameters( effect, NULL, DIEP_DURATION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - hr = IDirectInputEffect_GetParameters( effect, &desc, 0 ); - ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); - desc.dwSize = sizeof(DIEFFECT_DX5) + 2; - hr = IDirectInputEffect_GetParameters( effect, &desc, 0 ); - ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); - desc.dwSize = sizeof(DIEFFECT_DX5); - hr = IDirectInputEffect_GetParameters( effect, &desc, 0 ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_STARTDELAY ); - ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); - desc.dwSize = sizeof(DIEFFECT_DX6); - hr = IDirectInputEffect_GetParameters( effect, &desc, 0 ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - - 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_acquire, sizeof(expect_acquire) ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ - - desc.dwDuration = 0xdeadbeef; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DURATION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc_init, "%u", dwDuration ); - memset( &desc, 0xcd, sizeof(desc) ); - desc.dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5); - desc.dwFlags = 0; - desc.dwStartDelay = 0xdeadbeef; - flags = DIEP_GAIN | DIEP_SAMPLEPERIOD | DIEP_TRIGGERREPEATINTERVAL | - (version >= 0x700 ? DIEP_STARTDELAY : 0); - hr = IDirectInputEffect_GetParameters( effect, &desc, flags ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc_init, "%u", dwSamplePeriod ); - check_member( desc, expect_desc_init, "%u", dwGain ); - if (version >= 0x700) check_member( desc, expect_desc_init, "%u", dwStartDelay ); - else ok( desc.dwStartDelay == 0xdeadbeef, "got dwStartDelay %#x\n", desc.dwStartDelay ); - check_member( desc, expect_desc_init, "%u", dwTriggerRepeatInterval ); - - memset( &desc, 0xcd, sizeof(desc) ); - desc.dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5); - desc.dwFlags = 0; - desc.lpEnvelope = NULL; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ENVELOPE ); - ok( hr == E_POINTER, "GetParameters returned %#x\n", hr ); - desc.lpEnvelope = &envelope; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ENVELOPE ); - ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); - envelope.dwSize = sizeof(DIENVELOPE); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ENVELOPE ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - - desc.dwFlags = 0; - desc.cAxes = 0; - desc.rgdwAxes = NULL; - desc.rglDirection = NULL; - desc.lpEnvelope = NULL; - desc.cbTypeSpecificParams = 0; - desc.lpvTypeSpecificParams = NULL; - hr = IDirectInputEffect_GetParameters( effect, &desc, version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5 ); - ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TRIGGERBUTTON ); - ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES ); - ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); - desc.dwFlags = DIEFF_OBJECTOFFSETS; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TRIGGERBUTTON ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc_init, "%#x", dwTriggerButton ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc_init, "%u", cAxes ); - desc.dwFlags = DIEFF_OBJECTIDS; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TRIGGERBUTTON ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc_init, "%#x", dwTriggerButton ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc_init, "%u", cAxes ); - desc.dwFlags |= DIEFF_CARTESIAN; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - ok( desc.dwFlags == DIEFF_OBJECTIDS, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_OBJECTIDS ); - desc.dwFlags |= DIEFF_POLAR; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); - ok( desc.dwFlags == DIEFF_OBJECTIDS, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_OBJECTIDS ); - desc.dwFlags |= DIEFF_SPHERICAL; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc_init, "%u", cAxes ); - ok( desc.dwFlags == DIEFF_OBJECTIDS, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_OBJECTIDS ); - - desc.dwFlags |= DIEFF_SPHERICAL; - desc.cAxes = 2; - desc.rgdwAxes = axes; - desc.rglDirection = directions; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES | DIEP_DIRECTION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc_init, "%u", cAxes ); - check_member( desc, expect_desc_init, "%u", rgdwAxes[0] ); - check_member( desc, expect_desc_init, "%u", rgdwAxes[1] ); - check_member( desc, expect_desc_init, "%p", rglDirection ); - ok( desc.dwFlags == DIEFF_OBJECTIDS, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_OBJECTIDS ); - - desc.dwFlags |= DIEFF_SPHERICAL; - desc.lpEnvelope = &envelope; - desc.cbTypeSpecificParams = sizeof(periodic); - desc.lpvTypeSpecificParams = &periodic; - hr = IDirectInputEffect_GetParameters( effect, &desc, version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5 ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc_init, "%u", dwDuration ); - check_member( desc, expect_desc_init, "%u", dwSamplePeriod ); - check_member( desc, expect_desc_init, "%u", dwGain ); - check_member( desc, expect_desc_init, "%#x", dwTriggerButton ); - check_member( desc, expect_desc_init, "%u", dwTriggerRepeatInterval ); - check_member( desc, expect_desc_init, "%u", cAxes ); - check_member( desc, expect_desc_init, "%u", rgdwAxes[0] ); - check_member( desc, expect_desc_init, "%u", rgdwAxes[1] ); - check_member( desc, expect_desc_init, "%p", rglDirection ); - check_member( desc, expect_desc_init, "%p", lpEnvelope ); - check_member( desc, expect_desc_init, "%u", cbTypeSpecificParams ); - 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_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_acquire, sizeof(expect_acquire) ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ - - hr = IDirectInputEffect_Download( effect ); - ok( hr == DIERR_INCOMPLETEEFFECT, "Download returned %#x\n", hr ); - hr = IDirectInputEffect_Unload( effect ); - ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); - - hr = IDirectInputEffect_SetParameters( effect, NULL, DIEP_NODOWNLOAD ); - ok( hr == E_POINTER, "SetParameters returned %#x\n", hr ); - memset( &desc, 0, sizeof(desc) ); - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_NODOWNLOAD ); - ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); - desc.dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5); - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_NODOWNLOAD ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - - 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_acquire, sizeof(expect_acquire) ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - 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 ); - - desc.dwTriggerButton = -1; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DURATION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc, "%u", dwDuration ); - check_member( desc, expect_desc_init, "%u", dwSamplePeriod ); - check_member( desc, expect_desc_init, "%u", dwGain ); - check_member( desc, expect_desc_init, "%#x", dwTriggerButton ); - check_member( desc, expect_desc_init, "%u", dwTriggerRepeatInterval ); - check_member( desc, expect_desc_init, "%u", cAxes ); - check_member( desc, expect_desc_init, "%p", rglDirection ); - check_member( desc, expect_desc_init, "%p", lpEnvelope ); - check_member( desc, expect_desc_init, "%u", cbTypeSpecificParams ); - check_member( desc, expect_desc_init, "%u", dwStartDelay ); - - hr = IDirectInputEffect_Download( effect ); - ok( hr == DIERR_INCOMPLETEEFFECT, "Download returned %#x\n", hr ); - hr = IDirectInputEffect_Unload( effect ); - ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); - - flags = DIEP_GAIN | DIEP_SAMPLEPERIOD | DIEP_TRIGGERREPEATINTERVAL | DIEP_NODOWNLOAD; - if (version >= 0x700) flags |= DIEP_STARTDELAY; - hr = IDirectInputEffect_SetParameters( effect, &expect_desc, flags ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - desc.dwDuration = 0; - flags = DIEP_DURATION | DIEP_GAIN | DIEP_SAMPLEPERIOD | DIEP_TRIGGERREPEATINTERVAL; - if (version >= 0x700) flags |= DIEP_STARTDELAY; - hr = IDirectInputEffect_GetParameters( effect, &desc, flags ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc, "%u", dwDuration ); - check_member( desc, expect_desc, "%u", dwSamplePeriod ); - check_member( desc, expect_desc, "%u", dwGain ); - check_member( desc, expect_desc_init, "%#x", dwTriggerButton ); - check_member( desc, expect_desc, "%u", dwTriggerRepeatInterval ); - check_member( desc, expect_desc_init, "%u", cAxes ); - check_member( desc, expect_desc_init, "%p", rglDirection ); - check_member( desc, expect_desc_init, "%p", lpEnvelope ); - check_member( desc, expect_desc_init, "%u", cbTypeSpecificParams ); - if (version >= 0x700) check_member( desc, expect_desc, "%u", dwStartDelay ); - else ok( desc.dwStartDelay == 0, "got dwStartDelay %#x\n", desc.dwStartDelay ); - - hr = IDirectInputEffect_Download( effect ); - ok( hr == DIERR_INCOMPLETEEFFECT, "Download returned %#x\n", hr ); - hr = IDirectInputEffect_Unload( effect ); - ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); - - desc.lpEnvelope = NULL; - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_ENVELOPE | DIEP_NODOWNLOAD ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - desc.lpEnvelope = &envelope; - envelope.dwSize = 0; - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_ENVELOPE | DIEP_NODOWNLOAD ); - ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); - - hr = IDirectInputEffect_SetParameters( effect, &expect_desc, DIEP_ENVELOPE | DIEP_NODOWNLOAD ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - - desc.lpEnvelope = &envelope; - envelope.dwSize = sizeof(DIENVELOPE); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ENVELOPE ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( envelope, expect_envelope, "%u", dwAttackLevel ); - check_member( envelope, expect_envelope, "%u", dwAttackTime ); - check_member( envelope, expect_envelope, "%u", dwFadeLevel ); - check_member( envelope, expect_envelope, "%u", dwFadeTime ); - - hr = IDirectInputEffect_Download( effect ); - ok( hr == DIERR_INCOMPLETEEFFECT, "Download returned %#x\n", hr ); - hr = IDirectInputEffect_Unload( effect ); - ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); - - desc.dwFlags = 0; - desc.cAxes = 0; - desc.rgdwAxes = NULL; - desc.rglDirection = NULL; - desc.lpEnvelope = NULL; - desc.cbTypeSpecificParams = 0; - desc.lpvTypeSpecificParams = NULL; - flags = version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5; - hr = IDirectInputEffect_SetParameters( effect, &desc, flags | DIEP_NODOWNLOAD ); - ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_TRIGGERBUTTON | DIEP_NODOWNLOAD ); - ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_AXES | DIEP_NODOWNLOAD ); - ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); - - desc.dwFlags = DIEFF_OBJECTOFFSETS; - desc.cAxes = 1; - desc.rgdwAxes = axes; - desc.rgdwAxes[0] = DIJOFS_X; - desc.dwTriggerButton = DIJOFS_BUTTON( 1 ); - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_DIRECTION | DIEP_NODOWNLOAD ); - ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); - hr = IDirectInputEffect_SetParameters( effect, &expect_desc, DIEP_AXES | DIEP_TRIGGERBUTTON | DIEP_NODOWNLOAD ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_AXES | DIEP_TRIGGERBUTTON | DIEP_NODOWNLOAD ); - ok( hr == DIERR_ALREADYINITIALIZED, "SetParameters returned %#x\n", hr ); - - desc.cAxes = 0; - desc.dwFlags = DIEFF_OBJECTIDS; - desc.rgdwAxes = axes; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES | DIEP_TRIGGERBUTTON ); - ok( hr == DIERR_MOREDATA, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc, "%u", cAxes ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES | DIEP_TRIGGERBUTTON ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc, "%#x", dwTriggerButton ); - check_member( desc, expect_desc, "%u", cAxes ); - check_member( desc, expect_desc, "%u", rgdwAxes[0] ); - check_member( desc, expect_desc, "%u", rgdwAxes[1] ); - check_member( desc, expect_desc, "%u", rgdwAxes[2] ); - - desc.dwFlags = DIEFF_OBJECTOFFSETS; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_AXES | DIEP_TRIGGERBUTTON ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - ok( desc.dwTriggerButton == 0x30, "got %#x expected %#x\n", desc.dwTriggerButton, 0x30 ); - ok( desc.rgdwAxes[0] == 8, "got %#x expected %#x\n", desc.rgdwAxes[0], 8 ); - ok( desc.rgdwAxes[1] == 0, "got %#x expected %#x\n", desc.rgdwAxes[1], 0 ); - ok( desc.rgdwAxes[2] == 4, "got %#x expected %#x\n", desc.rgdwAxes[2], 4 ); - - hr = IDirectInputEffect_Download( effect ); - ok( hr == DIERR_INCOMPLETEEFFECT, "Download returned %#x\n", hr ); - hr = IDirectInputEffect_Unload( effect ); - ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); - - desc.dwFlags = DIEFF_CARTESIAN; - desc.cAxes = 0; - desc.rglDirection = directions; - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_DIRECTION | DIEP_NODOWNLOAD ); - ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); - desc.cAxes = 3; - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_DIRECTION | DIEP_NODOWNLOAD ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - desc.dwFlags = DIEFF_POLAR; - desc.cAxes = 3; - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_DIRECTION | DIEP_NODOWNLOAD ); - ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); - - hr = IDirectInputEffect_SetParameters( effect, &expect_desc, DIEP_DIRECTION | DIEP_NODOWNLOAD ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - - desc.dwFlags = DIEFF_SPHERICAL; - desc.cAxes = 1; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DIERR_MOREDATA, "GetParameters returned %#x\n", hr ); - ok( desc.dwFlags == DIEFF_SPHERICAL, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_SPHERICAL ); - check_member( desc, expect_desc, "%u", cAxes ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc, "%u", cAxes ); - ok( desc.rglDirection[0] == 3000, "got rglDirection[0] %d expected %d\n", desc.rglDirection[0], 3000 ); - ok( desc.rglDirection[1] == 30000, "got rglDirection[1] %d expected %d\n", desc.rglDirection[1], 30000 ); - ok( desc.rglDirection[2] == 0, "got rglDirection[2] %d expected %d\n", desc.rglDirection[2], 0 ); - desc.dwFlags = DIEFF_CARTESIAN; - desc.cAxes = 2; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DIERR_MOREDATA, "GetParameters returned %#x\n", hr ); - ok( desc.dwFlags == DIEFF_CARTESIAN, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_CARTESIAN ); - check_member( desc, expect_desc, "%u", cAxes ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc, "%u", cAxes ); - ok( desc.rglDirection[0] == 4330, "got rglDirection[0] %d expected %d\n", desc.rglDirection[0], 4330 ); - ok( desc.rglDirection[1] == 2500, "got rglDirection[1] %d expected %d\n", desc.rglDirection[1], 2500 ); - ok( desc.rglDirection[2] == -8660, "got rglDirection[2] %d expected %d\n", desc.rglDirection[2], -8660 ); - desc.dwFlags = DIEFF_POLAR; - desc.cAxes = 3; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); - - hr = IDirectInputEffect_Download( effect ); - ok( hr == DIERR_INCOMPLETEEFFECT, "Download returned %#x\n", hr ); - hr = IDirectInputEffect_Unload( effect ); - ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); - - desc.cbTypeSpecificParams = 0; - desc.lpvTypeSpecificParams = &periodic; - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS | DIEP_NODOWNLOAD ); - ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); - desc.cbTypeSpecificParams = sizeof(DIPERIODIC); - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS | DIEP_NODOWNLOAD ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - hr = IDirectInputEffect_SetParameters( effect, &expect_desc, DIEP_TYPESPECIFICPARAMS | DIEP_NODOWNLOAD ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( periodic, expect_periodic, "%u", dwMagnitude ); - check_member( periodic, expect_periodic, "%d", lOffset ); - check_member( periodic, expect_periodic, "%u", dwPhase ); - check_member( periodic, expect_periodic, "%u", dwPeriod ); - - hr = IDirectInputEffect_Start( effect, 1, DIES_NODOWNLOAD ); - ok( hr == DIERR_NOTDOWNLOADED, "Start returned %#x\n", hr ); - hr = IDirectInputEffect_Stop( effect ); - ok( hr == DIERR_NOTDOWNLOADED, "Stop returned %#x\n", hr ); - - set_hid_expect( file, expect_download, 3 * sizeof(struct hid_expect) ); - hr = IDirectInputEffect_Download( effect ); - ok( hr == DI_OK, "Download returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - hr = IDirectInputEffect_Download( effect ); - ok( hr == DI_NOEFFECT, "Download returned %#x\n", hr ); - - hr = IDirectInputEffect_Start( effect, 1, 0xdeadbeef ); - ok( hr == DIERR_INVALIDPARAM, "Start returned %#x\n", hr ); - - set_hid_expect( file, &expect_start_solo, sizeof(expect_start_solo) ); - hr = IDirectInputEffect_Start( effect, 1, DIES_SOLO ); - ok( hr == DI_OK, "Start returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, &expect_stop, sizeof(expect_stop) ); - hr = IDirectInputEffect_Stop( effect ); - ok( hr == DI_OK, "Stop returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, &expect_start, sizeof(expect_start) ); - hr = IDirectInputEffect_Start( effect, 1, 0 ); - ok( hr == DI_OK, "Start returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, &expect_start_4, sizeof(expect_start_4) ); - hr = IDirectInputEffect_Start( effect, 4, 0 ); - ok( hr == DI_OK, "Start returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, &expect_start_0, sizeof(expect_start_4) ); - hr = IDirectInputEffect_Start( effect, 0, 0 ); - ok( hr == DI_OK, "Start returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_unload, sizeof(struct hid_expect) ); - hr = IDirectInputEffect_Unload( effect ); - ok( hr == DI_OK, "Unload returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_download, 4 * sizeof(struct hid_expect) ); - hr = IDirectInputEffect_SetParameters( effect, &expect_desc, DIEP_START ); - ok( hr == DI_OK, "SetParameters returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_unload, sizeof(struct hid_expect) ); - hr = IDirectInputEffect_Unload( effect ); - ok( hr == DI_OK, "Unload returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_download, 3 * sizeof(struct hid_expect) ); - hr = IDirectInputEffect_Download( effect ); - ok( hr == DI_OK, "Download returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_unload, 2 * sizeof(struct hid_expect) ); - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - hr = IDirectInputEffect_Start( effect, 1, DIES_NODOWNLOAD ); - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "Start returned %#x\n", hr ); - hr = IDirectInputEffect_Stop( effect ); - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "Stop returned %#x\n", hr ); - - set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ - - hr = IDirectInputEffect_Unload( effect ); - ok( hr == DI_NOEFFECT, "Unload returned %#x\n", hr ); - - ref = IDirectInputEffect_Release( effect ); - ok( ref == 0, "Release returned %d\n", ref ); - - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, &effect, NULL ); - ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); - - desc.dwFlags = DIEFF_POLAR | DIEFF_OBJECTIDS; - desc.cAxes = 2; - desc.rgdwAxes[0] = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR; - desc.rgdwAxes[1] = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFACTUATOR; - desc.rglDirection[0] = 3000; - desc.rglDirection[1] = 0; - desc.rglDirection[2] = 0; - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_AXES | DIEP_DIRECTION | DIEP_NODOWNLOAD ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - desc.rglDirection[0] = 0; - - desc.dwFlags = DIEFF_SPHERICAL; - desc.cAxes = 1; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DIERR_MOREDATA, "GetParameters returned %#x\n", hr ); - ok( desc.dwFlags == DIEFF_SPHERICAL, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_SPHERICAL ); - ok( desc.cAxes == 2, "got cAxes %u expected 2\n", desc.cAxes ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - ok( desc.cAxes == 2, "got cAxes %u expected 2\n", desc.cAxes ); - ok( desc.rglDirection[0] == 30000, "got rglDirection[0] %d expected %d\n", desc.rglDirection[0], 30000 ); - ok( desc.rglDirection[1] == 0, "got rglDirection[1] %d expected %d\n", desc.rglDirection[1], 0 ); - ok( desc.rglDirection[2] == 0, "got rglDirection[2] %d expected %d\n", desc.rglDirection[2], 0 ); - - desc.dwFlags = DIEFF_CARTESIAN; - desc.cAxes = 1; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DIERR_MOREDATA, "GetParameters returned %#x\n", hr ); - ok( desc.dwFlags == DIEFF_CARTESIAN, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_CARTESIAN ); - ok( desc.cAxes == 2, "got cAxes %u expected 2\n", desc.cAxes ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - ok( desc.cAxes == 2, "got cAxes %u expected 2\n", desc.cAxes ); - ok( desc.rglDirection[0] == 5000, "got rglDirection[0] %d expected %d\n", desc.rglDirection[0], 5000 ); - ok( desc.rglDirection[1] == -8660, "got rglDirection[1] %d expected %d\n", desc.rglDirection[1], -8660 ); - ok( desc.rglDirection[2] == 0, "got rglDirection[2] %d expected %d\n", desc.rglDirection[2], 0 ); - - desc.dwFlags = DIEFF_POLAR; - desc.cAxes = 1; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DIERR_MOREDATA, "GetParameters returned %#x\n", hr ); - ok( desc.dwFlags == DIEFF_POLAR, "got flags %#x, expected %#x\n", desc.dwFlags, DIEFF_POLAR ); - ok( desc.cAxes == 2, "got cAxes %u expected 2\n", desc.cAxes ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - ok( desc.cAxes == 2, "got cAxes %u expected 2\n", desc.cAxes ); - ok( desc.rglDirection[0] == 3000, "got rglDirection[0] %d expected %d\n", desc.rglDirection[0], 3000 ); - ok( desc.rglDirection[1] == 0, "got rglDirection[1] %d expected %d\n", desc.rglDirection[1], 0 ); - ok( desc.rglDirection[2] == 0, "got rglDirection[2] %d expected %d\n", desc.rglDirection[2], 0 ); - - ref = IDirectInputEffect_Release( effect ); - ok( ref == 0, "Release returned %d\n", ref ); - - for (i = 1; i < 4; i++) - { - struct hid_expect expect_directions[] = - { - /* 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 */ - {0}, - /* effect control */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {0x02,0x01,0x03,0x00}, - }, - }; - struct hid_expect expect_spherical = - { - .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,i >= 2 ? 0x55 : 0,i >= 3 ? 0x1c : 0}, - }; - struct hid_expect expect_cartesian = - { - .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,i >= 2 ? 0x63 : 0,i >= 3 ? 0x1d : 0}, - }; - struct hid_expect expect_polar = - { - .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,i >= 2 ? 0x3f : 0,i >= 3 ? 0x00 : 0}, - }; - - winetest_push_context( "%u axes", i ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, &effect, NULL ); - ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); - - desc.dwFlags = DIEFF_OBJECTIDS; - desc.cAxes = i; - desc.rgdwAxes[0] = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR; - desc.rgdwAxes[1] = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFACTUATOR; - desc.rgdwAxes[2] = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ) | DIDFT_FFACTUATOR; - desc.rglDirection[0] = 0; - desc.rglDirection[1] = 0; - desc.rglDirection[2] = 0; - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_AXES | DIEP_NODOWNLOAD ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - - desc.dwFlags = DIEFF_CARTESIAN; - desc.cAxes = i == 3 ? 2 : 3; - desc.rglDirection[0] = 1000; - desc.rglDirection[1] = 2000; - desc.rglDirection[2] = 3000; - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_DIRECTION | DIEP_NODOWNLOAD ); - ok( hr == DIERR_INVALIDPARAM, "SetParameters returned %#x\n", hr ); - desc.cAxes = i; - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_DIRECTION | DIEP_NODOWNLOAD ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - - desc.dwFlags = DIEFF_SPHERICAL; - desc.cAxes = i; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - desc.cAxes = 3; - memset( desc.rglDirection, 0xcd, 3 * sizeof(LONG) ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - ok( desc.cAxes == i, "got cAxes %u expected 2\n", desc.cAxes ); - if (i == 1) - { - ok( desc.rglDirection[0] == 0, "got rglDirection[0] %d expected %d\n", desc.rglDirection[0], 0 ); - ok( desc.rglDirection[1] == 0xcdcdcdcd, "got rglDirection[1] %d expected %d\n", - desc.rglDirection[1], 0xcdcdcdcd ); - ok( desc.rglDirection[2] == 0xcdcdcdcd, "got rglDirection[2] %d expected %d\n", - desc.rglDirection[2], 0xcdcdcdcd ); - } - else - { - ok( desc.rglDirection[0] == 6343, "got rglDirection[0] %d expected %d\n", - desc.rglDirection[0], 6343 ); - if (i == 2) - { - ok( desc.rglDirection[1] == 0, "got rglDirection[1] %d expected %d\n", - desc.rglDirection[1], 0 ); - ok( desc.rglDirection[2] == 0xcdcdcdcd, "got rglDirection[2] %d expected %d\n", - desc.rglDirection[2], 0xcdcdcdcd ); - } - else - { - ok( desc.rglDirection[1] == 5330, "got rglDirection[1] %d expected %d\n", - desc.rglDirection[1], 5330 ); - ok( desc.rglDirection[2] == 0, "got rglDirection[2] %d expected %d\n", - desc.rglDirection[2], 0 ); - } - } - - desc.dwFlags = DIEFF_CARTESIAN; - desc.cAxes = i; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - desc.cAxes = 3; - memset( desc.rglDirection, 0xcd, 3 * sizeof(LONG) ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - ok( desc.cAxes == i, "got cAxes %u expected 2\n", desc.cAxes ); - ok( desc.rglDirection[0] == 1000, "got rglDirection[0] %d expected %d\n", desc.rglDirection[0], 1000 ); - if (i == 1) - ok( desc.rglDirection[1] == 0xcdcdcdcd, "got rglDirection[1] %d expected %d\n", - desc.rglDirection[1], 0xcdcdcdcd ); - else - ok( desc.rglDirection[1] == 2000, "got rglDirection[1] %d expected %d\n", - desc.rglDirection[1], 2000 ); - if (i <= 2) - ok( desc.rglDirection[2] == 0xcdcdcdcd, "got rglDirection[2] %d expected %d\n", - desc.rglDirection[2], 0xcdcdcdcd ); - else - ok( desc.rglDirection[2] == 3000, "got rglDirection[2] %d expected %d\n", - desc.rglDirection[2], 3000 ); - - desc.dwFlags = DIEFF_POLAR; - desc.cAxes = 1; - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - if (i != 2) ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); - else ok( hr == DIERR_MOREDATA, "GetParameters returned %#x\n", hr ); - desc.cAxes = 3; - memset( desc.rglDirection, 0xcd, 3 * sizeof(LONG) ); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_DIRECTION ); - if (i != 2) ok( hr == DIERR_INVALIDPARAM, "GetParameters returned %#x\n", hr ); - else - { - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - ok( desc.cAxes == i, "got cAxes %u expected 2\n", desc.cAxes ); - ok( desc.rglDirection[0] == 15343, "got rglDirection[0] %d expected %d\n", - desc.rglDirection[0], 15343 ); - ok( desc.rglDirection[1] == 0, "got rglDirection[1] %d expected %d\n", desc.rglDirection[1], 0 ); - ok( desc.rglDirection[2] == 0xcdcdcdcd, "got rglDirection[2] %d expected %d\n", - desc.rglDirection[2], 0xcdcdcdcd ); - } - - ref = IDirectInputEffect_Release( effect ); - ok( ref == 0, "Release returned %d\n", ref ); - - desc = expect_desc; - desc.dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS; - desc.cAxes = i; - desc.rgdwAxes = axes; - desc.rglDirection = directions; - desc.rglDirection[0] = 3000; - desc.rglDirection[1] = 4000; - desc.rglDirection[2] = 5000; - flags = version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5; - expect_directions[2] = expect_spherical; - set_hid_expect( file, expect_directions, sizeof(expect_directions) ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, &desc, &effect, NULL ); - 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, NULL, 0 ); - - desc = expect_desc; - desc.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTIDS; - desc.cAxes = i; - desc.rgdwAxes = axes; - desc.rglDirection = directions; - desc.rglDirection[0] = 6000; - desc.rglDirection[1] = 7000; - desc.rglDirection[2] = 8000; - flags = version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5; - expect_directions[2] = expect_cartesian; - set_hid_expect( file, expect_directions, sizeof(expect_directions) ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, &desc, &effect, NULL ); - 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, NULL, 0 ); - - if (i == 2) - { - desc = expect_desc; - desc.dwFlags = DIEFF_POLAR | DIEFF_OBJECTIDS; - desc.cAxes = i; - desc.rgdwAxes = axes; - desc.rglDirection = directions; - desc.rglDirection[0] = 9000; - desc.rglDirection[1] = 10000; - desc.rglDirection[2] = 11000; - flags = version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5; - expect_directions[2] = expect_polar; - set_hid_expect( file, expect_directions, sizeof(expect_directions) ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, &desc, &effect, NULL ); - 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, NULL, 0 ); - } - - 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.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 ); - set_hid_expect( file, NULL, 0 ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, &expect_desc, &effect, NULL ); - 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_acquire, sizeof(expect_acquire) ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ -} - -static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file, DWORD version ) -{ - struct hid_expect expect_create[] = - { - /* set condition */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 7, - .report_len = 8, - .report_buf = {0x07,0x00,0xf9,0x19,0xd9,0xff,0xff,0x99}, - }, - /* set condition */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 7, - .report_len = 8, - .report_buf = {0x07,0x00,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, - }, - /* update effect */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 3, - .report_len = 11, - .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0x00}, - }, - }; - struct hid_expect expect_create_1[] = - { - /* set condition */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 7, - .report_len = 8, - .report_buf = {0x07,0x00,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, - }, - /* update effect */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 3, - .report_len = 11, - .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x3f,0x00}, - }, - }; - struct hid_expect expect_create_2[] = - { - /* set condition */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 7, - .report_len = 8, - .report_buf = {0x07,0x00,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, - }, - /* update effect */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 3, - .report_len = 11, - .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0xf1}, - }, - }; - struct hid_expect expect_create_3[] = - { - /* set condition */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 7, - .report_len = 8, - .report_buf = {0x07,0x00,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, - }, - /* update effect */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 3, - .report_len = 11, - .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0x00}, - }, - }; - struct hid_expect expect_destroy = - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {0x02, 0x01, 0x03, 0x00}, - }; - static const DWORD expect_axes[3] = - { - DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFACTUATOR, - DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR, - DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ) | DIDFT_FFACTUATOR, - }; - static const LONG expect_directions[3] = { - +3000, - 0, - 0, - }; - static const DIENVELOPE expect_envelope = - { - .dwSize = sizeof(DIENVELOPE), - .dwAttackLevel = 1000, - .dwAttackTime = 2000, - .dwFadeLevel = 3000, - .dwFadeTime = 4000, - }; - static const DICONDITION expect_condition[3] = - { - { - .lOffset = -500, - .lPositiveCoefficient = 2000, - .lNegativeCoefficient = -3000, - .dwPositiveSaturation = -4000, - .dwNegativeSaturation = -5000, - .lDeadBand = 6000, - }, - { - .lOffset = 6000, - .lPositiveCoefficient = 5000, - .lNegativeCoefficient = -4000, - .dwPositiveSaturation = 3000, - .dwNegativeSaturation = 2000, - .lDeadBand = 1000, - }, - { - .lOffset = -7000, - .lPositiveCoefficient = -8000, - .lNegativeCoefficient = 9000, - .dwPositiveSaturation = 10000, - .dwNegativeSaturation = 11000, - .lDeadBand = -12000, - }, - }; - const DIEFFECT expect_desc = - { - .dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5), - .dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS, - .dwDuration = 1000, - .dwSamplePeriod = 2000, - .dwGain = 3000, - .dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER, - .dwTriggerRepeatInterval = 5000, - .cAxes = 2, - .rgdwAxes = (void *)expect_axes, - .rglDirection = (void *)expect_directions, - .lpEnvelope = (void *)&expect_envelope, - .cbTypeSpecificParams = 2 * sizeof(DICONDITION), - .lpvTypeSpecificParams = (void *)expect_condition, - .dwStartDelay = 6000, - }; - struct check_created_effect_params check_params = {0}; - DIENVELOPE envelope = - {.dwSize = sizeof(DIENVELOPE)}; - DICONDITION condition[2] = {0}; - IDirectInputEffect *effect; - LONG directions[4] = {0}; - DWORD axes[4] = {0}; - DIEFFECT desc = - { - .dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5), - .dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS, - .cAxes = 4, - .rgdwAxes = axes, - .rglDirection = directions, - .lpEnvelope = &envelope, - .cbTypeSpecificParams = 2 * sizeof(DICONDITION), - .lpvTypeSpecificParams = condition, - }; - HRESULT hr; - ULONG ref; - GUID guid; - - set_hid_expect( file, expect_create, sizeof(expect_create) ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &expect_desc, &effect, NULL ); - ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - check_params.expect_effect = effect; - hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, check_created_effect_objects, &check_params, 0 ); - ok( hr == DI_OK, "EnumCreatedEffectObjects returned %#x\n", hr ); - ok( check_params.count == 1, "got count %u, expected 1\n", check_params.count ); - - hr = IDirectInputEffect_GetEffectGuid( effect, &guid ); - ok( hr == DI_OK, "GetEffectGuid returned %#x\n", hr ); - ok( IsEqualGUID( &guid, &GUID_Spring ), "got guid %s, expected %s\n", debugstr_guid( &guid ), - debugstr_guid( &GUID_Spring ) ); - - hr = IDirectInputEffect_GetParameters( effect, &desc, version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5 ); - ok( hr == DI_OK, "GetParameters returned %#x\n", hr ); - check_member( desc, expect_desc, "%u", dwDuration ); - check_member( desc, expect_desc, "%u", dwSamplePeriod ); - check_member( desc, expect_desc, "%u", dwGain ); - check_member( desc, expect_desc, "%#x", dwTriggerButton ); - check_member( desc, expect_desc, "%u", dwTriggerRepeatInterval ); - check_member( desc, expect_desc, "%u", cAxes ); - check_member( desc, expect_desc, "%#x", rgdwAxes[0] ); - check_member( desc, expect_desc, "%#x", rgdwAxes[1] ); - check_member( desc, expect_desc, "%d", rglDirection[0] ); - check_member( desc, expect_desc, "%d", rglDirection[1] ); - check_member( desc, expect_desc, "%u", cbTypeSpecificParams ); - if (version >= 0x700) check_member( desc, expect_desc, "%u", dwStartDelay ); - else ok( desc.dwStartDelay == 0, "got dwStartDelay %#x\n", desc.dwStartDelay ); - check_member( envelope, expect_envelope, "%u", dwAttackLevel ); - check_member( envelope, expect_envelope, "%u", dwAttackTime ); - check_member( envelope, expect_envelope, "%u", dwFadeLevel ); - check_member( envelope, expect_envelope, "%u", dwFadeTime ); - check_member( condition[0], expect_condition[0], "%d", lOffset ); - check_member( condition[0], expect_condition[0], "%d", lPositiveCoefficient ); - check_member( condition[0], expect_condition[0], "%d", lNegativeCoefficient ); - check_member( condition[0], expect_condition[0], "%u", dwPositiveSaturation ); - check_member( condition[0], expect_condition[0], "%u", dwNegativeSaturation ); - check_member( condition[0], expect_condition[0], "%d", lDeadBand ); - check_member( condition[1], expect_condition[1], "%d", lOffset ); - check_member( condition[1], expect_condition[1], "%d", lPositiveCoefficient ); - check_member( condition[1], expect_condition[1], "%d", lNegativeCoefficient ); - check_member( condition[1], expect_condition[1], "%u", dwPositiveSaturation ); - check_member( condition[1], expect_condition[1], "%u", dwNegativeSaturation ); - check_member( condition[1], expect_condition[1], "%d", lDeadBand ); - - set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); - ref = IDirectInputEffect_Release( effect ); - ok( ref == 0, "Release returned %d\n", ref ); - set_hid_expect( file, NULL, 0 ); - - desc = expect_desc; - desc.cAxes = 1; - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); - ok( hr == DIERR_INVALIDPARAM, "CreateEffect returned %#x\n", hr ); - desc.cbTypeSpecificParams = 1 * sizeof(DICONDITION); - desc.lpvTypeSpecificParams = (void *)&expect_condition[1]; - set_hid_expect( file, expect_create_1, sizeof(expect_create_1) ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); - ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); - ref = IDirectInputEffect_Release( effect ); - ok( ref == 0, "Release returned %d\n", ref ); - set_hid_expect( file, NULL, 0 ); - - desc = expect_desc; - desc.cAxes = 3; - desc.rglDirection = directions; - desc.rglDirection[0] = +3000; - desc.rglDirection[1] = -2000; - desc.rglDirection[2] = +1000; - desc.cbTypeSpecificParams = 1 * sizeof(DICONDITION); - desc.lpvTypeSpecificParams = (void *)&expect_condition[1]; - set_hid_expect( file, expect_create_2, sizeof(expect_create_2) ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); - ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); - ref = IDirectInputEffect_Release( effect ); - ok( ref == 0, "Release returned %d\n", ref ); - set_hid_expect( file, NULL, 0 ); - - desc = expect_desc; - desc.cAxes = 2; - desc.rgdwAxes = axes; - desc.rgdwAxes[0] = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ) | DIDFT_FFACTUATOR; - desc.rgdwAxes[1] = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR; - desc.rglDirection = directions; - desc.rglDirection[0] = +3000; - desc.rglDirection[1] = -2000; - desc.cbTypeSpecificParams = 1 * sizeof(DICONDITION); - desc.lpvTypeSpecificParams = (void *)&expect_condition[1]; - set_hid_expect( file, expect_create_3, sizeof(expect_create_3) ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); - ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); - ref = IDirectInputEffect_Release( effect ); - ok( ref == 0, "Release returned %d\n", ref ); - set_hid_expect( file, NULL, 0 ); - - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, NULL, &effect, NULL ); - ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); - desc = expect_desc; - desc.cAxes = 0; - desc.cbTypeSpecificParams = 1 * sizeof(DICONDITION); - desc.lpvTypeSpecificParams = (void *)&expect_condition[0]; - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS | DIEP_NODOWNLOAD ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - desc.cbTypeSpecificParams = 0 * sizeof(DICONDITION); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS ); - ok( hr == DIERR_MOREDATA, "SetParameters returned %#x\n", hr ); - ok( desc.cbTypeSpecificParams == 1 * sizeof(DICONDITION), "got %u\n", desc.cbTypeSpecificParams ); - desc.cbTypeSpecificParams = 0 * sizeof(DICONDITION); - hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS | DIEP_NODOWNLOAD ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - desc.cbTypeSpecificParams = 0 * sizeof(DICONDITION); - hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_TYPESPECIFICPARAMS ); - ok( hr == DI_OK, "SetParameters returned %#x\n", hr ); - ok( desc.cbTypeSpecificParams == 0 * sizeof(DICONDITION), "got %u\n", desc.cbTypeSpecificParams ); - ref = IDirectInputEffect_Release( effect ); - ok( ref == 0, "Release returned %d\n", ref ); -} - -static void test_force_feedback_joystick( DWORD version ) -{ -#include "psh_hid_macros.h" - const unsigned char report_descriptor[] = { - USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Application), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Report), - REPORT_ID(1, 1), - - USAGE(1, HID_USAGE_GENERIC_X), - USAGE(1, HID_USAGE_GENERIC_Y), - USAGE(1, HID_USAGE_GENERIC_Z), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 3), - INPUT(1, Data|Var|Abs), - - USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), - USAGE_MINIMUM(1, 1), - USAGE_MAXIMUM(1, 2), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 2), - INPUT(1, Data|Var|Abs), - REPORT_COUNT(1, 6), - INPUT(1, Cnst|Var|Abs), - END_COLLECTION, - - USAGE_PAGE(1, HID_USAGE_PAGE_PID), - USAGE(1, PID_USAGE_STATE_REPORT), - COLLECTION(1, Report), - REPORT_ID(1, 2), - - USAGE(1, PID_USAGE_DEVICE_PAUSED), - USAGE(1, PID_USAGE_ACTUATORS_ENABLED), - USAGE(1, PID_USAGE_SAFETY_SWITCH), - USAGE(1, PID_USAGE_ACTUATOR_OVERRIDE_SWITCH), - USAGE(1, PID_USAGE_ACTUATOR_POWER), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 5), - INPUT(1, Data|Var|Abs), - REPORT_COUNT(1, 3), - INPUT(1, Cnst|Var|Abs), - - USAGE(1, PID_USAGE_EFFECT_PLAYING), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 1), - INPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), - LOGICAL_MAXIMUM(1, 0x7f), - LOGICAL_MINIMUM(1, 0x00), - REPORT_SIZE(1, 7), - REPORT_COUNT(1, 1), - INPUT(1, Data|Var|Abs), - END_COLLECTION, - - USAGE_PAGE(1, HID_USAGE_PAGE_PID), - USAGE(1, PID_USAGE_DEVICE_CONTROL_REPORT), - COLLECTION(1, Report), - REPORT_ID(1, 1), - - USAGE(1, PID_USAGE_DEVICE_CONTROL), - COLLECTION(1, Logical), - USAGE(1, PID_USAGE_DC_DEVICE_RESET), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 2), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 2), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Ary|Abs), - END_COLLECTION, - END_COLLECTION, - - USAGE(1, PID_USAGE_EFFECT_OPERATION_REPORT), - COLLECTION(1, Report), - REPORT_ID(1, 2), - - USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_EFFECT_OPERATION), - COLLECTION(1, NamedArray), - USAGE(1, PID_USAGE_OP_EFFECT_START), - USAGE(1, PID_USAGE_OP_EFFECT_START_SOLO), - USAGE(1, PID_USAGE_OP_EFFECT_STOP), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 3), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 3), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Ary|Abs), - END_COLLECTION, - - USAGE(1, PID_USAGE_LOOP_COUNT), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - END_COLLECTION, - - USAGE(1, PID_USAGE_SET_EFFECT_REPORT), - COLLECTION(1, Report), - REPORT_ID(1, 3), - - USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_EFFECT_TYPE), - COLLECTION(1, NamedArray), - USAGE(1, PID_USAGE_ET_SQUARE), - USAGE(1, PID_USAGE_ET_SINE), - USAGE(1, PID_USAGE_ET_SPRING), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 3), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 3), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Ary|Abs), - END_COLLECTION, - - USAGE(1, PID_USAGE_AXES_ENABLE), - COLLECTION(1, Logical), - USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_X), - USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_Y), - USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_Z), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 3), - OUTPUT(1, Data|Var|Abs), - END_COLLECTION, - USAGE(1, PID_USAGE_DIRECTION_ENABLE), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - REPORT_COUNT(1, 4), - OUTPUT(1, Cnst|Var|Abs), - - USAGE(1, PID_USAGE_DURATION), - USAGE(1, PID_USAGE_START_DELAY), - UNIT(2, 0x1003), /* Eng Lin:Time */ - UNIT_EXPONENT(1, -3), /* 10^-3 */ - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x7fff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(2, 0x7fff), - REPORT_SIZE(1, 16), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - UNIT(1, 0), - UNIT_EXPONENT(1, 0), - - USAGE(1, PID_USAGE_TRIGGER_BUTTON), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 0x08), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 0x08), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_DIRECTION), - COLLECTION(1, Logical), - USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|1), - USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|2), - UNIT(1, 0x14), /* Eng Rot:Angular Pos */ - UNIT_EXPONENT(1, -2), /* 10^-2 */ - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x00ff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(4, 0x00008ca0), - UNIT(1, 0), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - UNIT_EXPONENT(1, 0), - UNIT(1, 0), - END_COLLECTION, - END_COLLECTION, - - USAGE(1, PID_USAGE_SET_PERIODIC_REPORT), - COLLECTION(1, Logical), - REPORT_ID(1, 5), - - USAGE(1, PID_USAGE_MAGNITUDE), - 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, - - USAGE(1, PID_USAGE_SET_ENVELOPE_REPORT), - COLLECTION(1, Logical), - REPORT_ID(1, 6), - - USAGE(1, PID_USAGE_ATTACK_LEVEL), - USAGE(1, PID_USAGE_FADE_LEVEL), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x00ff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(2, 0x2710), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_ATTACK_TIME), - USAGE(1, PID_USAGE_FADE_TIME), - UNIT(2, 0x1003), /* Eng Lin:Time */ - UNIT_EXPONENT(1, -3), /* 10^-3 */ - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x7fff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(2, 0x7fff), - REPORT_SIZE(1, 16), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - PHYSICAL_MAXIMUM(1, 0), - UNIT_EXPONENT(1, 0), - UNIT(1, 0), - END_COLLECTION, - - - USAGE(1, PID_USAGE_SET_CONDITION_REPORT), - COLLECTION(1, Logical), - REPORT_ID(1, 7), - - USAGE(1, PID_USAGE_TYPE_SPECIFIC_BLOCK_OFFSET), - COLLECTION(1, Logical), - USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|1), - USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|2), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 2), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - END_COLLECTION, - REPORT_SIZE(1, 4), - REPORT_COUNT(1, 1), - OUTPUT(1, Cnst|Var|Abs), - - USAGE(1, PID_USAGE_CP_OFFSET), - LOGICAL_MINIMUM(1, 0x80), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(2, 0xd8f0), - PHYSICAL_MAXIMUM(2, 0x2710), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_POSITIVE_COEFFICIENT), - USAGE(1, PID_USAGE_NEGATIVE_COEFFICIENT), - LOGICAL_MINIMUM(1, 0x80), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(2, 0xd8f0), - PHYSICAL_MAXIMUM(2, 0x2710), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_POSITIVE_SATURATION), - USAGE(1, PID_USAGE_NEGATIVE_SATURATION), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x00ff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(2, 0x2710), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_DEAD_BAND), - 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, - - - 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 -#include "pop_hid_macros.h" - - static const HIDP_CAPS hid_caps = - { - .InputReportByteLength = 5, - }; - const DIDEVCAPS expect_caps = - { - .dwSize = sizeof(DIDEVCAPS), - .dwFlags = DIDC_FORCEFEEDBACK | DIDC_ATTACHED | DIDC_EMULATED | DIDC_STARTDELAY | - DIDC_FFFADE | DIDC_FFATTACK | DIDC_DEADBAND | DIDC_SATURATION, - .dwDevType = version >= 0x800 ? DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK - : DIDEVTYPE_HID | (DIDEVTYPEJOYSTICK_UNKNOWN << 8) | DIDEVTYPE_JOYSTICK, - .dwAxes = 3, - .dwButtons = 2, - .dwFFSamplePeriod = 1000000, - .dwFFMinTimeResolution = 1000000, - .dwHardwareRevision = 1, - .dwFFDriverVersion = 1, - }; - 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}, - }, - }; - 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 = 8, - .report_len = 2, - .report_buf = {8, 0x19}, - }; - struct hid_expect expect_set_device_gain_2 = - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 8, - .report_len = 2, - .report_buf = {8, 0x33}, - }; - - const DIDEVICEINSTANCEW expect_devinst = - { - .dwSize = sizeof(DIDEVICEINSTANCEW), - .guidInstance = expect_guid_product, - .guidProduct = expect_guid_product, - .dwDevType = version >= 0x800 ? DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK - : DIDEVTYPE_HID | (DIDEVTYPEJOYSTICK_UNKNOWN << 8) | DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine test root driver", - .tszProductName = L"Wine test root driver", - .guidFFDriver = IID_IDirectInputPIDDriver, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_JOYSTICK, - }; - const DIDEVICEOBJECTINSTANCEW expect_objects_5[] = - { - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_XAxis, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(0)|DIDFT_FFACTUATOR, - .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, - .tszName = L"X Axis", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_X, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_YAxis, - .dwOfs = 0x4, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(1)|DIDFT_FFACTUATOR, - .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, - .tszName = L"Y Axis", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_Y, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_ZAxis, - .dwOfs = 0x8, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(2)|DIDFT_FFACTUATOR, - .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, - .tszName = L"Z Axis", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_Z, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Button, - .dwOfs = 0x30, - .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(0)|DIDFT_FFEFFECTTRIGGER, - .dwFlags = DIDOI_FFEFFECTTRIGGER, - .tszName = L"Button 0", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_BUTTON, - .wUsage = 0x1, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Button, - .dwOfs = 0x31, - .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(1)|DIDFT_FFEFFECTTRIGGER, - .dwFlags = DIDOI_FFEFFECTTRIGGER, - .tszName = L"Button 1", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_BUTTON, - .wUsage = 0x2, - .wReportId = 1, - }, - }; - const DIDEVICEOBJECTINSTANCEW expect_objects[] = - { - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_ZAxis, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(2)|DIDFT_FFACTUATOR, - .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, - .tszName = L"Z Axis", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_Z, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_YAxis, - .dwOfs = 0x4, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(1)|DIDFT_FFACTUATOR, - .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, - .tszName = L"Y Axis", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_Y, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_XAxis, - .dwOfs = 0x8, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(0)|DIDFT_FFACTUATOR, - .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, - .tszName = L"X Axis", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_X, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Button, - .dwOfs = version >= 0x800 ? 0x68 : 0x10, - .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(0)|DIDFT_FFEFFECTTRIGGER, - .dwFlags = DIDOI_FFEFFECTTRIGGER, - .tszName = L"Button 0", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_BUTTON, - .wUsage = 0x1, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Button, - .dwOfs = version >= 0x800 ? 0x69 : 0x11, - .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(1)|DIDFT_FFEFFECTTRIGGER, - .dwFlags = DIDOI_FFEFFECTTRIGGER, - .tszName = L"Button 1", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_BUTTON, - .wUsage = 0x2, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x70 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(12)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"DC Device Reset", - .wCollectionNumber = 4, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_DC_DEVICE_RESET, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x10 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(13)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Effect Block Index", - .wCollectionNumber = 5, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_EFFECT_BLOCK_INDEX, - .wReportId = 2, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x71 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(14)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Op Effect Start", - .wCollectionNumber = 6, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_OP_EFFECT_START, - .wReportId = 2, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x72 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(15)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Op Effect Start Solo", - .wCollectionNumber = 6, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_OP_EFFECT_START_SOLO, - .wReportId = 2, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x73 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(16)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Op Effect Stop", - .wCollectionNumber = 6, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_OP_EFFECT_STOP, - .wReportId = 2, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x14 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(17)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Loop Count", - .wCollectionNumber = 5, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_LOOP_COUNT, - .wReportId = 2, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x18 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(18)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Effect Block Index", - .wCollectionNumber = 7, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_EFFECT_BLOCK_INDEX, - .wReportId = 3, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x74 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(19)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"ET Square", - .wCollectionNumber = 8, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_ET_SQUARE, - .wReportId = 3, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x75 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(20)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"ET Sine", - .wCollectionNumber = 8, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_ET_SINE, - .wReportId = 3, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x76 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(21)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"ET Spring", - .wCollectionNumber = 8, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_ET_SPRING, - .wReportId = 3, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x77 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(22)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Z Axis", - .wCollectionNumber = 9, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_Z, - .wReportId = 3, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x78 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(23)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Y Axis", - .wCollectionNumber = 9, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_Y, - .wReportId = 3, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x79 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(24)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"X Axis", - .wCollectionNumber = 9, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_X, - .wReportId = 3, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x7a : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(25)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Direction Enable", - .wCollectionNumber = 7, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_DIRECTION_ENABLE, - .wReportId = 3, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x1c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(26)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Start Delay", - .wCollectionNumber = 7, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_START_DELAY, - .wReportId = 3, - .dwDimension = 0x1003, - .wExponent = -3, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x20 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(27)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Duration", - .wCollectionNumber = 7, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_DURATION, - .wReportId = 3, - .dwDimension = 0x1003, - .wExponent = -3, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x24 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(28)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Trigger Button", - .wCollectionNumber = 7, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_TRIGGER_BUTTON, - .wReportId = 3, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x28 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(29)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Unknown 29", - .wCollectionNumber = 10, - .wUsagePage = HID_USAGE_PAGE_ORDINAL, - .wUsage = 2, - .wReportId = 3, - .wExponent = -2, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x2c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(30)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Unknown 30", - .wCollectionNumber = 10, - .wUsagePage = HID_USAGE_PAGE_ORDINAL, - .wUsage = 1, - .wReportId = 3, - .wExponent = -2, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x30 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(31)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Magnitude", - .wCollectionNumber = 11, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_MAGNITUDE, - .wReportId = 5, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x34 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(32)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Fade Level", - .wCollectionNumber = 12, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_FADE_LEVEL, - .wReportId = 6, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x38 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(33)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Attack Level", - .wCollectionNumber = 12, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_ATTACK_LEVEL, - .wReportId = 6, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x3c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(34)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Fade Time", - .wCollectionNumber = 12, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_FADE_TIME, - .wReportId = 6, - .dwDimension = 0x1003, - .wExponent = -3, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x40 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(35)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Attack Time", - .wCollectionNumber = 12, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_ATTACK_TIME, - .wReportId = 6, - .dwDimension = 0x1003, - .wExponent = -3, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x44 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(36)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Unknown 36", - .wCollectionNumber = 14, - .wUsagePage = HID_USAGE_PAGE_ORDINAL, - .wUsage = 2, - .wReportId = 7, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x48 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(37)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Unknown 37", - .wCollectionNumber = 14, - .wUsagePage = HID_USAGE_PAGE_ORDINAL, - .wUsage = 1, - .wReportId = 7, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x4c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(38)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"CP Offset", - .wCollectionNumber = 13, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_CP_OFFSET, - .wReportId = 7, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x50 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(39)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Negative Coefficient", - .wCollectionNumber = 13, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_NEGATIVE_COEFFICIENT, - .wReportId = 7, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x54 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(40)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Positive Coefficient", - .wCollectionNumber = 13, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_POSITIVE_COEFFICIENT, - .wReportId = 7, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x58 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(41)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Negative Saturation", - .wCollectionNumber = 13, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_NEGATIVE_SATURATION, - .wReportId = 7, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x5c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(42)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Positive Saturation", - .wCollectionNumber = 13, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_POSITIVE_SATURATION, - .wReportId = 7, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x60 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(43)|DIDFT_OUTPUT, - .dwFlags = 0x80008000, - .tszName = L"Dead Band", - .wCollectionNumber = 13, - .wUsagePage = HID_USAGE_PAGE_PID, - .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, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(0), - .tszName = L"Collection 0 - Joystick", - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_JOYSTICK, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(1), - .tszName = L"Collection 1 - Joystick", - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_JOYSTICK, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(2), - .tszName = L"Collection 2 - PID State Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_STATE_REPORT, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(3), - .tszName = L"Collection 3 - PID Device Control Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_DEVICE_CONTROL_REPORT, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(4), - .tszName = L"Collection 4 - PID Device Control", - .wCollectionNumber = 3, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_DEVICE_CONTROL, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(5), - .tszName = L"Collection 5 - Effect Operation Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_EFFECT_OPERATION_REPORT, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(6), - .tszName = L"Collection 6 - Effect Operation", - .wCollectionNumber = 5, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_EFFECT_OPERATION, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(7), - .tszName = L"Collection 7 - Set Effect Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_SET_EFFECT_REPORT, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(8), - .tszName = L"Collection 8 - Effect Type", - .wCollectionNumber = 7, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_EFFECT_TYPE, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(9), - .tszName = L"Collection 9 - Axes Enable", - .wCollectionNumber = 7, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_AXES_ENABLE, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(10), - .tszName = L"Collection 10 - Direction", - .wCollectionNumber = 7, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_DIRECTION, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(11), - .tszName = L"Collection 11 - Set Periodic Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_SET_PERIODIC_REPORT, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(12), - .tszName = L"Collection 12 - Set Envelope Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_SET_ENVELOPE_REPORT, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(13), - .tszName = L"Collection 13 - Set Condition Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_SET_CONDITION_REPORT, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(14), - .tszName = L"Collection 14 - Type Specific Block Offset", - .wCollectionNumber = 13, - .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[] = - { - { - .dwSize = sizeof(DIEFFECTINFOW), - .guid = GUID_Square, - .dwEffType = DIEFT_PERIODIC | DIEFT_STARTDELAY | DIEFT_FFFADE | DIEFT_FFATTACK, - .dwStaticParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | - DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, - .dwDynamicParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | - DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, - .tszName = L"GUID_Square", - }, - { - .dwSize = sizeof(DIEFFECTINFOW), - .guid = GUID_Sine, - .dwEffType = DIEFT_PERIODIC | DIEFT_STARTDELAY | DIEFT_FFFADE | DIEFT_FFATTACK, - .dwStaticParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | - DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, - .dwDynamicParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | - DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, - .tszName = L"GUID_Sine", - }, - { - .dwSize = sizeof(DIEFFECTINFOW), - .guid = GUID_Spring, - .dwEffType = DIEFT_CONDITION | DIEFT_STARTDELAY | DIEFT_DEADBAND | DIEFT_SATURATION, - .dwStaticParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | - DIEP_DURATION, - .dwDynamicParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | - DIEP_DURATION, - .tszName = L"GUID_Spring", - } - }; - - struct check_objects_todos todo_objects_5[ARRAY_SIZE(expect_objects_5)] = - { - {.guid = TRUE, .type = TRUE, .usage = TRUE, .name = TRUE}, - {0}, - {.guid = TRUE, .type = TRUE, .usage = TRUE, .name = TRUE}, - }; - struct check_objects_params check_objects_params = - { - .version = version, - .expect_count = version < 0x700 ? ARRAY_SIZE(expect_objects_5) : ARRAY_SIZE(expect_objects), - .expect_objs = version < 0x700 ? expect_objects_5 : expect_objects, - .todo_objs = version < 0x700 ? todo_objects_5 : NULL, - .todo_extra = version < 0x700 ? TRUE : FALSE, - }; - struct check_effects_params check_effects_params = - { - .expect_count = ARRAY_SIZE(expect_effects), - .expect_effects = expect_effects, - }; - DIPROPDWORD prop_dword = - { - .diph = - { - .dwSize = sizeof(DIPROPDWORD), - .dwHeaderSize = sizeof(DIPROPHEADER), - .dwHow = DIPH_DEVICE, - }, - }; - DIPROPGUIDANDPATH prop_guid_path = - { - .diph = - { - .dwSize = sizeof(DIPROPGUIDANDPATH), - .dwHeaderSize = sizeof(DIPROPHEADER), - .dwHow = DIPH_DEVICE, - }, - }; - DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; - WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; - DIDEVICEOBJECTDATA objdata = {0}; - DIEFFECTINFOW effectinfo = {0}; - IDirectInputDevice8W *device; - DIEFFESCAPE escape = {0}; - DIDEVCAPS caps = {0}; - char buffer[1024]; - ULONG res, ref; - HANDLE file; - HRESULT hr; - HWND hwnd; - - winetest_push_context( "version %#x", version ); - - GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - - cleanup_registry_keys(); - if (!dinput_driver_start( report_descriptor, sizeof(report_descriptor), &hid_caps, NULL, 0 )) goto done; - if (FAILED(hr = create_dinput_device( version, &devinst, &device ))) goto done; - - hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); - ok( hr == DI_OK, "GetDeviceInfo returned %#x\n", hr ); - check_member( devinst, expect_devinst, "%d", dwSize ); - todo_wine - check_member_guid( devinst, expect_devinst, guidInstance ); - check_member_guid( devinst, expect_devinst, guidProduct ); - check_member( devinst, expect_devinst, "%#x", dwDevType ); - todo_wine - check_member_wstr( devinst, expect_devinst, tszInstanceName ); - todo_wine - check_member_wstr( devinst, expect_devinst, tszProductName ); - check_member_guid( devinst, expect_devinst, guidFFDriver ); - check_member( devinst, expect_devinst, "%04x", wUsagePage ); - check_member( devinst, expect_devinst, "%04x", wUsage ); - - caps.dwSize = sizeof(DIDEVCAPS); - hr = IDirectInputDevice8_GetCapabilities( device, &caps ); - ok( hr == DI_OK, "GetCapabilities returned %#x\n", hr ); - check_member( caps, expect_caps, "%d", dwSize ); - check_member( caps, expect_caps, "%#x", dwFlags ); - check_member( caps, expect_caps, "%#x", dwDevType ); - check_member( caps, expect_caps, "%d", dwAxes ); - check_member( caps, expect_caps, "%d", dwButtons ); - check_member( caps, expect_caps, "%d", dwPOVs ); - check_member( caps, expect_caps, "%d", dwFFSamplePeriod ); - check_member( caps, expect_caps, "%d", dwFFMinTimeResolution ); - check_member( caps, expect_caps, "%d", dwFirmwareRevision ); - check_member( caps, expect_caps, "%d", dwHardwareRevision ); - check_member( caps, expect_caps, "%d", dwFFDriverVersion ); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_FFGAIN returned %#x\n", hr ); - ok( prop_dword.dwData == 10000, "got %u expected %u\n", prop_dword.dwData, 10000 ); - - hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); - - hr = IDirectInputDevice8_EnumObjects( device, check_objects, &check_objects_params, DIDFT_ALL ); - ok( hr == DI_OK, "EnumObjects returned %#x\n", hr ); - ok( check_objects_params.index >= check_objects_params.expect_count, "missing %u objects\n", - check_objects_params.expect_count - check_objects_params.index ); - - res = 0; - hr = IDirectInputDevice8_EnumEffects( device, check_effect_count, &res, 0xfe ); - ok( hr == DI_OK, "EnumEffects returned %#x\n", hr ); - ok( res == 0, "got %u expected %u\n", res, 0 ); - res = 0; - hr = IDirectInputDevice8_EnumEffects( device, check_effect_count, &res, DIEFT_PERIODIC ); - ok( hr == DI_OK, "EnumEffects returned %#x\n", hr ); - ok( res == 2, "got %u expected %u\n", res, 2 ); - hr = IDirectInputDevice8_EnumEffects( device, check_effects, &check_effects_params, DIEFT_ALL ); - ok( hr == DI_OK, "EnumEffects returned %#x\n", hr ); - ok( check_effects_params.index >= check_effects_params.expect_count, "missing %u effects\n", - check_effects_params.expect_count - check_effects_params.index ); - - effectinfo.dwSize = sizeof(DIEFFECTINFOW); - hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_Sine ); - ok( hr == DI_OK, "GetEffectInfo returned %#x\n", hr ); - check_member_guid( effectinfo, expect_effects[1], guid ); - check_member( effectinfo, expect_effects[1], "%#x", dwEffType ); - check_member( effectinfo, expect_effects[1], "%#x", dwStaticParams ); - check_member( effectinfo, expect_effects[1], "%#x", dwDynamicParams ); - check_member_wstr( effectinfo, expect_effects[1], tszName ); - - hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); - ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); - - hr = IDirectInputDevice8_GetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph ); - 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, - 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, - NULL, NULL, NULL, NULL ); - - hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE ); - ok( hr == DI_OK, "SetCooperativeLevel 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 = DIPROPAUTOCENTER_ON; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); - ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_AUTOCENTER returned %#x\n", hr ); - prop_dword.diph.dwHow = DIPH_DEVICE; - prop_dword.diph.dwObj = 0; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_AUTOCENTER returned %#x\n", hr ); - - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_FFGAIN returned %#x\n", hr ); - prop_dword.dwData = 1000; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_FFGAIN returned %#x\n", hr ); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); - ok( hr == DIERR_READONLY, "SetProperty DIPROP_FFLOAD returned %#x\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetForceFeedbackState returned %#x\n", hr ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "SendForceFeedbackCommand returned %#x\n", hr ); - - escape.dwSize = sizeof(DIEFFESCAPE); - escape.dwCommand = 0; - escape.lpvInBuffer = buffer; - escape.cbInBuffer = 10; - escape.lpvOutBuffer = buffer + 10; - escape.cbOutBuffer = 10; - hr = IDirectInputDevice8_Escape( device, &escape ); - todo_wine - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "Escape returned: %#x\n", hr ); - - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); - ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr ); - - set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - 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 ); - 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 ); - 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 - ok( hr == DIERR_UNSUPPORTED, "Escape returned: %#x\n", hr ); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); - todo_wine - ok( hr == 0x80040301, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - todo_wine - ok( hr == 0x80040301, "GetForceFeedbackState returned %#x\n", hr ); - - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, 0xdeadbeef ); - ok( hr == DIERR_INVALIDPARAM, "SendForceFeedbackCommand returned %#x\n", hr ); - - set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); - ok( hr == DI_OK, "SendForceFeedbackCommand returned %#x\n", hr ); - 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 ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_PAUSE ); - ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#x\n", hr ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_CONTINUE ); - ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#x\n", hr ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSON ); - ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#x\n", hr ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSOFF ); - ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#x\n", hr ); - - objdata.dwOfs = 0x1e; - objdata.dwData = 0x80; - res = 1; - hr = IDirectInputDevice8_SendDeviceData( device, sizeof(DIDEVICEOBJECTDATA), &objdata, &res, 0 ); - if (version < 0x800) ok( hr == DI_OK, "SendDeviceData returned %#x\n", hr ); - else todo_wine ok( hr == DIERR_INVALIDPARAM, "SendDeviceData returned %#x\n", hr ); - - test_periodic_effect( device, file, version ); - test_condition_effect( device, file, version ); - - 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 ); - - ref = IDirectInputDevice8_Release( device ); - ok( ref == 0, "Release returned %d\n", ref ); - - DestroyWindow( hwnd ); - CloseHandle( file ); - -done: - pnp_driver_stop(); - cleanup_registry_keys(); - SetCurrentDirectoryW( cwd ); - winetest_pop_context(); -} - -static void test_device_managed_effect(void) -{ -#include "psh_hid_macros.h" - const unsigned char report_descriptor[] = { - USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Application), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Report), - REPORT_ID(1, 1), - - USAGE(1, HID_USAGE_GENERIC_X), - USAGE(1, HID_USAGE_GENERIC_Y), - USAGE(1, HID_USAGE_GENERIC_Z), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 3), - INPUT(1, Data|Var|Abs), - - USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), - USAGE_MINIMUM(1, 1), - USAGE_MAXIMUM(1, 2), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 2), - INPUT(1, Data|Var|Abs), - REPORT_COUNT(1, 6), - INPUT(1, Cnst|Var|Abs), - END_COLLECTION, - - USAGE_PAGE(1, HID_USAGE_PAGE_PID), - USAGE(1, PID_USAGE_STATE_REPORT), - COLLECTION(1, Report), - REPORT_ID(1, 2), - - USAGE(1, PID_USAGE_DEVICE_PAUSED), - USAGE(1, PID_USAGE_ACTUATORS_ENABLED), - USAGE(1, PID_USAGE_SAFETY_SWITCH), - USAGE(1, PID_USAGE_ACTUATOR_OVERRIDE_SWITCH), - USAGE(1, PID_USAGE_ACTUATOR_POWER), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 5), - INPUT(1, Data|Var|Abs), - REPORT_COUNT(1, 3), - INPUT(1, Cnst|Var|Abs), - - USAGE(1, PID_USAGE_EFFECT_PLAYING), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 8), - INPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - INPUT(1, Data|Var|Abs), - END_COLLECTION, - - USAGE_PAGE(1, HID_USAGE_PAGE_PID), - USAGE(1, PID_USAGE_DEVICE_CONTROL_REPORT), - COLLECTION(1, Report), - REPORT_ID(1, 1), - - USAGE(1, PID_USAGE_DEVICE_CONTROL), - COLLECTION(1, Logical), - USAGE(1, PID_USAGE_DC_DEVICE_RESET), - USAGE(1, PID_USAGE_DC_DEVICE_PAUSE), - USAGE(1, PID_USAGE_DC_DEVICE_CONTINUE), - USAGE(1, PID_USAGE_DC_ENABLE_ACTUATORS), - USAGE(1, PID_USAGE_DC_DISABLE_ACTUATORS), - USAGE(1, PID_USAGE_DC_STOP_ALL_EFFECTS), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 6), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 6), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Ary|Abs), - END_COLLECTION, - END_COLLECTION, - - USAGE(1, PID_USAGE_EFFECT_OPERATION_REPORT), - COLLECTION(1, Report), - REPORT_ID(1, 2), - - USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_EFFECT_OPERATION), - COLLECTION(1, NamedArray), - USAGE(1, PID_USAGE_OP_EFFECT_START), - USAGE(1, PID_USAGE_OP_EFFECT_START_SOLO), - USAGE(1, PID_USAGE_OP_EFFECT_STOP), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 3), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 3), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Ary|Abs), - END_COLLECTION, - - USAGE(1, PID_USAGE_LOOP_COUNT), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - END_COLLECTION, - - USAGE(1, PID_USAGE_SET_EFFECT_REPORT), - COLLECTION(1, Report), - REPORT_ID(1, 3), - - USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_EFFECT_TYPE), - COLLECTION(1, NamedArray), - USAGE(1, PID_USAGE_ET_SQUARE), - USAGE(1, PID_USAGE_ET_SINE), - USAGE(1, PID_USAGE_ET_SPRING), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 3), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 3), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Ary|Abs), - END_COLLECTION, - - USAGE(1, PID_USAGE_AXES_ENABLE), - COLLECTION(1, Logical), - USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_X), - USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_Y), - USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_Z), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 3), - OUTPUT(1, Data|Var|Abs), - END_COLLECTION, - USAGE(1, PID_USAGE_DIRECTION_ENABLE), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - REPORT_COUNT(1, 4), - OUTPUT(1, Cnst|Var|Abs), - - USAGE(1, PID_USAGE_DURATION), - USAGE(1, PID_USAGE_START_DELAY), - UNIT(2, 0x1003), /* Eng Lin:Time */ - UNIT_EXPONENT(1, -3), /* 10^-3 */ - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x7fff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(2, 0x7fff), - REPORT_SIZE(1, 16), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - UNIT(1, 0), - UNIT_EXPONENT(1, 0), - - USAGE(1, PID_USAGE_TRIGGER_BUTTON), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 0x08), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 0x08), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_DIRECTION), - COLLECTION(1, Logical), - USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|1), - USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|2), - UNIT(1, 0x14), /* Eng Rot:Angular Pos */ - UNIT_EXPONENT(1, -2), /* 10^-2 */ - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x00ff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(4, 0x00008ca0), - UNIT(1, 0), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - UNIT_EXPONENT(1, 0), - UNIT(1, 0), - END_COLLECTION, - END_COLLECTION, - - USAGE(1, PID_USAGE_SET_CONDITION_REPORT), - COLLECTION(1, Logical), - REPORT_ID(1, 4), - - USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_PARAMETER_BLOCK_OFFSET), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 4), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_TYPE_SPECIFIC_BLOCK_OFFSET), - COLLECTION(1, Logical), - USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|1), - USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|2), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 2), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - END_COLLECTION, - - USAGE(1, PID_USAGE_CP_OFFSET), - LOGICAL_MINIMUM(1, 0x80), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(2, 0xd8f0), - PHYSICAL_MAXIMUM(2, 0x2710), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_POSITIVE_COEFFICIENT), - USAGE(1, PID_USAGE_NEGATIVE_COEFFICIENT), - LOGICAL_MINIMUM(1, 0x80), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(2, 0xd8f0), - PHYSICAL_MAXIMUM(2, 0x2710), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_POSITIVE_SATURATION), - USAGE(1, PID_USAGE_NEGATIVE_SATURATION), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x00ff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(2, 0x2710), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_DEAD_BAND), - 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, - - USAGE(1, PID_USAGE_BLOCK_FREE_REPORT), - COLLECTION(1, Logical), - REPORT_ID(1, 5), - - USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - END_COLLECTION, - - USAGE(1, PID_USAGE_DEVICE_GAIN_REPORT), - COLLECTION(1, Logical), - REPORT_ID(1, 6), - - 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, - - USAGE(1, PID_USAGE_POOL_REPORT), - COLLECTION(1, Logical), - REPORT_ID(1, 1), - - USAGE(1, PID_USAGE_RAM_POOL_SIZE), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(4, 0xffff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(4, 0xffff), - REPORT_SIZE(1, 16), - REPORT_COUNT(1, 1), - FEATURE(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_SIMULTANEOUS_EFFECTS_MAX), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - FEATURE(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_DEVICE_MANAGED_POOL), - USAGE(1, PID_USAGE_SHARED_PARAMETER_BLOCKS), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 8), - FEATURE(1, Data|Var|Abs), - END_COLLECTION, - - USAGE(1, PID_USAGE_CREATE_NEW_EFFECT_REPORT), - COLLECTION(1, Logical), - REPORT_ID(1, 2), - - USAGE(1, PID_USAGE_EFFECT_TYPE), - COLLECTION(1, NamedArray), - USAGE(1, PID_USAGE_ET_SQUARE), - USAGE(1, PID_USAGE_ET_SINE), - USAGE(1, PID_USAGE_ET_SPRING), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 3), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 3), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - FEATURE(1, Data|Ary|Abs), - END_COLLECTION, - END_COLLECTION, - - USAGE(1, PID_USAGE_BLOCK_LOAD_REPORT), - COLLECTION(1, Logical), - REPORT_ID(1, 3), - - USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - FEATURE(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_BLOCK_LOAD_STATUS), - COLLECTION(1, NamedArray), - USAGE(1, PID_USAGE_BLOCK_LOAD_SUCCESS), - USAGE(1, PID_USAGE_BLOCK_LOAD_FULL), - USAGE(1, PID_USAGE_BLOCK_LOAD_ERROR), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 3), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 3), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - FEATURE(1, Data|Ary|Abs), - END_COLLECTION, - - USAGE(1, PID_USAGE_RAM_POOL_AVAILABLE), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(4, 0xffff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(4, 0xffff), - REPORT_SIZE(1, 16), - REPORT_COUNT(1, 1), - FEATURE(1, Data|Var|Abs), - END_COLLECTION, - END_COLLECTION, - }; -#include "pop_hid_macros.h" - - static const HIDP_CAPS hid_caps = - { - .InputReportByteLength = 5, - }; - struct hid_expect expect_acquire[] = - { - /* device control */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, - .report_len = 2, - .report_buf = {1, 0x01}, - }, - /* device gain */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 6, - .report_len = 2, - .report_buf = {6, 0xff}, - }, - }; - struct hid_expect expect_reset[] = - { - /* device control */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, - .report_len = 2, - .report_buf = {1, 0x01}, - }, - }; - struct hid_expect expect_enable_actuators[] = - { - /* device control */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, - .report_len = 2, - .report_buf = {1, 0x04}, - }, - }; - struct hid_expect expect_disable_actuators[] = - { - /* device control */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, - .report_len = 2, - .report_buf = {1, 0x05}, - }, - }; - struct hid_expect expect_stop_all[] = - { - /* device control */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, - .report_len = 2, - .report_buf = {1, 0x06}, - }, - }; - struct hid_expect expect_device_pause[] = - { - /* device control */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, - .report_len = 2, - .report_buf = {1, 0x02}, - }, - }; - struct hid_expect expect_device_continue[] = - { - /* device control */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, - .report_len = 2, - .report_buf = {1, 0x03}, - }, - }; - struct hid_expect expect_create[] = - { - /* create new effect */ - { - .code = IOCTL_HID_SET_FEATURE, - .report_id = 2, - .report_len = 2, - .report_buf = {2,0x03}, - }, - /* block load */ - { - .code = IOCTL_HID_GET_FEATURE, - .report_id = 3, - .report_len = 5, - .report_buf = {3,0x01,0x01,0x00,0x00}, - }, - /* set condition */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 4, - .report_len = 9, - .report_buf = {4,0x01,0x00,0xf9,0x19,0xd9,0xff,0xff,0x99}, - }, - /* set condition */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 4, - .report_len = 9, - .report_buf = {4,0x01,0x01,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, - }, - /* update effect */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 3, - .report_len = 11, - .report_buf = {3,0x01,0x03,0x08,0x01,0x00,0x06,0x00,0x01,0x55,0x00}, - }, - }; - struct hid_expect expect_create_2[] = - { - /* create new effect */ - { - .code = IOCTL_HID_SET_FEATURE, - .report_id = 2, - .report_len = 2, - .report_buf = {2,0x03}, - }, - /* block load */ - { - .code = IOCTL_HID_GET_FEATURE, - .report_id = 3, - .report_len = 5, - .report_buf = {3,0x02,0x01,0x00,0x00}, - }, - /* set condition */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 4, - .report_len = 9, - .report_buf = {4,0x02,0x00,0xf9,0x19,0xd9,0xff,0xff,0x99}, - }, - /* set condition */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 4, - .report_len = 9, - .report_buf = {4,0x02,0x01,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, - }, - /* update effect */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 3, - .report_len = 11, - .report_buf = {3,0x02,0x03,0x08,0x01,0x00,0x06,0x00,0x01,0x55,0x00}, - }, - }; - struct hid_expect expect_create_delay[] = - { - /* create new effect */ - { - .code = IOCTL_HID_SET_FEATURE, - .report_id = 2, - .report_len = 2, - .report_buf = {2,0x03}, - }, - /* block load */ - { - .code = IOCTL_HID_GET_FEATURE, - .report_id = 3, - .report_len = 5, - .report_buf = {3,0x01,0x01,0x00,0x00}, - }, - /* set condition */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 4, - .report_len = 9, - .report_buf = {4,0x01,0x00,0xf9,0x19,0xd9,0xff,0xff,0x99}, - }, - /* set condition */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 4, - .report_len = 9, - .report_buf = {4,0x01,0x01,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, - }, - /* update effect */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 3, - .report_len = 11, - .report_buf = {3,0x01,0x03,0x08,0x01,0x00,0xff,0x7f,0x01,0x55,0x00}, - }, - }; - struct hid_expect expect_create_duration[] = - { - /* create new effect */ - { - .code = IOCTL_HID_SET_FEATURE, - .report_id = 2, - .report_len = 2, - .report_buf = {2,0x03}, - }, - /* block load */ - { - .code = IOCTL_HID_GET_FEATURE, - .report_id = 3, - .report_len = 5, - .report_buf = {3,0x01,0x01,0x00,0x00}, - }, - /* set condition */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 4, - .report_len = 9, - .report_buf = {4,0x01,0x00,0xf9,0x19,0xd9,0xff,0xff,0x99}, - }, - /* set condition */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 4, - .report_len = 9, - .report_buf = {4,0x01,0x01,0x4c,0x3f,0xcc,0x4c,0x33,0x19}, - }, - /* update effect */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 3, - .report_len = 11, - .report_buf = {3,0x01,0x03,0x08,0x00,0x00,0x00,0x00,0x01,0x55,0x00}, - }, - }; - struct hid_expect expect_start = - { - /* effect control */ - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {2,0x01,0x01,0x01}, - }; - struct hid_expect expect_start_2 = - { - /* effect control */ - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {2,0x02,0x02,0x01}, - }; - struct hid_expect expect_stop = - { - /* effect control */ - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {2,0x01,0x03,0x00}, - }; - struct hid_expect expect_stop_2 = - { - /* effect control */ - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {2,0x02,0x03,0x00}, - }; - struct hid_expect expect_destroy[] = - { - /* effect operation */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {2,0x01,0x03,0x00}, - }, - /* block free */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 5, - .report_len = 2, - .report_buf = {5,0x01}, - }, - }; - struct hid_expect expect_destroy_2[] = - { - /* effect operation */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {2,0x02,0x03,0x00}, - }, - /* block free */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 5, - .report_len = 2, - .report_buf = {5,0x02}, - }, - }; - struct hid_expect device_state_input[] = - { - /* effect state */ - { - .code = IOCTL_HID_READ_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {2,0xff,0x00,0xff}, - }, - /* device state */ - { - .code = IOCTL_HID_READ_REPORT, - .report_id = 1, - .report_len = 5, - .report_buf = {1,0x12,0x34,0x56,0xff}, - }, - }; - struct hid_expect device_state_input_0[] = - { - /* effect state */ - { - .code = IOCTL_HID_READ_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {2,0xff,0x00,0xff}, - }, - /* device state */ - { - .code = IOCTL_HID_READ_REPORT, - .report_id = 1, - .report_len = 5, - .report_buf = {1,0x56,0x12,0x34,0xff}, - }, - }; - struct hid_expect device_state_input_1[] = - { - /* effect state */ - { - .code = IOCTL_HID_READ_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {2,0x00,0x01,0x01}, - }, - /* device state */ - { - .code = IOCTL_HID_READ_REPORT, - .report_id = 1, - .report_len = 5, - .report_buf = {1,0x65,0x43,0x21,0x00}, - }, - }; - struct hid_expect device_state_input_2[] = - { - /* effect state */ - { - .code = IOCTL_HID_READ_REPORT, - .report_id = 2, - .report_len = 4, - .report_buf = {2,0x03,0x00,0x01}, - }, - /* device state */ - { - .code = IOCTL_HID_READ_REPORT, - .report_id = 1, - .report_len = 5, - .report_buf = {1,0x12,0x34,0x56,0xff}, - }, - }; - struct hid_expect expect_pool[] = - { - /* device pool */ - { - .code = IOCTL_HID_GET_FEATURE, - .report_id = 1, - .report_len = 5, - .report_buf = {1,0x10,0x00,0x04,0x03}, - .todo = TRUE, - }, - /* device pool */ - { - .code = IOCTL_HID_GET_FEATURE, - .report_id = 1, - .report_len = 5, - .report_buf = {1,0x10,0x00,0x04,0x03}, - .todo = TRUE, - }, - }; - static const DWORD expect_axes[3] = - { - DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFACTUATOR, - DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR, - DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ) | DIDFT_FFACTUATOR, - }; - static const LONG expect_directions[3] = { - +3000, - 0, - 0, - }; - static const DIENVELOPE expect_envelope = - { - .dwSize = sizeof(DIENVELOPE), - .dwAttackLevel = 1000, - .dwAttackTime = 2000, - .dwFadeLevel = 3000, - .dwFadeTime = 4000, - }; - static const DICONDITION expect_condition[3] = - { - { - .lOffset = -500, - .lPositiveCoefficient = 2000, - .lNegativeCoefficient = -3000, - .dwPositiveSaturation = -4000, - .dwNegativeSaturation = -5000, - .lDeadBand = 6000, - }, - { - .lOffset = 6000, - .lPositiveCoefficient = 5000, - .lNegativeCoefficient = -4000, - .dwPositiveSaturation = 3000, - .dwNegativeSaturation = 2000, - .lDeadBand = 1000, - }, - { - .lOffset = -7000, - .lPositiveCoefficient = -8000, - .lNegativeCoefficient = 9000, - .dwPositiveSaturation = 10000, - .dwNegativeSaturation = 11000, - .lDeadBand = -12000, - }, - }; - const DIEFFECT expect_desc = - { - .dwSize = sizeof(DIEFFECT_DX6), - .dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS, - .dwDuration = 1000, - .dwSamplePeriod = 2000, - .dwGain = 3000, - .dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER, - .dwTriggerRepeatInterval = 5000, - .cAxes = 2, - .rgdwAxes = (void *)expect_axes, - .rglDirection = (void *)expect_directions, - .lpEnvelope = (void *)&expect_envelope, - .cbTypeSpecificParams = 2 * sizeof(DICONDITION), - .lpvTypeSpecificParams = (void *)expect_condition, - .dwStartDelay = 6000, - }; - DIPROPGUIDANDPATH prop_guid_path = - { - .diph = - { - .dwSize = sizeof(DIPROPGUIDANDPATH), - .dwHeaderSize = sizeof(DIPROPHEADER), - .dwHow = DIPH_DEVICE, - }, - }; - DIPROPDWORD prop_dword = - { - .diph = - { - .dwSize = sizeof(DIPROPDWORD), - .dwHeaderSize = sizeof(DIPROPHEADER), - .dwHow = DIPH_DEVICE, - }, - }; - DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; - WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; - IDirectInputDevice8W *device; - IDirectInputEffect *effect, *effect2; - HANDLE file, event; - ULONG res, ref; - DIEFFECT desc; - DWORD flags; - HRESULT hr; - HWND hwnd; - - GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - - cleanup_registry_keys(); - if (!dinput_driver_start( report_descriptor, sizeof(report_descriptor), &hid_caps, - expect_pool, sizeof(expect_pool) )) goto done; - if (FAILED(hr = create_dinput_device( DIRECTINPUT_VERSION, &devinst, &device ))) goto done; - - hr = IDirectInputDevice8_GetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph ); - 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, - 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, - NULL, NULL, NULL, NULL ); - - event = CreateEventW( NULL, FALSE, FALSE, NULL ); - ok( event != NULL, "CreateEventW failed, last error %u\n", GetLastError() ); - hr = IDirectInputDevice8_SetEventNotification( device, event ); - ok( hr == DI_OK, "SetEventNotification returned: %#x\n", hr ); - hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); - ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr ); - hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); - ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); - - hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetForceFeedbackState returned %#x\n", hr ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "SendForceFeedbackCommand returned %#x\n", hr ); - - set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - wait_hid_expect( file, 100 ); - - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); - ok( prop_dword.dwData == 0, "got DIPROP_FFLOAD %#x\n", prop_dword.dwData ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_STOPPED|DIGFFS_EMPTY; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); - ok( prop_dword.dwData == 0, "got DIPROP_FFLOAD %#x\n", prop_dword.dwData ); - set_hid_expect( file, NULL, 0 ); - - send_hid_input( file, device_state_input, sizeof(struct hid_expect) ); - res = WaitForSingleObject( event, 100 ); - ok( res == WAIT_TIMEOUT, "WaitForSingleObject returned %#x\n", res ); - send_hid_input( file, device_state_input, sizeof(device_state_input) ); - res = WaitForSingleObject( event, 100 ); - ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", res ); - - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_PAUSED|DIGFFS_EMPTY|DIGFFS_ACTUATORSON|DIGFFS_POWERON|DIGFFS_SAFETYSWITCHON|DIGFFS_USERFFSWITCHON; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, NULL, &effect, NULL ); - ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); - - hr = IDirectInputEffect_GetEffectStatus( effect, NULL ); - ok( hr == E_POINTER, "GetEffectStatus returned %#x\n", hr ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DIERR_NOTDOWNLOADED, "GetEffectStatus returned %#x\n", hr ); - ok( res == 0, "got status %#x\n", res ); - - flags = DIEP_ALLPARAMS; - hr = IDirectInputEffect_SetParameters( effect, &expect_desc, flags | DIEP_NODOWNLOAD ); - ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#x\n", hr ); - - set_hid_expect( file, expect_reset, sizeof(struct hid_expect) ); - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetEffectStatus returned %#x\n", hr ); - - set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - wait_hid_expect( file, 100 ); - - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DIERR_NOTDOWNLOADED, "GetEffectStatus returned %#x\n", hr ); - ok( res == 0, "got status %#x\n", res ); - - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_STOPPED|DIGFFS_EMPTY; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_create, sizeof(expect_create) ); - hr = IDirectInputEffect_Download( effect ); - ok( hr == DI_OK, "Download returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == 0, "got status %#x\n", res ); - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_STOPPED; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); - ok( hr == DI_OK, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); - ok( prop_dword.dwData == 0, "got DIPROP_FFLOAD %#x\n", prop_dword.dwData ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, &expect_start, sizeof(expect_start) ); - hr = IDirectInputEffect_Start( effect, 1, DIES_NODOWNLOAD ); - ok( hr == DI_OK, "Start returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_create_2, sizeof(expect_create_2) ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &expect_desc, &effect2, NULL ); - ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - set_hid_expect( file, &expect_start_2, sizeof(expect_start_2) ); - hr = IDirectInputEffect_Start( effect2, 1, DIES_SOLO ); - ok( hr == DI_OK, "Start returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect2, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == DIEGES_PLAYING, "got status %#x\n", res ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == DIEGES_PLAYING, "got status %#x\n", res ); - set_hid_expect( file, &expect_stop_2, sizeof(expect_stop_2) ); - hr = IDirectInputEffect_Stop( effect2 ); - ok( hr == DI_OK, "Stop returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect2, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == 0, "got status %#x\n", res ); - set_hid_expect( file, expect_destroy_2, sizeof(expect_destroy_2) ); - ref = IDirectInputEffect_Release( effect2 ); - ok( ref == 0, "Release returned %d\n", ref ); - set_hid_expect( file, NULL, 0 ); - - /* sending commands has no direct effect on status */ - set_hid_expect( file, expect_stop_all, sizeof(expect_stop_all) ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_STOPALL ); - ok( hr == DI_OK, "SendForceFeedbackCommand returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == DIEGES_PLAYING, "got status %#x\n", res ); - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_STOPPED; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_device_pause, sizeof(expect_device_pause) ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_PAUSE ); - ok( hr == DI_OK, "SendForceFeedbackCommand returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == DIEGES_PLAYING, "got status %#x\n", res ); - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_STOPPED; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_device_continue, sizeof(expect_device_continue) ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_CONTINUE ); - ok( hr == DI_OK, "SendForceFeedbackCommand returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == DIEGES_PLAYING, "got status %#x\n", res ); - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_STOPPED; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_disable_actuators, sizeof(expect_disable_actuators) ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSOFF ); - ok( hr == DI_OK, "SendForceFeedbackCommand returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == DIEGES_PLAYING, "got status %#x\n", res ); - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_STOPPED; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_enable_actuators, sizeof(expect_enable_actuators) ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSON ); - ok( hr == DI_OK, "SendForceFeedbackCommand returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == DIEGES_PLAYING, "got status %#x\n", res ); - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_STOPPED; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, &expect_stop, sizeof(expect_stop) ); - hr = IDirectInputEffect_Stop( effect ); - ok( hr == DI_OK, "Stop returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == 0, "got status %#x\n", res ); - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_STOPPED; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - send_hid_input( file, device_state_input_0, sizeof(device_state_input_0) ); - res = WaitForSingleObject( event, 100 ); - ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", res ); - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_PAUSED|DIGFFS_ACTUATORSON|DIGFFS_POWERON|DIGFFS_SAFETYSWITCHON|DIGFFS_USERFFSWITCHON; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - send_hid_input( file, device_state_input_1, sizeof(device_state_input_1) ); - res = WaitForSingleObject( event, 100 ); - ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", res ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == DIEGES_PLAYING, "got status %#x\n", res ); - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_ACTUATORSOFF|DIGFFS_POWEROFF|DIGFFS_SAFETYSWITCHOFF|DIGFFS_USERFFSWITCHOFF; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - send_hid_input( file, device_state_input_2, sizeof(device_state_input_2) ); - res = WaitForSingleObject( event, 100 ); - ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", res ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == 0, "got status %#x\n", res ); - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_PAUSED|DIGFFS_ACTUATORSON|DIGFFS_POWEROFF|DIGFFS_SAFETYSWITCHOFF|DIGFFS_USERFFSWITCHOFF; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, &expect_stop, sizeof(expect_stop) ); - hr = IDirectInputEffect_Stop( effect ); - ok( hr == DI_OK, "Stop returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == 0, "got status %#x\n", res ); - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_PAUSED|DIGFFS_ACTUATORSON|DIGFFS_POWEROFF|DIGFFS_SAFETYSWITCHOFF|DIGFFS_USERFFSWITCHOFF; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - set_hid_expect( file, expect_destroy, sizeof(expect_destroy) ); - hr = IDirectInputEffect_Unload( effect ); - ok( hr == DI_OK, "Unload returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DIERR_NOTDOWNLOADED, "GetEffectStatus returned %#x\n", hr ); - ok( res == 0, "got status %#x\n", res ); - set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DI_OK, "GetForceFeedbackState returned %#x\n", hr ); - flags = DIGFFS_EMPTY|DIGFFS_PAUSED|DIGFFS_ACTUATORSON|DIGFFS_POWEROFF|DIGFFS_SAFETYSWITCHOFF|DIGFFS_USERFFSWITCHOFF; - ok( res == flags, "got state %#x\n", res ); - set_hid_expect( file, NULL, 0 ); - - ref = IDirectInputEffect_Release( effect ); - ok( ref == 0, "Release returned %d\n", ref ); - - /* start delay has no direct effect on effect status */ - desc = expect_desc; - desc.dwStartDelay = 32767000; - set_hid_expect( file, expect_create_delay, sizeof(expect_create_delay) ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); - ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == 0, "got status %#x\n", res ); - set_hid_expect( file, &expect_start, sizeof(expect_start) ); - hr = IDirectInputEffect_Start( effect, 1, 0 ); - ok( hr == DI_OK, "Start returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == DIEGES_PLAYING, "got status %#x\n", res ); - set_hid_expect( file, expect_destroy, sizeof(expect_destroy) ); - ref = IDirectInputEffect_Release( effect ); - ok( ref == 0, "Release returned %d\n", ref ); - set_hid_expect( file, NULL, 0 ); - - /* duration has no direct effect on effect status */ - desc = expect_desc; - desc.dwDuration = 100; - desc.dwStartDelay = 0; - set_hid_expect( file, expect_create_duration, sizeof(expect_create_duration) ); - hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); - ok( hr == DI_OK, "CreateEffect returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == 0, "got status %#x\n", res ); - set_hid_expect( file, &expect_start, sizeof(expect_start) ); - hr = IDirectInputEffect_Start( effect, 1, 0 ); - ok( hr == DI_OK, "Start returned %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - Sleep( 100 ); - res = 0xdeadbeef; - hr = IDirectInputEffect_GetEffectStatus( effect, &res ); - ok( hr == DI_OK, "GetEffectStatus returned %#x\n", hr ); - ok( res == DIEGES_PLAYING, "got status %#x\n", res ); - set_hid_expect( file, expect_destroy, sizeof(expect_destroy) ); - 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(struct hid_expect) ); - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); - set_hid_expect( file, NULL, 0 ); - - ref = IDirectInputDevice8_Release( device ); - ok( ref == 0, "Release returned %d\n", ref ); - - DestroyWindow( hwnd ); - CloseHandle( event ); - CloseHandle( file ); - -done: - pnp_driver_stop(); - cleanup_registry_keys(); - SetCurrentDirectoryW( cwd ); - winetest_pop_context(); -} - -static void test_winmm_joystick(void) -{ -#include "psh_hid_macros.h" - const unsigned char report_desc[] = { - USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Application), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Report), - REPORT_ID(1, 1), - - USAGE(1, HID_USAGE_GENERIC_X), - USAGE(1, HID_USAGE_GENERIC_Y), - USAGE(1, HID_USAGE_GENERIC_Z), - USAGE(1, HID_USAGE_GENERIC_WHEEL), - USAGE(1, HID_USAGE_GENERIC_SLIDER), - USAGE(1, HID_USAGE_GENERIC_RX), - USAGE(1, HID_USAGE_GENERIC_RY), - USAGE(1, HID_USAGE_GENERIC_RZ), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(4, 0xffff), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(4, 0xffff), - REPORT_SIZE(1, 16), - REPORT_COUNT(1, 8), - INPUT(1, Data|Var|Abs), - - USAGE(1, HID_USAGE_GENERIC_HATSWITCH), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 8), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 8), - REPORT_SIZE(1, 4), - REPORT_COUNT(1, 1), - INPUT(1, Data|Var|Abs|Null), - - USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), - USAGE_MINIMUM(1, 1), - USAGE_MAXIMUM(1, 4), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 4), - INPUT(1, Data|Var|Abs), - END_COLLECTION, - END_COLLECTION, - }; -#include "pop_hid_macros.h" - - static const HIDP_CAPS hid_caps = - { - .InputReportByteLength = 18, - }; - static const JOYCAPS2W expect_regcaps = - { - .szRegKey = L"DINPUT.DLL", - }; - static const JOYCAPS2W expect_caps = - { - .wMid = 0x1209, - .wPid = 0x0001, - .szPname = L"Microsoft PC-joystick driver", - .wXmax = 0xffff, - .wYmax = 0xffff, - .wZmax = 0xffff, - .wNumButtons = 4, - .wPeriodMin = 10, - .wPeriodMax = 1000, - .wRmax = 0xffff, - .wUmax = 0xffff, - .wVmax = 0xffff, - .wCaps = JOYCAPS_HASZ|JOYCAPS_HASR|JOYCAPS_HASU|JOYCAPS_HASV|JOYCAPS_HASPOV|JOYCAPS_POV4DIR, - .wMaxAxes = 6, - .wNumAxes = 6, - .wMaxButtons = 32, - .szRegKey = L"DINPUT.DLL", - }; - struct hid_expect injected_input[] = - { - { - .code = IOCTL_HID_READ_REPORT, - .report_buf = {1,0x00,0x00,0x00,0x08,0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x38,0xf1}, - }, - { - .code = IOCTL_HID_READ_REPORT, - .report_buf = {1,0x00,0x38,0x00,0x30,0x00,0x28,0x00,0x20,0x00,0x18,0x00,0x10,0x00,0x08,0x00,0x00,0x63}, - }, - }; - static const JOYINFOEX expect_infoex[] = - { - { - .dwSize = sizeof(JOYINFOEX), .dwFlags = 0xff, - .dwXpos = 0x7fff, .dwYpos = 0x7fff, .dwZpos = 0x7fff, .dwRpos = 0x7fff, .dwUpos = 0x7fff, .dwVpos = 0x7fff, - .dwButtons = 0, .dwButtonNumber = 0, .dwPOV = 0xffff, - .dwReserved1 = 0xcdcdcdcd, .dwReserved2 = 0xcdcdcdcd, - }, - { - .dwSize = sizeof(JOYINFOEX), .dwFlags = 0xff, - .dwXpos = 0, .dwYpos = 0x07ff, .dwZpos = 0x17ff, .dwRpos = 0x37ff, .dwUpos = 0x1fff, .dwVpos = 0x27ff, - .dwButtons = 0xf, .dwButtonNumber = 0x4, .dwPOV = 0, - .dwReserved1 = 0xcdcdcdcd, .dwReserved2 = 0xcdcdcdcd, - }, - { - .dwSize = sizeof(JOYINFOEX), .dwFlags = 0xff, - .dwXpos = 0x37ff, .dwYpos = 0x2fff, .dwZpos = 0x1fff, .dwRpos = 0, .dwUpos = 0x17ff, .dwVpos = 0x0fff, - .dwButtons = 0x6, .dwButtonNumber = 0x2, .dwPOV = 0x2328, - .dwReserved1 = 0xcdcdcdcd, .dwReserved2 = 0xcdcdcdcd, - }, - }; - static const JOYINFO expect_info = - { - .wXpos = 0x7fff, - .wYpos = 0x7fff, - .wZpos = 0x7fff, - .wButtons = 0, - }; - JOYINFOEX infoex = {.dwSize = sizeof(JOYINFOEX)}; - DIPROPGUIDANDPATH prop_guid_path = - { - .diph = - { - .dwSize = sizeof(DIPROPGUIDANDPATH), - .dwHeaderSize = sizeof(DIPROPHEADER), - .dwHow = DIPH_DEVICE, - }, - }; - WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; - DIDEVICEINSTANCEW devinst = {0}; - IDirectInputDevice8W *device; - JOYCAPS2W caps = {0}; - JOYINFO info = {0}; - HANDLE event, file; - HRESULT hr; - UINT ret; - - GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); - GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); - SetCurrentDirectoryW( tempdir ); - - cleanup_registry_keys(); - - ret = joyGetNumDevs(); - ok( ret == 16, "joyGetNumDevs returned %u\n", ret ); - - ret = joyGetDevCapsW( 0, (JOYCAPSW *)&caps, sizeof(JOYCAPSW) ); - ok( ret == JOYERR_PARMS, "joyGetDevCapsW returned %u\n", ret ); - - memset( &caps, 0xcd, sizeof(caps) ); - ret = joyGetDevCapsW( -1, (JOYCAPSW *)&caps, sizeof(caps) ); - ok( ret == 0, "joyGetDevCapsW returned %u\n", ret ); - check_member( caps, expect_regcaps, "%#x", wMid ); - check_member( caps, expect_regcaps, "%#x", wPid ); - check_member_wstr( caps, expect_regcaps, szPname ); - check_member( caps, expect_regcaps, "%#x", wXmin ); - check_member( caps, expect_regcaps, "%#x", wXmax ); - check_member( caps, expect_regcaps, "%#x", wYmin ); - check_member( caps, expect_regcaps, "%#x", wYmax ); - check_member( caps, expect_regcaps, "%#x", wZmin ); - check_member( caps, expect_regcaps, "%#x", wZmax ); - check_member( caps, expect_regcaps, "%#x", wNumButtons ); - check_member( caps, expect_regcaps, "%#x", wPeriodMin ); - check_member( caps, expect_regcaps, "%#x", wPeriodMax ); - check_member( caps, expect_regcaps, "%#x", wRmin ); - check_member( caps, expect_regcaps, "%#x", wRmax ); - check_member( caps, expect_regcaps, "%#x", wUmin ); - check_member( caps, expect_regcaps, "%#x", wUmax ); - check_member( caps, expect_regcaps, "%#x", wVmin ); - check_member( caps, expect_regcaps, "%#x", wVmax ); - check_member( caps, expect_regcaps, "%#x", wCaps ); - check_member( caps, expect_regcaps, "%#x", wMaxAxes ); - check_member( caps, expect_regcaps, "%#x", wNumAxes ); - check_member( caps, expect_regcaps, "%#x", wMaxButtons ); - check_member_wstr( caps, expect_regcaps, szRegKey ); - check_member_wstr( caps, expect_regcaps, szOEMVxD ); - check_member_guid( caps, expect_regcaps, ManufacturerGuid ); - check_member_guid( caps, expect_regcaps, ProductGuid ); - check_member_guid( caps, expect_regcaps, NameGuid ); - - if (!dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 )) goto done; - - ret = joyGetNumDevs(); - ok( ret == 16, "joyGetNumDevs returned %u\n", ret ); - - ret = joyGetPosEx( 1, &infoex ); - ok( ret == JOYERR_PARMS, "joyGetPosEx returned %u\n", ret ); - ret = joyGetPosEx( 0, &infoex ); - /* first call for an index sometimes fail */ - if (ret == JOYERR_PARMS) ret = joyGetPosEx( 0, &infoex ); - ok( ret == 0, "joyGetPosEx returned %u\n", ret ); - - ret = joyGetDevCapsW( 1, (JOYCAPSW *)&caps, sizeof(JOYCAPSW) ); - ok( ret == JOYERR_PARMS, "joyGetDevCapsW returned %u\n", ret ); - - memset( &caps, 0xcd, sizeof(caps) ); - ret = joyGetDevCapsW( 0, (JOYCAPSW *)&caps, sizeof(caps) ); - ok( ret == 0, "joyGetDevCapsW returned %u\n", ret ); - check_member( caps, expect_caps, "%#x", wMid ); - check_member( caps, expect_caps, "%#x", wPid ); - todo_wine - check_member_wstr( caps, expect_caps, szPname ); - check_member( caps, expect_caps, "%#x", wXmin ); - check_member( caps, expect_caps, "%#x", wXmax ); - check_member( caps, expect_caps, "%#x", wYmin ); - check_member( caps, expect_caps, "%#x", wYmax ); - check_member( caps, expect_caps, "%#x", wZmin ); - check_member( caps, expect_caps, "%#x", wZmax ); - check_member( caps, expect_caps, "%#x", wNumButtons ); - check_member( caps, expect_caps, "%#x", wPeriodMin ); - check_member( caps, expect_caps, "%#x", wPeriodMax ); - check_member( caps, expect_caps, "%#x", wRmin ); - check_member( caps, expect_caps, "%#x", wRmax ); - check_member( caps, expect_caps, "%#x", wUmin ); - check_member( caps, expect_caps, "%#x", wUmax ); - check_member( caps, expect_caps, "%#x", wVmin ); - check_member( caps, expect_caps, "%#x", wVmax ); - check_member( caps, expect_caps, "%#x", wCaps ); - check_member( caps, expect_caps, "%#x", wMaxAxes ); - check_member( caps, expect_caps, "%#x", wNumAxes ); - check_member( caps, expect_caps, "%#x", wMaxButtons ); - check_member_wstr( caps, expect_caps, szRegKey ); - check_member_wstr( caps, expect_caps, szOEMVxD ); - check_member_guid( caps, expect_caps, ManufacturerGuid ); - check_member_guid( caps, expect_caps, ProductGuid ); - check_member_guid( caps, expect_caps, NameGuid ); - - ret = joyGetDevCapsW( 0, (JOYCAPSW *)&caps, sizeof(JOYCAPSW) ); - ok( ret == 0, "joyGetDevCapsW returned %u\n", ret ); - ret = joyGetDevCapsW( 0, NULL, sizeof(JOYCAPSW) ); - ok( ret == MMSYSERR_INVALPARAM, "joyGetDevCapsW returned %u\n", ret ); - ret = joyGetDevCapsW( 0, (JOYCAPSW *)&caps, sizeof(JOYCAPSW) + 4 ); - ok( ret == JOYERR_PARMS, "joyGetDevCapsW returned %u\n", ret ); - ret = joyGetDevCapsW( 0, (JOYCAPSW *)&caps, sizeof(JOYCAPSW) - 4 ); - ok( ret == JOYERR_PARMS, "joyGetDevCapsW returned %u\n", ret ); - - infoex.dwSize = sizeof(JOYINFOEX); - infoex.dwFlags = JOY_RETURNALL; - ret = joyGetPosEx( -1, &infoex ); - ok( ret == JOYERR_PARMS, "joyGetPosEx returned %u\n", ret ); - ret = joyGetPosEx( 1, &infoex ); - ok( ret == JOYERR_PARMS, "joyGetPosEx returned %u\n", ret ); - ret = joyGetPosEx( 16, &infoex ); - ok( ret == JOYERR_PARMS, "joyGetPosEx returned %u\n", ret ); - - memset( &infoex, 0xcd, sizeof(infoex) ); - infoex.dwSize = sizeof(JOYINFOEX); - infoex.dwFlags = JOY_RETURNALL; - ret = joyGetPosEx( 0, &infoex ); - ok( ret == 0, "joyGetPosEx returned %u\n", ret ); - check_member( infoex, expect_infoex[0], "%#x", dwSize ); - check_member( infoex, expect_infoex[0], "%#x", dwFlags ); - check_member( infoex, expect_infoex[0], "%#x", dwXpos ); - check_member( infoex, expect_infoex[0], "%#x", dwYpos ); - check_member( infoex, expect_infoex[0], "%#x", dwZpos ); - check_member( infoex, expect_infoex[0], "%#x", dwRpos ); - check_member( infoex, expect_infoex[0], "%#x", dwUpos ); - check_member( infoex, expect_infoex[0], "%#x", dwVpos ); - check_member( infoex, expect_infoex[0], "%#x", dwButtons ); - check_member( infoex, expect_infoex[0], "%#x", dwButtonNumber ); - check_member( infoex, expect_infoex[0], "%#x", dwPOV ); - check_member( infoex, expect_infoex[0], "%#x", dwReserved1 ); - check_member( infoex, expect_infoex[0], "%#x", dwReserved2 ); - - infoex.dwSize = sizeof(JOYINFOEX) - 4; - ret = joyGetPosEx( 0, &infoex ); - ok( ret == JOYERR_PARMS, "joyGetPosEx returned %u\n", ret ); - - ret = joyGetPos( -1, &info ); - ok( ret == JOYERR_PARMS, "joyGetPos returned %u\n", ret ); - ret = joyGetPos( 1, &info ); - ok( ret == JOYERR_PARMS, "joyGetPos returned %u\n", ret ); - memset( &info, 0xcd, sizeof(info) ); - ret = joyGetPos( 0, &info ); - ok( ret == 0, "joyGetPos returned %u\n", ret ); - check_member( info, expect_info, "%#x", wXpos ); - check_member( info, expect_info, "%#x", wYpos ); - check_member( info, expect_info, "%#x", wZpos ); - check_member( info, expect_info, "%#x", wButtons ); - - if (FAILED(hr = create_dinput_device( DIRECTINPUT_VERSION, &devinst, &device ))) goto done; - - event = CreateEventW( NULL, FALSE, FALSE, NULL ); - ok( event != NULL, "CreateEventW failed, last error %u\n", GetLastError() ); - hr = IDirectInputDevice8_SetEventNotification( device, event ); - ok( hr == DI_OK, "SetEventNotification returned: %#x\n", hr ); - - hr = IDirectInputDevice8_GetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph ); - 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, - FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL ); - ok( file != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError() ); - - hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); - ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); - hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE ); - ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); - - send_hid_input( file, &injected_input[0], sizeof(struct hid_expect) ); - ret = WaitForSingleObject( event, 100 ); - ok( ret != WAIT_TIMEOUT, "WaitForSingleObject returned %#x\n", ret ); - Sleep( 50 ); /* leave some time for winmm to keep up */ - - memset( &infoex, 0xcd, sizeof(infoex) ); - infoex.dwSize = sizeof(JOYINFOEX); - infoex.dwFlags = JOY_RETURNALL; - ret = joyGetPosEx( 0, &infoex ); - ok( ret == 0, "joyGetPosEx returned %u\n", ret ); - check_member( infoex, expect_infoex[1], "%#x", dwSize ); - check_member( infoex, expect_infoex[1], "%#x", dwFlags ); - check_member( infoex, expect_infoex[1], "%#x", dwXpos ); - check_member( infoex, expect_infoex[1], "%#x", dwYpos ); - check_member( infoex, expect_infoex[1], "%#x", dwZpos ); - check_member( infoex, expect_infoex[1], "%#x", dwRpos ); - check_member( infoex, expect_infoex[1], "%#x", dwUpos ); - check_member( infoex, expect_infoex[1], "%#x", dwVpos ); - check_member( infoex, expect_infoex[1], "%#x", dwButtons ); - check_member( infoex, expect_infoex[1], "%#x", dwButtonNumber ); - check_member( infoex, expect_infoex[1], "%#x", dwPOV ); - - send_hid_input( file, &injected_input[1], sizeof(struct hid_expect) ); - ret = WaitForSingleObject( event, 100 ); - ok( ret != WAIT_TIMEOUT, "WaitForSingleObject returned %#x\n", ret ); - Sleep( 50 ); /* leave some time for winmm to keep up */ - - memset( &infoex, 0xcd, sizeof(infoex) ); - infoex.dwSize = sizeof(JOYINFOEX); - infoex.dwFlags = JOY_RETURNALL; - ret = joyGetPosEx( 0, &infoex ); - ok( ret == 0, "joyGetPosEx returned %u\n", ret ); - check_member( infoex, expect_infoex[2], "%#x", dwSize ); - check_member( infoex, expect_infoex[2], "%#x", dwFlags ); - check_member( infoex, expect_infoex[2], "%#x", dwXpos ); - check_member( infoex, expect_infoex[2], "%#x", dwYpos ); - check_member( infoex, expect_infoex[2], "%#x", dwZpos ); - check_member( infoex, expect_infoex[2], "%#x", dwRpos ); - check_member( infoex, expect_infoex[2], "%#x", dwUpos ); - check_member( infoex, expect_infoex[2], "%#x", dwVpos ); - check_member( infoex, expect_infoex[2], "%#x", dwButtons ); - check_member( infoex, expect_infoex[2], "%#x", dwButtonNumber ); - check_member( infoex, expect_infoex[2], "%#x", dwPOV ); - - ret = IDirectInputDevice8_Release( device ); - ok( ret == 0, "Release returned %d\n", ret ); - - CloseHandle( event ); - CloseHandle( file ); - -done: - pnp_driver_stop(); - cleanup_registry_keys(); - SetCurrentDirectoryW( cwd ); -} - START_TEST( hid ) { - HANDLE mapping; - BOOL is_wow64; + if (!dinput_test_init()) return;
- instance = GetModuleHandleW( NULL ); - localized = GetUserDefaultLCID() != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); - pSignerSign = (void *)GetProcAddress( LoadLibraryW( L"mssign32" ), "SignerSign" ); - - if (IsWow64Process( GetCurrentProcess(), &is_wow64 ) && is_wow64) - { - skip( "Running in WoW64.\n" ); - return; - } - - mapping = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(*test_data), - L"Global\winetest_dinput_section" ); - if (!mapping && GetLastError() == ERROR_ACCESS_DENIED) - { - win_skip( "Failed to create test data mapping.\n" ); - return; - } - ok( !!mapping, "got error %u\n", GetLastError() ); - test_data = MapViewOfFile( mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024 ); - test_data->running_under_wine = !strcmp( winetest_platform, "wine" ); - test_data->winetest_report_success = winetest_report_success; - test_data->winetest_debug = winetest_debug; - - okfile = CreateFileW( L"C:\windows\winetest_dinput_okfile", GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL ); - ok( okfile != INVALID_HANDLE_VALUE, "failed to create file, error %u\n", GetLastError() ); - - subtest( "driver_hid" ); test_hidp_kdr(); test_hid_driver( 0, FALSE ); test_hid_driver( 1, FALSE ); test_hid_driver( 0, TRUE ); test_hid_driver( 1, TRUE );
- CoInitialize( NULL ); - if (test_device_types( 0x800 )) - { - /* This needs to be done before doing anything involving dinput.dll - * on Windows, or the tests will fail, dinput8.dll is fine though. */ - test_winmm_joystick(); - - test_device_types( 0x500 ); - test_device_types( 0x700 ); - - test_simple_joystick(); - test_force_feedback_joystick( 0x500 ); - test_force_feedback_joystick( 0x700 ); - test_force_feedback_joystick( 0x800 ); - - test_device_managed_effect(); - } - CoUninitialize(); - - UnmapViewOfFile( test_data ); - CloseHandle( mapping ); - CloseHandle( okfile ); - DeleteFileW( L"C:\windows\winetest_dinput_okfile" ); + dinput_test_exit(); } diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c new file mode 100644 index 00000000000..f1fd4be36e5 --- /dev/null +++ b/dlls/dinput/tests/joystick8.c @@ -0,0 +1,2594 @@ +/* + * Copyright 2022 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define DIRECTINPUT_VERSION 0x0800 + +#include <stdarg.h> +#include <stddef.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" + +#define COBJMACROS +#include "dinput.h" +#include "dinputd.h" +#include "devguid.h" +#include "mmsystem.h" + +#include "wine/hid.h" + +#include "dinput_test.h" + +struct check_objects_todos +{ + BOOL type; + BOOL guid; + BOOL usage; + BOOL name; +}; + +struct check_objects_params +{ + DWORD version; + UINT index; + UINT expect_count; + const DIDEVICEOBJECTINSTANCEW *expect_objs; + const struct check_objects_todos *todo_objs; + BOOL todo_extra; +}; + +static BOOL CALLBACK check_objects( const DIDEVICEOBJECTINSTANCEW *obj, void *args ) +{ + static const DIDEVICEOBJECTINSTANCEW unexpected_obj = {0}; + static const struct check_objects_todos todo_none = {0}; + struct check_objects_params *params = args; + const DIDEVICEOBJECTINSTANCEW *exp = params->expect_objs + params->index; + const struct check_objects_todos *todo; + + if (!params->todo_objs) todo = &todo_none; + else todo = params->todo_objs + params->index; + + todo_wine_if( params->todo_extra && params->index >= params->expect_count ) + ok( params->index < params->expect_count, "unexpected extra object\n" ); + if (params->index >= params->expect_count) return DIENUM_STOP; + + winetest_push_context( "obj[%d]", params->index ); + + ok( params->index < params->expect_count, "unexpected extra object\n" ); + if (params->index >= params->expect_count) exp = &unexpected_obj; + + check_member( *obj, *exp, "%u", dwSize ); + todo_wine_if( todo->guid ) + check_member_guid( *obj, *exp, guidType ); + todo_wine_if( params->version < 0x700 && (obj->dwType & DIDFT_BUTTON) ) + check_member( *obj, *exp, "%#x", dwOfs ); + todo_wine_if( todo->type ) + check_member( *obj, *exp, "%#x", dwType ); + check_member( *obj, *exp, "%#x", dwFlags ); + if (!localized) todo_wine_if( todo->name )check_member_wstr( *obj, *exp, tszName ); + check_member( *obj, *exp, "%u", dwFFMaxForce ); + check_member( *obj, *exp, "%u", dwFFForceResolution ); + check_member( *obj, *exp, "%u", wCollectionNumber ); + check_member( *obj, *exp, "%u", wDesignatorIndex ); + check_member( *obj, *exp, "%#04x", wUsagePage ); + todo_wine_if( todo->usage ) + check_member( *obj, *exp, "%#04x", wUsage ); + check_member( *obj, *exp, "%#04x", dwDimension ); + check_member( *obj, *exp, "%#04x", wExponent ); + check_member( *obj, *exp, "%u", wReportId ); + + winetest_pop_context(); + + params->index++; + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK check_object_count( const DIDEVICEOBJECTINSTANCEW *obj, void *args ) +{ + DWORD *count = args; + *count = *count + 1; + return DIENUM_CONTINUE; +} + +struct check_effects_params +{ + UINT index; + UINT expect_count; + const DIEFFECTINFOW *expect_effects; +}; + +static BOOL CALLBACK check_effects( const DIEFFECTINFOW *effect, void *args ) +{ + static const DIEFFECTINFOW unexpected_effect = {0}; + struct check_effects_params *params = args; + const DIEFFECTINFOW *exp = params->expect_effects + params->index; + + winetest_push_context( "effect[%d]", params->index ); + + ok( params->index < params->expect_count, "unexpected extra object\n" ); + if (params->index >= params->expect_count) exp = &unexpected_effect; + + check_member( *effect, *exp, "%u", dwSize ); + check_member_guid( *effect, *exp, guid ); + check_member( *effect, *exp, "%#x", dwEffType ); + check_member( *effect, *exp, "%#x", dwStaticParams ); + check_member( *effect, *exp, "%#x", dwDynamicParams ); + check_member_wstr( *effect, *exp, tszName ); + + winetest_pop_context(); + params->index++; + + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK check_effect_count( const DIEFFECTINFOW *effect, void *args ) +{ + DWORD *count = args; + *count = *count + 1; + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK check_no_created_effect_objects( IDirectInputEffect *effect, void *context ) +{ + ok( 0, "unexpected effect %p\n", effect ); + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK enum_device_count( const DIDEVICEINSTANCEW *devinst, void *context ) +{ + DWORD *count = context; + *count = *count + 1; + return DIENUM_CONTINUE; +} + +static void check_dinput_devices( DWORD version, DIDEVICEINSTANCEW *devinst ) +{ + DIPROPDWORD prop_dword = + { + .diph = + { + .dwSize = sizeof(DIPROPDWORD), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + IDirectInputDevice8W *device; + IDirectInput8W *di8; + IDirectInputW *di; + ULONG ref, count; + HRESULT hr; + + if (version >= 0x800) + { + hr = DirectInput8Create( instance, version, &IID_IDirectInput8W, (void **)&di8, NULL ); + ok( hr == DI_OK, "DirectInput8Create returned %#x\n", hr ); + + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_ALL, NULL, NULL, DIEDFL_ALLDEVICES ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_ALL, enum_device_count, &count, 0xdeadbeef ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + hr = IDirectInput8_EnumDevices( di8, 0xdeadbeef, enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + + count = 0; + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_ALL, enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 3, "got count %u, expected 0\n", count ); + count = 0; + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_DEVICE, enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 0, "got count %u, expected 0\n", count ); + count = 0; + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_POINTER, enum_device_count, &count, + DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + todo_wine + ok( count == 3, "got count %u, expected 3\n", count ); + count = 0; + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_KEYBOARD, enum_device_count, &count, + DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + todo_wine + ok( count == 3, "got count %u, expected 3\n", count ); + count = 0; + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_GAMECTRL, enum_device_count, &count, + DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 1, "got count %u, expected 1\n", count ); + + count = 0; + hr = IDirectInput8_EnumDevices( di8, (devinst->dwDevType & 0xff), enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 1, "got count %u, expected 1\n", count ); + + count = 0; + hr = IDirectInput8_EnumDevices( di8, (devinst->dwDevType & 0xff), enum_device_count, &count, DIEDFL_FORCEFEEDBACK ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + if (IsEqualGUID( &devinst->guidFFDriver, &GUID_NULL )) ok( count == 0, "got count %u, expected 0\n", count ); + else ok( count == 1, "got count %u, expected 1\n", count ); + + count = 0; + hr = IDirectInput8_EnumDevices( di8, (devinst->dwDevType & 0xff) + 1, enum_device_count, &count, DIEDFL_ALLDEVICES ); + if ((devinst->dwDevType & 0xff) != DI8DEVTYPE_SUPPLEMENTAL) ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + else ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + ok( count == 0, "got count %u, expected 0\n", count ); + + hr = IDirectInput8_CreateDevice( di8, &devinst->guidInstance, NULL, NULL ); + ok( hr == E_POINTER, "CreateDevice returned %#x\n", hr ); + hr = IDirectInput8_CreateDevice( di8, NULL, &device, NULL ); + ok( hr == E_POINTER, "CreateDevice returned %#x\n", hr ); + hr = IDirectInput8_CreateDevice( di8, &GUID_NULL, &device, NULL ); + ok( hr == DIERR_DEVICENOTREG, "CreateDevice returned %#x\n", hr ); + + hr = IDirectInput8_CreateDevice( di8, &devinst->guidInstance, &device, NULL ); + ok( hr == DI_OK, "CreateDevice returned %#x\n", hr ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_VIDPID, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_VIDPID returned %#x\n", hr ); + /* Wine may get the wrong device here, because the test driver creates another instance of + hidclass.sys, and gets duplicate rawinput handles, which we use in the guidInstance */ + todo_wine_if( prop_dword.dwData != EXPECT_VIDPID ) + ok( prop_dword.dwData == EXPECT_VIDPID, "got %#x expected %#x\n", prop_dword.dwData, EXPECT_VIDPID ); + + ref = IDirectInputDevice8_Release( device ); + ok( ref == 0, "Release returned %d\n", ref ); + } + else + { + hr = DirectInputCreateEx( instance, version, &IID_IDirectInput2W, (void **)&di, NULL ); + ok( hr == DI_OK, "DirectInputCreateEx returned %#x\n", hr ); + + hr = IDirectInput_EnumDevices( di, 0, NULL, NULL, DIEDFL_ALLDEVICES ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + hr = IDirectInput_EnumDevices( di, 0, enum_device_count, &count, 0xdeadbeef ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + hr = IDirectInput_EnumDevices( di, 0xdeadbeef, enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + hr = IDirectInput_EnumDevices( di, 0, enum_device_count, &count, DIEDFL_INCLUDEHIDDEN ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + + count = 0; + hr = IDirectInput_EnumDevices( di, 0, enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 3, "got count %u, expected 0\n", count ); + count = 0; + hr = IDirectInput_EnumDevices( di, DIDEVTYPE_DEVICE, enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 0, "got count %u, expected 0\n", count ); + count = 0; + hr = IDirectInput_EnumDevices( di, DIDEVTYPE_MOUSE, enum_device_count, &count, + DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + todo_wine + ok( count == 3, "got count %u, expected 3\n", count ); + count = 0; + hr = IDirectInput_EnumDevices( di, DIDEVTYPE_KEYBOARD, enum_device_count, &count, + DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + todo_wine + ok( count == 3, "got count %u, expected 3\n", count ); + count = 0; + hr = IDirectInput_EnumDevices( di, DIDEVTYPE_JOYSTICK, enum_device_count, &count, + DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 1, "got count %u, expected 1\n", count ); + + count = 0; + hr = IDirectInput_EnumDevices( di, (devinst->dwDevType & 0xff), enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + ok( count == 1, "got count %u, expected 1\n", count ); + + count = 0; + hr = IDirectInput_EnumDevices( di, (devinst->dwDevType & 0xff), enum_device_count, &count, DIEDFL_FORCEFEEDBACK ); + ok( hr == DI_OK, "EnumDevices returned: %#x\n", hr ); + if (IsEqualGUID( &devinst->guidFFDriver, &GUID_NULL )) ok( count == 0, "got count %u, expected 0\n", count ); + else ok( count == 1, "got count %u, expected 1\n", count ); + + hr = IDirectInput_EnumDevices( di, 0x14, enum_device_count, &count, DIEDFL_ALLDEVICES ); + ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#x\n", hr ); + } +} + +static void test_simple_joystick(void) +{ +#include "psh_hid_macros.h" + static const unsigned char report_desc[] = + { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Report), + REPORT_ID(1, 1), + + USAGE(1, HID_USAGE_GENERIC_WHEEL), + USAGE(4, (0xff01u<<16)|(0x1234)), + USAGE(1, HID_USAGE_GENERIC_X), + USAGE(1, HID_USAGE_GENERIC_Y), + USAGE(4, (HID_USAGE_PAGE_SIMULATION<<16)|HID_USAGE_SIMULATION_RUDDER), + USAGE(4, (HID_USAGE_PAGE_DIGITIZER<<16)|HID_USAGE_DIGITIZER_TIP_PRESSURE), + USAGE(4, (HID_USAGE_PAGE_CONSUMER<<16)|HID_USAGE_CONSUMER_VOLUME), + LOGICAL_MINIMUM(1, 0xe7), + LOGICAL_MAXIMUM(1, 0x38), + PHYSICAL_MINIMUM(1, 0xe7), + PHYSICAL_MAXIMUM(1, 0x38), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 7), + INPUT(1, Data|Var|Abs), + + USAGE(1, HID_USAGE_GENERIC_HATSWITCH), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 8), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 8), + REPORT_SIZE(1, 4), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs|Null), + + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 2), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 4), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, + }; +#undef REPORT_ID_OR_USAGE_PAGE +#include "pop_hid_macros.h" + + static const HIDP_CAPS hid_caps = + { + .InputReportByteLength = 9, + }; + static const DIDEVCAPS expect_caps = + { + .dwSize = sizeof(DIDEVCAPS), + .dwFlags = DIDC_ATTACHED | DIDC_EMULATED, + .dwDevType = DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK, + .dwAxes = 6, + .dwPOVs = 1, + .dwButtons = 2, + }; + struct hid_expect injected_input[] = + { + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x38,0x38,0x10,0x10,0x10,0xf8}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x01,0x01,0x10,0x10,0x10,0x00}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x01,0x01,0x10,0x10,0x10,0x00}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x80,0x80,0x10,0x10,0x10,0xff}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x10,0xee,0x10,0x10,0x10,0x54}, + }, + }; + static const struct DIJOYSTATE2 expect_state[] = + { + {.lX = 32767, .lY = 32767, .lZ = 32767, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, + {.lX = 32767, .lY = 32767, .lZ = 32767, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, + {.lX = 65535, .lY = 65535, .lZ = 32767, .rgdwPOV = {31500, -1, -1, -1}, .rgbButtons = {0x80, 0x80}}, + {.lX = 20779, .lY = 20779, .lZ = 32767, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, + {.lX = 20779, .lY = 20779, .lZ = 32767, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, + {.lX = 0, .lY = 0, .lZ = 32767, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0x80, 0x80}}, + {.lX = 32767, .lY = 5594, .lZ = 32767, .rgdwPOV = {13500, -1, -1, -1}, .rgbButtons = {0x80}}, + }; + static const struct DIJOYSTATE2 expect_state_abs[] = + { + {.lX = -9000, .lY = 26000, .lZ = 26000, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, + {.lX = -9000, .lY = 26000, .lZ = 26000, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, + {.lX = -4000, .lY = 51000, .lZ = 26000, .rgdwPOV = {31500, -1, -1, -1}, .rgbButtons = {0x80, 0x80}}, + {.lX = -10667, .lY = 12905, .lZ = 26000, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, + {.lX = -10667, .lY = 12905, .lZ = 26000, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, + {.lX = -14000, .lY = 1000, .lZ = 26000, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0x80, 0x80}}, + {.lX = -9000, .lY = 1000, .lZ = 26000, .rgdwPOV = {13500, -1, -1, -1}, .rgbButtons = {0x80}}, + }; + static const struct DIJOYSTATE2 expect_state_rel[] = + { + {.lX = 0, .lY = 0, .rgdwPOV = {13500, -1, -1, -1}, .rgbButtons = {0x80, 0}}, + {.lX = 9016, .lY = -984, .lZ = -25984, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, + {.lX = 40, .lY = 40, .rgdwPOV = {31500, -1, -1, -1}, .rgbButtons = {0x80, 0x80}}, + {.lX = -55, .lY = -55, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, + {.lX = 0, .lY = 0, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0, 0}}, + {.lX = -129, .lY = -129, .rgdwPOV = {-1, -1, -1, -1}, .rgbButtons = {0x80, 0x80}}, + {.lX = 144, .lY = 110, .rgdwPOV = {13500, -1, -1, -1}, .rgbButtons = {0x80}}, + }; + static const DIDEVICEOBJECTDATA expect_objdata[] = + { + {.dwOfs = 0x4, .dwData = 0xffff, .dwSequence = 0xa}, + {.dwOfs = 0x4, .dwData = 0xffff, .dwSequence = 0xa}, + {.dwOfs = 0, .dwData = 0xffff, .dwSequence = 0xa}, + {.dwOfs = 0x20, .dwData = 31500, .dwSequence = 0xa}, + {.dwOfs = 0x30, .dwData = 0x80, .dwSequence = 0xa}, + {.dwOfs = 0x4, .dwData = 0x512b, .dwSequence = 0xd}, + {.dwOfs = 0, .dwData = 0x512b, .dwSequence = 0xd}, + {.dwOfs = 0x20, .dwData = -1, .dwSequence = 0xd}, + {.dwOfs = 0x30, .dwData = 0, .dwSequence = 0xd}, + {.dwOfs = 0x31, .dwData = 0, .dwSequence = 0xd}, + {.dwOfs = 0x4, .dwData = 0, .dwSequence = 0xf}, + {.dwOfs = 0, .dwData = 0, .dwSequence = 0xf}, + {.dwOfs = 0x30, .dwData = 0x80, .dwSequence = 0xf}, + {.dwOfs = 0x31, .dwData = 0x80, .dwSequence = 0xf}, + }; + + const DIDEVICEINSTANCEW expect_devinst = + { + .dwSize = sizeof(DIDEVICEINSTANCEW), + .guidInstance = expect_guid_product, + .guidProduct = expect_guid_product, + .dwDevType = DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK, + .tszInstanceName = L"Wine test root driver", + .tszProductName = L"Wine test root driver", + .guidFFDriver = GUID_NULL, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }; + const DIDEVICEOBJECTINSTANCEW expect_objects[] = + { + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(6), + .tszName = L"Volume", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_CONSUMER, + .wUsage = HID_USAGE_CONSUMER_VOLUME, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = 0x4, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(7), + .tszName = L"Tip Pressure", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_DIGITIZER, + .wUsage = HID_USAGE_DIGITIZER_TIP_PRESSURE, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_RzAxis, + .dwOfs = 0x8, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(5), + .dwFlags = DIDOI_ASPECTPOSITION, + .tszName = L"Rudder", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_SIMULATION, + .wUsage = HID_USAGE_SIMULATION_RUDDER, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_YAxis, + .dwOfs = 0xc, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(1), + .dwFlags = DIDOI_ASPECTPOSITION, + .tszName = L"Y Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_Y, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_XAxis, + .dwOfs = 0x10, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(0), + .dwFlags = DIDOI_ASPECTPOSITION, + .tszName = L"X Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_X, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_ZAxis, + .dwOfs = 0x18, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(2), + .dwFlags = DIDOI_ASPECTPOSITION, + .tszName = L"Wheel", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_WHEEL, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_POV, + .dwOfs = 0x1c, + .dwType = DIDFT_POV|DIDFT_MAKEINSTANCE(0), + .tszName = L"Hat Switch", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_HATSWITCH, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Button, + .dwOfs = 0x20, + .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(0), + .tszName = L"Button 0", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_BUTTON, + .wUsage = 0x1, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Button, + .dwOfs = 0x21, + .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(1), + .tszName = L"Button 1", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_BUTTON, + .wUsage = 0x2, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(0), + .tszName = L"Collection 0 - Joystick", + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(1), + .tszName = L"Collection 1 - Joystick", + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }, + }; + const DIEFFECTINFOW expect_effects[] = {}; + + struct check_objects_params check_objects_params = + { + .version = DIRECTINPUT_VERSION, + .expect_count = ARRAY_SIZE(expect_objects), + .expect_objs = expect_objects, + }; + struct check_effects_params check_effects_params = + { + .expect_count = ARRAY_SIZE(expect_effects), + .expect_effects = expect_effects, + }; + DIPROPGUIDANDPATH prop_guid_path = + { + .diph = + { + .dwSize = sizeof(DIPROPGUIDANDPATH), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + DIPROPSTRING prop_string = + { + .diph = + { + .dwSize = sizeof(DIPROPSTRING), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + DIPROPDWORD prop_dword = + { + .diph = + { + .dwSize = sizeof(DIPROPDWORD), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + DIPROPRANGE prop_range = + { + .diph = + { + .dwSize = sizeof(DIPROPRANGE), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + DIPROPPOINTER prop_pointer = + { + .diph = + { + .dwSize = sizeof(DIPROPPOINTER), + .dwHeaderSize = sizeof(DIPROPHEADER), + }, + }; + DIOBJECTDATAFORMAT objdataformat[32] = {{0}}; + WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; + DIDEVICEOBJECTDATA objdata[32] = {{0}}; + DIDEVICEOBJECTINSTANCEW objinst = {0}; + DIDEVICEINSTANCEW devinst = {0}; + DIEFFECTINFOW effectinfo = {0}; + DIDATAFORMAT dataformat = {0}; + IDirectInputDevice8W *device; + IDirectInputEffect *effect; + DIEFFESCAPE escape = {0}; + DIDEVCAPS caps = {0}; + HANDLE event, file; + char buffer[1024]; + DIJOYSTATE2 state; + ULONG i, res, ref; + HRESULT hr; + WCHAR *tmp; + GUID guid; + HWND hwnd; + + GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); + GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); + SetCurrentDirectoryW( tempdir ); + + cleanup_registry_keys(); + if (!dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 )) goto done; + if (FAILED(hr = dinput_test_create_device( DIRECTINPUT_VERSION, &devinst, &device ))) goto done; + + check_dinput_devices( DIRECTINPUT_VERSION, &devinst ); + + hr = IDirectInputDevice8_Initialize( device, instance, 0x0700, &GUID_NULL ); + todo_wine + ok( hr == DIERR_BETADIRECTINPUTVERSION, "Initialize returned %#x\n", hr ); + hr = IDirectInputDevice8_Initialize( device, instance, DIRECTINPUT_VERSION, NULL ); + todo_wine + ok( hr == E_POINTER, "Initialize returned %#x\n", hr ); + hr = IDirectInputDevice8_Initialize( device, NULL, DIRECTINPUT_VERSION, &GUID_NULL ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "Initialize returned %#x\n", hr ); + hr = IDirectInputDevice8_Initialize( device, instance, DIRECTINPUT_VERSION, &GUID_NULL ); + todo_wine + ok( hr == REGDB_E_CLASSNOTREG, "Initialize returned %#x\n", hr ); + + hr = IDirectInputDevice8_Initialize( device, instance, DIRECTINPUT_VERSION, &devinst.guidInstance ); + ok( hr == DI_OK, "Initialize returned %#x\n", hr ); + guid = devinst.guidInstance; + memset( &devinst, 0, sizeof(devinst) ); + devinst.dwSize = sizeof(DIDEVICEINSTANCEW); + hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); + ok( hr == DI_OK, "GetDeviceInfo returned %#x\n", hr ); + ok( IsEqualGUID( &guid, &devinst.guidInstance ), "got %s expected %s\n", debugstr_guid( &guid ), + debugstr_guid( &devinst.guidInstance ) ); + hr = IDirectInputDevice8_Initialize( device, instance, DIRECTINPUT_VERSION, &devinst.guidProduct ); + ok( hr == DI_OK, "Initialize returned %#x\n", hr ); + + hr = IDirectInputDevice8_GetDeviceInfo( device, NULL ); + ok( hr == E_POINTER, "GetDeviceInfo returned %#x\n", hr ); + devinst.dwSize = sizeof(DIDEVICEINSTANCEW) + 1; + hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); + ok( hr == DIERR_INVALIDPARAM, "GetDeviceInfo returned %#x\n", hr ); + + devinst.dwSize = sizeof(DIDEVICEINSTANCE_DX3W); + hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); + ok( hr == DI_OK, "GetDeviceInfo returned %#x\n", hr ); + todo_wine + check_member_guid( devinst, expect_devinst, guidInstance ); + check_member_guid( devinst, expect_devinst, guidProduct ); + check_member( devinst, expect_devinst, "%#x", dwDevType ); + todo_wine + check_member_wstr( devinst, expect_devinst, tszInstanceName ); + todo_wine + check_member_wstr( devinst, expect_devinst, tszProductName ); + + memset( &devinst, 0, sizeof(devinst) ); + devinst.dwSize = sizeof(DIDEVICEINSTANCEW); + hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); + ok( hr == DI_OK, "GetDeviceInfo returned %#x\n", hr ); + check_member( devinst, expect_devinst, "%d", dwSize ); + todo_wine + check_member_guid( devinst, expect_devinst, guidInstance ); + check_member_guid( devinst, expect_devinst, guidProduct ); + check_member( devinst, expect_devinst, "%#x", dwDevType ); + todo_wine + check_member_wstr( devinst, expect_devinst, tszInstanceName ); + todo_wine + check_member_wstr( devinst, expect_devinst, tszProductName ); + check_member_guid( devinst, expect_devinst, guidFFDriver ); + check_member( devinst, expect_devinst, "%04x", wUsagePage ); + check_member( devinst, expect_devinst, "%04x", wUsage ); + + hr = IDirectInputDevice8_GetCapabilities( device, NULL ); + ok( hr == E_POINTER, "GetCapabilities returned %#x\n", hr ); + hr = IDirectInputDevice8_GetCapabilities( device, &caps ); + ok( hr == DIERR_INVALIDPARAM, "GetCapabilities returned %#x\n", hr ); + caps.dwSize = sizeof(DIDEVCAPS); + hr = IDirectInputDevice8_GetCapabilities( device, &caps ); + ok( hr == DI_OK, "GetCapabilities returned %#x\n", hr ); + check_member( caps, expect_caps, "%d", dwSize ); + check_member( caps, expect_caps, "%#x", dwFlags ); + check_member( caps, expect_caps, "%#x", dwDevType ); + check_member( caps, expect_caps, "%d", dwAxes ); + check_member( caps, expect_caps, "%d", dwButtons ); + check_member( caps, expect_caps, "%d", dwPOVs ); + check_member( caps, expect_caps, "%d", dwFFSamplePeriod ); + check_member( caps, expect_caps, "%d", dwFFMinTimeResolution ); + check_member( caps, expect_caps, "%d", dwFirmwareRevision ); + check_member( caps, expect_caps, "%d", dwHardwareRevision ); + check_member( caps, expect_caps, "%d", dwFFDriverVersion ); + + hr = IDirectInputDevice8_GetProperty( device, NULL, NULL ); + ok( hr == DIERR_INVALIDPARAM, "GetProperty returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, &GUID_NULL, NULL ); + ok( hr == DIERR_INVALIDPARAM, "GetProperty returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_VIDPID, NULL ); + ok( hr == DIERR_INVALIDPARAM, "GetProperty returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_VIDPID, &prop_string.diph ); + ok( hr == DIERR_INVALIDPARAM, "GetProperty returned %#x\n", hr ); + prop_dword.diph.dwHeaderSize = sizeof(DIPROPHEADER) - 1; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_VIDPID, &prop_dword.diph ); + ok( hr == DIERR_INVALIDPARAM, "GetProperty returned %#x\n", hr ); + prop_dword.diph.dwHeaderSize = sizeof(DIPROPHEADER); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_VIDPID, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_VIDPID returned %#x\n", hr ); + ok( prop_dword.dwData == EXPECT_VIDPID, "got %#x expected %#x\n", prop_dword.dwData, EXPECT_VIDPID ); + + hr = IDirectInputDevice8_GetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_GUIDANDPATH returned %#x\n", hr ); + todo_wine + ok( IsEqualGUID( &prop_guid_path.guidClass, &GUID_DEVCLASS_HIDCLASS ), "got guid %s\n", + debugstr_guid( &prop_guid_path.guidClass ) ); + todo_wine + ok( !wcsncmp( prop_guid_path.wszPath, expect_path, wcslen( expect_path ) ), "got path %s\n", + debugstr_w(prop_guid_path.wszPath) ); + if (!(tmp = wcsrchr( prop_guid_path.wszPath, '&' ))) + todo_wine ok( 0, "got path %s\n", debugstr_w(prop_guid_path.wszPath) ); + else + { + ok( !wcscmp( wcsrchr( prop_guid_path.wszPath, '&' ), expect_path_end ), "got path %s\n", + debugstr_w(prop_guid_path.wszPath) ); + } + + hr = IDirectInputDevice8_GetProperty( device, DIPROP_INSTANCENAME, &prop_string.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_INSTANCENAME returned %#x\n", hr ); + todo_wine + ok( !wcscmp( prop_string.wsz, expect_devinst.tszInstanceName ), "got instance %s\n", + debugstr_w(prop_string.wsz) ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_PRODUCTNAME, &prop_string.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_PRODUCTNAME returned %#x\n", hr ); + todo_wine + ok( !wcscmp( prop_string.wsz, expect_devinst.tszProductName ), "got product %s\n", + debugstr_w(prop_string.wsz) ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_TYPENAME, &prop_string.diph ); + todo_wine + ok( hr == DI_OK, "GetProperty DIPROP_TYPENAME returned %#x\n", hr ); + todo_wine + ok( !wcscmp( prop_string.wsz, expect_vidpid_str ), "got type %s\n", debugstr_w(prop_string.wsz) ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_USERNAME, &prop_string.diph ); + ok( hr == S_FALSE, "GetProperty DIPROP_USERNAME returned %#x\n", hr ); + todo_wine + ok( !wcscmp( prop_string.wsz, L"" ), "got user %s\n", debugstr_w(prop_string.wsz) ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_JOYSTICKID, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_JOYSTICKID returned %#x\n", hr ); + todo_wine + ok( prop_dword.dwData == 0, "got %#x expected %#x\n", prop_dword.dwData, 0 ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_AXISMODE, &prop_dword.diph ); + todo_wine + ok( hr == DI_OK, "GetProperty DIPROP_AXISMODE returned %#x\n", hr ); + todo_wine + ok( prop_dword.dwData == DIPROPAXISMODE_ABS, "got %u expected %u\n", prop_dword.dwData, DIPROPAXISMODE_ABS ); + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_BUFFERSIZE returned %#x\n", hr ); + ok( prop_dword.dwData == 0, "got %#x expected %#x\n", prop_dword.dwData, 0 ); + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_FFGAIN returned %#x\n", hr ); + ok( prop_dword.dwData == 10000, "got %u expected %u\n", prop_dword.dwData, 10000 ); + + hr = IDirectInputDevice8_GetProperty( device, DIPROP_CALIBRATION, &prop_dword.diph ); + ok( hr == DIERR_INVALIDPARAM, "GetProperty DIPROP_CALIBRATION returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_AUTOCENTER returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_DEADZONE, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_DEADZONE returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_FFLOAD returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_GRANULARITY, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_GRANULARITY returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_SATURATION, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_SATURATION returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_CALIBRATIONMODE returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_RANGE returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_KEYNAME, &prop_string.diph ); + ok( hr == DIERR_INVALIDPARAM, "GetProperty DIPROP_KEYNAME returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_LOGICALRANGE, &prop_range.diph ); + ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_LOGICALRANGE returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_PHYSICALRANGE, &prop_range.diph ); + ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_PHYSICALRANGE 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 ); + ok( hr == DI_OK, "GetProperty DIPROP_DEADZONE returned %#x\n", hr ); + 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 ); + ok( hr == DI_OK, "GetProperty DIPROP_GRANULARITY returned %#x\n", hr ); + 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 ); + ok( hr == DI_OK, "GetProperty DIPROP_SATURATION returned %#x\n", hr ); + ok( prop_dword.dwData == 10000, "got %u expected %u\n", prop_dword.dwData, 10000 ); + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_CALIBRATIONMODE returned %#x\n", hr ); + ok( prop_dword.dwData == DIPROPCALIBRATIONMODE_COOKED, "got %u expected %u\n", + prop_dword.dwData, DIPROPCALIBRATIONMODE_COOKED ); + + prop_string.diph.dwHow = DIPH_BYUSAGE; + prop_string.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_KEYNAME, &prop_string.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_KEYNAME returned %#x\n", hr ); + ok( !wcscmp( prop_string.wsz, expect_objects[4].tszName ), "got DIPROP_KEYNAME %s\n", + debugstr_w(prop_string.wsz) ); + prop_string.diph.dwObj = MAKELONG( 0x1, HID_USAGE_PAGE_BUTTON ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_KEYNAME, &prop_string.diph ); + todo_wine + ok( hr == DIERR_NOTFOUND, "GetProperty DIPROP_KEYNAME returned %#x\n", hr ); + prop_string.diph.dwHow = DIPH_BYUSAGE; + prop_string.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_KEYNAME, &prop_string.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_KEYNAME returned %#x\n", hr ); + + prop_range.diph.dwHow = DIPH_BYUSAGE; + prop_range.diph.dwObj = MAKELONG( 0, 0 ); + prop_range.lMin = 0xdeadbeef; + prop_range.lMax = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DIERR_NOTFOUND, "GetProperty DIPROP_RANGE returned %#x\n", hr ); + prop_range.diph.dwObj = MAKELONG( 0, HID_USAGE_PAGE_GENERIC ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DIERR_NOTFOUND, "GetProperty DIPROP_RANGE returned %#x\n", hr ); + prop_range.diph.dwObj = MAKELONG( HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_X ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DIERR_NOTFOUND, "GetProperty DIPROP_RANGE returned %#x\n", hr ); + prop_range.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); + prop_range.lMin = 0xdeadbeef; + prop_range.lMax = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_RANGE returned %#x\n", hr ); + ok( prop_range.lMin == 0, "got %d expected %d\n", prop_range.lMin, 0 ); + ok( prop_range.lMax == 65535, "got %d expected %d\n", prop_range.lMax, 65535 ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_LOGICALRANGE, &prop_range.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_LOGICALRANGE returned %#x\n", hr ); + ok( prop_range.lMin == -25, "got %d expected %d\n", prop_range.lMin, -25 ); + ok( prop_range.lMax == 56, "got %d expected %d\n", prop_range.lMax, 56 ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_PHYSICALRANGE, &prop_range.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_PHYSICALRANGE returned %#x\n", hr ); + ok( prop_range.lMin == -25, "got %d expected %d\n", prop_range.lMin, -25 ); + ok( prop_range.lMax == 56, "got %d expected %d\n", prop_range.lMax, 56 ); + + prop_pointer.diph.dwHow = DIPH_BYUSAGE; + prop_pointer.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); + todo_wine + ok( hr == DIERR_NOTINITIALIZED, "GetProperty DIPROP_APPDATA returned %#x\n", hr ); + + hr = IDirectInputDevice8_EnumObjects( device, NULL, NULL, DIDFT_ALL ); + ok( hr == DIERR_INVALIDPARAM, "EnumObjects returned %#x\n", hr ); + hr = IDirectInputDevice8_EnumObjects( device, check_object_count, &res, 0x20 ); + ok( hr == DIERR_INVALIDPARAM, "EnumObjects 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 ); + ok( res == 8, "got %u expected %u\n", res, 8 ); + hr = IDirectInputDevice8_EnumObjects( device, check_objects, &check_objects_params, DIDFT_ALL ); + ok( hr == DI_OK, "EnumObjects returned %#x\n", hr ); + ok( check_objects_params.index >= check_objects_params.expect_count, "missing %u objects\n", + check_objects_params.expect_count - check_objects_params.index ); + + hr = IDirectInputDevice8_GetObjectInfo( device, NULL, 0, DIPH_DEVICE ); + ok( hr == E_POINTER, "GetObjectInfo returned: %#x\n", hr ); + hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, 0, DIPH_DEVICE ); + ok( hr == DIERR_INVALIDPARAM, "GetObjectInfo returned: %#x\n", hr ); + objinst.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW); + hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, 0, DIPH_DEVICE ); + ok( hr == DIERR_INVALIDPARAM, "GetObjectInfo returned: %#x\n", hr ); + + res = MAKELONG( HID_USAGE_GENERIC_Z, HID_USAGE_PAGE_GENERIC ); + hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, res, DIPH_BYUSAGE ); + ok( hr == DIERR_NOTFOUND, "GetObjectInfo returned: %#x\n", hr ); + res = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); + hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, res, DIPH_BYUSAGE ); + ok( hr == DI_OK, "GetObjectInfo returned: %#x\n", hr ); + + check_member( objinst, expect_objects[4], "%u", dwSize ); + check_member_guid( objinst, expect_objects[4], guidType ); + check_member( objinst, expect_objects[4], "%#x", dwOfs ); + check_member( objinst, expect_objects[4], "%#x", dwType ); + check_member( objinst, expect_objects[4], "%#x", dwFlags ); + if (!localized) check_member_wstr( objinst, expect_objects[4], tszName ); + check_member( objinst, expect_objects[4], "%u", dwFFMaxForce ); + check_member( objinst, expect_objects[4], "%u", dwFFForceResolution ); + check_member( objinst, expect_objects[4], "%u", wCollectionNumber ); + check_member( objinst, expect_objects[4], "%u", wDesignatorIndex ); + check_member( objinst, expect_objects[4], "%#04x", wUsagePage ); + check_member( objinst, expect_objects[4], "%#04x", wUsage ); + check_member( objinst, expect_objects[4], "%#04x", dwDimension ); + check_member( objinst, expect_objects[4], "%#04x", wExponent ); + check_member( objinst, expect_objects[4], "%u", wReportId ); + + hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, 0x14, DIPH_BYOFFSET ); + ok( hr == DIERR_NOTFOUND, "GetObjectInfo returned: %#x\n", hr ); + hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, 0, DIPH_BYOFFSET ); + ok( hr == DIERR_NOTFOUND, "GetObjectInfo returned: %#x\n", hr ); + res = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 3 ); + hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, res, DIPH_BYID ); + ok( hr == DIERR_NOTFOUND, "GetObjectInfo returned: %#x\n", hr ); + res = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 1 ); + hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, res, DIPH_BYID ); + ok( hr == DI_OK, "GetObjectInfo returned: %#x\n", hr ); + + check_member( objinst, expect_objects[8], "%u", dwSize ); + check_member_guid( objinst, expect_objects[8], guidType ); + check_member( objinst, expect_objects[8], "%#x", dwOfs ); + check_member( objinst, expect_objects[8], "%#x", dwType ); + check_member( objinst, expect_objects[8], "%#x", dwFlags ); + if (!localized) check_member_wstr( objinst, expect_objects[8], tszName ); + check_member( objinst, expect_objects[8], "%u", dwFFMaxForce ); + check_member( objinst, expect_objects[8], "%u", dwFFForceResolution ); + check_member( objinst, expect_objects[8], "%u", wCollectionNumber ); + check_member( objinst, expect_objects[8], "%u", wDesignatorIndex ); + check_member( objinst, expect_objects[8], "%#04x", wUsagePage ); + check_member( objinst, expect_objects[8], "%#04x", wUsage ); + check_member( objinst, expect_objects[8], "%#04x", dwDimension ); + check_member( objinst, expect_objects[8], "%#04x", wExponent ); + check_member( objinst, expect_objects[8], "%u", wReportId ); + + hr = IDirectInputDevice8_EnumEffects( device, NULL, NULL, DIEFT_ALL ); + ok( hr == DIERR_INVALIDPARAM, "EnumEffects returned %#x\n", hr ); + res = 0; + hr = IDirectInputDevice8_EnumEffects( device, check_effect_count, &res, 0xfe ); + ok( hr == DI_OK, "EnumEffects returned %#x\n", hr ); + ok( res == 0, "got %u expected %u\n", res, 0 ); + res = 0; + hr = IDirectInputDevice8_EnumEffects( device, check_effect_count, &res, DIEFT_PERIODIC ); + ok( hr == DI_OK, "EnumEffects returned %#x\n", hr ); + ok( res == 0, "got %u expected %u\n", res, 0 ); + hr = IDirectInputDevice8_EnumEffects( device, check_effects, &check_effects_params, DIEFT_ALL ); + ok( hr == DI_OK, "EnumEffects returned %#x\n", hr ); + ok( check_effects_params.index >= check_effects_params.expect_count, "missing %u effects\n", + check_effects_params.expect_count - check_effects_params.index ); + + hr = IDirectInputDevice8_GetEffectInfo( device, NULL, &GUID_Sine ); + ok( hr == E_POINTER, "GetEffectInfo returned %#x\n", hr ); + effectinfo.dwSize = sizeof(DIEFFECTINFOW) + 1; + hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_Sine ); + ok( hr == DIERR_INVALIDPARAM, "GetEffectInfo returned %#x\n", hr ); + effectinfo.dwSize = sizeof(DIEFFECTINFOW); + hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_NULL ); + ok( hr == DIERR_DEVICENOTREG, "GetEffectInfo returned %#x\n", hr ); + hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_Sine ); + ok( hr == DIERR_DEVICENOTREG, "GetEffectInfo returned %#x\n", hr ); + + hr = IDirectInputDevice8_SetDataFormat( device, NULL ); + ok( hr == E_POINTER, "SetDataFormat returned: %#x\n", hr ); + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); + dataformat.dwSize = sizeof(DIDATAFORMAT); + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); + dataformat.dwObjSize = sizeof(DIOBJECTDATAFORMAT); + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); + hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); + ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); + + hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, DIJOFS_Y, DIPH_BYOFFSET ); + ok( hr == DI_OK, "GetObjectInfo returned: %#x\n", hr ); + + check_member( objinst, expect_objects[3], "%u", dwSize ); + check_member_guid( objinst, expect_objects[3], guidType ); + check_member( objinst, expect_objects[3], "%#x", dwOfs ); + check_member( objinst, expect_objects[3], "%#x", dwType ); + check_member( objinst, expect_objects[3], "%#x", dwFlags ); + if (!localized) check_member_wstr( objinst, expect_objects[3], tszName ); + check_member( objinst, expect_objects[3], "%u", dwFFMaxForce ); + check_member( objinst, expect_objects[3], "%u", dwFFForceResolution ); + check_member( objinst, expect_objects[3], "%u", wCollectionNumber ); + check_member( objinst, expect_objects[3], "%u", wDesignatorIndex ); + check_member( objinst, expect_objects[3], "%#04x", wUsagePage ); + check_member( objinst, expect_objects[3], "%#04x", wUsage ); + check_member( objinst, expect_objects[3], "%#04x", dwDimension ); + check_member( objinst, expect_objects[3], "%#04x", wExponent ); + check_member( objinst, expect_objects[3], "%u", wReportId ); + + hr = IDirectInputDevice8_SetEventNotification( device, (HANDLE)0xdeadbeef ); + todo_wine + ok( hr == E_HANDLE, "SetEventNotification returned: %#x\n", hr ); + event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( event != NULL, "CreateEventW failed, last error %u\n", GetLastError() ); + hr = IDirectInputDevice8_SetEventNotification( device, event ); + 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, + FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL ); + ok( file != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError() ); + + hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, 0 ); + ok( hr == DIERR_INVALIDPARAM, "SetCooperativeLevel returned: %#x\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_BACKGROUND ); + ok( hr == DIERR_INVALIDPARAM, "SetCooperativeLevel returned: %#x\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE ); + ok( hr == E_HANDLE, "SetCooperativeLevel returned: %#x\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); + ok( hr == E_HANDLE, "SetCooperativeLevel returned: %#x\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_FOREGROUND | DISCL_EXCLUSIVE ); + ok( hr == E_HANDLE, "SetCooperativeLevel returned: %#x\n", hr ); + + hwnd = CreateWindowW( L"static", L"dinput", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 10, 10, 200, 200, + NULL, NULL, NULL, NULL ); + SetForegroundWindow( hwnd ); + + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE ); + ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); + ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE ); + ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr ); + + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_NOEFFECT, "Unacquire returned: %#x\n", hr ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE ); + ok( hr == DIERR_ACQUIRED, "SetCooperativeLevel returned: %#x\n", hr ); + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + + DestroyWindow( hwnd ); + + hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE ); + ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr ); + + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); + ok( hr == DIERR_NOTACQUIRED, "GetDeviceState returned: %#x\n", hr ); + + hr = IDirectInputDevice8_Poll( device ); + ok( hr == DIERR_NOTACQUIRED, "Poll returned: %#x\n", hr ); + + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); + + hr = IDirectInputDevice8_Poll( device ); + ok( hr == DI_NOEFFECT, "Poll returned: %#x\n", hr ); + + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2) + 1, &state ); + ok( hr == DIERR_INVALIDPARAM, "GetDeviceState returned: %#x\n", hr ); + + for (i = 0; i < ARRAY_SIZE(injected_input); ++i) + { + winetest_push_context( "state[%d]", i ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); + ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); + check_member( state, expect_state[i], "%d", lX ); + check_member( state, expect_state[i], "%d", lY ); + check_member( state, expect_state[i], "%d", lZ ); + check_member( state, expect_state[i], "%d", lRx ); + check_member( state, expect_state[i], "%#x", rgdwPOV[0] ); + check_member( state, expect_state[i], "%#x", rgdwPOV[1] ); + check_member( state, expect_state[i], "%#x", rgbButtons[0] ); + check_member( state, expect_state[i], "%#x", rgbButtons[1] ); + check_member( state, expect_state[i], "%#x", rgbButtons[2] ); + + send_hid_input( file, &injected_input[i], sizeof(*injected_input) ); + + res = WaitForSingleObject( event, 100 ); + if (i == 0 || i == 3) ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" ); + else ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + ResetEvent( event ); + winetest_pop_context(); + } + + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); + ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); + winetest_push_context( "state[%d]", i ); + check_member( state, expect_state[i], "%d", lX ); + check_member( state, expect_state[i], "%d", lY ); + check_member( state, expect_state[i], "%d", lZ ); + check_member( state, expect_state[i], "%d", lRx ); + check_member( state, expect_state[i], "%#x", rgdwPOV[0] ); + check_member( state, expect_state[i], "%#x", rgdwPOV[1] ); + check_member( state, expect_state[i], "%#x", rgbButtons[0] ); + check_member( state, expect_state[i], "%#x", rgbButtons[1] ); + check_member( state, expect_state[i], "%#x", rgbButtons[2] ); + winetest_pop_context(); + + res = 1; + hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA) - 1, objdata, &res, DIGDD_PEEK ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "GetDeviceData returned %#x\n", hr ); + res = 1; + hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, DIGDD_PEEK ); + ok( hr == DIERR_NOTBUFFERED, "GetDeviceData returned %#x\n", hr ); + + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire 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 = 1; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_BUFFERSIZE returned %#x\n", hr ); + prop_dword.diph.dwHow = DIPH_DEVICE; + prop_dword.diph.dwObj = 0; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_BUFFERSIZE returned %#x\n", hr ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + + res = 1; + hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, DIGDD_PEEK ); + ok( hr == DI_OK, "GetDeviceData returned %#x\n", hr ); + ok( res == 0, "got %u expected %u\n", res, 0 ); + + send_hid_input( file, &injected_input[0], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + ResetEvent( event ); + + res = 1; + hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, DIGDD_PEEK ); + ok( hr == DI_BUFFEROVERFLOW, "GetDeviceData returned %#x\n", hr ); + ok( res == 0, "got %u expected %u\n", res, 0 ); + res = 1; + hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, 0 ); + todo_wine + ok( hr == DI_OK, "GetDeviceData returned %#x\n", hr ); + ok( res == 0, "got %u expected %u\n", res, 0 ); + + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + prop_dword.diph.dwHow = DIPH_DEVICE; + prop_dword.diph.dwObj = 0; + prop_dword.dwData = 10; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_BUFFERSIZE returned %#x\n", hr ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + + send_hid_input( file, &injected_input[1], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + ResetEvent( event ); + + res = 1; + hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, DIGDD_PEEK ); + ok( hr == DI_OK, "GetDeviceData returned %#x\n", hr ); + ok( res == 1, "got %u expected %u\n", res, 1 ); + check_member( objdata[0], expect_objdata[0], "%#x", dwOfs ); + check_member( objdata[0], expect_objdata[0], "%#x", dwData ); + ok( objdata[0].uAppData == -1, "got %p, expected %p\n", (void *)objdata[0].uAppData, (void *)-1 ); + res = 4; + hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, 0 ); + ok( hr == DI_OK, "GetDeviceData returned %#x\n", hr ); + ok( res == 4, "got %u expected %u\n", res, 4 ); + for (i = 0; i < 4; ++i) + { + winetest_push_context( "objdata[%d]", i ); + check_member( objdata[i], expect_objdata[1 + i], "%#x", dwOfs ); + check_member( objdata[i], expect_objdata[1 + i], "%#x", dwData ); + ok( objdata[i].uAppData == -1, "got %p, expected %p\n", (void *)objdata[i].uAppData, (void *)-1 ); + winetest_pop_context(); + } + + send_hid_input( file, &injected_input[2], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + ResetEvent( event ); + send_hid_input( file, &injected_input[4], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + ResetEvent( event ); + + res = 1; + hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, 0 ); + ok( hr == DI_BUFFEROVERFLOW, "GetDeviceData returned %#x\n", hr ); + ok( res == 1, "got %u expected %u\n", res, 1 ); + todo_wine + check_member( objdata[0], expect_objdata[5], "%#x", dwOfs ); + todo_wine + check_member( objdata[0], expect_objdata[5], "%#x", dwData ); + ok( objdata[0].uAppData == -1, "got %p, expected %p\n", (void *)objdata[0].uAppData, (void *)-1 ); + res = ARRAY_SIZE(objdata); + hr = IDirectInputDevice8_GetDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, 0 ); + ok( hr == DI_OK, "GetDeviceData returned %#x\n", hr ); + ok( res == 8, "got %u expected %u\n", res, 8 ); + for (i = 0; i < 8; ++i) + { + winetest_push_context( "objdata[%d]", i ); + todo_wine + check_member( objdata[i], expect_objdata[6 + i], "%#x", dwOfs ); + todo_wine_if( i == 1 || i == 2 || i == 6 ) + check_member( objdata[i], expect_objdata[6 + i], "%#x", dwData ); + ok( objdata[i].uAppData == -1, "got %p, expected %p\n", (void *)objdata[i].uAppData, (void *)-1 ); + winetest_pop_context(); + } + + send_hid_input( file, &injected_input[3], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + ResetEvent( event ); + + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); + ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); + check_member( state, expect_state[3], "%d", lX ); + check_member( state, expect_state[3], "%d", lY ); + check_member( state, expect_state[3], "%d", lZ ); + check_member( state, expect_state[3], "%d", lRx ); + check_member( state, expect_state[3], "%d", rgdwPOV[0] ); + check_member( state, expect_state[3], "%d", rgdwPOV[1] ); + check_member( state, expect_state[3], "%#x", rgbButtons[0] ); + check_member( state, expect_state[3], "%#x", rgbButtons[1] ); + check_member( state, expect_state[3], "%#x", rgbButtons[2] ); + + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + + dataformat.dwSize = sizeof(DIDATAFORMAT); + dataformat.dwObjSize = sizeof(DIOBJECTDATAFORMAT); + dataformat.dwFlags = DIDF_ABSAXIS; + dataformat.dwDataSize = sizeof(buffer); + dataformat.dwNumObjs = 0; + dataformat.rgodf = objdataformat; + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); + + dataformat.dwNumObjs = 1; + dataformat.dwDataSize = 8; + objdataformat[0].pguid = NULL; + objdataformat[0].dwOfs = 2; + objdataformat[0].dwType = DIDFT_AXIS | DIDFT_ANYINSTANCE; + objdataformat[0].dwFlags = 0; + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); + objdataformat[0].dwOfs = 4; + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); + dataformat.dwDataSize = 10; + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); + dataformat.dwDataSize = 8; + objdataformat[0].dwOfs = 2; + objdataformat[0].dwType = DIDFT_OPTIONAL | 0xff | DIDFT_ANYINSTANCE; + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); + + dataformat.dwNumObjs = 2; + dataformat.dwDataSize = 5; + objdataformat[0].pguid = NULL; + objdataformat[0].dwOfs = 4; + objdataformat[0].dwType = DIDFT_BUTTON | DIDFT_ANYINSTANCE; + objdataformat[0].dwFlags = 0; + objdataformat[1].pguid = NULL; + objdataformat[1].dwOfs = 0; + objdataformat[1].dwType = DIDFT_AXIS | DIDFT_MAKEINSTANCE( 0 ); + objdataformat[1].dwFlags = 0; + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); + dataformat.dwDataSize = 8; + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); + + dataformat.dwNumObjs = 4; + dataformat.dwDataSize = 12; + objdataformat[0].pguid = NULL; + objdataformat[0].dwOfs = 0; + objdataformat[0].dwType = DIDFT_AXIS | DIDFT_MAKEINSTANCE( 0 ); + objdataformat[0].dwFlags = 0; + objdataformat[1].pguid = NULL; + objdataformat[1].dwOfs = 0; + objdataformat[1].dwType = DIDFT_AXIS | DIDFT_MAKEINSTANCE( 0 ); + objdataformat[1].dwFlags = 0; + objdataformat[2].pguid = &GUID_ZAxis; + objdataformat[2].dwOfs = 8; + objdataformat[2].dwType = 0xff | DIDFT_ANYINSTANCE; + objdataformat[2].dwFlags = 0; + objdataformat[3].pguid = &GUID_POV; + objdataformat[3].dwOfs = 0; + objdataformat[3].dwType = 0xff | DIDFT_ANYINSTANCE; + objdataformat[3].dwFlags = 0; + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); + objdataformat[1].dwType = DIDFT_AXIS | DIDFT_MAKEINSTANCE( 12 ); + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); + objdataformat[1].dwType = DIDFT_AXIS | DIDFT_MAKEINSTANCE( 0xff ); + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); + objdataformat[1].dwType = DIDFT_AXIS | DIDFT_MAKEINSTANCE( 1 ); + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); + objdataformat[1].pguid = &GUID_RzAxis; + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); + objdataformat[1].pguid = &GUID_Unknown; + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DIERR_INVALIDPARAM, "SetDataFormat returned: %#x\n", hr ); + objdataformat[1].pguid = &GUID_YAxis; + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); + objdataformat[1].pguid = NULL; + objdataformat[1].dwType = DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_MAKEINSTANCE( 0 ); + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); + + dataformat.dwNumObjs = 0; + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + + send_hid_input( file, &injected_input[4], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + todo_wine + ok( res == WAIT_TIMEOUT, "WaitForSingleObject failed\n" ); + ResetEvent( event ); + + hr = IDirectInputDevice8_GetDeviceState( device, dataformat.dwDataSize, buffer ); + ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + + dataformat.dwNumObjs = 4; + hr = IDirectInputDevice8_SetDataFormat( device, &dataformat ); + ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + + send_hid_input( file, &injected_input[4], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + todo_wine + ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + ResetEvent( event ); + send_hid_input( file, &injected_input[3], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + ResetEvent( event ); + + hr = IDirectInputDevice8_GetDeviceState( device, dataformat.dwDataSize, buffer ); + ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); + ok( ((ULONG *)buffer)[0] == 0x512b, "got %#x, expected %#x\n", ((ULONG *)buffer)[0], 0x512b ); + ok( ((ULONG *)buffer)[1] == 0, "got %#x, expected %#x\n", ((ULONG *)buffer)[1], 0 ); + ok( ((ULONG *)buffer)[2] == 0x7fff, "got %#x, expected %#x\n", ((ULONG *)buffer)[2], 0x7fff ); + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + + hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); + ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + + send_hid_input( file, &injected_input[4], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + ResetEvent( event ); + send_hid_input( file, &injected_input[3], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + ResetEvent( event ); + + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); + ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); + check_member( state, expect_state[3], "%d", lX ); + check_member( state, expect_state[3], "%d", lY ); + check_member( state, expect_state[3], "%d", lZ ); + check_member( state, expect_state[3], "%d", lRx ); + check_member( state, expect_state[3], "%d", rgdwPOV[0] ); + check_member( state, expect_state[3], "%d", rgdwPOV[1] ); + check_member( state, expect_state[3], "%#x", rgbButtons[0] ); + check_member( state, expect_state[3], "%#x", rgbButtons[1] ); + check_member( state, expect_state[3], "%#x", rgbButtons[2] ); + + prop_range.diph.dwHow = DIPH_DEVICE; + prop_range.diph.dwObj = 0; + prop_range.lMin = 1000; + prop_range.lMax = 51000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_RANGE returned %#x\n", hr ); + prop_range.diph.dwHow = DIPH_BYUSAGE; + prop_range.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); + prop_range.lMin = -4000; + prop_range.lMax = -14000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_RANGE returned %#x\n", hr ); + prop_range.lMin = -14000; + prop_range.lMax = -4000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_RANGE returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_LOGICALRANGE, &prop_range.diph ); + ok( hr == DIERR_ACQUIRED, "SetProperty DIPROP_LOGICALRANGE returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_PHYSICALRANGE, &prop_range.diph ); + ok( hr == DIERR_ACQUIRED, "SetProperty DIPROP_PHYSICALRANGE returned %#x\n", hr ); + + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_LOGICALRANGE, &prop_range.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_LOGICALRANGE returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_PHYSICALRANGE, &prop_range.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_PHYSICALRANGE returned %#x\n", hr ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + + prop_range.diph.dwHow = DIPH_DEVICE; + prop_range.diph.dwObj = 0; + prop_range.lMin = 0xdeadbeef; + prop_range.lMax = 0xdeadbeef; + 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_BYUSAGE; + prop_range.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); + prop_range.lMin = 0xdeadbeef; + prop_range.lMax = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_RANGE returned %#x\n", hr ); + ok( prop_range.lMin == -14000, "got %d expected %d\n", prop_range.lMin, -14000 ); + ok( prop_range.lMax == -4000, "got %d expected %d\n", prop_range.lMax, -4000 ); + prop_range.diph.dwHow = DIPH_BYUSAGE; + prop_range.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_Y, HID_USAGE_PAGE_GENERIC ); + prop_range.lMin = 0xdeadbeef; + prop_range.lMax = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_RANGE returned %#x\n", hr ); + ok( prop_range.lMin == 1000, "got %d expected %d\n", prop_range.lMin, 1000 ); + ok( prop_range.lMax == 51000, "got %d expected %d\n", prop_range.lMax, 51000 ); + + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); + ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); + check_member( state, expect_state_abs[1], "%d", lX ); + check_member( state, expect_state_abs[1], "%d", lY ); + check_member( state, expect_state_abs[1], "%d", lZ ); + check_member( state, expect_state_abs[1], "%d", lRx ); + check_member( state, expect_state_abs[1], "%d", rgdwPOV[0] ); + check_member( state, expect_state_abs[1], "%d", rgdwPOV[1] ); + check_member( state, expect_state_abs[1], "%#x", rgbButtons[0] ); + check_member( state, expect_state_abs[1], "%#x", rgbButtons[1] ); + check_member( state, expect_state_abs[1], "%#x", rgbButtons[2] ); + + hr = IDirectInputDevice8_SetProperty( device, NULL, NULL ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, &GUID_NULL, NULL ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_VIDPID, NULL ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_VIDPID, &prop_string.diph ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty returned %#x\n", hr ); + + prop_dword.diph.dwHow = DIPH_DEVICE; + prop_dword.diph.dwObj = 0; + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_VIDPID, &prop_dword.diph ); + ok( hr == DIERR_READONLY, "SetProperty DIPROP_VIDPID returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph ); + ok( hr == DIERR_READONLY, "SetProperty DIPROP_GUIDANDPATH returned %#x\n", hr ); + + prop_string.diph.dwHow = DIPH_DEVICE; + prop_string.diph.dwObj = 0; + wcscpy( prop_string.wsz, L"instance name" ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_INSTANCENAME, &prop_string.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_INSTANCENAME returned %#x\n", hr ); + + wcscpy( prop_string.wsz, L"product name" ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_PRODUCTNAME, &prop_string.diph ); + todo_wine + ok( hr == DI_OK, "SetProperty DIPROP_PRODUCTNAME returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_PRODUCTNAME, &prop_string.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_PRODUCTNAME returned %#x\n", hr ); + todo_wine + ok( !wcscmp( prop_string.wsz, expect_devinst.tszProductName ), "got product %s\n", + debugstr_w(prop_string.wsz) ); + + hr = IDirectInputDevice8_SetProperty( device, DIPROP_TYPENAME, &prop_string.diph ); + ok( hr == DIERR_READONLY, "SetProperty DIPROP_TYPENAME returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_USERNAME, &prop_string.diph ); + ok( hr == DIERR_READONLY, "SetProperty DIPROP_USERNAME returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + ok( hr == DIERR_READONLY, "SetProperty DIPROP_FFLOAD returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_GRANULARITY, &prop_dword.diph ); + ok( hr == DIERR_READONLY, "SetProperty DIPROP_GRANULARITY returned %#x\n", hr ); + + hr = IDirectInputDevice8_SetProperty( device, DIPROP_JOYSTICKID, &prop_dword.diph ); + todo_wine + ok( hr == DIERR_ACQUIRED, "SetProperty DIPROP_JOYSTICKID returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_AXISMODE, &prop_dword.diph ); + ok( hr == DIERR_ACQUIRED, "SetProperty DIPROP_AXISMODE returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); + ok( hr == DIERR_ACQUIRED, "SetProperty DIPROP_BUFFERSIZE returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); + ok( hr == DIERR_ACQUIRED, "SetProperty DIPROP_AUTOCENTER returned %#x\n", hr ); + prop_pointer.diph.dwHow = DIPH_BYUSAGE; + prop_pointer.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); + todo_wine + ok( hr == DIERR_ACQUIRED, "SetProperty DIPROP_APPDATA returned %#x\n", hr ); + + prop_dword.diph.dwHow = DIPH_DEVICE; + prop_dword.diph.dwObj = 0; + prop_dword.dwData = 10001; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_DEADZONE, &prop_dword.diph ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_DEADZONE returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_SATURATION, &prop_dword.diph ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_SATURATION returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_CALIBRATIONMODE returned %#x\n", hr ); + prop_dword.dwData = 1000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_DEADZONE, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_DEADZONE returned %#x\n", hr ); + prop_dword.dwData = 6000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_SATURATION, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_SATURATION returned %#x\n", hr ); + prop_dword.dwData = DIPROPCALIBRATIONMODE_COOKED; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_CALIBRATIONMODE returned %#x\n", hr ); + + hr = IDirectInputDevice8_GetProperty( device, DIPROP_DEADZONE, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_DEADZONE returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_SATURATION, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_SATURATION returned %#x\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_CALIBRATIONMODE 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 ); + ok( hr == DI_OK, "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 ); + ok( hr == DI_OK, "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 ); + ok( hr == DI_OK, "GetProperty DIPROP_DEADZONE returned %#x\n", hr ); + 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 ); + ok( hr == DI_OK, "GetProperty DIPROP_SATURATION returned %#x\n", hr ); + 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 ); + ok( hr == DI_OK, "GetProperty DIPROP_DEADZONE returned %#x\n", hr ); + 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 ); + ok( hr == DI_OK, "GetProperty DIPROP_SATURATION returned %#x\n", hr ); + ok( prop_dword.dwData == 6000, "got %u expected %u\n", prop_dword.dwData, 6000 ); + + for (i = 0; i < ARRAY_SIZE(injected_input); ++i) + { + winetest_push_context( "state[%d]", i ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); + ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); + if (broken( state.lX == -10750 )) win_skip( "Ignoring 32-bit rounding\n" ); + else + { + check_member( state, expect_state_abs[i], "%d", lX ); + 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 ); + check_member( state, expect_state_abs[i], "%d", rgdwPOV[0] ); + check_member( state, expect_state_abs[i], "%d", rgdwPOV[1] ); + check_member( state, expect_state_abs[i], "%#x", rgbButtons[0] ); + check_member( state, expect_state_abs[i], "%#x", rgbButtons[1] ); + check_member( state, expect_state_abs[i], "%#x", rgbButtons[2] ); + + send_hid_input( file, &injected_input[i], sizeof(*injected_input) ); + + res = WaitForSingleObject( event, 100 ); + if (i == 0 || i == 3) ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" ); + else ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + ResetEvent( event ); + winetest_pop_context(); + } + + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); + ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); + winetest_push_context( "state[%d]", i ); + check_member( state, expect_state_abs[i], "%d", lX ); + 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 ); + check_member( state, expect_state_abs[i], "%d", rgdwPOV[0] ); + check_member( state, expect_state_abs[i], "%d", rgdwPOV[1] ); + check_member( state, expect_state_abs[i], "%#x", rgbButtons[0] ); + check_member( state, expect_state_abs[i], "%#x", rgbButtons[1] ); + check_member( state, expect_state_abs[i], "%#x", rgbButtons[2] ); + winetest_pop_context(); + + prop_dword.diph.dwHow = DIPH_BYUSAGE; + prop_dword.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); + prop_dword.dwData = DIPROPCALIBRATIONMODE_RAW; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_CALIBRATIONMODE returned %#x\n", hr ); + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_CALIBRATIONMODE returned %#x\n", hr ); + ok( prop_dword.dwData == DIPROPCALIBRATIONMODE_RAW, "got %u expected %u\n", prop_dword.dwData, + DIPROPCALIBRATIONMODE_RAW ); + + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); + ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); + winetest_push_context( "state[%d]", i ); + todo_wine + ok( state.lX == 15, "got lX %d, expected %d\n", state.lX, 15 ); + check_member( state, expect_state_abs[0], "%d", lY ); + check_member( state, expect_state_abs[0], "%d", lZ ); + check_member( state, expect_state_abs[0], "%d", lRx ); + check_member( state, expect_state_abs[0], "%d", rgdwPOV[0] ); + check_member( state, expect_state_abs[0], "%d", rgdwPOV[1] ); + winetest_pop_context(); + + prop_dword.dwData = DIPROPCALIBRATIONMODE_COOKED; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_CALIBRATIONMODE, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_CALIBRATIONMODE returned %#x\n", hr ); + + send_hid_input( file, &injected_input[ARRAY_SIZE(injected_input) - 1], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + + prop_dword.diph.dwHow = DIPH_DEVICE; + prop_dword.diph.dwObj = 0; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_JOYSTICKID, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_JOYSTICKID returned %#x\n", hr ); + prop_dword.dwData = 0x1000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_BUFFERSIZE returned %#x\n", hr ); + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_AUTOCENTER returned %#x\n", hr ); + prop_dword.dwData = DIPROPAUTOCENTER_ON; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_AUTOCENTER returned %#x\n", hr ); + prop_pointer.diph.dwHow = DIPH_BYUSAGE; + prop_pointer.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); + prop_pointer.uData = 0xfeedcafe; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_APPDATA returned %#x\n", hr ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_AXISMODE, &prop_dword.diph ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_AXISMODE returned %#x\n", hr ); + prop_dword.dwData = DIPROPAXISMODE_REL; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_AXISMODE, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_AXISMODE returned %#x\n", hr ); + + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_AXISMODE, &prop_dword.diph ); + todo_wine + ok( hr == DI_OK, "GetProperty DIPROP_AXISMODE returned %#x\n", hr ); + todo_wine + ok( prop_dword.dwData == DIPROPAXISMODE_REL, "got %u expected %u\n", prop_dword.dwData, DIPROPAXISMODE_REL ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_BUFFERSIZE returned %#x\n", hr ); + ok( prop_dword.dwData == 0x1000, "got %#x expected %#x\n", prop_dword.dwData, 0x1000 ); + + prop_pointer.diph.dwHow = DIPH_BYUSAGE; + prop_pointer.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); + todo_wine + ok( hr == DI_OK, "GetProperty DIPROP_APPDATA returned %#x\n", hr ); + ok( prop_pointer.uData == 0xfeedcafe, "got %p expected %p\n", (void *)prop_pointer.uData, (void *)0xfeedcafe ); + + prop_dword.diph.dwHow = DIPH_DEVICE; + prop_dword.diph.dwObj = 0; + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_FFGAIN returned %#x\n", hr ); + prop_dword.dwData = 1000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_FFGAIN returned %#x\n", hr ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_CALIBRATION, &prop_dword.diph ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_CALIBRATION returned %#x\n", hr ); + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_DEADZONE, &prop_dword.diph ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_DEADZONE returned %#x\n", hr ); + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_SATURATION, &prop_dword.diph ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_SATURATION returned %#x\n", hr ); + + for (i = 0; i < ARRAY_SIZE(injected_input); ++i) + { + winetest_push_context( "state[%d]", i ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); + ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); + todo_wine + check_member( state, expect_state_rel[i], "%d", lX ); + todo_wine + check_member( state, expect_state_rel[i], "%d", lY ); + todo_wine + check_member( state, expect_state_rel[i], "%d", lZ ); + check_member( state, expect_state_rel[i], "%d", lRx ); + check_member( state, expect_state_rel[i], "%d", rgdwPOV[0] ); + check_member( state, expect_state_rel[i], "%d", rgdwPOV[1] ); + check_member( state, expect_state_rel[i], "%#x", rgbButtons[0] ); + check_member( state, expect_state_rel[i], "%#x", rgbButtons[1] ); + check_member( state, expect_state_rel[i], "%#x", rgbButtons[2] ); + + send_hid_input( file, &injected_input[i], sizeof(*injected_input) ); + + res = WaitForSingleObject( event, 100 ); + if (i == 3) ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" ); + else ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + ResetEvent( event ); + winetest_pop_context(); + } + + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(DIJOYSTATE2), &state ); + ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr ); + winetest_push_context( "state[%d]", i ); + todo_wine + check_member( state, expect_state_rel[i], "%d", lX ); + todo_wine + check_member( state, expect_state_rel[i], "%d", lY ); + todo_wine + check_member( state, expect_state_rel[i], "%d", lZ ); + check_member( state, expect_state_rel[i], "%d", lRx ); + check_member( state, expect_state_rel[i], "%d", rgdwPOV[0] ); + check_member( state, expect_state_rel[i], "%d", rgdwPOV[1] ); + check_member( state, expect_state_rel[i], "%#x", rgbButtons[0] ); + check_member( state, expect_state_rel[i], "%#x", rgbButtons[1] ); + check_member( state, expect_state_rel[i], "%#x", rgbButtons[2] ); + winetest_pop_context(); + + hr = IDirectInputDevice8_GetForceFeedbackState( device, NULL ); + ok( hr == E_POINTER, "GetForceFeedbackState returned %#x\n", hr ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DIERR_UNSUPPORTED, "GetForceFeedbackState returned %#x\n", hr ); + + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, 0xdeadbeef ); + ok( hr == DIERR_INVALIDPARAM, "SendForceFeedbackCommand returned %#x\n", hr ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); + ok( hr == DIERR_UNSUPPORTED, "SendForceFeedbackCommand returned %#x\n", hr ); + + objdata[0].dwOfs = 0xd; + objdata[0].dwData = 0x80; + res = 1; + hr = IDirectInputDevice8_SendDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, 0xdeadbeef ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "SendDeviceData returned %#x\n", hr ); + res = 1; + hr = IDirectInputDevice8_SendDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, 1 /*DISDD_CONTINUE*/ ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "SendDeviceData returned %#x\n", hr ); + res = 1; + hr = IDirectInputDevice8_SendDeviceData( device, sizeof(DIDEVICEOBJECTDATA), objdata, &res, 0 ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "SendDeviceData returned %#x\n", hr ); + + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, NULL, NULL ); + ok( hr == E_POINTER, "CreateEffect returned %#x\n", hr ); + hr = IDirectInputDevice8_CreateEffect( device, NULL, NULL, &effect, NULL ); + ok( hr == DIERR_UNSUPPORTED, "CreateEffect returned %#x\n", hr ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_NULL, NULL, &effect, NULL ); + ok( hr == DIERR_UNSUPPORTED, "CreateEffect returned %#x\n", hr ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, &effect, NULL ); + ok( hr == DIERR_UNSUPPORTED, "CreateEffect returned %#x\n", hr ); + + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#x\n", hr ); + + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, &effect, NULL ); + ok( hr == DIERR_UNSUPPORTED, "CreateEffect returned %#x\n", hr ); + + hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, NULL, effect, 0 ); + ok( hr == DIERR_INVALIDPARAM, "EnumCreatedEffectObjects returned %#x\n", hr ); + hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, check_no_created_effect_objects, effect, 0xdeadbeef ); + ok( hr == DIERR_INVALIDPARAM, "EnumCreatedEffectObjects returned %#x\n", hr ); + hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, check_no_created_effect_objects, (void *)0xdeadbeef, 0 ); + ok( hr == DI_OK, "EnumCreatedEffectObjects returned %#x\n", hr ); + + hr = IDirectInputDevice8_Escape( device, NULL ); + todo_wine + ok( hr == E_POINTER, "Escape returned: %#x\n", hr ); + hr = IDirectInputDevice8_Escape( device, &escape ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "Escape returned: %#x\n", hr ); + escape.dwSize = sizeof(DIEFFESCAPE) + 1; + hr = IDirectInputDevice8_Escape( device, &escape ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "Escape returned: %#x\n", hr ); + escape.dwSize = sizeof(DIEFFESCAPE); + escape.dwCommand = 0; + escape.lpvInBuffer = buffer; + escape.cbInBuffer = 10; + escape.lpvOutBuffer = buffer + 10; + escape.cbOutBuffer = 10; + hr = IDirectInputDevice8_Escape( device, &escape ); + todo_wine + ok( hr == DIERR_UNSUPPORTED, "Escape returned: %#x\n", hr ); + + ref = IDirectInputDevice8_Release( device ); + ok( ref == 0, "Release returned %d\n", ref ); + + CloseHandle( event ); + CloseHandle( file ); + +done: + pnp_driver_stop(); + cleanup_registry_keys(); + SetCurrentDirectoryW( cwd ); +} + +struct device_desc +{ + const BYTE *report_desc_buf; + ULONG report_desc_len; + HIDP_CAPS hid_caps; +}; + +static BOOL test_device_types( DWORD version ) +{ +#include "psh_hid_macros.h" + static const unsigned char unknown_desc[] = + { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Physical), + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 6), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 8), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, + }; + static const unsigned char limited_desc[] = + { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Physical), + USAGE(1, HID_USAGE_GENERIC_X), + USAGE(1, HID_USAGE_GENERIC_Y), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 127), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 127), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + INPUT(1, Data|Var|Abs), + + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 6), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 8), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, + }; + static const unsigned char gamepad_desc[] = + { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_GAMEPAD), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_GAMEPAD), + COLLECTION(1, Physical), + USAGE(1, HID_USAGE_GENERIC_X), + USAGE(1, HID_USAGE_GENERIC_Y), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 127), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 127), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + INPUT(1, Data|Var|Abs), + + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 6), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 8), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, + }; + static const unsigned char joystick_desc[] = + { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Physical), + USAGE(1, HID_USAGE_GENERIC_X), + USAGE(1, HID_USAGE_GENERIC_Y), + USAGE(1, HID_USAGE_GENERIC_Z), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 127), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 127), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 3), + INPUT(1, Data|Var|Abs), + + USAGE(1, HID_USAGE_GENERIC_HATSWITCH), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 8), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 8), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs|Null), + + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 5), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 8), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, + }; +#include "pop_hid_macros.h" + + static struct device_desc device_desc[] = + { + { + .report_desc_buf = unknown_desc, + .report_desc_len = sizeof(unknown_desc), + .hid_caps = + { + .InputReportByteLength = 1, + }, + }, + { + .report_desc_buf = limited_desc, + .report_desc_len = sizeof(limited_desc), + .hid_caps = + { + .InputReportByteLength = 3, + }, + }, + { + .report_desc_buf = gamepad_desc, + .report_desc_len = sizeof(gamepad_desc), + .hid_caps = + { + .InputReportByteLength = 3, + }, + }, + { + .report_desc_buf = joystick_desc, + .report_desc_len = sizeof(joystick_desc), + .hid_caps = + { + .InputReportByteLength = 5, + }, + }, + }; + const DIDEVCAPS expect_caps[] = + { + { + .dwSize = sizeof(DIDEVCAPS), + .dwFlags = DIDC_ATTACHED|DIDC_EMULATED, + .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPESUPPLEMENTAL_UNKNOWN << 8)|DI8DEVTYPE_SUPPLEMENTAL + : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, + .dwButtons = 6, + }, + { + .dwSize = sizeof(DIDEVCAPS), + .dwFlags = DIDC_ATTACHED|DIDC_EMULATED, + .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEJOYSTICK_LIMITED << 8)|DI8DEVTYPE_JOYSTICK + : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, + .dwAxes = 2, + .dwButtons = 6, + }, + { + .dwSize = sizeof(DIDEVCAPS), + .dwFlags = DIDC_ATTACHED|DIDC_EMULATED, + .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEGAMEPAD_STANDARD << 8)|DI8DEVTYPE_GAMEPAD + : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_GAMEPAD << 8)|DIDEVTYPE_JOYSTICK, + .dwAxes = 2, + .dwButtons = 6, + }, + { + .dwSize = sizeof(DIDEVCAPS), + .dwFlags = DIDC_ATTACHED|DIDC_EMULATED, + .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEJOYSTICK_STANDARD << 8)|DI8DEVTYPE_JOYSTICK + : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, + .dwAxes = 3, + .dwPOVs = 1, + .dwButtons = 5, + }, + }; + + const DIDEVICEINSTANCEW expect_devinst[] = + { + { + .dwSize = sizeof(DIDEVICEINSTANCEW), + .guidInstance = expect_guid_product, + .guidProduct = expect_guid_product, + .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPESUPPLEMENTAL_UNKNOWN << 8)|DI8DEVTYPE_SUPPLEMENTAL + : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, + .tszInstanceName = L"Wine test root driver", + .tszProductName = L"Wine test root driver", + .guidFFDriver = GUID_NULL, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }, + { + .dwSize = sizeof(DIDEVICEINSTANCEW), + .guidInstance = expect_guid_product, + .guidProduct = expect_guid_product, + .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEJOYSTICK_LIMITED << 8)|DI8DEVTYPE_JOYSTICK + : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, + .tszInstanceName = L"Wine test root driver", + .tszProductName = L"Wine test root driver", + .guidFFDriver = GUID_NULL, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }, + { + .dwSize = sizeof(DIDEVICEINSTANCEW), + .guidInstance = expect_guid_product, + .guidProduct = expect_guid_product, + .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEGAMEPAD_STANDARD << 8)|DI8DEVTYPE_GAMEPAD + : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_GAMEPAD << 8)|DIDEVTYPE_JOYSTICK, + .tszInstanceName = L"Wine test root driver", + .tszProductName = L"Wine test root driver", + .guidFFDriver = GUID_NULL, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_GAMEPAD, + }, + { + .dwSize = sizeof(DIDEVICEINSTANCEW), + .guidInstance = expect_guid_product, + .guidProduct = expect_guid_product, + .dwDevType = version >= 0x800 ? DIDEVTYPE_HID|(DI8DEVTYPEJOYSTICK_STANDARD << 8)|DI8DEVTYPE_JOYSTICK + : DIDEVTYPE_HID|(DIDEVTYPEJOYSTICK_UNKNOWN << 8)|DIDEVTYPE_JOYSTICK, + .tszInstanceName = L"Wine test root driver", + .tszProductName = L"Wine test root driver", + .guidFFDriver = GUID_NULL, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }, + }; + + DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; + DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; + WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; + IDirectInputDevice8W *device; + BOOL success = TRUE; + ULONG i, ref; + HRESULT hr; + + winetest_push_context( "%#x", version ); + + for (i = 0; i < ARRAY_SIZE(device_desc) && success; ++i) + { + winetest_push_context( "desc[%d]", i ); + GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); + GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); + SetCurrentDirectoryW( tempdir ); + + cleanup_registry_keys(); + if (!dinput_driver_start( device_desc[i].report_desc_buf, device_desc[i].report_desc_len, + &device_desc[i].hid_caps, NULL, 0 )) + { + success = FALSE; + goto done; + } + + if (FAILED(hr = dinput_test_create_device( version, &devinst, &device ))) + { + success = FALSE; + goto done; + } + + hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); + ok( hr == DI_OK, "GetDeviceInfo returned %#x\n", hr ); + check_member( devinst, expect_devinst[i], "%d", dwSize ); + todo_wine + check_member_guid( devinst, expect_devinst[i], guidInstance ); + check_member_guid( devinst, expect_devinst[i], guidProduct ); + todo_wine_if( version <= 0x700 && i == 3 ) + check_member( devinst, expect_devinst[i], "%#x", dwDevType ); + todo_wine + check_member_wstr( devinst, expect_devinst[i], tszInstanceName ); + todo_wine + check_member_wstr( devinst, expect_devinst[i], tszProductName ); + check_member_guid( devinst, expect_devinst[i], guidFFDriver ); + check_member( devinst, expect_devinst[i], "%04x", wUsagePage ); + check_member( devinst, expect_devinst[i], "%04x", wUsage ); + + hr = IDirectInputDevice8_GetCapabilities( device, &caps ); + ok( hr == DI_OK, "GetCapabilities returned %#x\n", hr ); + check_member( caps, expect_caps[i], "%d", dwSize ); + check_member( caps, expect_caps[i], "%#x", dwFlags ); + todo_wine_if( version <= 0x700 && i == 3 ) + check_member( caps, expect_caps[i], "%#x", dwDevType ); + check_member( caps, expect_caps[i], "%d", dwAxes ); + check_member( caps, expect_caps[i], "%d", dwButtons ); + check_member( caps, expect_caps[i], "%d", dwPOVs ); + check_member( caps, expect_caps[i], "%d", dwFFSamplePeriod ); + check_member( caps, expect_caps[i], "%d", dwFFMinTimeResolution ); + check_member( caps, expect_caps[i], "%d", dwFirmwareRevision ); + check_member( caps, expect_caps[i], "%d", dwHardwareRevision ); + check_member( caps, expect_caps[i], "%d", dwFFDriverVersion ); + + ref = IDirectInputDevice8_Release( device ); + ok( ref == 0, "Release returned %d\n", ref ); + + done: + pnp_driver_stop(); + cleanup_registry_keys(); + SetCurrentDirectoryW( cwd ); + winetest_pop_context(); + } + + winetest_pop_context(); + + return success; +} + +static BOOL test_winmm_joystick(void) +{ +#include "psh_hid_macros.h" + const unsigned char report_desc[] = { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Report), + REPORT_ID(1, 1), + + USAGE(1, HID_USAGE_GENERIC_X), + USAGE(1, HID_USAGE_GENERIC_Y), + USAGE(1, HID_USAGE_GENERIC_Z), + USAGE(1, HID_USAGE_GENERIC_WHEEL), + USAGE(1, HID_USAGE_GENERIC_SLIDER), + USAGE(1, HID_USAGE_GENERIC_RX), + USAGE(1, HID_USAGE_GENERIC_RY), + USAGE(1, HID_USAGE_GENERIC_RZ), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(4, 0xffff), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(4, 0xffff), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 8), + INPUT(1, Data|Var|Abs), + + USAGE(1, HID_USAGE_GENERIC_HATSWITCH), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 8), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 8), + REPORT_SIZE(1, 4), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs|Null), + + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 4), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 4), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, + }; +#include "pop_hid_macros.h" + + static const HIDP_CAPS hid_caps = + { + .InputReportByteLength = 18, + }; + static const JOYCAPS2W expect_regcaps = + { + .szRegKey = L"DINPUT.DLL", + }; + static const JOYCAPS2W expect_caps = + { + .wMid = 0x1209, + .wPid = 0x0001, + .szPname = L"Microsoft PC-joystick driver", + .wXmax = 0xffff, + .wYmax = 0xffff, + .wZmax = 0xffff, + .wNumButtons = 4, + .wPeriodMin = 10, + .wPeriodMax = 1000, + .wRmax = 0xffff, + .wUmax = 0xffff, + .wVmax = 0xffff, + .wCaps = JOYCAPS_HASZ | JOYCAPS_HASR | JOYCAPS_HASU | JOYCAPS_HASV | JOYCAPS_HASPOV | JOYCAPS_POV4DIR, + .wMaxAxes = 6, + .wNumAxes = 6, + .wMaxButtons = 32, + .szRegKey = L"DINPUT.DLL", + }; + struct hid_expect injected_input[] = + { + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x00,0x00,0x00,0x08,0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x38,0xf1}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x00,0x38,0x00,0x30,0x00,0x28,0x00,0x20,0x00,0x18,0x00,0x10,0x00,0x08,0x00,0x00,0x63}, + }, + }; + static const JOYINFOEX expect_infoex[] = + { + { + .dwSize = sizeof(JOYINFOEX), .dwFlags = 0xff, + .dwXpos = 0x7fff, .dwYpos = 0x7fff, .dwZpos = 0x7fff, .dwRpos = 0x7fff, .dwUpos = 0x7fff, .dwVpos = 0x7fff, + .dwButtons = 0, .dwButtonNumber = 0, .dwPOV = 0xffff, + .dwReserved1 = 0xcdcdcdcd, .dwReserved2 = 0xcdcdcdcd, + }, + { + .dwSize = sizeof(JOYINFOEX), .dwFlags = 0xff, + .dwXpos = 0, .dwYpos = 0x07ff, .dwZpos = 0x17ff, .dwRpos = 0x37ff, .dwUpos = 0x1fff, .dwVpos = 0x27ff, + .dwButtons = 0xf, .dwButtonNumber = 0x4, .dwPOV = 0, + .dwReserved1 = 0xcdcdcdcd, .dwReserved2 = 0xcdcdcdcd, + }, + { + .dwSize = sizeof(JOYINFOEX), .dwFlags = 0xff, + .dwXpos = 0x37ff, .dwYpos = 0x2fff, .dwZpos = 0x1fff, .dwRpos = 0, .dwUpos = 0x17ff, .dwVpos = 0x0fff, + .dwButtons = 0x6, .dwButtonNumber = 0x2, .dwPOV = 0x2328, + .dwReserved1 = 0xcdcdcdcd, .dwReserved2 = 0xcdcdcdcd, + }, + }; + static const JOYINFO expect_info = + { + .wXpos = 0x7fff, + .wYpos = 0x7fff, + .wZpos = 0x7fff, + .wButtons = 0, + }; + JOYINFOEX infoex = {.dwSize = sizeof(JOYINFOEX)}; + DIPROPGUIDANDPATH prop_guid_path = + { + .diph = + { + .dwSize = sizeof(DIPROPGUIDANDPATH), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; + IDirectInputDevice8W *device = NULL; + DIDEVICEINSTANCEW devinst = {0}; + JOYCAPS2W caps = {0}; + JOYINFO info = {0}; + HANDLE event, file; + HRESULT hr; + UINT ret; + + GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); + GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); + SetCurrentDirectoryW( tempdir ); + + cleanup_registry_keys(); + + ret = joyGetNumDevs(); + ok( ret == 16, "joyGetNumDevs returned %u\n", ret ); + + ret = joyGetDevCapsW( 0, (JOYCAPSW *)&caps, sizeof(JOYCAPSW) ); + ok( ret == JOYERR_PARMS, "joyGetDevCapsW returned %u\n", ret ); + + memset( &caps, 0xcd, sizeof(caps) ); + ret = joyGetDevCapsW( -1, (JOYCAPSW *)&caps, sizeof(caps) ); + ok( ret == 0, "joyGetDevCapsW returned %u\n", ret ); + check_member( caps, expect_regcaps, "%#x", wMid ); + check_member( caps, expect_regcaps, "%#x", wPid ); + check_member_wstr( caps, expect_regcaps, szPname ); + check_member( caps, expect_regcaps, "%#x", wXmin ); + check_member( caps, expect_regcaps, "%#x", wXmax ); + check_member( caps, expect_regcaps, "%#x", wYmin ); + check_member( caps, expect_regcaps, "%#x", wYmax ); + check_member( caps, expect_regcaps, "%#x", wZmin ); + check_member( caps, expect_regcaps, "%#x", wZmax ); + check_member( caps, expect_regcaps, "%#x", wNumButtons ); + check_member( caps, expect_regcaps, "%#x", wPeriodMin ); + check_member( caps, expect_regcaps, "%#x", wPeriodMax ); + check_member( caps, expect_regcaps, "%#x", wRmin ); + check_member( caps, expect_regcaps, "%#x", wRmax ); + check_member( caps, expect_regcaps, "%#x", wUmin ); + check_member( caps, expect_regcaps, "%#x", wUmax ); + check_member( caps, expect_regcaps, "%#x", wVmin ); + check_member( caps, expect_regcaps, "%#x", wVmax ); + check_member( caps, expect_regcaps, "%#x", wCaps ); + check_member( caps, expect_regcaps, "%#x", wMaxAxes ); + check_member( caps, expect_regcaps, "%#x", wNumAxes ); + check_member( caps, expect_regcaps, "%#x", wMaxButtons ); + check_member_wstr( caps, expect_regcaps, szRegKey ); + check_member_wstr( caps, expect_regcaps, szOEMVxD ); + check_member_guid( caps, expect_regcaps, ManufacturerGuid ); + check_member_guid( caps, expect_regcaps, ProductGuid ); + check_member_guid( caps, expect_regcaps, NameGuid ); + + if (!dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 )) goto done; + + ret = joyGetNumDevs(); + ok( ret == 16, "joyGetNumDevs returned %u\n", ret ); + + ret = joyGetPosEx( 1, &infoex ); + ok( ret == JOYERR_PARMS, "joyGetPosEx returned %u\n", ret ); + ret = joyGetPosEx( 0, &infoex ); + /* first call for an index sometimes fail */ + if (ret == JOYERR_PARMS) ret = joyGetPosEx( 0, &infoex ); + ok( ret == 0, "joyGetPosEx returned %u\n", ret ); + + ret = joyGetDevCapsW( 1, (JOYCAPSW *)&caps, sizeof(JOYCAPSW) ); + ok( ret == JOYERR_PARMS, "joyGetDevCapsW returned %u\n", ret ); + + memset( &caps, 0xcd, sizeof(caps) ); + ret = joyGetDevCapsW( 0, (JOYCAPSW *)&caps, sizeof(caps) ); + ok( ret == 0, "joyGetDevCapsW returned %u\n", ret ); + check_member( caps, expect_caps, "%#x", wMid ); + check_member( caps, expect_caps, "%#x", wPid ); + todo_wine + check_member_wstr( caps, expect_caps, szPname ); + check_member( caps, expect_caps, "%#x", wXmin ); + check_member( caps, expect_caps, "%#x", wXmax ); + check_member( caps, expect_caps, "%#x", wYmin ); + check_member( caps, expect_caps, "%#x", wYmax ); + check_member( caps, expect_caps, "%#x", wZmin ); + check_member( caps, expect_caps, "%#x", wZmax ); + check_member( caps, expect_caps, "%#x", wNumButtons ); + check_member( caps, expect_caps, "%#x", wPeriodMin ); + check_member( caps, expect_caps, "%#x", wPeriodMax ); + check_member( caps, expect_caps, "%#x", wRmin ); + check_member( caps, expect_caps, "%#x", wRmax ); + check_member( caps, expect_caps, "%#x", wUmin ); + check_member( caps, expect_caps, "%#x", wUmax ); + check_member( caps, expect_caps, "%#x", wVmin ); + check_member( caps, expect_caps, "%#x", wVmax ); + check_member( caps, expect_caps, "%#x", wCaps ); + check_member( caps, expect_caps, "%#x", wMaxAxes ); + check_member( caps, expect_caps, "%#x", wNumAxes ); + check_member( caps, expect_caps, "%#x", wMaxButtons ); + check_member_wstr( caps, expect_caps, szRegKey ); + check_member_wstr( caps, expect_caps, szOEMVxD ); + check_member_guid( caps, expect_caps, ManufacturerGuid ); + check_member_guid( caps, expect_caps, ProductGuid ); + check_member_guid( caps, expect_caps, NameGuid ); + + ret = joyGetDevCapsW( 0, (JOYCAPSW *)&caps, sizeof(JOYCAPSW) ); + ok( ret == 0, "joyGetDevCapsW returned %u\n", ret ); + ret = joyGetDevCapsW( 0, NULL, sizeof(JOYCAPSW) ); + ok( ret == MMSYSERR_INVALPARAM, "joyGetDevCapsW returned %u\n", ret ); + ret = joyGetDevCapsW( 0, (JOYCAPSW *)&caps, sizeof(JOYCAPSW) + 4 ); + ok( ret == JOYERR_PARMS, "joyGetDevCapsW returned %u\n", ret ); + ret = joyGetDevCapsW( 0, (JOYCAPSW *)&caps, sizeof(JOYCAPSW) - 4 ); + ok( ret == JOYERR_PARMS, "joyGetDevCapsW returned %u\n", ret ); + + infoex.dwSize = sizeof(JOYINFOEX); + infoex.dwFlags = JOY_RETURNALL; + ret = joyGetPosEx( -1, &infoex ); + ok( ret == JOYERR_PARMS, "joyGetPosEx returned %u\n", ret ); + ret = joyGetPosEx( 1, &infoex ); + ok( ret == JOYERR_PARMS, "joyGetPosEx returned %u\n", ret ); + ret = joyGetPosEx( 16, &infoex ); + ok( ret == JOYERR_PARMS, "joyGetPosEx returned %u\n", ret ); + + memset( &infoex, 0xcd, sizeof(infoex) ); + infoex.dwSize = sizeof(JOYINFOEX); + infoex.dwFlags = JOY_RETURNALL; + ret = joyGetPosEx( 0, &infoex ); + ok( ret == 0, "joyGetPosEx returned %u\n", ret ); + check_member( infoex, expect_infoex[0], "%#x", dwSize ); + check_member( infoex, expect_infoex[0], "%#x", dwFlags ); + check_member( infoex, expect_infoex[0], "%#x", dwXpos ); + check_member( infoex, expect_infoex[0], "%#x", dwYpos ); + check_member( infoex, expect_infoex[0], "%#x", dwZpos ); + check_member( infoex, expect_infoex[0], "%#x", dwRpos ); + check_member( infoex, expect_infoex[0], "%#x", dwUpos ); + check_member( infoex, expect_infoex[0], "%#x", dwVpos ); + check_member( infoex, expect_infoex[0], "%#x", dwButtons ); + check_member( infoex, expect_infoex[0], "%#x", dwButtonNumber ); + check_member( infoex, expect_infoex[0], "%#x", dwPOV ); + check_member( infoex, expect_infoex[0], "%#x", dwReserved1 ); + check_member( infoex, expect_infoex[0], "%#x", dwReserved2 ); + + infoex.dwSize = sizeof(JOYINFOEX) - 4; + ret = joyGetPosEx( 0, &infoex ); + ok( ret == JOYERR_PARMS, "joyGetPosEx returned %u\n", ret ); + + ret = joyGetPos( -1, &info ); + ok( ret == JOYERR_PARMS, "joyGetPos returned %u\n", ret ); + ret = joyGetPos( 1, &info ); + ok( ret == JOYERR_PARMS, "joyGetPos returned %u\n", ret ); + memset( &info, 0xcd, sizeof(info) ); + ret = joyGetPos( 0, &info ); + ok( ret == 0, "joyGetPos returned %u\n", ret ); + check_member( info, expect_info, "%#x", wXpos ); + check_member( info, expect_info, "%#x", wYpos ); + check_member( info, expect_info, "%#x", wZpos ); + check_member( info, expect_info, "%#x", wButtons ); + + if (FAILED(hr = dinput_test_create_device( DIRECTINPUT_VERSION, &devinst, &device ))) goto done; + + event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( event != NULL, "CreateEventW failed, last error %u\n", GetLastError() ); + hr = IDirectInputDevice8_SetEventNotification( device, event ); + ok( hr == DI_OK, "SetEventNotification returned: %#x\n", hr ); + + hr = IDirectInputDevice8_GetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph ); + 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, + FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL ); + ok( file != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError() ); + + hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); + ok( hr == DI_OK, "SetDataFormat returned: %#x\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE ); + ok( hr == DI_OK, "SetCooperativeLevel returned: %#x\n", hr ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#x\n", hr ); + + send_hid_input( file, &injected_input[0], sizeof(struct hid_expect) ); + ret = WaitForSingleObject( event, 100 ); + ok( ret != WAIT_TIMEOUT, "WaitForSingleObject returned %#x\n", ret ); + Sleep( 50 ); /* leave some time for winmm to keep up */ + + memset( &infoex, 0xcd, sizeof(infoex) ); + infoex.dwSize = sizeof(JOYINFOEX); + infoex.dwFlags = JOY_RETURNALL; + ret = joyGetPosEx( 0, &infoex ); + ok( ret == 0, "joyGetPosEx returned %u\n", ret ); + check_member( infoex, expect_infoex[1], "%#x", dwSize ); + check_member( infoex, expect_infoex[1], "%#x", dwFlags ); + check_member( infoex, expect_infoex[1], "%#x", dwXpos ); + check_member( infoex, expect_infoex[1], "%#x", dwYpos ); + check_member( infoex, expect_infoex[1], "%#x", dwZpos ); + check_member( infoex, expect_infoex[1], "%#x", dwRpos ); + check_member( infoex, expect_infoex[1], "%#x", dwUpos ); + check_member( infoex, expect_infoex[1], "%#x", dwVpos ); + check_member( infoex, expect_infoex[1], "%#x", dwButtons ); + check_member( infoex, expect_infoex[1], "%#x", dwButtonNumber ); + check_member( infoex, expect_infoex[1], "%#x", dwPOV ); + + send_hid_input( file, &injected_input[1], sizeof(struct hid_expect) ); + ret = WaitForSingleObject( event, 100 ); + ok( ret != WAIT_TIMEOUT, "WaitForSingleObject returned %#x\n", ret ); + Sleep( 50 ); /* leave some time for winmm to keep up */ + + memset( &infoex, 0xcd, sizeof(infoex) ); + infoex.dwSize = sizeof(JOYINFOEX); + infoex.dwFlags = JOY_RETURNALL; + ret = joyGetPosEx( 0, &infoex ); + ok( ret == 0, "joyGetPosEx returned %u\n", ret ); + check_member( infoex, expect_infoex[2], "%#x", dwSize ); + check_member( infoex, expect_infoex[2], "%#x", dwFlags ); + check_member( infoex, expect_infoex[2], "%#x", dwXpos ); + check_member( infoex, expect_infoex[2], "%#x", dwYpos ); + check_member( infoex, expect_infoex[2], "%#x", dwZpos ); + check_member( infoex, expect_infoex[2], "%#x", dwRpos ); + check_member( infoex, expect_infoex[2], "%#x", dwUpos ); + check_member( infoex, expect_infoex[2], "%#x", dwVpos ); + check_member( infoex, expect_infoex[2], "%#x", dwButtons ); + check_member( infoex, expect_infoex[2], "%#x", dwButtonNumber ); + check_member( infoex, expect_infoex[2], "%#x", dwPOV ); + + ret = IDirectInputDevice8_Release( device ); + ok( ret == 0, "Release returned %d\n", ret ); + + CloseHandle( event ); + CloseHandle( file ); + +done: + pnp_driver_stop(); + cleanup_registry_keys(); + SetCurrentDirectoryW( cwd ); + + return device != NULL; +} + +START_TEST( joystick8 ) +{ + if (!dinput_test_init()) return; + + CoInitialize( NULL ); + if (test_device_types( 0x800 )) + { + /* This needs to be done before doing anything involving dinput.dll + * on Windows, or the tests will fail, dinput8.dll is fine though. */ + test_winmm_joystick(); + + test_device_types( 0x500 ); + test_device_types( 0x700 ); + + test_simple_joystick(); + } + CoUninitialize(); + + dinput_test_exit(); +}