Commit e3431a02 authored by Arkadiusz Hiler's avatar Arkadiusz Hiler Committed by Alexandre Julliard

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.
parent 94a7b32a
...@@ -209,13 +209,14 @@ static BOOL hid_device_add_hatswitch_count(struct unix_device *iface, BYTE count ...@@ -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"); ERR("hatswitches should be added before buttons!\n");
else if ((iface->hid_device_state.bit_size % 8)) else if ((iface->hid_device_state.bit_size % 8))
ERR("hatswitches should be byte aligned, missing padding!\n"); 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"); ERR("report size overflow, too many elements!\n");
else else
{ {
if (!iface->hid_device_state.hatswitch_count) iface->hid_device_state.hatswitch_start = offset; 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.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; return TRUE;
} }
...@@ -231,16 +232,28 @@ BOOL hid_device_add_hatswitch(struct unix_device *iface, INT count) ...@@ -231,16 +232,28 @@ BOOL hid_device_add_hatswitch(struct unix_device *iface, INT count)
USAGE(1, HID_USAGE_GENERIC_HATSWITCH), USAGE(1, HID_USAGE_GENERIC_HATSWITCH),
LOGICAL_MINIMUM(1, 1), LOGICAL_MINIMUM(1, 1),
LOGICAL_MAXIMUM(1, 8), LOGICAL_MAXIMUM(1, 8),
REPORT_SIZE(1, 8), REPORT_SIZE(1, 4),
REPORT_COUNT(4, count), REPORT_COUNT(4, count),
UNIT(1, 0x0), /* None */ UNIT(1, 0x0), /* None */
INPUT(1, Data|Var|Abs|Null), 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)) if (!hid_device_add_hatswitch_count(iface, count))
return FALSE; 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, 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) ...@@ -1409,8 +1422,9 @@ BOOL hid_device_set_button(struct unix_device *iface, ULONG index, BOOL is_set)
* +1 | 6 5 4 * +1 | 6 5 4
* v * 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; *x = *y = 0;
if (value == 8 || value == 1 || value == 2) *y = -1; if (value == 8 || value == 1 || value == 2) *y = -1;
if (value == 6 || value == 5 || value == 4) *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) ...@@ -1418,49 +1432,61 @@ static void hatswitch_decompose(BYTE value, LONG *x, LONG *y)
if (value == 2 || value == 3 || value == 4) *x = +1; 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; BYTE new_value = 0;
else if (x == 0 && y < 0) *value = 1; if (x == 0 && y == 0) new_value = 0;
else if (x > 0 && y < 0) *value = 2; else if (x == 0 && y < 0) new_value = 1;
else if (x > 0 && y == 0) *value = 3; else if (x > 0 && y < 0) new_value = 2;
else if (x > 0 && y > 0) *value = 4; else if (x > 0 && y == 0) new_value = 3;
else if (x == 0 && y > 0) *value = 5; else if (x > 0 && y > 0) new_value = 4;
else if (x < 0 && y > 0) *value = 6; else if (x == 0 && y > 0) new_value = 5;
else if (x < 0 && y == 0) *value = 7; else if (x < 0 && y > 0) new_value = 6;
else if (x < 0 && y < 0) *value = 8; 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) BOOL hid_device_set_hatswitch_x(struct unix_device *iface, ULONG index, LONG new_x)
{ {
struct hid_device_state *state = &iface->hid_device_state; 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; LONG x, y;
if (index > state->hatswitch_count) return FALSE; if (index > state->hatswitch_count) return FALSE;
hatswitch_decompose(state->report_buf[offset], &x, &y); hatswitch_decompose(state->report_buf[offset], index, &x, &y);
hatswitch_compose(new_x, y, &state->report_buf[offset]); hatswitch_compose(new_x, y, &state->report_buf[offset], index);
return TRUE; return TRUE;
} }
BOOL hid_device_set_hatswitch_y(struct unix_device *iface, ULONG index, LONG new_y) BOOL hid_device_set_hatswitch_y(struct unix_device *iface, ULONG index, LONG new_y)
{ {
struct hid_device_state *state = &iface->hid_device_state; 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; LONG x, y;
if (index > state->hatswitch_count) return FALSE; if (index > state->hatswitch_count) return FALSE;
hatswitch_decompose(state->report_buf[offset], &x, &y); hatswitch_decompose(state->report_buf[offset], index, &x, &y);
hatswitch_compose(x, new_y, &state->report_buf[offset]); hatswitch_compose(x, new_y, &state->report_buf[offset], index);
return TRUE; return TRUE;
} }
BOOL hid_device_move_hatswitch(struct unix_device *iface, ULONG index, LONG x, LONG y) BOOL hid_device_move_hatswitch(struct unix_device *iface, ULONG index, LONG x, LONG y)
{ {
struct hid_device_state *state = &iface->hid_device_state; 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; LONG old_x, old_y;
if (index > state->hatswitch_count) return FALSE; if (index > state->hatswitch_count) return FALSE;
hatswitch_decompose(state->report_buf[offset], &old_x, &old_y); hatswitch_decompose(state->report_buf[offset], index, &old_x, &old_y);
hatswitch_compose(old_x + x, old_y + y, &state->report_buf[offset]); hatswitch_compose(old_x + x, old_y + y, &state->report_buf[offset], index);
return TRUE; return TRUE;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment