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 =