|
38 | 38 | #define MAX_CONTROLLERS (PS2_MAX_PORT * PS2_MAX_SLOT) |
39 | 39 | #define PS2_ANALOG_STICKS 2 |
40 | 40 | #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. |
42 | 42 | #define PS2_TOTAL_AXIS (PS2_ANALOG_STICKS * PS2_ANALOG_AXIS) |
43 | 43 |
|
44 | 44 | struct JoyInfo |
@@ -269,9 +269,9 @@ static bool PS2_JoystickOpen(SDL_Joystick *joystick, int device_index) |
269 | 269 | } |
270 | 270 | PS2_InitializePad(info->port, info->slot); |
271 | 271 |
|
272 | | - joystick->nbuttons = PS2_BUTTONS; |
| 272 | + joystick->nbuttons = PS2_BUTTONS - 4; // we steal 4 (the d-pad) for a hat switch. |
273 | 273 | joystick->naxes = PS2_TOTAL_AXIS; |
274 | | - joystick->nhats = 0; |
| 274 | + joystick->nhats = 1; // treat the dpad buttons as a hat. |
275 | 275 |
|
276 | 276 | SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); |
277 | 277 |
|
@@ -347,19 +347,49 @@ static void PS2_JoystickUpdate(SDL_Joystick *joystick) |
347 | 347 | int ret = padRead(info->port, info->slot, &buttons); // port, slot, buttons |
348 | 348 | if (ret != 0) { |
349 | 349 | // 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++; |
359 | 368 | } |
360 | 369 | } |
| 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; |
361 | 392 | } |
362 | | - info->btns = pressed_buttons; |
363 | 393 |
|
364 | 394 | // Analog |
365 | 395 | all_axis[0] = buttons.ljoy_h; |
|
0 commit comments