Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 00fd01b483a..80991e8c150 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -2296,7 +2296,7 @@ static void convert_directions_to_spherical( const DIEFFECT *in, DIEFFECT *out ) tmp = atan2( in->rglDirection[i], tmp ); out->rglDirection[i - 1] = tmp * 18000 / M_PI; } - out->rglDirection[in->cAxes - 1] = 0; + if (in->cAxes) out->rglDirection[in->cAxes - 1] = 0; out->cAxes = in->cAxes; break; case DIEFF_POLAR: @@ -2306,7 +2306,8 @@ static void convert_directions_to_spherical( const DIEFFECT *in, DIEFFECT *out ) out->cAxes = in->cAxes; break; case DIEFF_SPHERICAL: - for (i = 0; i < in->cAxes - 1; ++i) + if (!in->cAxes) i = 0; + else for (i = 0; i < in->cAxes - 1; ++i) { out->rglDirection[i] = in->rglDirection[i] % 36000; if (out->rglDirection[i] < 0) out->rglDirection[i] += 36000;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/hid.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index 64e4f2955ae..df648a2019a 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -237,28 +237,29 @@ BOOL hid_device_add_hatswitch(struct unix_device *iface, INT count)
static BOOL hid_device_add_axis_count(struct unix_device *iface, BOOL rel, BYTE count) { - USHORT offset = iface->hid_device_state.bit_size / 8; + struct hid_device_state *state = &iface->hid_device_state; + USHORT offset = state->bit_size / 8;
- if (!rel && iface->hid_device_state.rel_axis_count) + if (!rel && state->rel_axis_count) ERR("absolute axes should be added before relative axes!\n"); - else if (iface->hid_device_state.button_count || iface->hid_device_state.hatswitch_count) + else if (state->button_count || state->hatswitch_count) ERR("axes should be added before buttons or hatswitches!\n"); - else if ((iface->hid_device_state.bit_size % 8)) + else if ((state->bit_size % 8)) ERR("axes should be byte aligned, missing padding!\n"); - else if (iface->hid_device_state.bit_size + 32 * count > 0x80000) + else if (state->bit_size + 32 * count > 0x80000) ERR("report size overflow, too many elements!\n"); else if (rel) { - if (!iface->hid_device_state.rel_axis_count) iface->hid_device_state.rel_axis_start = offset; - iface->hid_device_state.rel_axis_count += count; - iface->hid_device_state.bit_size += 32 * count; + if (!state->rel_axis_count) state->rel_axis_start = offset; + state->rel_axis_count += count; + state->bit_size += 32 * count; return TRUE; } else { - if (!iface->hid_device_state.abs_axis_count) iface->hid_device_state.abs_axis_start = offset; - iface->hid_device_state.abs_axis_count += count; - iface->hid_device_state.bit_size += 32 * count; + if (!state->abs_axis_count) state->abs_axis_start = offset; + state->abs_axis_count += count; + state->bit_size += 32 * count; return TRUE; }
And use the same usages as for the axes themselves instead of generic HID usages.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/hid.c | 22 +++++++++++++++++----- dlls/winebus.sys/unix_private.h | 2 ++ 2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index df648a2019a..8d34fc86e63 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -235,10 +235,11 @@ BOOL hid_device_add_hatswitch(struct unix_device *iface, INT count) return hid_report_descriptor_append(desc, template, sizeof(template)); }
-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, + USAGE usage_page, const USAGE *usages) { struct hid_device_state *state = &iface->hid_device_state; - USHORT offset = state->bit_size / 8; + USHORT i, offset = state->bit_size / 8;
if (!rel && state->rel_axis_count) ERR("absolute axes should be added before relative axes!\n"); @@ -257,6 +258,17 @@ static BOOL hid_device_add_axis_count(struct unix_device *iface, BOOL rel, BYTE } else { + if (state->abs_axis_count + count > ARRAY_SIZE(state->abs_axis_usages)) + { + ERR("absolute axis usage overflow, too many elements!\n"); + return FALSE; + } + for (i = 0; i < count; ++i) + { + state->abs_axis_usages[state->abs_axis_count + i].UsagePage = usage_page; + state->abs_axis_usages[state->abs_axis_count + i].Usage = usages[i]; + } + if (!state->abs_axis_count) state->abs_axis_start = offset; state->abs_axis_count += count; state->bit_size += 32 * count; @@ -289,7 +301,7 @@ BOOL hid_device_add_axes(struct unix_device *iface, BYTE count, USAGE usage_page }; int i;
- if (!hid_device_add_axis_count(iface, rel, count)) + if (!hid_device_add_axis_count(iface, rel, count, usage_page, usages)) return FALSE;
if (!hid_report_descriptor_append(desc, template_begin, sizeof(template_begin))) @@ -872,8 +884,8 @@ BOOL hid_device_add_physical(struct unix_device *iface, USAGE *usages, USHORT co
USAGE(1, PID_USAGE_AXES_ENABLE), COLLECTION(1, Logical), - USAGE(4, (HID_USAGE_PAGE_GENERIC<<16)|HID_USAGE_GENERIC_X), - USAGE(4, (HID_USAGE_PAGE_GENERIC<<16)|HID_USAGE_GENERIC_Y), + USAGE(4, (state->abs_axis_usages[0].UsagePage<<16)|state->abs_axis_usages[0].Usage), + USAGE(4, (state->abs_axis_usages[1].UsagePage<<16)|state->abs_axis_usages[1].Usage), LOGICAL_MINIMUM(1, 0), LOGICAL_MAXIMUM(1, 1), REPORT_SIZE(1, 1), diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 04545b7eb98..3c37f219a4b 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -24,6 +24,7 @@ #include <windef.h> #include <winbase.h> #include <winternl.h> +#include <ddk/hidsdi.h>
#include "unixlib.h"
@@ -189,6 +190,7 @@ struct hid_physical struct hid_device_state { ULONG bit_size; + USAGE_AND_PAGE abs_axis_usages[32]; USHORT abs_axis_start; USHORT abs_axis_count; USHORT rel_axis_start;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/joystick8.c | 234 ++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+)
diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 0bfdd113633..9c700c00971 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -2590,6 +2590,238 @@ static BOOL test_device_types( DWORD version ) return success; }
+static void test_driving_wheel_axes(void) +{ +#include "psh_hid_macros.h" + static const unsigned char report_desc[] = + { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Report), + REPORT_ID(1, 1), + + USAGE_PAGE(1, HID_USAGE_PAGE_SIMULATION), + USAGE(1, HID_USAGE_SIMULATION_RUDDER), + USAGE(1, HID_USAGE_SIMULATION_THROTTLE), + USAGE(1, HID_USAGE_SIMULATION_ACCELERATOR), + USAGE(1, HID_USAGE_SIMULATION_BRAKE), + USAGE(1, HID_USAGE_SIMULATION_CLUTCH), + USAGE(1, HID_USAGE_SIMULATION_STEERING), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 6), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, + }; +#undef REPORT_ID_OR_USAGE_PAGE +#include "pop_hid_macros.h" + + static const HIDP_CAPS hid_caps = + { + .InputReportByteLength = 7, + }; + const DIDEVCAPS expect_caps = + { + .dwSize = sizeof(DIDEVCAPS), + .dwFlags = DIDC_ATTACHED | DIDC_EMULATED, + .dwDevType = DIDEVTYPE_HID | (DI8DEVTYPEDRIVING_LIMITED << 8) | DI8DEVTYPE_DRIVING, + .dwAxes = 6, + }; + const DIDEVICEINSTANCEW expect_devinst = + { + .dwSize = sizeof(DIDEVICEINSTANCEW), + .guidInstance = expect_guid_product, + .guidProduct = expect_guid_product, + .dwDevType = DIDEVTYPE_HID | (DI8DEVTYPEDRIVING_LIMITED << 8) | DI8DEVTYPE_DRIVING, + .tszInstanceName = L"Wine test root driver", + .tszProductName = L"Wine test root driver", + .guidFFDriver = GUID_NULL, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }; + const DIDEVICEOBJECTINSTANCEW expect_objects[] = + { + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_XAxis, + .dwOfs = 0, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(0), + .dwFlags = DIDOI_ASPECTPOSITION, + .tszName = L"Steering", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_SIMULATION, + .wUsage = HID_USAGE_SIMULATION_STEERING, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = 0x4, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(6), + .dwFlags = 0, + .tszName = L"Clutch", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_SIMULATION, + .wUsage = HID_USAGE_SIMULATION_CLUTCH, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_RzAxis, + .dwOfs = 0x8, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(5), + .dwFlags = DIDOI_ASPECTPOSITION, + .tszName = L"Brake", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_SIMULATION, + .wUsage = HID_USAGE_SIMULATION_BRAKE, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_YAxis, + .dwOfs = 0xc, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(1), + .dwFlags = DIDOI_ASPECTPOSITION, + .tszName = L"Accelerator", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_SIMULATION, + .wUsage = HID_USAGE_SIMULATION_ACCELERATOR, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Slider, + .dwOfs = 0x10, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(2), + .dwFlags = DIDOI_ASPECTPOSITION, + .tszName = L"Throttle", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_SIMULATION, + .wUsage = HID_USAGE_SIMULATION_THROTTLE, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_RzAxis, + .dwOfs = 0x14, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(7), + .dwFlags = DIDOI_ASPECTPOSITION, + .tszName = L"Rudder", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_SIMULATION, + .wUsage = HID_USAGE_SIMULATION_RUDDER, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(0), + .tszName = L"Collection 0 - Joystick", + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(1), + .tszName = L"Collection 1 - Joystick", + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }, + }; + struct check_objects_todos object_todos[ARRAY_SIZE(expect_objects)] = + { + {.name = TRUE}, + {.name = TRUE}, + {.name = TRUE}, + {.name = TRUE}, + {.name = TRUE}, + }; + struct check_objects_params check_objects_params = + { + .version = DIRECTINPUT_VERSION, + .expect_count = ARRAY_SIZE(expect_objects), + .expect_objs = expect_objects, + .todo_objs = object_todos, + }; + + WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; + DIDEVICEINSTANCEW devinst = {0}; + IDirectInputDevice8W *device; + DIDEVCAPS caps = {0}; + HRESULT hr; + ULONG ref; + + GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); + GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); + SetCurrentDirectoryW( tempdir ); + + cleanup_registry_keys(); + if (!dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 )) goto done; + if (FAILED(hr = dinput_test_create_device( DIRECTINPUT_VERSION, &devinst, &device ))) goto done; + + check_dinput_devices( DIRECTINPUT_VERSION, &devinst ); + + memset( &devinst, 0, sizeof(devinst) ); + devinst.dwSize = sizeof(DIDEVICEINSTANCEW); + hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); + ok( hr == DI_OK, "GetDeviceInfo returned %#lx\n", hr ); + check_member( devinst, expect_devinst, "%lu", dwSize ); + todo_wine + check_member_guid( devinst, expect_devinst, guidInstance ); + check_member_guid( devinst, expect_devinst, guidProduct ); + todo_wine + check_member( devinst, expect_devinst, "%#lx", dwDevType ); + todo_wine + check_member_wstr( devinst, expect_devinst, tszInstanceName ); + todo_wine + check_member_wstr( devinst, expect_devinst, tszProductName ); + check_member_guid( devinst, expect_devinst, guidFFDriver ); + check_member( devinst, expect_devinst, "%04x", wUsagePage ); + check_member( devinst, expect_devinst, "%04x", wUsage ); + + hr = IDirectInputDevice8_GetCapabilities( device, NULL ); + ok( hr == E_POINTER, "GetCapabilities returned %#lx\n", hr ); + hr = IDirectInputDevice8_GetCapabilities( device, &caps ); + ok( hr == DIERR_INVALIDPARAM, "GetCapabilities returned %#lx\n", hr ); + caps.dwSize = sizeof(DIDEVCAPS); + hr = IDirectInputDevice8_GetCapabilities( device, &caps ); + ok( hr == DI_OK, "GetCapabilities returned %#lx\n", hr ); + check_member( caps, expect_caps, "%lu", dwSize ); + check_member( caps, expect_caps, "%#lx", dwFlags ); + todo_wine + check_member( caps, expect_caps, "%#lx", dwDevType ); + check_member( caps, expect_caps, "%lu", dwAxes ); + check_member( caps, expect_caps, "%lu", dwButtons ); + check_member( caps, expect_caps, "%lu", dwPOVs ); + check_member( caps, expect_caps, "%lu", dwFFSamplePeriod ); + check_member( caps, expect_caps, "%lu", dwFFMinTimeResolution ); + check_member( caps, expect_caps, "%lu", dwFirmwareRevision ); + check_member( caps, expect_caps, "%lu", dwHardwareRevision ); + check_member( caps, expect_caps, "%lu", dwFFDriverVersion ); + + hr = IDirectInputDevice8_EnumObjects( device, check_objects, &check_objects_params, DIDFT_ALL ); + ok( hr == DI_OK, "EnumObjects returned %#lx\n", hr ); + ok( check_objects_params.index >= check_objects_params.expect_count, "missing %u objects\n", + check_objects_params.expect_count - check_objects_params.index ); + + ref = IDirectInputDevice8_Release( device ); + ok( ref == 0, "Release returned %ld\n", ref ); + +done: + pnp_driver_stop(); + cleanup_registry_keys(); + SetCurrentDirectoryW( cwd ); + winetest_pop_context(); +} + static BOOL test_winmm_joystick(void) { #include "psh_hid_macros.h" @@ -2966,6 +3198,8 @@ START_TEST( joystick8 ) test_simple_joystick( 0x500 ); test_simple_joystick( 0x700 ); test_simple_joystick( 0x800 ); + + test_driving_wheel_axes(); } CoUninitialize();