Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/dinput_test.h | 4 +- dlls/dinput/tests/force_feedback.c | 737 +++++++++++++++++++++++++++++ dlls/dinput/tests/hid.c | 9 +- 3 files changed, 747 insertions(+), 3 deletions(-)
diff --git a/dlls/dinput/tests/dinput_test.h b/dlls/dinput/tests/dinput_test.h index 8fefb0c8c42..0adbd0b1ac8 100644 --- a/dlls/dinput/tests/dinput_test.h +++ b/dlls/dinput/tests/dinput_test.h @@ -103,8 +103,8 @@ BOOL sync_ioctl_( const char *file, int line, HANDLE device, DWORD code, void *i #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 wait_hid_expect( a, b ) wait_hid_expect_( __FILE__, __LINE__, a, b, FALSE ) +void wait_hid_expect_( const char *file, int line, HANDLE device, DWORD timeout, BOOL todo );
#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 ); diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index fd6ec3b3c63..e414bd700af 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -29,11 +29,51 @@ #define COBJMACROS #include "dinput.h" #include "dinputd.h" +#include "roapi.h" +#include "unknwn.h" +#include "winstring.h"
#include "wine/hid.h"
#include "dinput_test.h"
+#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#include "windows.foundation.h" +#define WIDL_using_Windows_Devices_Haptics +#define WIDL_using_Windows_Gaming_Input +#define WIDL_using_Windows_Gaming_Input_ForceFeedback +#include "windows.gaming.input.h" +#include "windows.gaming.input.forcefeedback.h" +#undef Size + +#define MAKE_FUNC(f) static typeof(f) *p ## f +MAKE_FUNC( RoGetActivationFactory ); +MAKE_FUNC( RoInitialize ); +MAKE_FUNC( WindowsCreateString ); +MAKE_FUNC( WindowsDeleteString ); +MAKE_FUNC( WindowsGetStringRawBuffer ); +#undef MAKE_FUNC + +static BOOL load_combase_functions(void) +{ + HMODULE combase = GetModuleHandleW( L"combase.dll" ); + +#define LOAD_FUNC(m, f) if (!(p ## f = (void *)GetProcAddress( m, #f ))) goto failed; + LOAD_FUNC( combase, RoGetActivationFactory ); + LOAD_FUNC( combase, RoInitialize ); + LOAD_FUNC( combase, WindowsCreateString ); + LOAD_FUNC( combase, WindowsDeleteString ); + LOAD_FUNC( combase, WindowsGetStringRawBuffer ); +#undef LOAD_FUNC + + return TRUE; + +failed: + win_skip("Failed to load combase.dll functions, skipping tests\n"); + return FALSE; +} + struct check_objects_todos { BOOL type; @@ -4323,6 +4363,702 @@ done: winetest_pop_context(); }
+#define check_interface( a, b, c ) check_interface_( __LINE__, a, b, c ) +static void check_interface_( unsigned int line, void *iface_ptr, REFIID iid, BOOL supported ) +{ + IUnknown *iface = iface_ptr; + HRESULT hr, expected; + IUnknown *unk; + + expected = supported ? S_OK : E_NOINTERFACE; + hr = IUnknown_QueryInterface( iface, iid, (void **)&unk ); + ok_(__FILE__, line)( hr == expected, "got hr %#lx, expected %#lx.\n", hr, expected ); + if (SUCCEEDED(hr)) IUnknown_Release( unk ); +} + +#define check_runtimeclass( a, b ) check_runtimeclass_( __LINE__, (IInspectable *)a, b ) +static void check_runtimeclass_( int line, IInspectable *inspectable, const WCHAR *class_name ) +{ + const WCHAR *buffer; + UINT32 length; + HSTRING str; + HRESULT hr; + + hr = IInspectable_GetRuntimeClassName( inspectable, &str ); + ok_(__FILE__, line)( hr == S_OK, "GetRuntimeClassName returned %#lx\n", hr ); + buffer = pWindowsGetStringRawBuffer( str, &length ); + ok_(__FILE__, line)( !wcscmp( buffer, class_name ), "got class name %s\n", debugstr_w(buffer) ); + pWindowsDeleteString( str ); +} + +struct controller_handler +{ + IEventHandler_RawGameController IEventHandler_RawGameController_iface; + HANDLE event; + BOOL invoked; +}; + +static inline struct controller_handler *impl_from_IEventHandler_RawGameController( IEventHandler_RawGameController *iface ) +{ + return CONTAINING_RECORD( iface, struct controller_handler, IEventHandler_RawGameController_iface ); +} + +static HRESULT WINAPI controller_handler_QueryInterface( IEventHandler_RawGameController *iface, REFIID iid, void **out ) +{ + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IEventHandler_RawGameController )) + { + IUnknown_AddRef( iface ); + *out = iface; + return S_OK; + } + + trace( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI controller_handler_AddRef( IEventHandler_RawGameController *iface ) +{ + return 2; +} + +static ULONG WINAPI controller_handler_Release( IEventHandler_RawGameController *iface ) +{ + return 1; +} + +static HRESULT WINAPI controller_handler_Invoke( IEventHandler_RawGameController *iface, + IInspectable *sender, IRawGameController *controller ) +{ + struct controller_handler *impl = impl_from_IEventHandler_RawGameController( iface ); + + trace( "iface %p, sender %p, controller %p\n", iface, sender, controller ); + + ok( sender == NULL, "got sender %p\n", sender ); + SetEvent( impl->event ); + impl->invoked = TRUE; + + return S_OK; +} + +static const IEventHandler_RawGameControllerVtbl controller_handler_vtbl = +{ + controller_handler_QueryInterface, + controller_handler_AddRef, + controller_handler_Release, + controller_handler_Invoke, +}; + +static struct controller_handler controller_added = {{&controller_handler_vtbl}}; + +static void test_windows_gaming_input(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, Physical), + REPORT_ID(1, 1), + + USAGE(4, (HID_USAGE_PAGE_SIMULATION<<16)|HID_USAGE_SIMULATION_STEERING), + USAGE(4, (HID_USAGE_PAGE_SIMULATION<<16)|HID_USAGE_SIMULATION_ACCELERATOR), + USAGE(4, (HID_USAGE_PAGE_SIMULATION<<16)|HID_USAGE_SIMULATION_BRAKE), + USAGE(4, (HID_USAGE_PAGE_SIMULATION<<16)|HID_USAGE_SIMULATION_CLUTCH), + USAGE(1, HID_USAGE_GENERIC_X), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 127), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 127), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 5), + 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, + + 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, + }; +#undef REPORT_ID_OR_USAGE_PAGE +#include "pop_hid_macros.h" + + struct hid_device_desc desc = + { + .use_report_id = TRUE, + .caps = { .InputReportByteLength = 8 }, + .attributes = default_attributes, + }; + struct hid_expect expect_init[] = + { + /* device pool */ + { + .code = IOCTL_HID_GET_FEATURE, + .report_id = 1, + .report_len = 5, + .report_buf = {1,0x10,0x00,0x04,0x03}, + .todo = TRUE, + }, + }; + struct hid_expect expect_acquire[] = + { + /* device pool */ + { + .code = IOCTL_HID_GET_FEATURE, + .report_id = 1, + .report_len = 5, + .report_buf = {1,0x10,0x00,0x04,0x03}, + .todo = TRUE, + }, + /* device control */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x06}, + .todo = TRUE, + }, + /* device control */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x05}, + .todo = TRUE, + }, + /* device control */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x01}, + .todo = TRUE, + }, + /* device gain */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 6, + .report_len = 2, + .report_buf = {6, 0xff}, + .todo = TRUE, + }, + }; + static const WCHAR *force_feedback_motor = RuntimeClass_Windows_Gaming_Input_ForceFeedback_ForceFeedbackMotor; + static const WCHAR *controller_class_name = RuntimeClass_Windows_Gaming_Input_RawGameController; + + DIPROPGUIDANDPATH guid_path = + { + .diph = + { + .dwSize = sizeof(DIPROPGUIDANDPATH), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; + IVectorView_RawGameController *controllers_view; + IRawGameControllerStatics *controller_statics; + EventRegistrationToken controller_added_token; + IVectorView_ForceFeedbackMotor *motors_view; + IRawGameController *raw_controller; + IDirectInputDevice8W *device; + IForceFeedbackMotor *motor; + HSTRING str; + HANDLE file; + UINT32 size; + HRESULT hr; + + if (!load_combase_functions()) return; + + cleanup_registry_keys(); + + hr = pRoInitialize( RO_INIT_MULTITHREADED ); + ok( hr == RPC_E_CHANGED_MODE, "RoInitialize returned %#lx\n", hr ); + + hr = pWindowsCreateString( controller_class_name, wcslen( controller_class_name ), &str ); + ok( hr == S_OK, "WindowsCreateString returned %#lx\n", hr ); + hr = pRoGetActivationFactory( str, &IID_IRawGameControllerStatics, (void **)&controller_statics ); + ok( hr == S_OK || broken( hr == REGDB_E_CLASSNOTREG ), "RoGetActivationFactory returned %#lx\n", hr ); + pWindowsDeleteString( str ); + + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip( "%s runtimeclass not registered, skipping tests.\n", wine_dbgstr_w( controller_class_name ) ); + goto done; + } + + controller_added.event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( !!controller_added.event, "CreateEventW failed, error %lu\n", GetLastError() ); + + hr = IRawGameControllerStatics_add_RawGameControllerAdded( controller_statics, &controller_added.IEventHandler_RawGameController_iface, + &controller_added_token ); + ok( hr == S_OK, "add_RawGameControllerAdded returned %#lx\n", hr ); + ok( controller_added_token.value, "got token %I64u\n", controller_added_token.value ); + + desc.report_descriptor_len = sizeof(report_desc); + memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) ); + desc.expect_size = sizeof(expect_init); + memcpy( desc.expect, expect_init, sizeof(expect_init) ); + fill_context( __LINE__, desc.context, ARRAY_SIZE(desc.context) ); + + if (!hid_device_start( &desc )) goto done; + WaitForSingleObject( controller_added.event, INFINITE ); + CloseHandle( controller_added.event ); + + if (FAILED(hr = dinput_test_create_device( 0x800, &devinst, &device ))) goto done; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_GUIDANDPATH, &guid_path.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_GUIDANDPATH returned %#lx\n", hr ); + IDirectInputDevice8_Release( device ); + + file = CreateFileW( 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 %lu\n", GetLastError() ); + + hr = IRawGameControllerStatics_remove_RawGameControllerAdded( controller_statics, controller_added_token ); + ok( hr == S_OK, "remove_RawGameControllerAdded returned %#lx\n", hr ); + + hr = IRawGameControllerStatics_get_RawGameControllers( controller_statics, &controllers_view ); + ok( hr == S_OK, "get_RawGameControllers returned %#lx\n", hr ); + hr = IVectorView_RawGameController_get_Size( controllers_view, &size ); + ok( hr == S_OK, "get_Size returned %#lx\n", hr ); + ok( size == 1, "got size %u\n", size ); + hr = IVectorView_RawGameController_GetAt( controllers_view, 0, &raw_controller ); + ok( hr == S_OK, "GetAt returned %#lx\n", hr ); + IVectorView_RawGameController_Release( controllers_view ); + + set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); + hr = IRawGameController_get_ForceFeedbackMotors( raw_controller, &motors_view ); + todo_wine + ok( hr == S_OK, "get_ForceFeedbackMotors returned %#lx\n", hr ); + wait_hid_expect_( __FILE__, __LINE__, file, 100, TRUE ); /* device gain reports are written asynchronously */ + if (!motors_view) goto skip_tests; + + hr = IVectorView_ForceFeedbackMotor_get_Size( motors_view, &size ); + ok( hr == S_OK, "get_Size returned %#lx\n", hr ); + todo_wine + ok( size == 1, "got size %u\n", size ); + hr = IVectorView_ForceFeedbackMotor_GetAt( motors_view, 0, &motor ); + todo_wine + ok( hr == S_OK, "GetAt returned %#lx\n", hr ); + IVectorView_ForceFeedbackMotor_Release( motors_view ); + + check_interface( motor, &IID_IUnknown, TRUE ); + check_interface( motor, &IID_IInspectable, TRUE ); + check_interface( motor, &IID_IAgileObject, TRUE ); + check_interface( motor, &IID_IForceFeedbackMotor, TRUE ); + check_runtimeclass( motor, force_feedback_motor ); + + IForceFeedbackMotor_Release( motor ); + +skip_tests: + IRawGameController_Release( raw_controller ); + + CloseHandle( file ); + IRawGameControllerStatics_Release( controller_statics ); + +done: + hid_device_stop( &desc ); + cleanup_registry_keys(); +} + START_TEST( force_feedback ) { if (!dinput_test_init()) return; @@ -4334,6 +5070,7 @@ START_TEST( force_feedback ) test_force_feedback_joystick( 0x500 ); test_force_feedback_joystick( 0x700 ); test_device_managed_effect(); + test_windows_gaming_input(); } CoUninitialize();
diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index 1059d6c2b57..4e107625064 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -887,6 +887,11 @@ BOOL sync_ioctl_( const char *file, int line, HANDLE device, DWORD code, void *i ok_(file, line)( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); ret = GetOverlappedResult( device, &ovl, &out_len, FALSE ); ok_(file, line)( ret, "GetOverlappedResult returned %lu\n", GetLastError() ); + if (!ret) + { + CancelIoEx( device, &ovl ); + WaitForSingleObject( ovl.hEvent, timeout ); + } } CloseHandle( ovl.hEvent );
@@ -906,10 +911,12 @@ void set_hid_expect_( const char *file, int line, HANDLE device, struct hid_expe ok_(file, line)( ret, "IOCTL_WINETEST_HID_SET_EXPECT failed, last error %lu\n", GetLastError() ); }
-void wait_hid_expect_( const char *file, int line, HANDLE device, DWORD timeout ) +void wait_hid_expect_( const char *file, int line, HANDLE device, DWORD timeout, BOOL todo ) { + todo_wine_if(todo) { 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 %lu\n", GetLastError() ); + }
set_hid_expect_( file, line, device, NULL, 0 ); }