Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better support for secondary stick in DirectInput driver #1463

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/allegro5/internal/aintern_wjoydxnu.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,14 @@ typedef struct
int num_sliders; TCHAR name_slider[MAX_SLIDERS][NAME_LEN];
int num_povs; TCHAR name_pov[MAX_POVS][NAME_LEN];
int num_buttons; TCHAR name_button[MAX_BUTTONS][NAME_LEN];
DWORD secondary_stick_axis_one, secondary_stick_axis_two;
} CAPS_AND_NAMES;


/* map a DirectInput axis to an Allegro (stick,axis) pair */
typedef struct
{
int stick, axis;
int stick, axis, j;
} AXIS_MAPPING;


Expand Down
49 changes: 47 additions & 2 deletions src/win/wjoydxnu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
#include <mmsystem.h>
#include <process.h>
#include <dinput.h>
#include <utility>

/* We need XInput detection if we actually compile the XInput driver in.
*/
Expand Down Expand Up @@ -146,6 +147,7 @@ ALLEGRO_JOYSTICK_DRIVER _al_joydrv_directx =
#define DEFINE_PRIVATE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
static const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }

DEFINE_PRIVATE_GUID(__al_GUID_None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
DEFINE_PRIVATE_GUID(__al_GUID_XAxis, 0xA36D02E0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
DEFINE_PRIVATE_GUID(__al_GUID_YAxis, 0xA36D02E1,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
DEFINE_PRIVATE_GUID(__al_GUID_ZAxis, 0xA36D02E2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
Expand Down Expand Up @@ -503,6 +505,7 @@ static BOOL CALLBACK object_enum_callback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVO
#define GUIDTYPE_EQ(x) GUID_EQUAL(lpddoi->guidType, x)

CAPS_AND_NAMES *can = (CAPS_AND_NAMES *)pvRef;
DWORD j = 0;

if (GUIDTYPE_EQ(__al_GUID_XAxis)) {
can->have_x = true;
Expand All @@ -515,18 +518,22 @@ static BOOL CALLBACK object_enum_callback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVO
else if (GUIDTYPE_EQ(__al_GUID_ZAxis)) {
can->have_z = true;
_tcsncpy(can->name_z, lpddoi->tszName, NAME_LEN);
j = DIJOFS_Z;
}
else if (GUIDTYPE_EQ(__al_GUID_RxAxis)) {
can->have_rx = true;
_tcsncpy(can->name_rx, lpddoi->tszName, NAME_LEN);
j = DIJOFS_RX;
}
else if (GUIDTYPE_EQ(__al_GUID_RyAxis)) {
can->have_ry = true;
_tcsncpy(can->name_ry, lpddoi->tszName, NAME_LEN);
j = DIJOFS_RY;
}
else if (GUIDTYPE_EQ(__al_GUID_RzAxis)) {
can->have_rz = true;
_tcsncpy(can->name_rz, lpddoi->tszName, NAME_LEN);
j = DIJOFS_RZ;
}
else if (GUIDTYPE_EQ(__al_GUID_Slider)) {
if (can->num_sliders < MAX_SLIDERS) {
Expand All @@ -550,6 +557,38 @@ static BOOL CALLBACK object_enum_callback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVO
}
}

// The first two axis (not X or Y) are stored and used as the secondary stick.
// The order of the enumeration is assumed to give us the X followed by the Y axis. However,
// an override is provided in the case that the second axis seen here is for Z, in which case that
// will be used as the X axis. This is to fit behaviors seen on specific controllers:
// - PS4 DualShock
// - Stadia
// ...it may be that using `Z` really is common for some input devices.
//
// Solution came from https://www.gamedev.net/forums/topic/613913-directinput-identifying-second-thumbstick/
if (j)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we have a backwards compatibility mechanism, we can merge a version of this. Could you add check like this https://github.com/liballeg/allegro5/blob/8575e373ab79c7bc25f8425990fc6780e75e69c8/src/macosx/hidjoy.m#L192C4-L192C76 here, so this behavior can be configured?

Also, could j be called something more informative, like... offset_override maybe?

{
if (can->secondary_stick_axis_one == 0)
{
can->secondary_stick_axis_one = j;
_tcsncpy(can->name_rx, lpddoi->tszName, NAME_LEN);
}
else if (can->secondary_stick_axis_two == 0)
{
can->secondary_stick_axis_two = j;
_tcsncpy(can->name_ry, lpddoi->tszName, NAME_LEN);

if (j == DIJOFS_Z)
{
std::swap(can->secondary_stick_axis_one, can->secondary_stick_axis_two);
std::swap(can->name_rx, can->name_ry);
}

can->have_rx = true;
can->have_ry = true;
}
}

return DIENUM_CONTINUE;

#undef GUIDTYPE_EQ
Expand Down Expand Up @@ -640,6 +679,7 @@ static void fill_joystick_info_using_caps_and_names(ALLEGRO_JOYSTICK_DIRECTX *jo
info->stick[N_STICK].axis[N_AXIS].name = ADD_STRING(can->name_rx, default_name_rx);
joy->rx_mapping.stick = N_STICK;
joy->rx_mapping.axis = N_AXIS;
joy->rx_mapping.j = can->secondary_stick_axis_one;
N_AXIS++;
}

Expand All @@ -648,6 +688,7 @@ static void fill_joystick_info_using_caps_and_names(ALLEGRO_JOYSTICK_DIRECTX *jo
info->stick[N_STICK].axis[N_AXIS].name = ADD_STRING(can->name_ry, default_name_ry);
joy->ry_mapping.stick = N_STICK;
joy->ry_mapping.axis = N_AXIS;
joy->ry_mapping.j = can->secondary_stick_axis_two;
N_AXIS++;
}

Expand Down Expand Up @@ -1497,9 +1538,13 @@ static void update_joystick(ALLEGRO_JOYSTICK_DIRECTX *joy)
handle_axis_event(joy, &joy->y_mapping, dwData);
else if (dwOfs == DIJOFS_Z)
handle_axis_event(joy, &joy->z_mapping, dwData);
else if (dwOfs == DIJOFS_RX)
else if (joy->rx_mapping.j && joy->rx_mapping.j == dwOfs)
handle_axis_event(joy, &joy->rx_mapping, dwData);
else if (joy->ry_mapping.j && joy->ry_mapping.j == dwOfs)
handle_axis_event(joy, &joy->ry_mapping, dwData);
else if (joy->rx_mapping.j == 0 && dwOfs == DIJOFS_RX)
handle_axis_event(joy, &joy->rx_mapping, dwData);
else if (dwOfs == DIJOFS_RY)
else if (joy->ry_mapping.j == 0 && dwOfs == DIJOFS_RY)
handle_axis_event(joy, &joy->ry_mapping, dwData);
else if (dwOfs == DIJOFS_RZ)
handle_axis_event(joy, &joy->rz_mapping, dwData);
Expand Down