From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/force_feedback.c | 224 ++++++++++++++++++++++++++++- 1 file changed, 223 insertions(+), 1 deletion(-)
diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index e0f5ce4bca1..f5b387f3566 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -39,6 +39,7 @@
#define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections +#define WIDL_using_Windows_Foundation_Numerics #include "windows.foundation.h" #define WIDL_using_Windows_Devices_Haptics #define WIDL_using_Windows_Gaming_Input @@ -4516,6 +4517,58 @@ static void check_bool_async_( int line, IAsyncOperation_boolean *async, UINT32 } }
+#define check_result_async( a, b, c, d, e ) check_result_async_( __LINE__, a, b, c, d, e ) +static void check_result_async_( int line, IAsyncOperation_ForceFeedbackLoadEffectResult *async, UINT32 expect_id, + AsyncStatus expect_status, HRESULT expect_hr, ForceFeedbackLoadEffectResult expect_result ) +{ + ForceFeedbackLoadEffectResult result; + AsyncStatus async_status; + IAsyncInfo *async_info; + HRESULT hr, async_hr; + UINT32 async_id; + + hr = IAsyncOperation_ForceFeedbackLoadEffectResult_QueryInterface( async, &IID_IAsyncInfo, (void **)&async_info ); + ok_(__FILE__, line)( hr == S_OK, "QueryInterface returned %#lx\n", hr ); + + async_id = 0xdeadbeef; + hr = IAsyncInfo_get_Id( async_info, &async_id ); + if (expect_status < 4) ok_(__FILE__, line)( hr == S_OK, "get_Id returned %#lx\n", hr ); + else ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "get_Id returned %#lx\n", hr ); + ok_(__FILE__, line)( async_id == expect_id, "got id %u\n", async_id ); + + async_status = 0xdeadbeef; + hr = IAsyncInfo_get_Status( async_info, &async_status ); + if (expect_status < 4) ok_(__FILE__, line)( hr == S_OK, "get_Status returned %#lx\n", hr ); + else ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "get_Status returned %#lx\n", hr ); + ok_(__FILE__, line)( async_status == expect_status, "got status %u\n", async_status ); + + async_hr = 0xdeadbeef; + hr = IAsyncInfo_get_ErrorCode( async_info, &async_hr ); + if (expect_status < 4) ok_(__FILE__, line)( hr == S_OK, "get_ErrorCode returned %#lx\n", hr ); + else ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "get_ErrorCode returned %#lx\n", hr ); + if (expect_status < 4) todo_wine_if(FAILED(expect_hr)) ok_(__FILE__, line)( async_hr == expect_hr, "got error %#lx\n", async_hr ); + else ok_(__FILE__, line)( async_hr == E_ILLEGAL_METHOD_CALL, "got error %#lx\n", async_hr ); + + IAsyncInfo_Release( async_info ); + + result = !expect_result; + hr = IAsyncOperation_ForceFeedbackLoadEffectResult_GetResults( async, &result ); + switch (expect_status) + { + case Completed: + case Error: + todo_wine_if(FAILED(expect_hr)) + ok_(__FILE__, line)( hr == expect_hr, "GetResults returned %#lx\n", hr ); + ok_(__FILE__, line)( result == expect_result, "got result %u\n", result ); + break; + case Canceled: + case Started: + default: + ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "GetResults returned %#lx\n", hr ); + break; + } +} + struct bool_async_handler { IAsyncOperationCompletedHandler_boolean IAsyncOperationCompletedHandler_boolean_iface; @@ -4582,7 +4635,75 @@ static IAsyncOperationCompletedHandler_booleanVtbl bool_async_handler_vtbl = bool_async_handler_Invoke, };
-struct bool_async_handler default_bool_async_handler = {{&bool_async_handler_vtbl}}; +static struct bool_async_handler default_bool_async_handler = {{&bool_async_handler_vtbl}}; + +struct result_async_handler +{ + IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResult IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResult_iface; + IAsyncOperation_ForceFeedbackLoadEffectResult *async; + AsyncStatus status; + BOOL invoked; + HANDLE event; +}; + +static inline struct result_async_handler *impl_from_IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResult( IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResult *iface ) +{ + return CONTAINING_RECORD( iface, struct result_async_handler, IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResult_iface ); +} + +static HRESULT WINAPI result_async_handler_QueryInterface( IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResult *iface, REFIID iid, void **out ) +{ + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResult )) + { + 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 result_async_handler_AddRef( IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResult *iface ) +{ + return 2; +} + +static ULONG WINAPI result_async_handler_Release( IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResult *iface ) +{ + return 1; +} + +static HRESULT WINAPI result_async_handler_Invoke( IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResult *iface, + IAsyncOperation_ForceFeedbackLoadEffectResult *async, AsyncStatus status ) +{ + struct result_async_handler *impl = impl_from_IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResult( iface ); + + trace( "iface %p, async %p, status %u\n", iface, async, status ); + + ok( !impl->invoked, "invoked twice\n" ); + impl->invoked = TRUE; + impl->async = async; + impl->status = status; + if (impl->event) SetEvent( impl->event ); + + return S_OK; +} + +static IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResultVtbl result_async_handler_vtbl = +{ + /*** IUnknown methods ***/ + result_async_handler_QueryInterface, + result_async_handler_AddRef, + result_async_handler_Release, + /*** IAsyncOperationCompletedHandler<ForceFeedbackLoadEffectResult> methods ***/ + result_async_handler_Invoke, +}; + +static struct result_async_handler default_result_async_handler = {{&result_async_handler_vtbl}};
static void test_windows_gaming_input(void) { @@ -5158,6 +5279,7 @@ static void test_windows_gaming_input(void) .report_buf = {6, 0x7f}, }, }; + static const WCHAR *constant_effect_class_name = RuntimeClass_Windows_Gaming_Input_ForceFeedback_ConstantForceEffect; static const WCHAR *force_feedback_motor = RuntimeClass_Windows_Gaming_Input_ForceFeedback_ForceFeedbackMotor; static const WCHAR *controller_class_name = RuntimeClass_Windows_Gaming_Input_RawGameController;
@@ -5171,15 +5293,24 @@ static void test_windows_gaming_input(void) }, }; DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; + IAsyncOperation_ForceFeedbackLoadEffectResult *result_async; IAsyncOperationCompletedHandler_boolean *tmp_handler; + struct result_async_handler result_async_handler; IVectorView_RawGameController *controllers_view; IRawGameControllerStatics *controller_statics; EventRegistrationToken controller_added_token; struct bool_async_handler bool_async_handler; IVectorView_ForceFeedbackMotor *motors_view; ForceFeedbackEffectAxes supported_axes; + IActivationFactory *activation_factory; + IConstantForceEffect *constant_effect; IAsyncOperation_boolean *bool_async; IRawGameController *raw_controller; + ForceFeedbackEffectState state; + Vector3 vector3 = {1., 0., 0.}; + TimeSpan duration = {10000000}; + IInspectable *tmp_inspectable; + IForceFeedbackEffect *effect; IDirectInputDevice8W *device; IForceFeedbackMotor *motor; BOOLEAN paused, enabled; @@ -5190,6 +5321,7 @@ static void test_windows_gaming_input(void) UINT32 size; HRESULT hr; DWORD ret; + LONG ref;
if (!load_combase_functions()) return;
@@ -5478,6 +5610,96 @@ static void test_windows_gaming_input(void) IAsyncOperation_boolean_Release( bool_async );
+ hr = pWindowsCreateString( force_feedback_motor, wcslen( force_feedback_motor ), &str ); + ok( hr == S_OK, "WindowsCreateString returned %#lx\n", hr ); + hr = pRoGetActivationFactory( str, &IID_IInspectable, (void **)&tmp_inspectable ); + ok( hr == REGDB_E_CLASSNOTREG, "RoGetActivationFactory returned %#lx\n", hr ); + pWindowsDeleteString( str ); + + + hr = pWindowsCreateString( constant_effect_class_name, wcslen( constant_effect_class_name ), &str ); + ok( hr == S_OK, "WindowsCreateString returned %#lx\n", hr ); + hr = pRoGetActivationFactory( str, &IID_IActivationFactory, (void **)&activation_factory ); + todo_wine + ok( hr == S_OK, "RoGetActivationFactory returned %#lx\n", hr ); + pWindowsDeleteString( str ); + if (hr != S_OK) goto skip_tests; + + hr = IActivationFactory_ActivateInstance( activation_factory, &tmp_inspectable ); + todo_wine + ok( hr == S_OK, "QueryInterface returned %#lx\n", hr ); + IActivationFactory_Release( activation_factory ); + + hr = IInspectable_QueryInterface( tmp_inspectable, &IID_IForceFeedbackEffect, (void **)&effect ); + todo_wine + ok( hr == S_OK, "QueryInterface returned %#lx\n", hr ); + IInspectable_Release( tmp_inspectable ); + + hr = IForceFeedbackEffect_QueryInterface( effect, &IID_IConstantForceEffect, (void **)&constant_effect ); + ok( hr == S_OK, "QueryInterface returned %#lx\n", hr ); + + hr = IConstantForceEffect_SetParameters( constant_effect, vector3, duration ); + todo_wine + ok( hr == S_OK, "SetParameters returned %#lx\n", hr ); + hr = IConstantForceEffect_SetParametersWithEnvelope( constant_effect, vector3, 0.1, 0.2, 0.3, + duration, duration, duration, duration, 1 ); + todo_wine + ok( hr == S_OK, "SetParametersWithEnvelope returned %#lx\n", hr ); + IConstantForceEffect_Release( constant_effect ); + + gain = 12345.6; + hr = IForceFeedbackEffect_get_Gain( effect, &gain ); + todo_wine + ok( hr == S_OK, "get_Gain returned %#lx\n", hr ); + todo_wine + ok( gain == 1.0, "get_MasterGain returned %f\n", gain ); + hr = IForceFeedbackEffect_put_Gain( effect, 0.5 ); + todo_wine + ok( hr == S_FALSE, "put_Gain returned %#lx\n", hr ); + state = 0xdeadbeef; + hr = IForceFeedbackEffect_get_State( effect, &state ); + todo_wine + ok( hr == S_OK, "get_State returned %#lx\n", hr ); + todo_wine + ok( state == ForceFeedbackEffectState_Stopped, "get_State returned %#lx\n", hr ); + hr = IForceFeedbackEffect_Start( effect ); + todo_wine + ok( hr == 0x86854003, "Start returned %#lx\n", hr ); + hr = IForceFeedbackEffect_Stop( effect ); + todo_wine + ok( hr == 0x86854003, "Stop returned %#lx\n", hr ); + + hr = IForceFeedbackMotor_LoadEffectAsync( motor, effect, &result_async ); + todo_wine + ok( hr == S_OK, "LoadEffectAsync returned %#lx\n", hr ); + result_async_handler = default_result_async_handler; + result_async_handler.event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( !!result_async_handler.event, "CreateEventW failed, error %lu\n", GetLastError() ); + hr = IAsyncOperation_ForceFeedbackLoadEffectResult_put_Completed( result_async, &result_async_handler.IAsyncOperationCompletedHandler_ForceFeedbackLoadEffectResult_iface ); + ok( hr == S_OK, "put_Completed returned %#lx\n", hr ); + ret = WaitForSingleObject( result_async_handler.event, 5000 ); + ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); + ret = CloseHandle( result_async_handler.event ); + ok( ret, "CloseHandle failed, error %lu\n", GetLastError() ); + check_result_async( result_async, 1, Error, 0x86854008, ForceFeedbackLoadEffectResult_EffectNotSupported ); + ref = IAsyncOperation_ForceFeedbackLoadEffectResult_Release( result_async ); + ok( ref == 0, "Release returned %lu\n", ref ); + + hr = IForceFeedbackEffect_Start( effect ); + todo_wine + ok( hr == 0x86854003, "Start returned %#lx\n", hr ); + hr = IForceFeedbackEffect_Stop( effect ); + todo_wine + ok( hr == 0x86854003, "Stop returned %#lx\n", hr ); + hr = IForceFeedbackMotor_TryUnloadEffectAsync( motor, effect, &bool_async ); + todo_wine + ok( hr == 0x86854003, "TryUnloadEffectAsync returned %#lx\n", hr ); + + ref = IForceFeedbackEffect_Release( effect ); + ok( ref == 0, "Release returned %lu\n", ref ); + + +skip_tests: IForceFeedbackMotor_Release( motor );
IRawGameController_Release( raw_controller );