It's been introduced in SDL2 2.0.9, released on 2018/10/31.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/bus_sdl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 31915a9fa0d..f71da77b77e 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -102,11 +102,11 @@ MAKE_FUNCPTR(SDL_HapticRumbleSupported); MAKE_FUNCPTR(SDL_HapticRunEffect); MAKE_FUNCPTR(SDL_HapticStopAll); MAKE_FUNCPTR(SDL_JoystickIsHaptic); -MAKE_FUNCPTR(SDL_JoystickRumble); MAKE_FUNCPTR(SDL_memset); MAKE_FUNCPTR(SDL_GameControllerAddMapping); MAKE_FUNCPTR(SDL_RegisterEvents); MAKE_FUNCPTR(SDL_PushEvent); +static int (*pSDL_JoystickRumble)(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms); static Uint16 (*pSDL_JoystickGetProduct)(SDL_Joystick * joystick); static Uint16 (*pSDL_JoystickGetProductVersion)(SDL_Joystick * joystick); static Uint16 (*pSDL_JoystickGetVendor)(SDL_Joystick * joystick); @@ -181,7 +181,7 @@ static BOOL descriptor_add_haptic(struct sdl_device *impl) pSDL_HapticRumbleInit(impl->sdl_haptic); }
- if (!pSDL_JoystickRumble(impl->sdl_joystick, 0, 0, 0)) + if (pSDL_JoystickRumble && !pSDL_JoystickRumble(impl->sdl_joystick, 0, 0, 0)) impl->effect_support |= WINE_SDL_JOYSTICK_RUMBLE;
if (impl->effect_support & EFFECT_SUPPORT_HAPTICS) @@ -658,12 +658,12 @@ NTSTATUS sdl_bus_init(void *args) LOAD_FUNCPTR(SDL_HapticRunEffect); LOAD_FUNCPTR(SDL_HapticStopAll); LOAD_FUNCPTR(SDL_JoystickIsHaptic); - LOAD_FUNCPTR(SDL_JoystickRumble); LOAD_FUNCPTR(SDL_memset); LOAD_FUNCPTR(SDL_GameControllerAddMapping); LOAD_FUNCPTR(SDL_RegisterEvents); LOAD_FUNCPTR(SDL_PushEvent); #undef LOAD_FUNCPTR + pSDL_JoystickRumble = dlsym(sdl_handle, "SDL_JoystickRumble"); pSDL_JoystickGetProduct = dlsym(sdl_handle, "SDL_JoystickGetProduct"); pSDL_JoystickGetProductVersion = dlsym(sdl_handle, "SDL_JoystickGetProductVersion"); pSDL_JoystickGetVendor = dlsym(sdl_handle, "SDL_JoystickGetVendor");
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/bus_sdl.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index f71da77b77e..17032e1dba9 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -102,7 +102,6 @@ MAKE_FUNCPTR(SDL_HapticRumbleSupported); MAKE_FUNCPTR(SDL_HapticRunEffect); MAKE_FUNCPTR(SDL_HapticStopAll); MAKE_FUNCPTR(SDL_JoystickIsHaptic); -MAKE_FUNCPTR(SDL_memset); MAKE_FUNCPTR(SDL_GameControllerAddMapping); MAKE_FUNCPTR(SDL_RegisterEvents); MAKE_FUNCPTR(SDL_PushEvent); @@ -658,7 +657,6 @@ NTSTATUS sdl_bus_init(void *args) LOAD_FUNCPTR(SDL_HapticRunEffect); LOAD_FUNCPTR(SDL_HapticStopAll); LOAD_FUNCPTR(SDL_JoystickIsHaptic); - LOAD_FUNCPTR(SDL_memset); LOAD_FUNCPTR(SDL_GameControllerAddMapping); LOAD_FUNCPTR(SDL_RegisterEvents); LOAD_FUNCPTR(SDL_PushEvent);
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/hid.c | 150 ++++++++++++++++++++++++++++++-- dlls/winebus.sys/unix_private.h | 26 ++++++ 2 files changed, 167 insertions(+), 9 deletions(-)
diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index c1dd75f77c4..2a02a660f03 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -24,6 +24,7 @@
#include <stdarg.h> #include <stdlib.h> +#include <assert.h>
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -316,12 +317,12 @@ BOOL hid_device_add_axes(struct unix_device *iface, BYTE count, USAGE usage_page BOOL hid_device_add_haptics(struct unix_device *iface) { struct hid_report_descriptor *desc = &iface->hid_report_descriptor; - const BYTE report_id = ++desc->next_report_id[HidP_Output]; - const BYTE template[] = + const BYTE vendor_report = ++desc->next_report_id[HidP_Output]; + const BYTE vendor_template[] = { USAGE_PAGE(2, HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN), COLLECTION(1, Report), - REPORT_ID(1, report_id), + REPORT_ID(1, vendor_report), /* padding */ REPORT_COUNT(1, 0x02), REPORT_SIZE(1, 0x08), @@ -342,8 +343,86 @@ BOOL hid_device_add_haptics(struct unix_device *iface) END_COLLECTION, };
- iface->hid_haptics.vendor_report = report_id; - return hid_report_descriptor_append(desc, template, sizeof(template)); + const BYTE haptics_features_report = ++desc->next_report_id[HidP_Feature]; + const BYTE haptics_waveform_report = ++desc->next_report_id[HidP_Output]; + const BYTE haptics_template[] = + { + USAGE_PAGE(2, HID_USAGE_PAGE_HAPTICS), + USAGE(1, HID_USAGE_HAPTICS_SIMPLE_CONTROLLER), + COLLECTION(1, Logical), + REPORT_ID(1, haptics_features_report), + + USAGE(1, HID_USAGE_HAPTICS_WAVEFORM_LIST), + COLLECTION(1, NamedArray), + USAGE_PAGE(1, HID_USAGE_PAGE_ORDINAL), + USAGE(1, 3), /* HID_USAGE_HAPTICS_WAVEFORM_RUMBLE */ + USAGE(1, 4), /* HID_USAGE_HAPTICS_WAVEFORM_BUZZ */ + REPORT_COUNT(1, 2), + REPORT_SIZE(1, 16), + FEATURE(1, Data|Var|Abs|Null), + END_COLLECTION, + + USAGE_PAGE(2, HID_USAGE_PAGE_HAPTICS), + USAGE(1, HID_USAGE_HAPTICS_DURATION_LIST), + COLLECTION(1, NamedArray), + USAGE_PAGE(1, HID_USAGE_PAGE_ORDINAL), + USAGE(1, 3), /* 0 (HID_USAGE_HAPTICS_WAVEFORM_RUMBLE) */ + USAGE(1, 4), /* 0 (HID_USAGE_HAPTICS_WAVEFORM_BUZZ) */ + REPORT_COUNT(1, 2), + REPORT_SIZE(1, 16), + FEATURE(1, Data|Var|Abs|Null), + END_COLLECTION, + + USAGE_PAGE(2, HID_USAGE_PAGE_HAPTICS), + USAGE(1, HID_USAGE_HAPTICS_WAVEFORM_CUTOFF_TIME), + UNIT(2, 0x1001), /* seconds */ + UNIT_EXPONENT(1, -3), /* 10^-3 */ + LOGICAL_MINIMUM(4, 0x00000000), + LOGICAL_MAXIMUM(4, 0x7fffffff), + PHYSICAL_MINIMUM(4, 0x00000000), + PHYSICAL_MAXIMUM(4, 0x7fffffff), + REPORT_SIZE(1, 32), + REPORT_COUNT(1, 1), + FEATURE(1, Data|Var|Abs), + /* reset global items */ + UNIT(1, 0), /* None */ + 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), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_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), + PHYSICAL_MINIMUM(4, 0x00000000), + PHYSICAL_MAXIMUM(4, 0x0000ffff), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + }; + + iface->hid_haptics.vendor_report = vendor_report; + + iface->hid_haptics.features_report = haptics_features_report; + iface->hid_haptics.waveform_report = haptics_waveform_report; + iface->hid_haptics.features.waveform_list[0] = HID_USAGE_HAPTICS_WAVEFORM_RUMBLE; + iface->hid_haptics.features.waveform_list[1] = HID_USAGE_HAPTICS_WAVEFORM_BUZZ; + iface->hid_haptics.features.duration_list[0] = 0; + iface->hid_haptics.features.duration_list[1] = 0; + iface->hid_haptics.features.waveform_cutoff_time_ms = 1000; + + if (!hid_report_descriptor_append(desc, vendor_template, sizeof(vendor_template))) + return FALSE; + + return hid_report_descriptor_append(desc, haptics_template, sizeof(haptics_template)); }
#include "pop_hid_macros.h" @@ -386,6 +465,29 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC io->Information = packet->reportBufferLen; io->Status = iface->hid_vtbl->haptics_start(iface, -1, left, right); } + else 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_INDEX; + struct hid_haptics_waveform *buzz = haptics->waveforms + HAPTICS_WAVEFORM_BUZZ_INDEX; + ULONG duration_ms; + + io->Information = sizeof(*waveform) + 1; + assert(packet->reportBufferLen == io->Information); + + if (waveform->manual_trigger == 0 || waveform->manual_trigger > HAPTICS_WAVEFORM_LAST_INDEX) + io->Status = STATUS_INVALID_PARAMETER; + else + { + if (waveform->manual_trigger == HAPTICS_WAVEFORM_STOP_INDEX) + memset(haptics->waveforms, 0, sizeof(haptics->waveforms)); + 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); + } + } else { io->Information = 0; @@ -395,14 +497,44 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC
static void hid_device_get_feature_report(struct unix_device *iface, HID_XFER_PACKET *packet, IO_STATUS_BLOCK *io) { - io->Information = 0; - io->Status = STATUS_NOT_IMPLEMENTED; + struct hid_haptics *haptics = &iface->hid_haptics; + + if (packet->reportId == haptics->features_report) + { + struct hid_haptics_features *features = (struct hid_haptics_features *)(packet->reportBuffer + 1); + + io->Information = sizeof(*features) + 1; + assert(packet->reportBufferLen == io->Information); + + *features = haptics->features; + io->Status = STATUS_SUCCESS; + } + else + { + io->Information = 0; + io->Status = STATUS_NOT_IMPLEMENTED; + } }
static void hid_device_set_feature_report(struct unix_device *iface, HID_XFER_PACKET *packet, IO_STATUS_BLOCK *io) { - io->Information = 0; - io->Status = STATUS_NOT_IMPLEMENTED; + struct hid_haptics *haptics = &iface->hid_haptics; + + if (packet->reportId == haptics->features_report) + { + struct hid_haptics_features *features = (struct hid_haptics_features *)(packet->reportBuffer + 1); + + io->Information = sizeof(*features) + 1; + assert(packet->reportBufferLen == io->Information); + + haptics->features.waveform_cutoff_time_ms = features->waveform_cutoff_time_ms; + io->Status = STATUS_SUCCESS; + } + else + { + io->Information = 0; + io->Status = STATUS_NOT_IMPLEMENTED; + } }
static const struct raw_device_vtbl raw_device_vtbl = diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 9684ac47067..5da5ca58e7f 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -57,9 +57,35 @@ struct hid_report_descriptor BYTE next_report_id[3]; };
+enum haptics_waveform_index +{ + HAPTICS_WAVEFORM_STOP_INDEX = 1, + HAPTICS_WAVEFORM_NULL_INDEX = 2, + HAPTICS_WAVEFORM_RUMBLE_INDEX = 3, + HAPTICS_WAVEFORM_BUZZ_INDEX = 4, + HAPTICS_WAVEFORM_LAST_INDEX = HAPTICS_WAVEFORM_BUZZ_INDEX, +}; + +struct hid_haptics_features +{ + WORD waveform_list[HAPTICS_WAVEFORM_LAST_INDEX - HAPTICS_WAVEFORM_NULL_INDEX]; + WORD duration_list[HAPTICS_WAVEFORM_LAST_INDEX - HAPTICS_WAVEFORM_NULL_INDEX]; + DWORD 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_INDEX + 1]; BYTE vendor_report; + BYTE features_report; + BYTE waveform_report; };
struct hid_device_state
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51587 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/xinput1_3/main.c | 135 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 109 insertions(+), 26 deletions(-)
diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c index d601c23f6f1..2881a370534 100644 --- a/dlls/xinput1_3/main.c +++ b/dlls/xinput1_3/main.c @@ -77,6 +77,11 @@ struct xinput_controller
char *input_report_buf; char *output_report_buf; + char *feature_report_buf; + + BYTE haptics_report; + BYTE haptics_rumble_index; + BYTE haptics_buzz_index; } hid; };
@@ -153,14 +158,17 @@ static void check_value_caps(struct xinput_controller *controller, USHORT usage, } }
-static BOOL controller_check_caps(struct xinput_controller *controller, PHIDP_PREPARSED_DATA preparsed) +static BOOL controller_check_caps(struct xinput_controller *controller, HANDLE device, PHIDP_PREPARSED_DATA preparsed) { + ULONG collections_count = 0, report_len = controller->hid.caps.FeatureReportByteLength; + char *report_buf = controller->hid.feature_report_buf; XINPUT_CAPABILITIES *caps = &controller->caps; + HIDP_VALUE_CAPS *value_caps, waveform_cap; + int i, u, waveform_list, button_count = 0; + HIDP_LINK_COLLECTION_NODE *collections; HIDP_BUTTON_CAPS *button_caps; - HIDP_VALUE_CAPS *value_caps; + USHORT caps_count = 0; NTSTATUS status; - int i, u; - int button_count = 0;
/* Count buttons */ memset(caps, 0, sizeof(XINPUT_CAPABILITIES)); @@ -210,11 +218,66 @@ static BOOL controller_check_caps(struct xinput_controller *controller, PHIDP_PR caps->Type = XINPUT_DEVTYPE_GAMEPAD; caps->SubType = XINPUT_DEVSUBTYPE_GAMEPAD;
- if (controller->hid.caps.NumberOutputValueCaps > 0) + collections_count = controller->hid.caps.NumberLinkCollectionNodes; + if (!(collections = malloc(sizeof(*collections) * controller->hid.caps.NumberLinkCollectionNodes))) return FALSE; + status = HidP_GetLinkCollectionNodes(collections, &collections_count, preparsed); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetLinkCollectionNodes returned %#x\n", status); + else for (i = 0; i < collections_count; ++i) + { + if (collections[i].LinkUsagePage != HID_USAGE_PAGE_HAPTICS) continue; + if (collections[i].LinkUsage == HID_USAGE_HAPTICS_WAVEFORM_LIST) break; + } + free(collections); + if (status != HIDP_STATUS_SUCCESS || i == collections_count) + { + WARN("could not find haptics waveform list collection\n"); + return TRUE; + } + waveform_list = i; + + caps_count = 1; + status = HidP_GetSpecificValueCaps(HidP_Feature, HID_USAGE_PAGE_ORDINAL, waveform_list, 3, &waveform_cap, &caps_count, preparsed); + if (status != HIDP_STATUS_SUCCESS || !caps_count) + { + WARN("could not find haptics waveform list report id, status %#x\n", status); + return TRUE; + } + + status = HidP_InitializeReportForID(HidP_Feature, waveform_cap.ReportID, preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_InitializeReportForID returned %#x\n", status); + if (!HidD_GetFeature(device, report_buf, report_len)) + { + WARN("failed to get waveform list report, error %u\n", GetLastError()); + return TRUE; + } + + controller->hid.haptics_buzz_index = 0; + controller->hid.haptics_rumble_index = 0; + for (i = 3; status == HIDP_STATUS_SUCCESS; ++i) + { + ULONG waveform = 0; + status = HidP_GetUsageValue(HidP_Feature, HID_USAGE_PAGE_ORDINAL, waveform_list, + i, &waveform, preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue returned %#x\n", status); + else if (waveform == HID_USAGE_HAPTICS_WAVEFORM_BUZZ) controller->hid.haptics_buzz_index = i; + else if (waveform == HID_USAGE_HAPTICS_WAVEFORM_RUMBLE) controller->hid.haptics_rumble_index = i; + } + + if (!controller->hid.haptics_buzz_index) WARN("haptics buzz not supported\n"); + if (!controller->hid.haptics_rumble_index) WARN("haptics rumble not supported\n"); + if (!controller->hid.haptics_rumble_index && !controller->hid.haptics_buzz_index) return TRUE; + + caps_count = 1; + status = HidP_GetSpecificValueCaps(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_MANUAL_TRIGGER, + &waveform_cap, &caps_count, preparsed); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetSpecificValueCaps MANUAL_TRIGGER returned %#x\n", status); + else if (!caps_count) WARN("haptics manual trigger not supported\n"); + else { caps->Flags |= XINPUT_CAPS_FFB_SUPPORTED; caps->Vibration.wLeftMotorSpeed = 255; caps->Vibration.wRightMotorSpeed = 255; + controller->hid.haptics_report = waveform_cap.ReportID; }
return TRUE; @@ -222,30 +285,47 @@ static BOOL controller_check_caps(struct xinput_controller *controller, PHIDP_PR
static DWORD HID_set_state(struct xinput_controller *controller, XINPUT_VIBRATION *state) { - char *output_report_buf = controller->hid.output_report_buf; - ULONG output_report_len = controller->hid.caps.OutputReportByteLength; + ULONG report_len = controller->hid.caps.OutputReportByteLength; + PHIDP_PREPARSED_DATA preparsed = controller->hid.preparsed; + char *report_buf = controller->hid.output_report_buf; + BYTE report_id = controller->hid.haptics_report; + NTSTATUS status;
- if (controller->caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) - { - controller->vibration.wLeftMotorSpeed = state->wLeftMotorSpeed; - controller->vibration.wRightMotorSpeed = state->wRightMotorSpeed; + if (!(controller->caps.Flags & XINPUT_CAPS_FFB_SUPPORTED)) return ERROR_SUCCESS;
- if (controller->enabled) - { - memset(output_report_buf, 0, output_report_len); - output_report_buf[0] = 1; - output_report_buf[1] = 0x8; - output_report_buf[3] = (BYTE)(state->wLeftMotorSpeed / 256); - output_report_buf[4] = (BYTE)(state->wRightMotorSpeed / 256); + controller->vibration.wLeftMotorSpeed = state->wLeftMotorSpeed; + controller->vibration.wRightMotorSpeed = state->wRightMotorSpeed;
- if (!HidD_SetOutputReport(controller->device, output_report_buf, output_report_len)) - { - WARN("unable to set output report, HidD_SetOutputReport failed with error %u\n", GetLastError()); - return GetLastError(); - } + if (!controller->enabled) return ERROR_SUCCESS;
- return ERROR_SUCCESS; - } + /* 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 %#x\n", status); + status = HidP_SetUsageValue(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_INTENSITY, + state->wLeftMotorSpeed, preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue INTENSITY returned %#x\n", status); + status = HidP_SetUsageValue(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_MANUAL_TRIGGER, + controller->hid.haptics_rumble_index, preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue MANUAL_TRIGGER returned %#x\n", status); + if (!HidD_SetOutputReport(controller->device, report_buf, report_len)) + { + WARN("HidD_SetOutputReport failed with error %u\n", GetLastError()); + return GetLastError(); + } + + /* send haptics buzz report (right motor) */ + status = HidP_InitializeReportForID(HidP_Output, report_id, preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_InitializeReportForID returned %#x\n", status); + status = HidP_SetUsageValue(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_INTENSITY, + state->wRightMotorSpeed, preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue INTENSITY returned %#x\n", status); + status = HidP_SetUsageValue(HidP_Output, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_MANUAL_TRIGGER, + controller->hid.haptics_buzz_index, preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_SetUsageValue MANUAL_TRIGGER returned %#x\n", status); + if (!HidD_SetOutputReport(controller->device, report_buf, report_len)) + { + WARN("HidD_SetOutputReport failed with error %u\n", GetLastError()); + return GetLastError(); }
return ERROR_SUCCESS; @@ -283,7 +363,8 @@ static BOOL controller_init(struct xinput_controller *controller, PHIDP_PREPARSE HANDLE event = NULL;
controller->hid.caps = *caps; - if (!controller_check_caps(controller, preparsed)) goto failed; + if (!(controller->hid.feature_report_buf = calloc(1, controller->hid.caps.FeatureReportByteLength))) goto failed; + if (!controller_check_caps(controller, device, preparsed)) goto failed; if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL))) goto failed;
TRACE("Found gamepad %s\n", debugstr_w(device_path)); @@ -307,6 +388,7 @@ static BOOL controller_init(struct xinput_controller *controller, PHIDP_PREPARSE failed: free(controller->hid.input_report_buf); free(controller->hid.output_report_buf); + free(controller->hid.feature_report_buf); memset(&controller->hid, 0, sizeof(controller->hid)); CloseHandle(event); return FALSE; @@ -379,6 +461,7 @@ static void controller_destroy(struct xinput_controller *controller)
free(controller->hid.input_report_buf); free(controller->hid.output_report_buf); + free(controller->hid.feature_report_buf); HidD_FreePreparsedData(controller->hid.preparsed); memset(&controller->hid, 0, sizeof(controller->hid)); }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/hid.c | 40 +-------------------------------- dlls/winebus.sys/unix_private.h | 1 - 2 files changed, 1 insertion(+), 40 deletions(-)
diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index 2a02a660f03..0c8e85dfc5f 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -317,32 +317,6 @@ BOOL hid_device_add_axes(struct unix_device *iface, BYTE count, USAGE usage_page BOOL hid_device_add_haptics(struct unix_device *iface) { struct hid_report_descriptor *desc = &iface->hid_report_descriptor; - const BYTE vendor_report = ++desc->next_report_id[HidP_Output]; - const BYTE vendor_template[] = - { - USAGE_PAGE(2, HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN), - COLLECTION(1, Report), - REPORT_ID(1, vendor_report), - /* padding */ - REPORT_COUNT(1, 0x02), - REPORT_SIZE(1, 0x08), - OUTPUT(1, Data|Var|Abs), - /* actuators */ - USAGE(1, 0x01), - LOGICAL_MINIMUM(1, 0x00), - LOGICAL_MAXIMUM(1, 0xff), - PHYSICAL_MINIMUM(1, 0x00), - PHYSICAL_MAXIMUM(1, 0xff), - REPORT_SIZE(1, 0x08), - REPORT_COUNT(1, 0x02), - OUTPUT(1, Data|Var|Abs), - /* padding */ - REPORT_COUNT(1, 0x02), - REPORT_SIZE(1, 0x08), - OUTPUT(1, Data|Var|Abs), - END_COLLECTION, - }; - const BYTE haptics_features_report = ++desc->next_report_id[HidP_Feature]; const BYTE haptics_waveform_report = ++desc->next_report_id[HidP_Output]; const BYTE haptics_template[] = @@ -409,8 +383,6 @@ BOOL hid_device_add_haptics(struct unix_device *iface) END_COLLECTION, };
- iface->hid_haptics.vendor_report = vendor_report; - iface->hid_haptics.features_report = haptics_features_report; iface->hid_haptics.waveform_report = haptics_waveform_report; iface->hid_haptics.features.waveform_list[0] = HID_USAGE_HAPTICS_WAVEFORM_RUMBLE; @@ -419,9 +391,6 @@ BOOL hid_device_add_haptics(struct unix_device *iface) iface->hid_haptics.features.duration_list[1] = 0; iface->hid_haptics.features.waveform_cutoff_time_ms = 1000;
- if (!hid_report_descriptor_append(desc, vendor_template, sizeof(vendor_template))) - return FALSE; - return hid_report_descriptor_append(desc, haptics_template, sizeof(haptics_template)); }
@@ -457,15 +426,8 @@ 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_haptics *haptics = &iface->hid_haptics; - if (packet->reportId == haptics->vendor_report) - { - WORD left = packet->reportBuffer[2] * 128; - WORD right = packet->reportBuffer[3] * 128;
- io->Information = packet->reportBufferLen; - io->Status = iface->hid_vtbl->haptics_start(iface, -1, left, right); - } - else if (packet->reportId == haptics->waveform_report) + 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_INDEX; diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 5da5ca58e7f..01638bf19fc 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -83,7 +83,6 @@ struct hid_haptics { struct hid_haptics_features features; struct hid_haptics_waveform waveforms[HAPTICS_WAVEFORM_LAST_INDEX + 1]; - BYTE vendor_report; BYTE features_report; BYTE waveform_report; };
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/bus_udev.c | 62 +++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-)
diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 8bc9b4bf64d..88db78360e2 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -126,6 +126,8 @@ struct lnxev_device BYTE rel_map[HID_REL_MAX]; BYTE hat_map[8]; BYTE button_map[KEY_MAX]; + + int haptic_effect_id; };
static inline struct base_device *impl_from_unix_device(struct unix_device *iface) @@ -372,6 +374,8 @@ static NTSTATUS build_report_descriptor(struct unix_device *iface, struct udev_d struct input_absinfo abs_info[HID_ABS_MAX]; BYTE absbits[(ABS_MAX+7)/8]; BYTE relbits[(REL_MAX+7)/8]; + BYTE ffbits[(FF_MAX+7)/8]; + struct ff_effect effect; USAGE_AND_PAGE usage; INT i, button_count, abs_count, rel_count, hat_count; const BYTE *device_usage = what_am_I(dev); @@ -387,6 +391,11 @@ static NTSTATUS build_report_descriptor(struct unix_device *iface, struct udev_d WARN("ioctl(EVIOCGBIT, EV_ABS) failed: %d %s\n", errno, strerror(errno)); memset(absbits, 0, sizeof(absbits)); } + if (ioctl(impl->base.device_fd, EVIOCGBIT(EV_FF, sizeof(ffbits)), ffbits) == -1) + { + WARN("ioctl(EVIOCGBIT, EV_FF) failed: %d %s\n", errno, strerror(errno)); + memset(ffbits, 0, sizeof(ffbits)); + }
if (!hid_device_begin_report_descriptor(iface, device_usage[0], device_usage[1])) return STATUS_NO_MEMORY; @@ -443,6 +452,23 @@ static NTSTATUS build_report_descriptor(struct unix_device *iface, struct udev_d if (!hid_device_end_input_report(iface)) return STATUS_NO_MEMORY;
+ impl->haptic_effect_id = -1; + if (test_bit(ffbits, FF_RUMBLE)) + { + effect.id = -1; + effect.type = FF_RUMBLE; + effect.replay.length = 0; + effect.u.rumble.strong_magnitude = 0; + effect.u.rumble.weak_magnitude = 0; + + if (ioctl(impl->base.device_fd, EVIOCSFF, &effect) == -1) + WARN("couldn't allocate rumble effect for haptics: %d %s\n", errno, strerror(errno)); + else if (!hid_device_add_haptics(iface)) + return FALSE; + else + impl->haptic_effect_id = effect.id; + } + if (!hid_device_end_report_descriptor(iface)) return STATUS_NO_MEMORY;
@@ -737,10 +763,42 @@ static void lnxev_device_read_report(struct unix_device *iface) static NTSTATUS lnxev_device_haptics_start(struct unix_device *iface, DWORD duration_ms, USHORT rumble_intensity, USHORT buzz_intensity) { - FIXME("iface %p, duration_ms %u, rumble_intensity %u, buzz_intensity %u stub!\n", 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, duration_ms %u, rumble_intensity %u, buzz_intensity %u stub!\n", iface, duration_ms, rumble_intensity, buzz_intensity);
- return STATUS_NOT_IMPLEMENTED; + effect.replay.length = duration_ms; + effect.u.rumble.strong_magnitude = rumble_intensity; + effect.u.rumble.weak_magnitude = buzz_intensity; + + if (ioctl(impl->base.device_fd, EVIOCSFF, &effect) == -1) + { + effect.id = -1; + if (ioctl(impl->base.device_fd, EVIOCSFF, &effect) == 1) + { + WARN("couldn't re-allocate rumble effect for haptics: %d %s\n", errno, strerror(errno)); + return STATUS_UNSUCCESSFUL; + } + impl->haptic_effect_id = effect.id; + } + + event.type = EV_FF; + event.code = effect.id; + event.value = 1; + if (write(impl->base.device_fd, &event, sizeof(event)) == -1) + { + WARN("couldn't start haptics rumble effect: %d %s\n", errno, strerror(errno)); + return STATUS_UNSUCCESSFUL; + } + + return STATUS_SUCCESS; }
static const struct hid_device_vtbl lnxev_device_vtbl =