-- v3: winmm: Reimplement joystick axis mapping. dinput/tests: Use exotic axes ordering for winmm tests.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dinput/tests/joystick8.c | 36 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 191e5273e1d..29cd0836cbd 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -4434,13 +4434,13 @@ static BOOL test_winmm_joystick(void) REPORT_ID(1, 1),
USAGE(1, HID_USAGE_GENERIC_X), - USAGE(1, HID_USAGE_GENERIC_Y), - USAGE(1, HID_USAGE_GENERIC_Z), USAGE(1, HID_USAGE_GENERIC_WHEEL), - USAGE(1, HID_USAGE_GENERIC_SLIDER), USAGE(1, HID_USAGE_GENERIC_RX), - USAGE(1, HID_USAGE_GENERIC_RY), + USAGE(1, HID_USAGE_GENERIC_DIAL), USAGE(1, HID_USAGE_GENERIC_RZ), + USAGE(1, HID_USAGE_GENERIC_SLIDER), + USAGE(1, HID_USAGE_GENERIC_Z), + USAGE(1, HID_USAGE_GENERIC_RY), LOGICAL_MINIMUM(1, 1), LOGICAL_MAXIMUM(4, 0xffff), PHYSICAL_MINIMUM(1, 1), @@ -4498,9 +4498,9 @@ static BOOL test_winmm_joystick(void) .wRmax = 0xffff, .wUmax = 0xffff, .wVmax = 0xffff, - .wCaps = JOYCAPS_HASZ | JOYCAPS_HASR | JOYCAPS_HASU | JOYCAPS_HASV | JOYCAPS_HASPOV | JOYCAPS_POV4DIR, + .wCaps = JOYCAPS_HASZ | JOYCAPS_HASR | JOYCAPS_HASU | JOYCAPS_HASPOV | JOYCAPS_POV4DIR, .wMaxAxes = 6, - .wNumAxes = 6, + .wNumAxes = 5, .wMaxButtons = 32, .szRegKey = L"DINPUT.DLL", }; @@ -4519,19 +4519,19 @@ static BOOL test_winmm_joystick(void) { { .dwSize = sizeof(JOYINFOEX), .dwFlags = 0xff, - .dwXpos = 0x7fff, .dwYpos = 0x7fff, .dwZpos = 0x7fff, .dwRpos = 0x7fff, .dwUpos = 0x7fff, .dwVpos = 0x7fff, + .dwXpos = 0x7fff, .dwYpos = 0x7fff, .dwZpos = 0x7fff, .dwRpos = 0x7fff, .dwUpos = 0x7fff, .dwVpos = 0, .dwButtons = 0, .dwButtonNumber = 0, .dwPOV = 0xffff, .dwReserved1 = 0xcdcdcdcd, .dwReserved2 = 0xcdcdcdcd, }, { .dwSize = sizeof(JOYINFOEX), .dwFlags = 0xff, - .dwXpos = 0, .dwYpos = 0x07ff, .dwZpos = 0x17ff, .dwRpos = 0x37ff, .dwUpos = 0x1fff, .dwVpos = 0x27ff, + .dwXpos = 0, .dwYpos = 0x0fff, .dwZpos = 0x2fff, .dwRpos = 0x1fff, .dwUpos = 0x27ff, .dwVpos = 0, .dwButtons = 0xf, .dwButtonNumber = 0x4, .dwPOV = 0, .dwReserved1 = 0xcdcdcdcd, .dwReserved2 = 0xcdcdcdcd, }, { .dwSize = sizeof(JOYINFOEX), .dwFlags = 0xff, - .dwXpos = 0x37ff, .dwYpos = 0x2fff, .dwZpos = 0x1fff, .dwRpos = 0, .dwUpos = 0x17ff, .dwVpos = 0x0fff, + .dwXpos = 0x37ff, .dwYpos = 0x27ff, .dwZpos = 0x07ff, .dwRpos = 0x17ff, .dwUpos = 0x0fff, .dwVpos = 0, .dwButtons = 0x6, .dwButtonNumber = 0x2, .dwPOV = 0x2328, .dwReserved1 = 0xcdcdcdcd, .dwReserved2 = 0xcdcdcdcd, }, @@ -4641,9 +4641,9 @@ static BOOL test_winmm_joystick(void) check_member( caps, expect_caps, "%#x", wUmax ); check_member( caps, expect_caps, "%#x", wVmin ); check_member( caps, expect_caps, "%#x", wVmax ); - check_member( caps, expect_caps, "%#x", wCaps ); + todo_wine check_member( caps, expect_caps, "%#x", wCaps ); check_member( caps, expect_caps, "%#x", wMaxAxes ); - check_member( caps, expect_caps, "%#x", wNumAxes ); + todo_wine check_member( caps, expect_caps, "%#x", wNumAxes ); check_member( caps, expect_caps, "%#x", wMaxButtons ); check_member_wstr( caps, expect_caps, szRegKey ); check_member_wstr( caps, expect_caps, szOEMVxD ); @@ -4677,11 +4677,11 @@ static BOOL test_winmm_joystick(void) check_member( infoex, expect_infoex[0], "%#lx", dwSize ); check_member( infoex, expect_infoex[0], "%#lx", dwFlags ); check_member( infoex, expect_infoex[0], "%#lx", dwXpos ); - check_member( infoex, expect_infoex[0], "%#lx", dwYpos ); + todo_wine check_member( infoex, expect_infoex[0], "%#lx", dwYpos ); check_member( infoex, expect_infoex[0], "%#lx", dwZpos ); check_member( infoex, expect_infoex[0], "%#lx", dwRpos ); check_member( infoex, expect_infoex[0], "%#lx", dwUpos ); - check_member( infoex, expect_infoex[0], "%#lx", dwVpos ); + todo_wine check_member( infoex, expect_infoex[0], "%#lx", dwVpos ); check_member( infoex, expect_infoex[0], "%#lx", dwButtons ); check_member( infoex, expect_infoex[0], "%#lx", dwButtonNumber ); check_member( infoex, expect_infoex[0], "%#lx", dwPOV ); @@ -4700,7 +4700,7 @@ static BOOL test_winmm_joystick(void) ret = joyGetPos( 0, &info ); ok( ret == 0, "joyGetPos returned %u\n", ret ); check_member( info, expect_info, "%#x", wXpos ); - check_member( info, expect_info, "%#x", wYpos ); + todo_wine check_member( info, expect_info, "%#x", wYpos ); check_member( info, expect_info, "%#x", wZpos ); check_member( info, expect_info, "%#x", wButtons );
@@ -4738,11 +4738,11 @@ static BOOL test_winmm_joystick(void) check_member( infoex, expect_infoex[1], "%#lx", dwSize ); check_member( infoex, expect_infoex[1], "%#lx", dwFlags ); check_member( infoex, expect_infoex[1], "%#lx", dwXpos ); - check_member( infoex, expect_infoex[1], "%#lx", dwYpos ); + todo_wine check_member( infoex, expect_infoex[1], "%#lx", dwYpos ); check_member( infoex, expect_infoex[1], "%#lx", dwZpos ); check_member( infoex, expect_infoex[1], "%#lx", dwRpos ); check_member( infoex, expect_infoex[1], "%#lx", dwUpos ); - check_member( infoex, expect_infoex[1], "%#lx", dwVpos ); + todo_wine check_member( infoex, expect_infoex[1], "%#lx", dwVpos ); check_member( infoex, expect_infoex[1], "%#lx", dwButtons ); check_member( infoex, expect_infoex[1], "%#lx", dwButtonNumber ); check_member( infoex, expect_infoex[1], "%#lx", dwPOV ); @@ -4760,11 +4760,11 @@ static BOOL test_winmm_joystick(void) check_member( infoex, expect_infoex[2], "%#lx", dwSize ); check_member( infoex, expect_infoex[2], "%#lx", dwFlags ); check_member( infoex, expect_infoex[2], "%#lx", dwXpos ); - check_member( infoex, expect_infoex[2], "%#lx", dwYpos ); + todo_wine check_member( infoex, expect_infoex[2], "%#lx", dwYpos ); check_member( infoex, expect_infoex[2], "%#lx", dwZpos ); check_member( infoex, expect_infoex[2], "%#lx", dwRpos ); check_member( infoex, expect_infoex[2], "%#lx", dwUpos ); - check_member( infoex, expect_infoex[2], "%#lx", dwVpos ); + todo_wine check_member( infoex, expect_infoex[2], "%#lx", dwVpos ); check_member( infoex, expect_infoex[2], "%#lx", dwButtons ); check_member( infoex, expect_infoex[2], "%#lx", dwButtonNumber ); check_member( infoex, expect_infoex[2], "%#lx", dwPOV );
From: Zebediah Figura zfigura@codeweavers.com
This should more closely match the algorithm used by native, discovered through extensive manual testing.
This does not include any automated tests, both because I could not get winmm to recognize a second plugged joystick, and (as I eventually discovered while testing) the number of tests that would be necessary to conclusively prove this algorithm turned out to be impractical.
--
I discovered that a certain joystick, an XBox clone (Logitech F310) was failing to report all of its axes to a winmm game (Super Smash Flash 2). The joystick reports axes X, Y, Z, RX, RY, RZ, but currently winmm does not map RY.
Checking Windows's joy.cpl implied that our HID usages were correct, so I instead started checking whether our mapping algorithm was correct for a synthetic joystick with the same usages.
It turned out that it was not. Native winmm appears to work in a way that is relatively intuitive to understand: for each axis, it runs through a list of candidate usages. If the candidate usage is present on the joystick, and wasn't already mapped to a different axis, then the axis is mapped. --- dlls/dinput/tests/joystick8.c | 16 +-- dlls/winmm/joystick.c | 203 ++++++++++++++++++++++------------ 2 files changed, 140 insertions(+), 79 deletions(-)
diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 29cd0836cbd..88d9e4d9ffe 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -4641,7 +4641,7 @@ static BOOL test_winmm_joystick(void) check_member( caps, expect_caps, "%#x", wUmax ); check_member( caps, expect_caps, "%#x", wVmin ); check_member( caps, expect_caps, "%#x", wVmax ); - todo_wine check_member( caps, expect_caps, "%#x", wCaps ); + check_member( caps, expect_caps, "%#x", wCaps ); check_member( caps, expect_caps, "%#x", wMaxAxes ); todo_wine check_member( caps, expect_caps, "%#x", wNumAxes ); check_member( caps, expect_caps, "%#x", wMaxButtons ); @@ -4677,11 +4677,11 @@ static BOOL test_winmm_joystick(void) check_member( infoex, expect_infoex[0], "%#lx", dwSize ); check_member( infoex, expect_infoex[0], "%#lx", dwFlags ); check_member( infoex, expect_infoex[0], "%#lx", dwXpos ); - todo_wine check_member( infoex, expect_infoex[0], "%#lx", dwYpos ); + check_member( infoex, expect_infoex[0], "%#lx", dwYpos ); check_member( infoex, expect_infoex[0], "%#lx", dwZpos ); check_member( infoex, expect_infoex[0], "%#lx", dwRpos ); check_member( infoex, expect_infoex[0], "%#lx", dwUpos ); - todo_wine check_member( infoex, expect_infoex[0], "%#lx", dwVpos ); + check_member( infoex, expect_infoex[0], "%#lx", dwVpos ); check_member( infoex, expect_infoex[0], "%#lx", dwButtons ); check_member( infoex, expect_infoex[0], "%#lx", dwButtonNumber ); check_member( infoex, expect_infoex[0], "%#lx", dwPOV ); @@ -4700,7 +4700,7 @@ static BOOL test_winmm_joystick(void) ret = joyGetPos( 0, &info ); ok( ret == 0, "joyGetPos returned %u\n", ret ); check_member( info, expect_info, "%#x", wXpos ); - todo_wine check_member( info, expect_info, "%#x", wYpos ); + check_member( info, expect_info, "%#x", wYpos ); check_member( info, expect_info, "%#x", wZpos ); check_member( info, expect_info, "%#x", wButtons );
@@ -4738,11 +4738,11 @@ static BOOL test_winmm_joystick(void) check_member( infoex, expect_infoex[1], "%#lx", dwSize ); check_member( infoex, expect_infoex[1], "%#lx", dwFlags ); check_member( infoex, expect_infoex[1], "%#lx", dwXpos ); - todo_wine check_member( infoex, expect_infoex[1], "%#lx", dwYpos ); + check_member( infoex, expect_infoex[1], "%#lx", dwYpos ); check_member( infoex, expect_infoex[1], "%#lx", dwZpos ); check_member( infoex, expect_infoex[1], "%#lx", dwRpos ); check_member( infoex, expect_infoex[1], "%#lx", dwUpos ); - todo_wine check_member( infoex, expect_infoex[1], "%#lx", dwVpos ); + check_member( infoex, expect_infoex[1], "%#lx", dwVpos ); check_member( infoex, expect_infoex[1], "%#lx", dwButtons ); check_member( infoex, expect_infoex[1], "%#lx", dwButtonNumber ); check_member( infoex, expect_infoex[1], "%#lx", dwPOV ); @@ -4760,11 +4760,11 @@ static BOOL test_winmm_joystick(void) check_member( infoex, expect_infoex[2], "%#lx", dwSize ); check_member( infoex, expect_infoex[2], "%#lx", dwFlags ); check_member( infoex, expect_infoex[2], "%#lx", dwXpos ); - todo_wine check_member( infoex, expect_infoex[2], "%#lx", dwYpos ); + check_member( infoex, expect_infoex[2], "%#lx", dwYpos ); check_member( infoex, expect_infoex[2], "%#lx", dwZpos ); check_member( infoex, expect_infoex[2], "%#lx", dwRpos ); check_member( infoex, expect_infoex[2], "%#lx", dwUpos ); - todo_wine check_member( infoex, expect_infoex[2], "%#lx", dwVpos ); + check_member( infoex, expect_infoex[2], "%#lx", dwVpos ); check_member( infoex, expect_infoex[2], "%#lx", dwButtons ); check_member( infoex, expect_infoex[2], "%#lx", dwButtonNumber ); check_member( infoex, expect_infoex[2], "%#lx", dwPOV ); diff --git a/dlls/winmm/joystick.c b/dlls/winmm/joystick.c index 0285074bd40..0028b5c168e 100644 --- a/dlls/winmm/joystick.c +++ b/dlls/winmm/joystick.c @@ -33,6 +33,7 @@ #include "winbase.h" #include "mmsystem.h"
+#include "hidusage.h" #include "initguid.h" #include "dinput.h"
@@ -51,69 +52,24 @@ static CRITICAL_SECTION_DEBUG critsect_debug = }; static CRITICAL_SECTION joystick_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
-struct joystick_state +enum axis { - LONG x; - LONG y; - LONG z; - LONG u; - LONG v; - LONG r; - LONG pov; - BYTE buttons[32]; + AXIS_X, + AXIS_Y, + AXIS_Z, + AXIS_R, + AXIS_U, + AXIS_V, + AXIS_COUNT, };
-static const DIOBJECTDATAFORMAT object_formats[] = -{ - { &GUID_XAxis, offsetof(struct joystick_state, x), DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, - { &GUID_YAxis, offsetof(struct joystick_state, y), DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, - { &GUID_ZAxis, offsetof(struct joystick_state, z), DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, - { &GUID_RzAxis, offsetof(struct joystick_state, r), DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, - { &GUID_Slider, offsetof(struct joystick_state, u), DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, - { &GUID_RxAxis, offsetof(struct joystick_state, v), DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, - { &GUID_POV, offsetof(struct joystick_state, pov), DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[0]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[1]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[2]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[3]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[4]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[5]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[6]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[7]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[8]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[9]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[10]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[11]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[12]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[13]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[14]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[15]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[16]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[17]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[18]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[19]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[20]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[21]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[22]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[23]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[24]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[25]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[26]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[27]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[28]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[29]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[30]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, - { NULL, offsetof(struct joystick_state, buttons[31]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, -}; +#define BUTTON_COUNT 32
-static const DIDATAFORMAT data_format = +struct joystick_state { - .dwSize = sizeof(DIDATAFORMAT), - .dwObjSize = sizeof(DIOBJECTDATAFORMAT), - .dwFlags = DIDF_ABSAXIS, - .dwDataSize = sizeof(struct joystick_state), - .dwNumObjs = ARRAY_SIZE(object_formats), - .rgodf = (DIOBJECTDATAFORMAT *)object_formats, + LONG axes[AXIS_COUNT]; + LONG pov; + BYTE buttons[BUTTON_COUNT]; };
#define JOY_PERIOD_MIN (10) /* min Capture time period */ @@ -175,6 +131,111 @@ void joystick_unload(void) IDirectInput8_Release( dinput ); }
+static int is_already_mapped( const DIOBJECTDATAFORMAT *object_formats, DWORD count, DWORD instance_number ) +{ + DWORD i; + + for (i = 0; i < count; ++i) + { + if (object_formats[i].dwType == instance_number) + return 1; + } + + return 0; +} + +struct usage_enum_params +{ + WORD usage; + int found; + DWORD instance_number; +}; + +static BOOL CALLBACK usage_enum_cb( const DIDEVICEOBJECTINSTANCEW *instance, void *ctx ) +{ + struct usage_enum_params *params = ctx; + + if (!(instance->dwFlags & DIDOI_ASPECTPOSITION)) + return DIENUM_CONTINUE; + + if (instance->wUsagePage != HID_USAGE_PAGE_GENERIC) + return DIENUM_CONTINUE; + + if ((params->usage == instance->wUsage) + || (params->usage == HID_USAGE_GENERIC_Z && instance->wUsage == HID_USAGE_GENERIC_WHEEL)) + { + params->instance_number = instance->dwType; + params->found = 1; + return DIENUM_STOP; + } + + return DIENUM_CONTINUE; +} + +static HRESULT set_data_format( IDirectInputDevice8W *device ) +{ + DIOBJECTDATAFORMAT object_formats[AXIS_COUNT + 1 + BUTTON_COUNT] = {{0}}; /* +1 for hat switch */ + DIOBJECTDATAFORMAT *object_format; + DIDATAFORMAT data_format = {0}; + unsigned int i, j; + + static const struct + { + WORD usages[5]; + } + usage_mappings[AXIS_COUNT] = + { + [AXIS_X] = {{HID_USAGE_GENERIC_X, HID_USAGE_GENERIC_RY}}, + [AXIS_Y] = {{HID_USAGE_GENERIC_Y, HID_USAGE_GENERIC_RX}}, + [AXIS_Z] = {{HID_USAGE_GENERIC_Z, HID_USAGE_GENERIC_SLIDER, HID_USAGE_GENERIC_DIAL}}, + [AXIS_R] = {{HID_USAGE_GENERIC_RZ, HID_USAGE_GENERIC_SLIDER, HID_USAGE_GENERIC_DIAL, HID_USAGE_GENERIC_RY, HID_USAGE_GENERIC_RX}}, + [AXIS_U] = {{HID_USAGE_GENERIC_SLIDER, HID_USAGE_GENERIC_DIAL, HID_USAGE_GENERIC_RY, HID_USAGE_GENERIC_RX}}, + [AXIS_V] = {{HID_USAGE_GENERIC_RX}}, + }; + + data_format.dwSize = sizeof(DIDATAFORMAT); + data_format.dwObjSize = sizeof(DIOBJECTDATAFORMAT); + data_format.dwFlags = DIDF_ABSAXIS; + data_format.dwDataSize = sizeof(struct joystick_state); + data_format.rgodf = object_formats; + + for (i = 0; i < ARRAY_SIZE(usage_mappings); ++i) + { + for (j = 0; j < ARRAY_SIZE(usage_mappings[i].usages) && usage_mappings[i].usages[j]; ++j) + { + struct usage_enum_params params = {.usage = usage_mappings[i].usages[j]}; + + /* We can almost use GetObjectInfo() here, except that winmm + * treats Z and wheel identically. */ + if (FAILED(IDirectInputDevice8_EnumObjects( device, usage_enum_cb, ¶ms, DIDFT_AXIS ))) + continue; + if (!params.found) + continue; + if (is_already_mapped( object_formats, data_format.dwNumObjs, params.instance_number )) + continue; + + object_format = &object_formats[data_format.dwNumObjs++]; + object_format->dwOfs = offsetof(struct joystick_state, axes[i]); + object_format->dwType = params.instance_number; + break; + } + } + + object_format = &object_formats[data_format.dwNumObjs++]; + object_format->pguid = &GUID_POV; + object_format->dwOfs = offsetof(struct joystick_state, pov); + object_format->dwType = DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE; + + for (i = 0; i < BUTTON_COUNT; ++i) + { + object_format = &object_formats[data_format.dwNumObjs++]; + object_format->dwOfs = offsetof(struct joystick_state, buttons[i]); + object_format->dwType = DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE; + } + + return IDirectInputDevice8_SetDataFormat( device, &data_format ); +} + static void find_joysticks(void) { static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; @@ -212,7 +273,7 @@ static void find_joysticks(void) WARN( "SetEventNotification device %p hr %#lx\n", device, hr ); else if (FAILED(hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_NONEXCLUSIVE|DISCL_BACKGROUND ))) WARN( "SetCooperativeLevel device %p hr %#lx\n", device, hr ); - else if (FAILED(hr = IDirectInputDevice8_SetDataFormat( device, &data_format ))) + else if (FAILED(hr = set_data_format( device ))) WARN( "SetDataFormat device %p hr %#lx\n", device, hr ); else if (FAILED(hr = IDirectInputDevice8_Acquire( device ))) WARN( "Acquire device %p hr %#lx\n", device, hr ); @@ -381,17 +442,17 @@ MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetDevCapsW( UINT_PTR id, JOYCAPSW *caps, U caps->wVmin = 0; caps->wVmax = 0xffff; caps->wCaps = 0; - caps->wMaxAxes = 6; + caps->wMaxAxes = AXIS_COUNT; caps->wNumAxes = min( dicaps.dwAxes, caps->wMaxAxes ); - caps->wMaxButtons = 32; + caps->wMaxButtons = BUTTON_COUNT;
- hr = IDirectInputDevice8_GetObjectInfo( device, &instance, offsetof(struct joystick_state, z), DIPH_BYOFFSET ); + hr = IDirectInputDevice8_GetObjectInfo( device, &instance, offsetof(struct joystick_state, axes[AXIS_Z]), DIPH_BYOFFSET ); if (SUCCEEDED(hr)) caps->wCaps |= JOYCAPS_HASZ; - hr = IDirectInputDevice8_GetObjectInfo( device, &instance, offsetof(struct joystick_state, r), DIPH_BYOFFSET ); + hr = IDirectInputDevice8_GetObjectInfo( device, &instance, offsetof(struct joystick_state, axes[AXIS_R]), DIPH_BYOFFSET ); if (SUCCEEDED(hr)) caps->wCaps |= JOYCAPS_HASR; - hr = IDirectInputDevice8_GetObjectInfo( device, &instance, offsetof(struct joystick_state, u), DIPH_BYOFFSET ); + hr = IDirectInputDevice8_GetObjectInfo( device, &instance, offsetof(struct joystick_state, axes[AXIS_U]), DIPH_BYOFFSET ); if (SUCCEEDED(hr)) caps->wCaps |= JOYCAPS_HASU; - hr = IDirectInputDevice8_GetObjectInfo( device, &instance, offsetof(struct joystick_state, v), DIPH_BYOFFSET ); + hr = IDirectInputDevice8_GetObjectInfo( device, &instance, offsetof(struct joystick_state, axes[AXIS_V]), DIPH_BYOFFSET ); if (SUCCEEDED(hr)) caps->wCaps |= JOYCAPS_HASV; hr = IDirectInputDevice8_GetObjectInfo( device, &instance, offsetof(struct joystick_state, pov), DIPH_BYOFFSET ); if (SUCCEEDED(hr)) caps->wCaps |= JOYCAPS_HASPOV|JOYCAPS_POV4DIR; @@ -493,12 +554,12 @@ MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetPosEx( UINT id, JOYINFOEX *info ) } else { - if (info->dwFlags & JOY_RETURNX) info->dwXpos = state.x; - if (info->dwFlags & JOY_RETURNY) info->dwYpos = state.y; - if (info->dwFlags & JOY_RETURNZ) info->dwZpos = state.z; - if (info->dwFlags & JOY_RETURNR) info->dwRpos = state.r; - if (info->dwFlags & JOY_RETURNU) info->dwUpos = state.u; - if (info->dwFlags & JOY_RETURNV) info->dwVpos = state.v; + if (info->dwFlags & JOY_RETURNX) info->dwXpos = state.axes[AXIS_X]; + if (info->dwFlags & JOY_RETURNY) info->dwYpos = state.axes[AXIS_Y]; + if (info->dwFlags & JOY_RETURNZ) info->dwZpos = state.axes[AXIS_Z]; + if (info->dwFlags & JOY_RETURNR) info->dwRpos = state.axes[AXIS_R]; + if (info->dwFlags & JOY_RETURNU) info->dwUpos = state.axes[AXIS_U]; + if (info->dwFlags & JOY_RETURNV) info->dwVpos = state.axes[AXIS_V]; if (info->dwFlags & JOY_RETURNPOV) { if (state.pov == ~0) info->dwPOV = 0xffff;
This merge request was approved by Zebediah Figura.
This merge request was approved by Rémi Bernon.