Module: wine Branch: master Commit: e3431a02e1d23ad506512b906f244eae1db05035 URL: https://gitlab.winehq.org/wine/wine/-/commit/e3431a02e1d23ad506512b906f244ea...
Author: Arkadiusz Hiler ahiler@codeweavers.com Date: Tue Jan 30 00:20:55 2024 +0200
winebus.sys: Use 4 bits for hat switches.
Declaring them as 8 bits crashes game due to how Unity's native hid support parses the data.
---
dlls/winebus.sys/hid.c | 74 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 24 deletions(-)
diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index 733f9a51f96..d31718c6293 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -209,13 +209,14 @@ static BOOL hid_device_add_hatswitch_count(struct unix_device *iface, BYTE count ERR("hatswitches should be added before buttons!\n"); else if ((iface->hid_device_state.bit_size % 8)) ERR("hatswitches should be byte aligned, missing padding!\n"); - else if (iface->hid_device_state.bit_size + 8 * count > 0x80000) + else if (iface->hid_device_state.bit_size + 4 * (count + 1) > 0x80000) ERR("report size overflow, too many elements!\n"); else { if (!iface->hid_device_state.hatswitch_count) iface->hid_device_state.hatswitch_start = offset; iface->hid_device_state.hatswitch_count += count; - iface->hid_device_state.bit_size += 8 * count; + iface->hid_device_state.bit_size += 4 * count; + if (count % 2) iface->hid_device_state.bit_size += 4; return TRUE; }
@@ -231,16 +232,28 @@ BOOL hid_device_add_hatswitch(struct unix_device *iface, INT count) USAGE(1, HID_USAGE_GENERIC_HATSWITCH), LOGICAL_MINIMUM(1, 1), LOGICAL_MAXIMUM(1, 8), - REPORT_SIZE(1, 8), + REPORT_SIZE(1, 4), REPORT_COUNT(4, count), UNIT(1, 0x0), /* None */ INPUT(1, Data|Var|Abs|Null), }; + const BYTE template_pad[] = + { + REPORT_COUNT(1, 4), + REPORT_SIZE(1, 1), + INPUT(1, Cnst|Ary|Abs), + };
if (!hid_device_add_hatswitch_count(iface, count)) return FALSE;
- return hid_report_descriptor_append(desc, template, sizeof(template)); + if (!hid_report_descriptor_append(desc, template, sizeof(template))) + return FALSE; + + if ((count % 2) && !hid_report_descriptor_append(desc, template_pad, sizeof(template_pad))) + return FALSE; + + return TRUE; }
static BOOL hid_device_add_axis_count(struct unix_device *iface, BOOL rel, BYTE count, @@ -1409,8 +1422,9 @@ BOOL hid_device_set_button(struct unix_device *iface, ULONG index, BOOL is_set) * +1 | 6 5 4 * v */ -static void hatswitch_decompose(BYTE value, LONG *x, LONG *y) +static void hatswitch_decompose(BYTE value, ULONG index, LONG *x, LONG *y) { + value = (index % 2) ? (value >> 4) : (value & 0x0f); *x = *y = 0; if (value == 8 || value == 1 || value == 2) *y = -1; if (value == 6 || value == 5 || value == 4) *y = +1; @@ -1418,49 +1432,61 @@ static void hatswitch_decompose(BYTE value, LONG *x, LONG *y) if (value == 2 || value == 3 || value == 4) *x = +1; }
-static void hatswitch_compose(LONG x, LONG y, BYTE *value) +static void hatswitch_compose(LONG x, LONG y, BYTE *value, ULONG index) { - if (x == 0 && y == 0) *value = 0; - else if (x == 0 && y < 0) *value = 1; - else if (x > 0 && y < 0) *value = 2; - else if (x > 0 && y == 0) *value = 3; - else if (x > 0 && y > 0) *value = 4; - else if (x == 0 && y > 0) *value = 5; - else if (x < 0 && y > 0) *value = 6; - else if (x < 0 && y == 0) *value = 7; - else if (x < 0 && y < 0) *value = 8; + BYTE new_value = 0; + if (x == 0 && y == 0) new_value = 0; + else if (x == 0 && y < 0) new_value = 1; + else if (x > 0 && y < 0) new_value = 2; + else if (x > 0 && y == 0) new_value = 3; + else if (x > 0 && y > 0) new_value = 4; + else if (x == 0 && y > 0) new_value = 5; + else if (x < 0 && y > 0) new_value = 6; + else if (x < 0 && y == 0) new_value = 7; + else if (x < 0 && y < 0) new_value = 8; + + if (index % 2) + { + *value &= 0xf; + *value |= new_value << 4; + } + else + { + *value &= 0xf0; + *value |= new_value; + } }
BOOL hid_device_set_hatswitch_x(struct unix_device *iface, ULONG index, LONG new_x) { struct hid_device_state *state = &iface->hid_device_state; - ULONG offset = state->hatswitch_start + index; + ULONG offset = state->hatswitch_start + index / 2; LONG x, y; if (index > state->hatswitch_count) return FALSE; - hatswitch_decompose(state->report_buf[offset], &x, &y); - hatswitch_compose(new_x, y, &state->report_buf[offset]); + hatswitch_decompose(state->report_buf[offset], index, &x, &y); + hatswitch_compose(new_x, y, &state->report_buf[offset], index); return TRUE; }
BOOL hid_device_set_hatswitch_y(struct unix_device *iface, ULONG index, LONG new_y) { struct hid_device_state *state = &iface->hid_device_state; - ULONG offset = state->hatswitch_start + index; + ULONG offset = state->hatswitch_start + index / 2; LONG x, y; if (index > state->hatswitch_count) return FALSE; - hatswitch_decompose(state->report_buf[offset], &x, &y); - hatswitch_compose(x, new_y, &state->report_buf[offset]); + hatswitch_decompose(state->report_buf[offset], index, &x, &y); + hatswitch_compose(x, new_y, &state->report_buf[offset], index); return TRUE; }
BOOL hid_device_move_hatswitch(struct unix_device *iface, ULONG index, LONG x, LONG y) { struct hid_device_state *state = &iface->hid_device_state; - ULONG offset = state->hatswitch_start + index; + ULONG offset = state->hatswitch_start + index / 2; LONG old_x, old_y; if (index > state->hatswitch_count) return FALSE; - hatswitch_decompose(state->report_buf[offset], &old_x, &old_y); - hatswitch_compose(old_x + x, old_y + y, &state->report_buf[offset]); + hatswitch_decompose(state->report_buf[offset], index, &old_x, &old_y); + hatswitch_compose(old_x + x, old_y + y, &state->report_buf[offset], index); return TRUE; }