Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/xinput1_3/main.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c index e669fa0af71..2179da1db72 100644 --- a/dlls/xinput1_3/main.c +++ b/dlls/xinput1_3/main.c @@ -81,6 +81,8 @@ struct xinput_controller char *feature_report_buf;
BYTE haptics_report; + BYTE haptics_none_ordinal; + BYTE haptics_stop_ordinal; BYTE haptics_rumble_ordinal; BYTE haptics_buzz_ordinal; } hid; @@ -244,6 +246,8 @@ static BOOL controller_check_caps(struct xinput_controller *controller, HANDLE d return TRUE; }
+ controller->hid.haptics_none_ordinal = 1; /* implicit None waveform ordinal, from the HID spec */ + controller->hid.haptics_stop_ordinal = 2; /* implicit Stop waveform ordinal, from the HID spec */ controller->hid.haptics_buzz_ordinal = 0; controller->hid.haptics_rumble_ordinal = 0; for (i = 3; status == HIDP_STATUS_SUCCESS; ++i) @@ -291,6 +295,22 @@ static DWORD HID_set_state(struct xinput_controller *controller, XINPUT_VIBRATIO
if (!controller->enabled) return ERROR_SUCCESS;
+ if (!state->wLeftMotorSpeed && !state->wRightMotorSpeed) + { + status = HidP_InitializeReportForID(HidP_Output, report_id, preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_InitializeReportForID returned %#lx\n", status); + status = HidP_SetUsageValue(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_MANUAL_TRIGGER, + controller->hid.haptics_stop_ordinal, preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue MANUAL_TRIGGER returned %#lx\n", status); + if (!HidD_SetOutputReport(controller->device, report_buf, report_len)) + { + WARN("HidD_SetOutputReport failed with error %lu\n", GetLastError()); + return GetLastError(); + } + + return 0; + } + /* send haptics rumble report (left motor) */ status = HidP_InitializeReportForID(HidP_Output, report_id, preparsed, report_buf, report_len); if (status != HIDP_STATUS_SUCCESS) WARN("HidP_InitializeReportForID returned %#lx\n", status);
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/bus_sdl.c | 29 +++++++++++++++++------------ dlls/winebus.sys/bus_udev.c | 24 ++++++++++++++++++++++++ dlls/winebus.sys/hid.c | 10 +++++++--- dlls/winebus.sys/unix_private.h | 1 + dlls/winebus.sys/unixlib.c | 12 ++++++++++++ 5 files changed, 61 insertions(+), 15 deletions(-)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 7fc95b54f95..93ba58ec9d6 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -417,18 +417,6 @@ NTSTATUS sdl_device_haptics_start(struct unix_device *iface, UINT duration_ms, effect.leftright.large_magnitude = rumble_intensity; effect.leftright.small_magnitude = buzz_intensity;
- if (!effect.leftright.large_magnitude && !effect.leftright.small_magnitude) - { - if (impl->effect_support & SDL_HAPTIC_LEFTRIGHT) - pSDL_HapticStopAll(impl->sdl_haptic); - else if (impl->effect_support & WINE_SDL_HAPTIC_RUMBLE) - pSDL_HapticRumbleStop(impl->sdl_haptic); - else if (impl->effect_support & WINE_SDL_JOYSTICK_RUMBLE) - pSDL_JoystickRumble(impl->sdl_joystick, 0, 0, 0); - - return STATUS_SUCCESS; - } - if (impl->effect_support & SDL_HAPTIC_LEFTRIGHT) { if (impl->haptic_effect_id >= 0) @@ -451,6 +439,22 @@ NTSTATUS sdl_device_haptics_start(struct unix_device *iface, UINT duration_ms, return STATUS_SUCCESS; }
+NTSTATUS sdl_device_haptics_stop(struct unix_device *iface) +{ + struct sdl_device *impl = impl_from_unix_device(iface); + + TRACE("iface %p.\n", iface); + + if (impl->effect_support & SDL_HAPTIC_LEFTRIGHT) + pSDL_HapticStopAll(impl->sdl_haptic); + else if (impl->effect_support & WINE_SDL_HAPTIC_RUMBLE) + pSDL_HapticRumbleStop(impl->sdl_haptic); + else if (impl->effect_support & WINE_SDL_JOYSTICK_RUMBLE) + pSDL_JoystickRumble(impl->sdl_joystick, 0, 0, 0); + + return STATUS_SUCCESS; +} + static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, USAGE control) { struct sdl_device *impl = impl_from_unix_device(iface); @@ -695,6 +699,7 @@ static const struct hid_device_vtbl sdl_device_vtbl = sdl_device_start, sdl_device_stop, sdl_device_haptics_start, + sdl_device_haptics_stop, sdl_device_physical_device_control, sdl_device_physical_device_set_gain, sdl_device_physical_effect_control, diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 9881b625086..08034c8a07e 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -906,6 +906,29 @@ static NTSTATUS lnxev_device_haptics_start(struct unix_device *iface, UINT durat return STATUS_SUCCESS; }
+static NTSTATUS lnxev_device_haptics_stop(struct unix_device *iface) +{ + struct lnxev_device *impl = lnxev_impl_from_unix_device(iface); + struct ff_effect effect = + { + .id = impl->haptic_effect_id, + .type = FF_RUMBLE, + }; + struct input_event event; + + TRACE("iface %p.\n", iface); + + if (effect.id == -1) return STATUS_SUCCESS; + + event.type = EV_FF; + event.code = effect.id; + event.value = 0; + if (write(impl->base.device_fd, &event, sizeof(event)) == -1) + WARN("couldn't stop haptics rumble effect: %d %s\n", errno, strerror(errno)); + + return STATUS_SUCCESS; +} + static NTSTATUS lnxev_device_physical_effect_run(struct lnxev_device *impl, BYTE index, int iterations) { @@ -1185,6 +1208,7 @@ static const struct hid_device_vtbl lnxev_device_vtbl = lnxev_device_start, lnxev_device_stop, lnxev_device_haptics_start, + lnxev_device_haptics_stop, lnxev_device_physical_device_control, lnxev_device_physical_device_set_gain, lnxev_device_physical_effect_control, diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index ec2250fbe80..529ca97aa7a 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -1050,12 +1050,16 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC else { if (waveform->manual_trigger == HAPTICS_WAVEFORM_STOP_ORDINAL) + { memset(haptics->waveforms, 0, sizeof(haptics->waveforms)); + io->Status = iface->hid_vtbl->haptics_stop(iface); + } else + { haptics->waveforms[waveform->manual_trigger] = *waveform; - - duration_ms = haptics->features.waveform_cutoff_time_ms; - io->Status = iface->hid_vtbl->haptics_start(iface, duration_ms, rumble->intensity, buzz->intensity); + duration_ms = haptics->features.waveform_cutoff_time_ms; + io->Status = iface->hid_vtbl->haptics_start(iface, duration_ms, rumble->intensity, buzz->intensity); + } } } else if (packet->reportId == physical->device_control_report) diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 74c1f4c092a..6b498c46ad7 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -107,6 +107,7 @@ struct hid_device_vtbl void (*stop)(struct unix_device *iface); NTSTATUS (*haptics_start)(struct unix_device *iface, UINT duration_ms, USHORT rumble_intensity, USHORT buzz_intensity); + NTSTATUS (*haptics_stop)(struct unix_device *iface); NTSTATUS (*physical_device_control)(struct unix_device *iface, USAGE control); NTSTATUS (*physical_device_set_gain)(struct unix_device *iface, BYTE percent); NTSTATUS (*physical_effect_control)(struct unix_device *iface, BYTE index, USAGE control, BYTE iterations); diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index 96bd41e67f7..f251e8e6af7 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -107,6 +107,11 @@ static NTSTATUS mouse_haptics_start(struct unix_device *iface, UINT duration, return STATUS_NOT_SUPPORTED; }
+static NTSTATUS mouse_haptics_stop(struct unix_device *iface) +{ + return STATUS_NOT_SUPPORTED; +} + static NTSTATUS mouse_physical_device_control(struct unix_device *iface, USAGE control) { return STATUS_NOT_SUPPORTED; @@ -135,6 +140,7 @@ static const struct hid_device_vtbl mouse_vtbl = mouse_start, mouse_stop, mouse_haptics_start, + mouse_haptics_stop, mouse_physical_device_control, mouse_physical_device_set_gain, mouse_physical_effect_control, @@ -190,6 +196,11 @@ static NTSTATUS keyboard_haptics_start(struct unix_device *iface, UINT duration, return STATUS_NOT_SUPPORTED; }
+static NTSTATUS keyboard_haptics_stop(struct unix_device *iface) +{ + return STATUS_NOT_SUPPORTED; +} + static NTSTATUS keyboard_physical_device_control(struct unix_device *iface, USAGE control) { return STATUS_NOT_SUPPORTED; @@ -218,6 +229,7 @@ static const struct hid_device_vtbl keyboard_vtbl = keyboard_start, keyboard_stop, keyboard_haptics_start, + keyboard_haptics_stop, keyboard_physical_device_control, keyboard_physical_device_set_gain, keyboard_physical_effect_control,
And only keep previously set waveform intensity in the device state.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/hid.c | 40 ++++++++++++++++++++------------- dlls/winebus.sys/unix_private.h | 8 +------ 2 files changed, 25 insertions(+), 23 deletions(-)
diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index 529ca97aa7a..d308e7f276b 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -309,6 +309,14 @@ BOOL hid_device_add_axes(struct unix_device *iface, BYTE count, USAGE usage_page return TRUE; }
+#include "pshpack1.h" +struct hid_haptics_waveform +{ + UINT16 intensity; + BYTE manual_trigger; +}; +#include "poppack.h" + BOOL hid_device_add_haptics(struct unix_device *iface) { struct hid_report_descriptor *desc = &iface->hid_report_descriptor; @@ -352,19 +360,19 @@ BOOL hid_device_add_haptics(struct unix_device *iface) UNIT_EXPONENT(1, 0),
REPORT_ID(1, haptics_waveform_report), - USAGE(1, HID_USAGE_HAPTICS_MANUAL_TRIGGER), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 4), - REPORT_SIZE(1, 16), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - USAGE(1, HID_USAGE_HAPTICS_INTENSITY), LOGICAL_MINIMUM(4, 0x00000000), LOGICAL_MAXIMUM(4, 0x0000ffff), REPORT_SIZE(1, 16), REPORT_COUNT(1, 1), OUTPUT(1, Data|Var|Abs), + + USAGE(1, HID_USAGE_HAPTICS_MANUAL_TRIGGER), + LOGICAL_MINIMUM(1, HAPTICS_WAVEFORM_NONE_ORDINAL), + LOGICAL_MAXIMUM(1, HAPTICS_WAVEFORM_LAST_ORDINAL), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), END_COLLECTION, };
@@ -1037,28 +1045,28 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC
if (packet->reportId == haptics->waveform_report) { - struct hid_haptics_waveform *waveform = (struct hid_haptics_waveform *)(packet->reportBuffer + 1); - struct hid_haptics_waveform *rumble = haptics->waveforms + HAPTICS_WAVEFORM_RUMBLE_ORDINAL; - struct hid_haptics_waveform *buzz = haptics->waveforms + HAPTICS_WAVEFORM_BUZZ_ORDINAL; + struct hid_haptics_waveform *report = (struct hid_haptics_waveform *)(packet->reportBuffer + 1); + UINT16 *rumble_intensity = haptics->waveform_intensity + HAPTICS_WAVEFORM_RUMBLE_ORDINAL; + UINT16 *buzz_intensity = haptics->waveform_intensity + HAPTICS_WAVEFORM_BUZZ_ORDINAL; ULONG duration_ms;
- io->Information = sizeof(*waveform) + 1; + io->Information = sizeof(*report) + 1; assert(packet->reportBufferLen == io->Information);
- if (waveform->manual_trigger == 0 || waveform->manual_trigger > HAPTICS_WAVEFORM_LAST_ORDINAL) + if (report->manual_trigger == 0 || report->manual_trigger > HAPTICS_WAVEFORM_LAST_ORDINAL) io->Status = STATUS_INVALID_PARAMETER; else { - if (waveform->manual_trigger == HAPTICS_WAVEFORM_STOP_ORDINAL) + if (report->manual_trigger == HAPTICS_WAVEFORM_STOP_ORDINAL) { - memset(haptics->waveforms, 0, sizeof(haptics->waveforms)); + memset(haptics->waveform_intensity, 0, sizeof(haptics->waveform_intensity)); io->Status = iface->hid_vtbl->haptics_stop(iface); } else { - haptics->waveforms[waveform->manual_trigger] = *waveform; + haptics->waveform_intensity[report->manual_trigger] = report->intensity; duration_ms = haptics->features.waveform_cutoff_time_ms; - io->Status = iface->hid_vtbl->haptics_start(iface, duration_ms, rumble->intensity, buzz->intensity); + io->Status = iface->hid_vtbl->haptics_start(iface, duration_ms, *rumble_intensity, *buzz_intensity); } } } diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 6b498c46ad7..04545b7eb98 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -144,16 +144,10 @@ struct hid_haptics_features UINT waveform_cutoff_time_ms; };
-struct hid_haptics_waveform -{ - WORD manual_trigger; - WORD intensity; -}; - struct hid_haptics { struct hid_haptics_features features; - struct hid_haptics_waveform waveforms[HAPTICS_WAVEFORM_LAST_ORDINAL + 1]; + UINT16 waveform_intensity[HAPTICS_WAVEFORM_LAST_ORDINAL + 1]; BYTE features_report; BYTE waveform_report; };
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/hid.c | 11 ++++++++++- dlls/xinput1_3/main.c | 6 ++++++ 2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index d308e7f276b..1b2681fdb94 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -314,6 +314,7 @@ struct hid_haptics_waveform { UINT16 intensity; BYTE manual_trigger; + BYTE repeat_count; }; #include "poppack.h"
@@ -373,6 +374,13 @@ BOOL hid_device_add_haptics(struct unix_device *iface) REPORT_SIZE(1, 8), REPORT_COUNT(1, 1), OUTPUT(1, Data|Var|Abs), + + USAGE(1, HID_USAGE_HAPTICS_REPEAT_COUNT), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), END_COLLECTION, };
@@ -1066,7 +1074,8 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC { haptics->waveform_intensity[report->manual_trigger] = report->intensity; duration_ms = haptics->features.waveform_cutoff_time_ms; - io->Status = iface->hid_vtbl->haptics_start(iface, duration_ms, *rumble_intensity, *buzz_intensity); + if (!report->repeat_count) io->Status = STATUS_SUCCESS; + else io->Status = iface->hid_vtbl->haptics_start(iface, duration_ms, *rumble_intensity, *buzz_intensity); } } } diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c index 2179da1db72..bc0baa21ebf 100644 --- a/dlls/xinput1_3/main.c +++ b/dlls/xinput1_3/main.c @@ -320,6 +320,9 @@ static DWORD HID_set_state(struct xinput_controller *controller, XINPUT_VIBRATIO status = HidP_SetUsageValue(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_MANUAL_TRIGGER, controller->hid.haptics_rumble_ordinal, preparsed, report_buf, report_len); if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue MANUAL_TRIGGER returned %#lx\n", status); + status = HidP_SetUsageValue(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_REPEAT_COUNT, + 1, preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue REPEAT_COUNT returned %#lx\n", status); if (!HidD_SetOutputReport(controller->device, report_buf, report_len)) { WARN("HidD_SetOutputReport failed with error %lu\n", GetLastError()); @@ -335,6 +338,9 @@ static DWORD HID_set_state(struct xinput_controller *controller, XINPUT_VIBRATIO status = HidP_SetUsageValue(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_MANUAL_TRIGGER, controller->hid.haptics_buzz_ordinal, preparsed, report_buf, report_len); if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue MANUAL_TRIGGER returned %#lx\n", status); + status = HidP_SetUsageValue(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_REPEAT_COUNT, + 1, preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue REPEAT_COUNT returned %#lx\n", status); if (!HidD_SetOutputReport(controller->device, report_buf, report_len)) { WARN("HidD_SetOutputReport failed with error %lu\n", GetLastError());
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/xinput1_3/main.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c index bc0baa21ebf..2966028491e 100644 --- a/dlls/xinput1_3/main.c +++ b/dlls/xinput1_3/main.c @@ -321,7 +321,7 @@ static DWORD HID_set_state(struct xinput_controller *controller, XINPUT_VIBRATIO controller->hid.haptics_rumble_ordinal, preparsed, report_buf, report_len); if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue MANUAL_TRIGGER returned %#lx\n", status); status = HidP_SetUsageValue(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_REPEAT_COUNT, - 1, preparsed, report_buf, report_len); + 0, preparsed, report_buf, report_len); if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue REPEAT_COUNT returned %#lx\n", status); if (!HidD_SetOutputReport(controller->device, report_buf, report_len)) { @@ -338,6 +338,21 @@ static DWORD HID_set_state(struct xinput_controller *controller, XINPUT_VIBRATIO status = HidP_SetUsageValue(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_MANUAL_TRIGGER, controller->hid.haptics_buzz_ordinal, preparsed, report_buf, report_len); if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue MANUAL_TRIGGER returned %#lx\n", status); + status = HidP_SetUsageValue(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_REPEAT_COUNT, + 0, preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue REPEAT_COUNT returned %#lx\n", status); + if (!HidD_SetOutputReport(controller->device, report_buf, report_len)) + { + WARN("HidD_SetOutputReport failed with error %lu\n", GetLastError()); + return GetLastError(); + } + + /* trigger haptics waveforms */ + status = HidP_InitializeReportForID(HidP_Output, report_id, preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_InitializeReportForID returned %#lx\n", status); + status = HidP_SetUsageValue(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_MANUAL_TRIGGER, + controller->hid.haptics_none_ordinal, preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue MANUAL_TRIGGER returned %#lx\n", status); status = HidP_SetUsageValue(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_REPEAT_COUNT, 1, preparsed, report_buf, report_len); if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue REPEAT_COUNT returned %#lx\n", status);