Report the D-Pad for HIDAPI gamepads as a hat

This makes it easier for games that don't use the gamepad API to handle D-Pad navigation, and is consistent with many other non-HIDAPI mappings.

Fixes https://github.com/libsdl-org/SDL/issues/8754
This commit is contained in:
Sam Lantinga
2023-12-27 11:28:27 -08:00
parent ce329d60e4
commit 70ba3f2830
14 changed files with 454 additions and 427 deletions

View File

@@ -240,8 +240,9 @@ static SDL_bool HIDAPI_DriverPS3_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joy
ctx->player_index = SDL_GetJoystickPlayerIndex(joystick);
/* Initialize the joystick capabilities */
joystick->nbuttons = 15;
joystick->nbuttons = 11;
joystick->naxes = 16;
joystick->nhats = 1;
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 100.0f);
@@ -314,47 +315,38 @@ static void HIDAPI_DriverPS3_HandleMiniStatePacket(SDL_Joystick *joystick, SDL_D
Uint64 timestamp = SDL_GetTicksNS();
if (ctx->last_state[4] != data[4]) {
SDL_bool dpad_up = SDL_FALSE;
SDL_bool dpad_down = SDL_FALSE;
SDL_bool dpad_left = SDL_FALSE;
SDL_bool dpad_right = SDL_FALSE;
Uint8 hat;
switch (data[4] & 0x0f) {
case 0:
dpad_up = SDL_TRUE;
hat = SDL_HAT_UP;
break;
case 1:
dpad_up = SDL_TRUE;
dpad_right = SDL_TRUE;
hat = SDL_HAT_RIGHTUP;
break;
case 2:
dpad_right = SDL_TRUE;
hat = SDL_HAT_RIGHT;
break;
case 3:
dpad_right = SDL_TRUE;
dpad_down = SDL_TRUE;
hat = SDL_HAT_RIGHTDOWN;
break;
case 4:
dpad_down = SDL_TRUE;
hat = SDL_HAT_DOWN;
break;
case 5:
dpad_left = SDL_TRUE;
dpad_down = SDL_TRUE;
hat = SDL_HAT_LEFTDOWN;
break;
case 6:
dpad_left = SDL_TRUE;
hat = SDL_HAT_LEFT;
break;
case 7:
dpad_up = SDL_TRUE;
dpad_left = SDL_TRUE;
hat = SDL_HAT_LEFTUP;
break;
default:
hat = SDL_HAT_CENTERED;
break;
}
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, dpad_down);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, dpad_up);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, dpad_right);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, dpad_left);
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, (data[4] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, (data[4] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
@@ -391,14 +383,26 @@ static void HIDAPI_DriverPS3_HandleStatePacket(SDL_Joystick *joystick, SDL_Drive
Uint64 timestamp = SDL_GetTicksNS();
if (ctx->last_state[2] != data[2]) {
Uint8 hat = 0;
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, (data[2] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, (data[2] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, (data[2] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, (data[2] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, (data[2] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, (data[2] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, (data[2] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
if (data[2] & 0x10) {
hat |= SDL_HAT_UP;
}
if (data[2] & 0x20) {
hat |= SDL_HAT_RIGHT;
}
if (data[2] & 0x40) {
hat |= SDL_HAT_DOWN;
}
if (data[2] & 0x80) {
hat |= SDL_HAT_LEFT;
}
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
}
if (ctx->last_state[3] != data[3]) {
@@ -639,8 +643,9 @@ static SDL_bool HIDAPI_DriverPS3ThirdParty_OpenJoystick(SDL_HIDAPI_Device *devic
SDL_zeroa(ctx->last_state);
/* Initialize the joystick capabilities */
joystick->nbuttons = 15;
joystick->nbuttons = 11;
joystick->naxes = 16;
joystick->nhats = 1;
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
return SDL_TRUE;
@@ -691,10 +696,7 @@ static void HIDAPI_DriverPS3ThirdParty_HandleStatePacket18(SDL_Joystick *joystic
}
if (ctx->last_state[1] != data[1]) {
SDL_bool dpad_up = SDL_FALSE;
SDL_bool dpad_down = SDL_FALSE;
SDL_bool dpad_left = SDL_FALSE;
SDL_bool dpad_right = SDL_FALSE;
Uint8 hat;
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, (data[1] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
@@ -703,40 +705,34 @@ static void HIDAPI_DriverPS3ThirdParty_HandleStatePacket18(SDL_Joystick *joystic
switch (data[1] >> 4) {
case 0:
dpad_up = SDL_TRUE;
hat = SDL_HAT_UP;
break;
case 1:
dpad_up = SDL_TRUE;
dpad_right = SDL_TRUE;
hat = SDL_HAT_RIGHTUP;
break;
case 2:
dpad_right = SDL_TRUE;
hat = SDL_HAT_RIGHT;
break;
case 3:
dpad_right = SDL_TRUE;
dpad_down = SDL_TRUE;
hat = SDL_HAT_RIGHTDOWN;
break;
case 4:
dpad_down = SDL_TRUE;
hat = SDL_HAT_DOWN;
break;
case 5:
dpad_left = SDL_TRUE;
dpad_down = SDL_TRUE;
hat = SDL_HAT_LEFTDOWN;
break;
case 6:
dpad_left = SDL_TRUE;
hat = SDL_HAT_LEFT;
break;
case 7:
dpad_up = SDL_TRUE;
dpad_left = SDL_TRUE;
hat = SDL_HAT_LEFTUP;
break;
default:
hat = SDL_HAT_CENTERED;
break;
}
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, dpad_down);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, dpad_up);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, dpad_right);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, dpad_left);
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
}
axis = ((int)data[16] * 257) - 32768;
@@ -813,53 +809,55 @@ static void HIDAPI_DriverPS3ThirdParty_HandleStatePacket19(SDL_Joystick *joystic
if (ctx->device->vendor_id == USB_VENDOR_SAITEK && ctx->device->product_id == USB_PRODUCT_SAITEK_CYBORG_V3) {
/* Cyborg V.3 Rumble Pad doesn't set the dpad bits as expected, so use the axes instead */
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, data[10] ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, data[9] ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, data[7] ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, data[8] ? SDL_PRESSED : SDL_RELEASED);
Uint8 hat = 0;
if (data[7]) {
hat |= SDL_HAT_RIGHT;
}
if (data[8]) {
hat |= SDL_HAT_LEFT;
}
if (data[9]) {
hat |= SDL_HAT_UP;
}
if (data[10]) {
hat |= SDL_HAT_DOWN;
}
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
} else {
if (ctx->last_state[2] != data[2]) {
SDL_bool dpad_up = SDL_FALSE;
SDL_bool dpad_down = SDL_FALSE;
SDL_bool dpad_left = SDL_FALSE;
SDL_bool dpad_right = SDL_FALSE;
Uint8 hat;
switch (data[2] & 0x0f) {
case 0:
dpad_up = SDL_TRUE;
hat = SDL_HAT_UP;
break;
case 1:
dpad_up = SDL_TRUE;
dpad_right = SDL_TRUE;
hat = SDL_HAT_RIGHTUP;
break;
case 2:
dpad_right = SDL_TRUE;
hat = SDL_HAT_RIGHT;
break;
case 3:
dpad_right = SDL_TRUE;
dpad_down = SDL_TRUE;
hat = SDL_HAT_RIGHTDOWN;
break;
case 4:
dpad_down = SDL_TRUE;
hat = SDL_HAT_DOWN;
break;
case 5:
dpad_left = SDL_TRUE;
dpad_down = SDL_TRUE;
hat = SDL_HAT_LEFTDOWN;
break;
case 6:
dpad_left = SDL_TRUE;
hat = SDL_HAT_LEFT;
break;
case 7:
dpad_up = SDL_TRUE;
dpad_left = SDL_TRUE;
hat = SDL_HAT_LEFTUP;
break;
default:
hat = SDL_HAT_CENTERED;
break;
}
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, dpad_down);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, dpad_up);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, dpad_right);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, dpad_left);
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
}
}