Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 83 +++++++++++++++++++++++++++++++++++--- dlls/dinput8/tests/hid.c | 11 +---- 2 files changed, 78 insertions(+), 16 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 834a5de0860..a6c6de3a889 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -780,6 +780,77 @@ static HRESULT WINAPI hid_joystick_GetDeviceInfo( IDirectInputDevice8W *iface, D return S_OK; }
+static HRESULT WINAPI hid_joystick_CreateEffect( IDirectInputDevice8W *iface, const GUID *guid, + const DIEFFECT *params, IDirectInputEffect **out, + IUnknown *outer ) +{ + FIXME( "iface %p, guid %s, params %p, out %p, outer %p stub!\n", iface, debugstr_guid( guid ), + params, out, outer ); + + if (!out) return E_POINTER; + + return DIERR_UNSUPPORTED; +} + +static HRESULT WINAPI hid_joystick_EnumEffects( IDirectInputDevice8W *iface, LPDIENUMEFFECTSCALLBACKW callback, + void *context, DWORD type ) +{ + FIXME( "iface %p, callback %p, context %p, type %#x stub!\n", iface, callback, context, type ); + + if (!callback) return DIERR_INVALIDPARAM; + + return DI_OK; +} + +static HRESULT WINAPI hid_joystick_GetEffectInfo( IDirectInputDevice8W *iface, DIEFFECTINFOW *info, + const GUID *guid ) +{ + FIXME( "iface %p, info %p, guid %s stub!\n", iface, info, debugstr_guid( guid ) ); + + if (!info) return E_POINTER; + if (info->dwSize != sizeof(DIEFFECTINFOW)) return DIERR_INVALIDPARAM; + + return DIERR_DEVICENOTREG; +} + +static HRESULT WINAPI hid_joystick_GetForceFeedbackState( IDirectInputDevice8W *iface, DWORD *out ) +{ + FIXME( "iface %p, out %p stub!\n", iface, out ); + + if (!out) return E_POINTER; + + return DIERR_UNSUPPORTED; +} + +static HRESULT WINAPI hid_joystick_SendForceFeedbackCommand( IDirectInputDevice8W *iface, DWORD command ) +{ + FIXME( "iface %p, command %x stub!\n", iface, command ); + + switch (command) + { + case DISFFC_RESET: + case DISFFC_STOPALL: + case DISFFC_PAUSE: + case DISFFC_CONTINUE: + case DISFFC_SETACTUATORSON: + case DISFFC_SETACTUATORSOFF: + return DIERR_UNSUPPORTED; + } + + return DIERR_INVALIDPARAM; +} + +static HRESULT WINAPI hid_joystick_EnumCreatedEffectObjects( IDirectInputDevice8W *iface, + LPDIENUMCREATEDEFFECTOBJECTSCALLBACK callback, + void *context, DWORD flags ) +{ + FIXME( "iface %p, callback %p, context %p, flags %#x stub!\n", iface, callback, context, flags ); + + if (!callback) return DIERR_INVALIDPARAM; + + return DIERR_UNSUPPORTED; +} + static HRESULT WINAPI hid_joystick_Poll( IDirectInputDevice8W *iface ) { struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); @@ -837,12 +908,12 @@ static const IDirectInputDevice8WVtbl hid_joystick_vtbl = IDirectInputDevice2WImpl_RunControlPanel, IDirectInputDevice2WImpl_Initialize, /*** IDirectInputDevice2 methods ***/ - IDirectInputDevice2WImpl_CreateEffect, - IDirectInputDevice2WImpl_EnumEffects, - IDirectInputDevice2WImpl_GetEffectInfo, - IDirectInputDevice2WImpl_GetForceFeedbackState, - IDirectInputDevice2WImpl_SendForceFeedbackCommand, - IDirectInputDevice2WImpl_EnumCreatedEffectObjects, + hid_joystick_CreateEffect, + hid_joystick_EnumEffects, + hid_joystick_GetEffectInfo, + hid_joystick_GetForceFeedbackState, + hid_joystick_SendForceFeedbackCommand, + hid_joystick_EnumCreatedEffectObjects, IDirectInputDevice2WImpl_Escape, hid_joystick_Poll, IDirectInputDevice2WImpl_SendDeviceData, diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index 1ab6e645947..e6439ed8fe5 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -4038,7 +4038,6 @@ static void test_simple_joystick(void) check_member( objinst, expect_objects[5], "%u", wReportId );
hr = IDirectInputDevice8_EnumEffects( device, NULL, NULL, DIEFT_ALL ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_EnumEffects returned %#x\n", hr ); res = 0; hr = IDirectInputDevice8_EnumEffects( device, check_effect_count, &res, 0xfe ); @@ -4054,18 +4053,14 @@ static void test_simple_joystick(void) check_effects_params.expect_count - check_effects_params.index );
hr = IDirectInputDevice8_GetEffectInfo( device, NULL, &GUID_Sine ); - todo_wine ok( hr == E_POINTER, "IDirectInputDevice8_GetEffectInfo returned %#x\n", hr ); effectinfo.dwSize = sizeof(DIEFFECTINFOW) + 1; hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_Sine ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_GetEffectInfo returned %#x\n", hr ); effectinfo.dwSize = sizeof(DIEFFECTINFOW); hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_NULL ); - todo_wine ok( hr == DIERR_DEVICENOTREG, "IDirectInputDevice8_GetEffectInfo returned %#x\n", hr ); hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_Sine ); - todo_wine ok( hr == DIERR_DEVICENOTREG, "IDirectInputDevice8_GetEffectInfo returned %#x\n", hr );
hr = IDirectInputDevice8_SetDataFormat( device, NULL ); @@ -4645,18 +4640,14 @@ static void test_simple_joystick(void) winetest_pop_context();
hr = IDirectInputDevice8_GetForceFeedbackState( device, NULL ); - todo_wine ok( hr == E_POINTER, "IDirectInputDevice8_GetForceFeedbackState returned %#x\n", hr ); res = 0xdeadbeef; hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - todo_wine ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_GetForceFeedbackState returned %#x\n", hr );
hr = IDirectInputDevice8_SendForceFeedbackCommand( device, 0xdeadbeef ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr ); hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); - todo_wine ok( hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr );
objdata[0].dwOfs = 0xd; @@ -5713,6 +5704,7 @@ static void test_force_feedback_joystick( void )
effectinfo.dwSize = sizeof(DIEFFECTINFOW); hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_Sine ); + todo_wine ok( hr == DI_OK, "IDirectInputDevice8_GetEffectInfo returned %#x\n", hr ); todo_wine check_member_guid( effectinfo, expect_effects[0], guid ); @@ -5802,7 +5794,6 @@ static void test_force_feedback_joystick( void ) ok( hr == 0x80040301, "IDirectInputDevice8_GetForceFeedbackState returned %#x\n", hr );
hr = IDirectInputDevice8_SendForceFeedbackCommand( device, 0xdeadbeef ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr );
set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) );
And include it in the HID report descriptor when SDL device has support for any haptic effect, or when UDEV lnxev device has any FF bit set.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/bus_sdl.c | 21 +++++++-- dlls/winebus.sys/bus_udev.c | 15 +++++++ dlls/winebus.sys/hid.c | 75 +++++++++++++++++++++++++++++++++ dlls/winebus.sys/unix_private.h | 8 ++++ dlls/winebus.sys/unixlib.c | 12 ++++++ 5 files changed, 128 insertions(+), 3 deletions(-)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 17032e1dba9..bd06717165d 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -115,6 +115,9 @@ static Uint16 (*pSDL_JoystickGetVendor)(SDL_Joystick * joystick); #define WINE_SDL_HAPTIC_RUMBLE 0x80000000 /* using SDL_HapticRumble API */
#define EFFECT_SUPPORT_HAPTICS (SDL_HAPTIC_LEFTRIGHT|WINE_SDL_HAPTIC_RUMBLE|WINE_SDL_JOYSTICK_RUMBLE) +#define EFFECT_SUPPORT_PHYSICAL (SDL_HAPTIC_CONSTANT|SDL_HAPTIC_RAMP|SDL_HAPTIC_SINE|SDL_HAPTIC_TRIANGLE| \ + SDL_HAPTIC_SAWTOOTHUP|SDL_HAPTIC_SAWTOOTHDOWN|SDL_HAPTIC_SPRING|SDL_HAPTIC_DAMPER|SDL_HAPTIC_INERTIA| \ + SDL_HAPTIC_FRICTION|SDL_HAPTIC_CUSTOM)
struct sdl_device { @@ -165,14 +168,12 @@ static void set_hat_value(struct unix_device *iface, int index, int value)
static BOOL descriptor_add_haptic(struct sdl_device *impl) { - unsigned int haptics_mask = SDL_HAPTIC_LEFTRIGHT; - if (!pSDL_JoystickIsHaptic(impl->sdl_joystick) || !(impl->sdl_haptic = pSDL_HapticOpenFromJoystick(impl->sdl_joystick))) impl->effect_support = 0; else { - impl->effect_support = pSDL_HapticQuery(impl->sdl_haptic) & haptics_mask; + impl->effect_support = pSDL_HapticQuery(impl->sdl_haptic); if (pSDL_HapticRumbleSupported(impl->sdl_haptic)) impl->effect_support |= WINE_SDL_HAPTIC_RUMBLE;
@@ -189,6 +190,12 @@ static BOOL descriptor_add_haptic(struct sdl_device *impl) return FALSE; }
+ if ((impl->effect_support & EFFECT_SUPPORT_PHYSICAL)) + { + if (!hid_device_add_physical(&impl->unix_device)) + return FALSE; + } + impl->haptic_effect_id = -1; return TRUE; } @@ -391,12 +398,20 @@ NTSTATUS sdl_device_haptics_start(struct unix_device *iface, DWORD duration_ms, return STATUS_SUCCESS; }
+static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, USAGE control) +{ + FIXME("iface %p, control %#04x stub\n", iface, control); + + return STATUS_NOT_SUPPORTED; +} + static const struct hid_device_vtbl sdl_device_vtbl = { sdl_device_destroy, sdl_device_start, sdl_device_stop, sdl_device_haptics_start, + sdl_device_physical_device_control, };
static BOOL set_report_from_joystick_event(struct sdl_device *impl, SDL_Event *event) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 909d91667e1..e4c0103b270 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -658,6 +658,13 @@ static NTSTATUS build_report_descriptor(struct unix_device *iface, struct udev_d impl->haptic_effect_id = effect.id; }
+ for (i = 0; i < FF_MAX; ++i) if (test_bit(ffbits, i)) break; + if (i != FF_MAX) + { + if (!hid_device_add_physical(iface)) + return STATUS_NO_MEMORY; + } + if (!hid_device_end_report_descriptor(iface)) return STATUS_NO_MEMORY;
@@ -802,12 +809,20 @@ static NTSTATUS lnxev_device_haptics_start(struct unix_device *iface, DWORD dura return STATUS_SUCCESS; }
+static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface, USAGE control) +{ + FIXME("iface %p, control %#04x stub!\n", iface, control); + + return STATUS_NOT_IMPLEMENTED; +} + static const struct hid_device_vtbl lnxev_device_vtbl = { lnxev_device_destroy, lnxev_device_start, lnxev_device_stop, lnxev_device_haptics_start, + lnxev_device_physical_device_control, }; #endif /* HAS_PROPER_INPUT_HEADER */
diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index 0c8e85dfc5f..12db1706ede 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -35,6 +35,7 @@ #include "ddk/hidsdi.h"
#include "wine/debug.h" +#include "wine/hid.h"
#include "unix_private.h"
@@ -394,6 +395,64 @@ BOOL hid_device_add_haptics(struct unix_device *iface) return hid_report_descriptor_append(desc, haptics_template, sizeof(haptics_template)); }
+#include "pshpack1.h" +struct pid_device_control +{ + BYTE control_index; +}; + +static const USAGE pid_device_control_usages[] = +{ + 0, /* HID nary collection indexes start at 1 */ + PID_USAGE_DC_ENABLE_ACTUATORS, + PID_USAGE_DC_DISABLE_ACTUATORS, + PID_USAGE_DC_STOP_ALL_EFFECTS, + PID_USAGE_DC_DEVICE_RESET, + PID_USAGE_DC_DEVICE_PAUSE, + PID_USAGE_DC_DEVICE_CONTINUE, +}; +#include "poppack.h" + +BOOL hid_device_add_physical(struct unix_device *iface) +{ + struct hid_report_descriptor *desc = &iface->hid_report_descriptor; + const BYTE device_control_report = ++desc->next_report_id[HidP_Output]; + const BYTE device_control_header[] = + { + USAGE_PAGE(1, HID_USAGE_PAGE_PID), + USAGE(1, PID_USAGE_DEVICE_CONTROL_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, device_control_report), + + USAGE(1, PID_USAGE_DEVICE_CONTROL), + COLLECTION(1, Logical), + }; + const BYTE device_control_footer[] = + { + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 6), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + END_COLLECTION, + }; + ULONG i; + + if (!hid_report_descriptor_append(desc, device_control_header, sizeof(device_control_header))) + return FALSE; + for (i = 1; i < ARRAY_SIZE(pid_device_control_usages); ++i) + { + if (!hid_report_descriptor_append_usage(desc, pid_device_control_usages[i])) + return FALSE; + } + if (!hid_report_descriptor_append(desc, device_control_footer, sizeof(device_control_footer))) + return FALSE; + + iface->hid_physical.device_control_report = device_control_report; + return TRUE; +} + #include "pop_hid_macros.h"
static void hid_device_destroy(struct unix_device *iface) @@ -425,6 +484,7 @@ NTSTATUS hid_device_get_report_descriptor(struct unix_device *iface, BYTE *buffe
static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PACKET *packet, IO_STATUS_BLOCK *io) { + struct hid_physical *physical = &iface->hid_physical; struct hid_haptics *haptics = &iface->hid_haptics;
if (packet->reportId == haptics->waveform_report) @@ -450,6 +510,21 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC io->Status = iface->hid_vtbl->haptics_start(iface, duration_ms, rumble->intensity, buzz->intensity); } } + else if (packet->reportId == physical->device_control_report) + { + struct pid_device_control *report = (struct pid_device_control *)(packet->reportBuffer + 1); + USAGE control; + + io->Information = sizeof(*report) + 1; + if (packet->reportBufferLen < io->Information) + io->Status = STATUS_BUFFER_TOO_SMALL; + else if (report->control_index >= ARRAY_SIZE(pid_device_control_usages)) + io->Status = STATUS_INVALID_PARAMETER; + else if (!(control = pid_device_control_usages[report->control_index])) + io->Status = STATUS_INVALID_PARAMETER; + else + io->Status = iface->hid_vtbl->physical_device_control(iface, control); + } else { io->Information = 0; diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 01638bf19fc..c62e4c9d0ab 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -47,6 +47,7 @@ struct hid_device_vtbl void (*stop)(struct unix_device *iface); NTSTATUS (*haptics_start)(struct unix_device *iface, DWORD duration_ms, USHORT rumble_intensity, USHORT buzz_intensity); + NTSTATUS (*physical_device_control)(struct unix_device *iface, USAGE control); };
struct hid_report_descriptor @@ -87,6 +88,11 @@ struct hid_haptics BYTE waveform_report; };
+struct hid_physical +{ + BYTE device_control_report; +}; + struct hid_device_state { ULONG bit_size; @@ -115,6 +121,7 @@ struct unix_device struct hid_report_descriptor hid_report_descriptor; struct hid_device_state hid_device_state; struct hid_haptics hid_haptics; + struct hid_physical hid_physical; };
extern void *raw_device_create(const struct raw_device_vtbl *vtbl, SIZE_T size) DECLSPEC_HIDDEN; @@ -152,6 +159,7 @@ extern BOOL hid_device_add_axes(struct unix_device *iface, BYTE count, USAGE usa const USAGE *usages, BOOL rel, LONG min, LONG max) DECLSPEC_HIDDEN;
extern BOOL hid_device_add_haptics(struct unix_device *iface) DECLSPEC_HIDDEN; +extern BOOL hid_device_add_physical(struct unix_device *iface) DECLSPEC_HIDDEN;
extern BOOL hid_device_set_abs_axis(struct unix_device *iface, ULONG index, LONG value) DECLSPEC_HIDDEN; extern BOOL hid_device_set_rel_axis(struct unix_device *iface, ULONG index, LONG value) DECLSPEC_HIDDEN; diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index 5cf23badf88..49a42ea04ad 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -88,12 +88,18 @@ static NTSTATUS mouse_haptics_start(struct unix_device *iface, DWORD duration, return STATUS_NOT_SUPPORTED; }
+static NTSTATUS mouse_physical_device_control(struct unix_device *iface, USAGE control) +{ + return STATUS_NOT_SUPPORTED; +} + static const struct hid_device_vtbl mouse_vtbl = { mouse_destroy, mouse_start, mouse_stop, mouse_haptics_start, + mouse_physical_device_control, };
static const struct device_desc mouse_device_desc = @@ -145,12 +151,18 @@ static NTSTATUS keyboard_haptics_start(struct unix_device *iface, DWORD duration return STATUS_NOT_SUPPORTED; }
+static NTSTATUS keyboard_physical_device_control(struct unix_device *iface, USAGE control) +{ + return STATUS_NOT_SUPPORTED; +} + static const struct hid_device_vtbl keyboard_vtbl = { keyboard_destroy, keyboard_start, keyboard_stop, keyboard_haptics_start, + keyboard_physical_device_control, };
static const struct device_desc keyboard_device_desc =
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 90 ++++++++++++++++++++++++++++++++++++++ dlls/dinput8/tests/hid.c | 6 --- 2 files changed, 90 insertions(+), 6 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index a6c6de3a889..b10ce7fc03b 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -78,6 +78,13 @@ struct extra_caps LONG saturation; };
+struct pid_control_report +{ + BYTE id; + ULONG collection; + ULONG control_coll; +}; + #define DEVICE_STATE_MAX_SIZE 1024
struct hid_joystick @@ -102,6 +109,8 @@ struct hid_joystick
BYTE device_state_report_id; BYTE device_state[DEVICE_STATE_MAX_SIZE]; + + struct pid_control_report pid_device_control; };
static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface ) @@ -1176,6 +1185,12 @@ static BOOL hid_joystick_device_try_open( UINT32 handle, const WCHAR *path, HAND instance->wUsagePage = caps->UsagePage; instance->wUsage = caps->Usage;
+ count = ARRAY_SIZE(buttons); + status = HidP_GetSpecificButtonCaps( HidP_Output, HID_USAGE_PAGE_PID, 0, + PID_USAGE_DC_DEVICE_RESET, buttons, &count, preparsed_data ); + if (status == HIDP_STATUS_SUCCESS && count > 0) + instance->guidFFDriver = IID_IDirectInputPIDDriver; + count = ARRAY_SIZE(buttons); status = HidP_GetSpecificButtonCaps( HidP_Input, HID_USAGE_PAGE_BUTTON, 0, 0, buttons, &count, preparsed_data ); if (status != HIDP_STATUS_SUCCESS) count = button_count = 0; @@ -1398,6 +1413,67 @@ static BOOL init_data_format( struct hid_joystick *impl, struct hid_value_caps * return DIENUM_CONTINUE; }
+static BOOL init_pid_reports( struct hid_joystick *impl, struct hid_value_caps *caps, + DIDEVICEOBJECTINSTANCEW *instance, void *data ) +{ + struct pid_control_report *device_control = &impl->pid_device_control; + +#define SET_COLLECTION( rep ) \ + do \ + { \ + if (rep->collection) FIXME( "duplicate " #rep " report!\n" ); \ + else rep->collection = DIDFT_GETINSTANCE( instance->dwType ); \ + } while (0) + +#define SET_SUB_COLLECTION( rep, sub ) \ + do { \ + if (instance->wCollectionNumber != rep->collection) \ + FIXME( "unexpected " #rep "." #sub " parent!\n" ); \ + else if (rep->sub) \ + FIXME( "duplicate " #rep "." #sub " collection!\n" ); \ + else \ + rep->sub = DIDFT_GETINSTANCE( instance->dwType ); \ + } while (0) + + if (instance->wUsagePage == HID_USAGE_PAGE_PID) + { + switch (instance->wUsage) + { + case PID_USAGE_DEVICE_CONTROL_REPORT: SET_COLLECTION( device_control ); break; + case PID_USAGE_DEVICE_CONTROL: SET_SUB_COLLECTION( device_control, control_coll ); break; + } + } + +#undef SET_SUB_COLLECTION +#undef SET_COLLECTION + + return DIENUM_CONTINUE; +} + +static BOOL init_pid_caps( struct hid_joystick *impl, struct hid_value_caps *caps, + DIDEVICEOBJECTINSTANCEW *instance, void *data ) +{ + struct pid_control_report *device_control = &impl->pid_device_control; + + if (!(instance->dwType & DIDFT_OUTPUT)) return DIENUM_CONTINUE; + +#define SET_REPORT_ID( rep ) \ + do \ + { \ + if (!rep->id) \ + rep->id = instance->wReportId; \ + else if (rep->id != instance->wReportId) \ + FIXME( "multiple " #rep " report ids!\n" ); \ + } while (0) + + if (instance->wCollectionNumber == device_control->control_coll) + SET_REPORT_ID( device_control ); + +#undef SET_REPORT_ID + + return DIENUM_CONTINUE; +} + static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID *guid, IDirectInputDevice8W **out ) { static const DIPROPHEADER filter = @@ -1485,6 +1561,20 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID impl->usages_buf = usages;
enum_objects( impl, &filter, DIDFT_ALL, init_objects, NULL ); + enum_objects( impl, &filter, DIDFT_COLLECTION, init_pid_reports, NULL ); + enum_objects( impl, &filter, DIDFT_NODATA, init_pid_caps, NULL ); + + TRACE( "device control id %u, coll %u, control coll %u\n", impl->pid_device_control.id, + impl->pid_device_control.collection, impl->pid_device_control.control_coll ); + + if (impl->pid_device_control.id) + { + impl->dev_caps.dwFlags |= DIDC_FORCEFEEDBACK; + impl->dev_caps.dwFFSamplePeriod = 1000000; + impl->dev_caps.dwFFMinTimeResolution = 1000000; + impl->dev_caps.dwHardwareRevision = 1; + impl->dev_caps.dwFFDriverVersion = 1; + }
format = impl->base.data_format.wine_df; if (format->dwDataSize > DEVICE_STATE_MAX_SIZE) diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index e6439ed8fe5..638d8f0aaeb 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -5646,7 +5646,6 @@ static void test_force_feedback_joystick( void ) check_member_wstr( devinst, expect_devinst, tszInstanceName ); todo_wine check_member_wstr( devinst, expect_devinst, tszProductName ); - todo_wine check_member_guid( devinst, expect_devinst, guidFFDriver ); check_member( devinst, expect_devinst, "%04x", wUsagePage ); check_member( devinst, expect_devinst, "%04x", wUsage ); @@ -5655,20 +5654,15 @@ static void test_force_feedback_joystick( void ) hr = IDirectInputDevice8_GetCapabilities( device, &caps ); ok( hr == DI_OK, "IDirectInputDevice8_GetCapabilities returned %#x\n", hr ); check_member( caps, expect_caps, "%d", dwSize ); - todo_wine 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 ); - todo_wine check_member( caps, expect_caps, "%d", dwFFSamplePeriod ); - todo_wine check_member( caps, expect_caps, "%d", dwFFMinTimeResolution ); check_member( caps, expect_caps, "%d", dwFirmwareRevision ); - todo_wine check_member( caps, expect_caps, "%d", dwHardwareRevision ); - todo_wine check_member( caps, expect_caps, "%d", dwFFDriverVersion );
prop_dword.dwData = 0xdeadbeef;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 51 +++++++++++++++++++++++++++++++------- dlls/dinput8/tests/hid.c | 18 +++++++------- 2 files changed, 51 insertions(+), 18 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index b10ce7fc03b..aee8118191f 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -104,6 +104,7 @@ struct hid_joystick struct extra_caps *input_extra_caps;
char *input_report_buf; + char *output_report_buf; USAGE_AND_PAGE *usages_buf; ULONG usages_count;
@@ -369,6 +370,7 @@ static ULONG WINAPI hid_joystick_Release( IDirectInputDevice8W *iface ) if (!(ref = IDirectInputDevice2WImpl_Release( iface ))) { HeapFree( GetProcessHeap(), 0, tmp.usages_buf ); + HeapFree( GetProcessHeap(), 0, tmp.output_report_buf ); HeapFree( GetProcessHeap(), 0, tmp.input_report_buf ); HeapFree( GetProcessHeap(), 0, tmp.input_extra_caps ); HidD_FreePreparsedData( tmp.preparsed ); @@ -833,20 +835,48 @@ static HRESULT WINAPI hid_joystick_GetForceFeedbackState( IDirectInputDevice8W *
static HRESULT WINAPI hid_joystick_SendForceFeedbackCommand( IDirectInputDevice8W *iface, DWORD command ) { - FIXME( "iface %p, command %x stub!\n", iface, command ); + struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); + struct pid_control_report *report = &impl->pid_device_control; + ULONG report_len = impl->caps.OutputReportByteLength; + char *report_buf = impl->output_report_buf; + NTSTATUS status; + USAGE usage; + ULONG count; + HRESULT hr; + + TRACE( "iface %p, flags %x.\n", iface, command );
switch (command) { - case DISFFC_RESET: - case DISFFC_STOPALL: - case DISFFC_PAUSE: - case DISFFC_CONTINUE: - case DISFFC_SETACTUATORSON: - case DISFFC_SETACTUATORSOFF: - return DIERR_UNSUPPORTED; + case DISFFC_RESET: usage = PID_USAGE_DC_DEVICE_RESET; break; + case DISFFC_STOPALL: usage = PID_USAGE_DC_STOP_ALL_EFFECTS; break; + case DISFFC_PAUSE: usage = PID_USAGE_DC_DEVICE_PAUSE; break; + case DISFFC_CONTINUE: usage = PID_USAGE_DC_DEVICE_CONTINUE; break; + case DISFFC_SETACTUATORSON: usage = PID_USAGE_DC_ENABLE_ACTUATORS; break; + case DISFFC_SETACTUATORSOFF: usage = PID_USAGE_DC_DISABLE_ACTUATORS; break; + default: return DIERR_INVALIDPARAM; }
- return DIERR_INVALIDPARAM; + if (!(impl->dev_caps.dwFlags & DIDC_FORCEFEEDBACK)) return DIERR_UNSUPPORTED; + + EnterCriticalSection( &impl->base.crit ); + if (!impl->base.acquired || !(impl->base.dwCoopLevel & DISCL_EXCLUSIVE)) + hr = DIERR_NOTEXCLUSIVEACQUIRED; + else + { + count = 1; + status = HidP_InitializeReportForID( HidP_Output, report->id, impl->preparsed, report_buf, report_len ); + if (status != HIDP_STATUS_SUCCESS) hr = status; + else status = HidP_SetUsages( HidP_Output, HID_USAGE_PAGE_PID, report->control_coll, &usage, + &count, impl->preparsed, report_buf, report_len ); + + if (status != HIDP_STATUS_SUCCESS) hr = status; + else if (WriteFile( impl->device, report_buf, report_len, NULL, NULL )) hr = DI_OK; + else hr = DIERR_GENERIC; + } + LeaveCriticalSection( &impl->base.crit ); + + return hr; }
static HRESULT WINAPI hid_joystick_EnumCreatedEffectObjects( IDirectInputDevice8W *iface, @@ -1555,6 +1585,9 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID size = impl->caps.InputReportByteLength; if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed; impl->input_report_buf = buffer; + size = impl->caps.OutputReportByteLength; + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed; + impl->output_report_buf = buffer; impl->usages_count = HidP_MaxUsageListLength( HidP_Input, 0, impl->preparsed ); size = impl->usages_count * sizeof(USAGE_AND_PAGE); if (!(usages = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed; diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index 638d8f0aaeb..618fb4e4c7c 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -5253,6 +5253,13 @@ static void test_force_feedback_joystick( void ) .dwFFDriverVersion = 1, }; struct hid_expect expect_dc_reset = + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x01}, + }; + struct hid_expect expect_dc_reset_todo = { .code = IOCTL_HID_WRITE_REPORT, .todo = TRUE, @@ -5751,7 +5758,6 @@ static void test_force_feedback_joystick( void ) todo_wine ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "IDirectInputDevice8_GetForceFeedbackState returned %#x\n", hr ); hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); - todo_wine ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr );
escape.dwSize = sizeof(DIEFFESCAPE); @@ -5769,7 +5775,7 @@ static void test_force_feedback_joystick( void ) hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); ok( hr == DI_OK, "IDirectInputDevice8_SetCooperativeLevel returned: %#x\n", hr );
- set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); + set_hid_expect( file, &expect_dc_reset_todo, sizeof(expect_dc_reset_todo) ); hr = IDirectInputDevice8_Acquire( device ); ok( hr == DI_OK, "IDirectInputDevice8_Acquire returned: %#x\n", hr ); set_hid_expect( file, NULL, 0 ); @@ -5792,24 +5798,18 @@ static void test_force_feedback_joystick( void )
set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); - todo_wine ok( hr == DI_OK, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr ); set_hid_expect( file, NULL, 0 );
hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_STOPALL ); - todo_wine ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr ); hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_PAUSE ); - todo_wine ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr ); hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_CONTINUE ); - todo_wine ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr ); hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSON ); - todo_wine ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr ); hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSOFF ); - todo_wine ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr );
objdata.dwOfs = 0x1e; @@ -5821,7 +5821,7 @@ static void test_force_feedback_joystick( void )
test_periodic_effect( device, file );
- set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); + set_hid_expect( file, &expect_dc_reset_todo, sizeof(expect_dc_reset_todo) ); hr = IDirectInputDevice8_Unacquire( device ); ok( hr == DI_OK, "IDirectInputDevice8_Unacquire returned: %#x\n", hr ); set_hid_expect( file, NULL, 0 );
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index aee8118191f..b6c4c960521 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -699,14 +699,18 @@ static HRESULT WINAPI hid_joystick_Acquire( IDirectInputDevice8W *iface )
TRACE( "iface %p.\n", iface );
- if ((hr = IDirectInputDevice2WImpl_Acquire( iface )) != DI_OK) return hr; - - memset( &impl->read_ovl, 0, sizeof(impl->read_ovl) ); - impl->read_ovl.hEvent = impl->base.read_event; - if (ReadFile( impl->device, impl->input_report_buf, report_len, NULL, &impl->read_ovl )) - impl->base.read_callback( iface ); + EnterCriticalSection( &impl->base.crit ); + hr = IDirectInputDevice2WImpl_Acquire( iface ); + if (hr == DI_OK) + { + memset( &impl->read_ovl, 0, sizeof(impl->read_ovl) ); + impl->read_ovl.hEvent = impl->base.read_event; + if (ReadFile( impl->device, impl->input_report_buf, report_len, NULL, &impl->read_ovl )) + impl->base.read_callback( iface ); + } + LeaveCriticalSection( &impl->base.crit );
- return DI_OK; + return hr; }
static HRESULT WINAPI hid_joystick_Unacquire( IDirectInputDevice8W *iface ) @@ -717,12 +721,16 @@ static HRESULT WINAPI hid_joystick_Unacquire( IDirectInputDevice8W *iface )
TRACE( "iface %p.\n", iface );
- if ((hr = IDirectInputDevice2WImpl_Unacquire( iface )) != DI_OK) return hr; - - ret = CancelIoEx( impl->device, &impl->read_ovl ); - if (!ret) WARN( "CancelIoEx failed, last error %u\n", GetLastError() ); + EnterCriticalSection( &impl->base.crit ); + if (impl->base.acquired) + { + ret = CancelIoEx( impl->device, &impl->read_ovl ); + if (!ret) WARN( "CancelIoEx failed, last error %u\n", GetLastError() ); + } + hr = IDirectInputDevice2WImpl_Unacquire( iface ); + LeaveCriticalSection( &impl->base.crit );
- return DI_OK; + return hr; }
static HRESULT WINAPI hid_joystick_GetDeviceState( IDirectInputDevice8W *iface, DWORD len, void *ptr )
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 4 ++++ dlls/dinput8/tests/hid.c | 12 ++---------- 2 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index b6c4c960521..ac67625cddc 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -707,6 +707,8 @@ static HRESULT WINAPI hid_joystick_Acquire( IDirectInputDevice8W *iface ) impl->read_ovl.hEvent = impl->base.read_event; if (ReadFile( impl->device, impl->input_report_buf, report_len, NULL, &impl->read_ovl )) impl->base.read_callback( iface ); + + IDirectInputDevice8_SendForceFeedbackCommand( iface, DISFFC_RESET ); } LeaveCriticalSection( &impl->base.crit );
@@ -726,6 +728,8 @@ static HRESULT WINAPI hid_joystick_Unacquire( IDirectInputDevice8W *iface ) { ret = CancelIoEx( impl->device, &impl->read_ovl ); if (!ret) WARN( "CancelIoEx failed, last error %u\n", GetLastError() ); + + IDirectInputDevice8_SendForceFeedbackCommand( iface, DISFFC_RESET ); } hr = IDirectInputDevice2WImpl_Unacquire( iface ); LeaveCriticalSection( &impl->base.crit ); diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index 618fb4e4c7c..7c46f19cc40 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -5259,14 +5259,6 @@ static void test_force_feedback_joystick( void ) .report_len = 2, .report_buf = {1, 0x01}, }; - struct hid_expect expect_dc_reset_todo = - { - .code = IOCTL_HID_WRITE_REPORT, - .todo = TRUE, - .report_id = 1, - .report_len = 2, - .report_buf = {1, 0x01}, - };
const DIDEVICEINSTANCEW expect_devinst = { @@ -5775,7 +5767,7 @@ static void test_force_feedback_joystick( void ) hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); ok( hr == DI_OK, "IDirectInputDevice8_SetCooperativeLevel returned: %#x\n", hr );
- set_hid_expect( file, &expect_dc_reset_todo, sizeof(expect_dc_reset_todo) ); + set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); hr = IDirectInputDevice8_Acquire( device ); ok( hr == DI_OK, "IDirectInputDevice8_Acquire returned: %#x\n", hr ); set_hid_expect( file, NULL, 0 ); @@ -5821,7 +5813,7 @@ static void test_force_feedback_joystick( void )
test_periodic_effect( device, file );
- set_hid_expect( file, &expect_dc_reset_todo, sizeof(expect_dc_reset_todo) ); + set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) ); hr = IDirectInputDevice8_Unacquire( device ); ok( hr == DI_OK, "IDirectInputDevice8_Unacquire returned: %#x\n", hr ); set_hid_expect( file, NULL, 0 );
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 63 +++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index ac67625cddc..a43ecde0e9c 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -818,10 +818,71 @@ static HRESULT WINAPI hid_joystick_CreateEffect( IDirectInputDevice8W *iface, co static HRESULT WINAPI hid_joystick_EnumEffects( IDirectInputDevice8W *iface, LPDIENUMEFFECTSCALLBACKW callback, void *context, DWORD type ) { - FIXME( "iface %p, callback %p, context %p, type %#x stub!\n", iface, callback, context, type ); + DIEFFECTINFOW info = {.dwSize = sizeof(info)}; + HRESULT hr; + + TRACE( "iface %p, callback %p, context %p, type %#x.\n", iface, callback, context, type );
if (!callback) return DIERR_INVALIDPARAM;
+ type = DIEFT_GETTYPE( type ); + + if (type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE) + { + hr = IDirectInputDevice8_GetEffectInfo( iface, &info, &GUID_ConstantForce ); + if (FAILED(hr) && hr != DIERR_DEVICENOTREG) return hr; + if (hr == DI_OK && callback( &info, context ) == DIENUM_STOP) return DI_OK; + } + + if (type == DIEFT_ALL || type == DIEFT_RAMPFORCE) + { + hr = IDirectInputDevice8_GetEffectInfo( iface, &info, &GUID_RampForce ); + if (FAILED(hr) && hr != DIERR_DEVICENOTREG) return hr; + if (hr == DI_OK && callback( &info, context ) == DIENUM_STOP) return DI_OK; + } + + if (type == DIEFT_ALL || type == DIEFT_PERIODIC) + { + hr = IDirectInputDevice8_GetEffectInfo( iface, &info, &GUID_Square ); + if (FAILED(hr) && hr != DIERR_DEVICENOTREG) return hr; + if (hr == DI_OK && callback( &info, context ) == DIENUM_STOP) return DI_OK; + + hr = IDirectInputDevice8_GetEffectInfo( iface, &info, &GUID_Sine ); + if (FAILED(hr) && hr != DIERR_DEVICENOTREG) return hr; + if (hr == DI_OK && callback( &info, context ) == DIENUM_STOP) return DI_OK; + + hr = IDirectInputDevice8_GetEffectInfo( iface, &info, &GUID_Triangle ); + if (FAILED(hr) && hr != DIERR_DEVICENOTREG) return hr; + if (hr == DI_OK && callback( &info, context ) == DIENUM_STOP) return DI_OK; + + hr = IDirectInputDevice8_GetEffectInfo( iface, &info, &GUID_SawtoothUp ); + if (FAILED(hr) && hr != DIERR_DEVICENOTREG) return hr; + if (hr == DI_OK && callback( &info, context ) == DIENUM_STOP) return DI_OK; + + hr = IDirectInputDevice8_GetEffectInfo( iface, &info, &GUID_SawtoothDown ); + if (FAILED(hr) && hr != DIERR_DEVICENOTREG) return hr; + if (hr == DI_OK && callback( &info, context ) == DIENUM_STOP) return DI_OK; + } + + if (type == DIEFT_ALL || type == DIEFT_CONDITION) + { + hr = IDirectInputDevice8_GetEffectInfo( iface, &info, &GUID_Spring ); + if (FAILED(hr) && hr != DIERR_DEVICENOTREG) return hr; + if (hr == DI_OK && callback( &info, context ) == DIENUM_STOP) return DI_OK; + + hr = IDirectInputDevice8_GetEffectInfo( iface, &info, &GUID_Damper ); + if (FAILED(hr) && hr != DIERR_DEVICENOTREG) return hr; + if (hr == DI_OK && callback( &info, context ) == DIENUM_STOP) return DI_OK; + + hr = IDirectInputDevice8_GetEffectInfo( iface, &info, &GUID_Inertia ); + if (FAILED(hr) && hr != DIERR_DEVICENOTREG) return hr; + if (hr == DI_OK && callback( &info, context ) == DIENUM_STOP) return DI_OK; + + hr = IDirectInputDevice8_GetEffectInfo( iface, &info, &GUID_Friction ); + if (FAILED(hr) && hr != DIERR_DEVICENOTREG) return hr; + if (hr == DI_OK && callback( &info, context ) == DIENUM_STOP) return DI_OK; + } + return DI_OK; }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 169 ++++++++++++++++++++++++++++++++++++- dlls/dinput8/tests/hid.c | 3 +- 2 files changed, 169 insertions(+), 3 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index a43ecde0e9c..8f5dbee9dc3 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -120,6 +120,17 @@ static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputD struct hid_joystick, base ); }
+struct hid_joystick_effect +{ + IDirectInputEffect IDirectInputEffect_iface; + LONG ref; +}; + +static inline struct hid_joystick_effect *impl_from_IDirectInputEffect( IDirectInputEffect *iface ) +{ + return CONTAINING_RECORD( iface, struct hid_joystick_effect, IDirectInputEffect_iface ); +} + static const GUID *object_usage_to_guid( USAGE usage_page, USAGE usage ) { switch (usage_page) @@ -803,16 +814,39 @@ static HRESULT WINAPI hid_joystick_GetDeviceInfo( IDirectInputDevice8W *iface, D return S_OK; }
+static HRESULT hid_joystick_effect_create( IDirectInputEffect **out ); + static HRESULT WINAPI hid_joystick_CreateEffect( IDirectInputDevice8W *iface, const GUID *guid, const DIEFFECT *params, IDirectInputEffect **out, IUnknown *outer ) { - FIXME( "iface %p, guid %s, params %p, out %p, outer %p stub!\n", iface, debugstr_guid( guid ), + struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); + DWORD flags = DIEP_ALLPARAMS; + HRESULT hr; + + TRACE( "iface %p, guid %s, params %p, out %p, outer %p\n", iface, debugstr_guid( guid ), params, out, outer );
if (!out) return E_POINTER; + *out = NULL;
- return DIERR_UNSUPPORTED; + if (!(impl->dev_caps.dwFlags & DIDC_FORCEFEEDBACK)) return DIERR_UNSUPPORTED; + if (FAILED(hr = hid_joystick_effect_create( out ))) return hr; + + hr = IDirectInputEffect_Initialize( *out, DINPUT_instance, impl->base.dinput->dwVersion, guid ); + if (FAILED(hr)) goto failed; + + if (!params) return DI_OK; + if (!impl->base.acquired || !(impl->base.dwCoopLevel & DISCL_EXCLUSIVE)) + flags |= DIEP_NODOWNLOAD; + hr = IDirectInputEffect_SetParameters( *out, params, flags ); + if (FAILED(hr)) goto failed; + return hr; + +failed: + IDirectInputEffect_Release( *out ); + *out = NULL; + return hr; }
static HRESULT WINAPI hid_joystick_EnumEffects( IDirectInputDevice8W *iface, LPDIENUMEFFECTSCALLBACKW callback, @@ -1721,3 +1755,134 @@ const struct dinput_device joystick_hid_device = hid_joystick_enum_device, hid_joystick_create_device, }; + +static HRESULT WINAPI hid_joystick_effect_QueryInterface( IDirectInputEffect *iface, REFIID iid, void **out ) +{ + TRACE( "iface %p, iid %s, out %p\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IDirectInputEffect )) + { + IDirectInputEffect_AddRef( iface ); + *out = iface; + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI hid_joystick_effect_AddRef( IDirectInputEffect *iface ) +{ + struct hid_joystick_effect *impl = impl_from_IDirectInputEffect( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %u.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI hid_joystick_effect_Release( IDirectInputEffect *iface ) +{ + struct hid_joystick_effect *impl = impl_from_IDirectInputEffect( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %u.\n", iface, ref ); + if (!ref) HeapFree( GetProcessHeap(), 0, impl ); + return ref; +} + +static HRESULT WINAPI hid_joystick_effect_Initialize( IDirectInputEffect *iface, HINSTANCE inst, + DWORD version, REFGUID guid ) +{ + FIXME( "iface %p, inst %p, version %u, guid %s stub!\n", iface, inst, version, debugstr_guid( guid ) ); + return DI_OK; +} + +static HRESULT WINAPI hid_joystick_effect_GetEffectGuid( IDirectInputEffect *iface, GUID *guid ) +{ + FIXME( "iface %p, guid %p stub!\n", iface, guid ); + return DIERR_UNSUPPORTED; +} + +static HRESULT WINAPI hid_joystick_effect_GetParameters( IDirectInputEffect *iface, DIEFFECT *params, DWORD flags ) +{ + FIXME( "iface %p, params %p, flags %#x stub!\n", iface, params, flags ); + return DIERR_UNSUPPORTED; +} + +static HRESULT WINAPI hid_joystick_effect_SetParameters( IDirectInputEffect *iface, + const DIEFFECT *params, DWORD flags ) +{ + FIXME( "iface %p, params %p, flags %#x stub!\n", iface, params, flags ); + return DIERR_UNSUPPORTED; +} + +static HRESULT WINAPI hid_joystick_effect_Start( IDirectInputEffect *iface, DWORD iterations, DWORD flags ) +{ + FIXME( "iface %p, iterations %u, flags %#x stub!\n", iface, iterations, flags ); + return DIERR_UNSUPPORTED; +} + +static HRESULT WINAPI hid_joystick_effect_Stop( IDirectInputEffect *iface ) +{ + FIXME( "iface %p stub!\n", iface ); + return DIERR_UNSUPPORTED; +} + +static HRESULT WINAPI hid_joystick_effect_GetEffectStatus( IDirectInputEffect *iface, DWORD *status ) +{ + FIXME( "iface %p, status %p stub!\n", iface, status ); + + if (!status) return E_POINTER; + + return DIERR_UNSUPPORTED; +} + +static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) +{ + FIXME( "iface %p stub!\n", iface ); + return DIERR_UNSUPPORTED; +} + +static HRESULT WINAPI hid_joystick_effect_Unload( IDirectInputEffect *iface ) +{ + FIXME( "iface %p stub!\n", iface ); + return DIERR_UNSUPPORTED; +} + +static HRESULT WINAPI hid_joystick_effect_Escape( IDirectInputEffect *iface, DIEFFESCAPE *escape ) +{ + FIXME( "iface %p, escape %p stub!\n", iface, escape ); + return DIERR_UNSUPPORTED; +} + +static IDirectInputEffectVtbl hid_joystick_effect_vtbl = +{ + /*** IUnknown methods ***/ + hid_joystick_effect_QueryInterface, + hid_joystick_effect_AddRef, + hid_joystick_effect_Release, + /*** IDirectInputEffect methods ***/ + hid_joystick_effect_Initialize, + hid_joystick_effect_GetEffectGuid, + hid_joystick_effect_GetParameters, + hid_joystick_effect_SetParameters, + hid_joystick_effect_Start, + hid_joystick_effect_Stop, + hid_joystick_effect_GetEffectStatus, + hid_joystick_effect_Download, + hid_joystick_effect_Unload, + hid_joystick_effect_Escape, +}; + +static HRESULT hid_joystick_effect_create( IDirectInputEffect **out ) +{ + struct hid_joystick_effect *impl; + + if (!(impl = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*impl) ))) + return DIERR_OUTOFMEMORY; + impl->IDirectInputEffect_iface.lpVtbl = &hid_joystick_effect_vtbl; + impl->ref = 1; + + *out = &impl->IDirectInputEffect_iface; + return DI_OK; +} diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index 7c46f19cc40..e83cc8a3f7b 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -5066,12 +5066,13 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file ) hr = IDirectInputDevice8_CreateEffect( device, NULL, NULL, &effect, NULL ); todo_wine ok( hr == E_POINTER, "IDirectInputDevice8_CreateEffect returned %#x\n", hr ); + if (hr == DI_OK) IDirectInputEffect_Release( effect ); hr = IDirectInputDevice8_CreateEffect( device, &GUID_NULL, NULL, &effect, NULL ); todo_wine ok( hr == DIERR_DEVICENOTREG, "IDirectInputDevice8_CreateEffect returned %#x\n", hr ); + if (hr == DI_OK) IDirectInputEffect_Release( effect );
hr = IDirectInputDevice8_CreateEffect( device, &GUID_Sine, NULL, &effect, NULL ); - todo_wine ok( hr == DI_OK, "IDirectInputDevice8_CreateEffect returned %#x\n", hr ); if (hr != DI_OK) return;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/bus_sdl.c | 48 +++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index bd06717165d..772ee092c83 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -47,10 +47,11 @@ #include "ddk/wdm.h" #include "ddk/hidtypes.h" #include "ddk/hidsdi.h" -#include "wine/debug.h" -#include "wine/unicode.h" #include "hidusage.h"
+#include "wine/debug.h" +#include "wine/hid.h" + #include "unix_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(plugplay); @@ -95,12 +96,15 @@ MAKE_FUNCPTR(SDL_HapticClose); MAKE_FUNCPTR(SDL_HapticDestroyEffect); MAKE_FUNCPTR(SDL_HapticNewEffect); MAKE_FUNCPTR(SDL_HapticOpenFromJoystick); +MAKE_FUNCPTR(SDL_HapticPause); MAKE_FUNCPTR(SDL_HapticQuery); MAKE_FUNCPTR(SDL_HapticRumbleInit); MAKE_FUNCPTR(SDL_HapticRumblePlay); MAKE_FUNCPTR(SDL_HapticRumbleSupported); MAKE_FUNCPTR(SDL_HapticRunEffect); +MAKE_FUNCPTR(SDL_HapticSetGain); MAKE_FUNCPTR(SDL_HapticStopAll); +MAKE_FUNCPTR(SDL_HapticUnpause); MAKE_FUNCPTR(SDL_JoystickIsHaptic); MAKE_FUNCPTR(SDL_GameControllerAddMapping); MAKE_FUNCPTR(SDL_RegisterEvents); @@ -130,6 +134,7 @@ struct sdl_device DWORD effect_support; SDL_Haptic *sdl_haptic; int haptic_effect_id; + int effect_ids[256]; };
static inline struct sdl_device *impl_from_unix_device(struct unix_device *iface) @@ -168,6 +173,8 @@ static void set_hat_value(struct unix_device *iface, int index, int value)
static BOOL descriptor_add_haptic(struct sdl_device *impl) { + USHORT i; + if (!pSDL_JoystickIsHaptic(impl->sdl_joystick) || !(impl->sdl_haptic = pSDL_HapticOpenFromJoystick(impl->sdl_joystick))) impl->effect_support = 0; @@ -197,6 +204,7 @@ static BOOL descriptor_add_haptic(struct sdl_device *impl) }
impl->haptic_effect_id = -1; + for (i = 0; i < ARRAY_SIZE(impl->effect_ids); ++i) impl->effect_ids[i] = -1; return TRUE; }
@@ -400,7 +408,38 @@ NTSTATUS sdl_device_haptics_start(struct unix_device *iface, DWORD duration_ms,
static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, USAGE control) { - FIXME("iface %p, control %#04x stub\n", iface, control); + struct sdl_device *impl = impl_from_unix_device(iface); + unsigned int i; + + TRACE("iface %p, control %#04x.\n", iface, control); + + switch (control) + { + case PID_USAGE_DC_ENABLE_ACTUATORS: + pSDL_HapticSetGain(impl->sdl_haptic, 100); + return STATUS_SUCCESS; + case PID_USAGE_DC_DISABLE_ACTUATORS: + pSDL_HapticSetGain(impl->sdl_haptic, 0); + return STATUS_SUCCESS; + case PID_USAGE_DC_STOP_ALL_EFFECTS: + pSDL_HapticStopAll(impl->sdl_haptic); + return STATUS_SUCCESS; + case PID_USAGE_DC_DEVICE_RESET: + pSDL_HapticStopAll(impl->sdl_haptic); + for (i = 0; i < ARRAY_SIZE(impl->effect_ids); ++i) + { + if (impl->effect_ids[i] < 0) continue; + pSDL_HapticDestroyEffect(impl->sdl_haptic, impl->effect_ids[i]); + impl->effect_ids[i] = -1; + } + return STATUS_SUCCESS; + case PID_USAGE_DC_DEVICE_PAUSE: + pSDL_HapticPause(impl->sdl_haptic); + return STATUS_SUCCESS; + case PID_USAGE_DC_DEVICE_CONTINUE: + pSDL_HapticUnpause(impl->sdl_haptic); + return STATUS_SUCCESS; + }
return STATUS_NOT_SUPPORTED; } @@ -665,12 +704,15 @@ NTSTATUS sdl_bus_init(void *args) LOAD_FUNCPTR(SDL_HapticDestroyEffect); LOAD_FUNCPTR(SDL_HapticNewEffect); LOAD_FUNCPTR(SDL_HapticOpenFromJoystick); + LOAD_FUNCPTR(SDL_HapticPause); LOAD_FUNCPTR(SDL_HapticQuery); LOAD_FUNCPTR(SDL_HapticRumbleInit); LOAD_FUNCPTR(SDL_HapticRumblePlay); LOAD_FUNCPTR(SDL_HapticRumbleSupported); LOAD_FUNCPTR(SDL_HapticRunEffect); + LOAD_FUNCPTR(SDL_HapticSetGain); LOAD_FUNCPTR(SDL_HapticStopAll); + LOAD_FUNCPTR(SDL_HapticUnpause); LOAD_FUNCPTR(SDL_JoystickIsHaptic); LOAD_FUNCPTR(SDL_GameControllerAddMapping); LOAD_FUNCPTR(SDL_RegisterEvents);
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/bus_udev.c | 60 ++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 4 deletions(-)
diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index e4c0103b270..454ab3ea870 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -70,9 +70,9 @@ #include "ddk/wdm.h" #include "ddk/hidtypes.h" #include "ddk/hidsdi.h" + #include "wine/debug.h" -#include "wine/heap.h" -#include "wine/unicode.h" +#include "wine/hid.h"
#ifdef HAS_PROPER_INPUT_HEADER # include "hidusage.h" @@ -140,6 +140,7 @@ struct lnxev_device BYTE button_map[KEY_MAX];
int haptic_effect_id; + int effect_ids[256]; };
static inline struct lnxev_device *lnxev_impl_from_unix_device(struct unix_device *iface) @@ -642,6 +643,8 @@ static NTSTATUS build_report_descriptor(struct unix_device *iface, struct udev_d return STATUS_NO_MEMORY;
impl->haptic_effect_id = -1; + for (i = 0; i < ARRAY_SIZE(impl->effect_ids); ++i) impl->effect_ids[i] = -1; + if (test_bit(ffbits, FF_RUMBLE)) { effect.id = -1; @@ -811,9 +814,58 @@ static NTSTATUS lnxev_device_haptics_start(struct unix_device *iface, DWORD dura
static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface, USAGE control) { - FIXME("iface %p, control %#04x stub!\n", iface, control); + struct lnxev_device *impl = lnxev_impl_from_unix_device(iface); + unsigned int i;
- return STATUS_NOT_IMPLEMENTED; + TRACE("iface %p, control %#04x.\n", iface, control); + + switch (control) + { + case PID_USAGE_DC_ENABLE_ACTUATORS: + { + struct input_event ie = + { + .type = EV_FF, + .code = FF_GAIN, + .value = 0xffff, + }; + if (write(impl->base.device_fd, &ie, sizeof(ie)) == -1) + WARN("write failed %d %s\n", errno, strerror(errno)); + return STATUS_SUCCESS; + } + case PID_USAGE_DC_DISABLE_ACTUATORS: + { + struct input_event ie = + { + .type = EV_FF, + .code = FF_GAIN, + .value = 0, + }; + if (write(impl->base.device_fd, &ie, sizeof(ie)) == -1) + WARN("write failed %d %s\n", errno, strerror(errno)); + return STATUS_SUCCESS; + } + case PID_USAGE_DC_STOP_ALL_EFFECTS: + FIXME("stop all not implemented!\n"); + return STATUS_NOT_IMPLEMENTED; + case PID_USAGE_DC_DEVICE_RESET: + for (i = 0; i < ARRAY_SIZE(impl->effect_ids); ++i) + { + if (impl->effect_ids[i] < 0) continue; + if (ioctl(impl->base.device_fd, EVIOCRMFF, impl->effect_ids[i]) == -1) + WARN("couldn't free effect, EVIOCRMFF ioctl failed: %d %s\n", errno, strerror(errno)); + impl->effect_ids[i] = -1; + } + return STATUS_SUCCESS; + case PID_USAGE_DC_DEVICE_PAUSE: + WARN("device pause not supported\n"); + return STATUS_NOT_SUPPORTED; + case PID_USAGE_DC_DEVICE_CONTINUE: + WARN("device continue not supported\n"); + return STATUS_NOT_SUPPORTED; + } + + return STATUS_NOT_SUPPORTED; }
static const struct hid_device_vtbl lnxev_device_vtbl =