Skip to content

Commit 18f8f3a

Browse files
committed
ps2: Treat the d-pad as a hat switch at the SDL_Joystick level.
Reference Issue #14830.
1 parent 968fac3 commit 18f8f3a

2 files changed

Lines changed: 44 additions & 14 deletions

File tree

src/joystick/SDL_gamepad_db.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,7 @@ static const char *s_GamepadMappings[] = {
865865
"default,*,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
866866
#endif
867867
#ifdef SDL_JOYSTICK_PS2
868-
"0000000050533220436f6e74726f6c00,PS2 Controller,crc:ed87,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
868+
"0000000050533220436f6e74726f6c00,PS2 Controller,crc:ed87,a:b14,b:b13,back:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
869869
#endif
870870
#ifdef SDL_JOYSTICK_PSP
871871
"00000000505350206275696c74696e00,PSP builtin joypad,crc:bb86,a:b2,b:b1,back:b10,dpdown:b6,dpleft:b7,dpright:b9,dpup:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",

src/joystick/ps2/SDL_sysjoystick.c

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
#define MAX_CONTROLLERS (PS2_MAX_PORT * PS2_MAX_SLOT)
3939
#define PS2_ANALOG_STICKS 2
4040
#define PS2_ANALOG_AXIS 2
41-
#define PS2_BUTTONS 16
41+
#define PS2_BUTTONS 16 // this is total physical buttons, but we steal the 4 from the dpad for a hat switch.
4242
#define PS2_TOTAL_AXIS (PS2_ANALOG_STICKS * PS2_ANALOG_AXIS)
4343

4444
struct JoyInfo
@@ -269,9 +269,9 @@ static bool PS2_JoystickOpen(SDL_Joystick *joystick, int device_index)
269269
}
270270
PS2_InitializePad(info->port, info->slot);
271271

272-
joystick->nbuttons = PS2_BUTTONS;
272+
joystick->nbuttons = PS2_BUTTONS - 4; // we steal 4 (the d-pad) for a hat switch.
273273
joystick->naxes = PS2_TOTAL_AXIS;
274-
joystick->nhats = 0;
274+
joystick->nhats = 1; // treat the dpad buttons as a hat.
275275

276276
SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true);
277277

@@ -347,19 +347,49 @@ static void PS2_JoystickUpdate(SDL_Joystick *joystick)
347347
int ret = padRead(info->port, info->slot, &buttons); // port, slot, buttons
348348
if (ret != 0) {
349349
// Buttons
350-
int32_t pressed_buttons = 0xffff ^ buttons.btns;
351-
;
352-
if (info->btns != pressed_buttons) {
353-
for (i = 0; i < PS2_BUTTONS; i++) {
354-
mask = (1 << i);
355-
previous = info->btns & mask;
356-
current = pressed_buttons & mask;
357-
if (previous != current) {
358-
SDL_SendJoystickButton(timestamp, joystick, i, (current != 0));
350+
#define HAT_MASK 0xF0 // mask out bits 4-7 (that's the dpad, which we treat as a hat elsewhere).
351+
const int32_t current_buttons = (0xffff ^ buttons.btns);
352+
const int32_t previous_buttons = info->btns;
353+
if (previous_buttons != current_buttons) { // did any buttons change?
354+
if ((previous_buttons & ~HAT_MASK) != (current_buttons & ~HAT_MASK)) { // did non-dpad buttons change?
355+
uint8_t buttonidx = 0;
356+
i = 0;
357+
while (i < PS2_BUTTONS-4) {
358+
if ((buttonidx < 4) || (buttonidx > 7)) { // skip dpad (we treat it as a hat).
359+
mask = (1 << buttonidx);
360+
previous = previous_buttons & mask;
361+
current = current_buttons & mask;
362+
if (previous != current) {
363+
SDL_SendJoystickButton(timestamp, joystick, i, (current != 0));
364+
}
365+
i++;
366+
}
367+
buttonidx++;
359368
}
360369
}
370+
371+
if ((previous_buttons & HAT_MASK) != (current_buttons & HAT_MASK)) { // did dpad buttons change?
372+
// The PS2 dpad looks like 4 buttons at this level, but we treat it as a hat switch, so apps that are talking to SDL_Joystick can hope to do basic directional things without a configuration step.
373+
// (but they should _really_ be using the gamepad API.)
374+
Uint8 hat = SDL_HAT_CENTERED;
375+
#define HATSTATE(ps2bit, sdlenum) if (pressed_hat_buttons & (1 << ps2bit)) { hat |= SDL_HAT_##sdlenum; }
376+
HATSTATE(4, UP);
377+
HATSTATE(5, RIGHT);
378+
HATSTATE(6, DOWN);
379+
HATSTATE(7, LEFT);
380+
#undef HATSTATE
381+
// this is a physical d-pad on the device, so it probably _can't_ send opposing buttons at the same time, but just in case, cancel them out.
382+
if ((hat & (SDL_HAT_UP|SDL_HAT_DOWN)) == (SDL_HAT_UP|SDL_HAT_DOWN)) {
383+
hat &= ~(SDL_HAT_UP|SDL_HAT_DOWN);
384+
}
385+
if ((hat & (SDL_HAT_LEFT|SDL_HAT_RIGHT)) == (SDL_HAT_LEFT|SDL_HAT_RIGHT)) {
386+
hat &= ~(SDL_HAT_LEFT|SDL_HAT_RIGHT);
387+
}
388+
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
389+
}
390+
391+
info->btns = current_buttons;
361392
}
362-
info->btns = pressed_buttons;
363393

364394
// Analog
365395
all_axis[0] = buttons.ljoy_h;

0 commit comments

Comments
 (0)