mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-06 19:38:14 +00:00
joystick: Emscripten can often fake a hat from the d-pad buttons.
Fixes #13817.
This commit is contained in:
@@ -66,8 +66,17 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int first_hat_button = -1;
|
||||||
|
int num_buttons = gamepadEvent->numButtons;
|
||||||
|
if ((SDL_strcmp(gamepadEvent->mapping, "standard") == 0) && (num_buttons >= 16)) { // maps to a game console gamepad layout, turn the d-pad into a hat.
|
||||||
|
num_buttons -= 4;
|
||||||
|
first_hat_button = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
item->first_hat_button = first_hat_button;
|
||||||
|
item->nhats = (first_hat_button >= 0) ? 1 : 0;
|
||||||
item->naxes = gamepadEvent->numAxes;
|
item->naxes = gamepadEvent->numAxes;
|
||||||
item->nbuttons = gamepadEvent->numButtons;
|
item->nbuttons = num_buttons;
|
||||||
item->device_instance = SDL_GetNextObjectID();
|
item->device_instance = SDL_GetNextObjectID();
|
||||||
|
|
||||||
item->timestamp = gamepadEvent->timestamp;
|
item->timestamp = gamepadEvent->timestamp;
|
||||||
@@ -76,9 +85,30 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep
|
|||||||
item->axis[i] = gamepadEvent->axis[i];
|
item->axis[i] = gamepadEvent->axis[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < item->nbuttons; i++) {
|
int buttonidx = 0;
|
||||||
item->analogButton[i] = gamepadEvent->analogButton[i];
|
for (i = 0; i < item->nbuttons; i++, buttonidx++) {
|
||||||
item->digitalButton[i] = gamepadEvent->digitalButton[i];
|
if (buttonidx == first_hat_button) {
|
||||||
|
buttonidx += 3; // skip these buttons, we're treating them as hat input.
|
||||||
|
}
|
||||||
|
item->analogButton[i] = gamepadEvent->analogButton[buttonidx];
|
||||||
|
item->digitalButton[i] = gamepadEvent->digitalButton[buttonidx];
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_assert(item->nhats <= 1); // there is (currently) only ever one of these, faked from the d-pad buttons.
|
||||||
|
if (item->nhats) {
|
||||||
|
Uint8 value = SDL_HAT_CENTERED;
|
||||||
|
// this currently expects the first button to be up, then down, then left, then right.
|
||||||
|
if (gamepadEvent->digitalButton[first_hat_button + 0]) {
|
||||||
|
value |= SDL_HAT_UP;
|
||||||
|
} else if (gamepadEvent->digitalButton[first_hat_button + 1]) {
|
||||||
|
value |= SDL_HAT_DOWN;
|
||||||
|
}
|
||||||
|
if (gamepadEvent->digitalButton[first_hat_button + 2]) {
|
||||||
|
value |= SDL_HAT_LEFT;
|
||||||
|
} else if (gamepadEvent->digitalButton[first_hat_button + 3]) {
|
||||||
|
value |= SDL_HAT_RIGHT;
|
||||||
|
}
|
||||||
|
item->hat = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SDL_joylist_tail) {
|
if (!SDL_joylist_tail) {
|
||||||
@@ -318,9 +348,8 @@ static bool EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
|||||||
joystick->hwdata = (struct joystick_hwdata *)item;
|
joystick->hwdata = (struct joystick_hwdata *)item;
|
||||||
item->joystick = joystick;
|
item->joystick = joystick;
|
||||||
|
|
||||||
// HTML5 Gamepad API doesn't say anything about these
|
// HTML5 Gamepad API doesn't offer hats, but we can fake it from the d-pad buttons on the "standard" mapping.
|
||||||
joystick->nhats = 0;
|
joystick->nhats = item->nhats;
|
||||||
|
|
||||||
joystick->nbuttons = item->nbuttons;
|
joystick->nbuttons = item->nbuttons;
|
||||||
joystick->naxes = item->naxes;
|
joystick->naxes = item->naxes;
|
||||||
|
|
||||||
@@ -361,15 +390,21 @@ static void EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick)
|
|||||||
result = emscripten_get_gamepad_status(item->index, &gamepadState);
|
result = emscripten_get_gamepad_status(item->index, &gamepadState);
|
||||||
if (result == EMSCRIPTEN_RESULT_SUCCESS) {
|
if (result == EMSCRIPTEN_RESULT_SUCCESS) {
|
||||||
if (gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) {
|
if (gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) {
|
||||||
for (i = 0; i < item->nbuttons; i++) {
|
const int first_hat_button = item->first_hat_button;
|
||||||
if (item->digitalButton[i] != gamepadState.digitalButton[i]) {
|
|
||||||
bool down = (gamepadState.digitalButton[i] != 0);
|
int buttonidx = 0;
|
||||||
|
for (i = 0; i < item->nbuttons; i++, buttonidx++) {
|
||||||
|
if (buttonidx == first_hat_button) {
|
||||||
|
buttonidx += 4; // skip these buttons, we're treating them as hat input.
|
||||||
|
}
|
||||||
|
if (item->digitalButton[i] != gamepadState.digitalButton[buttonidx]) {
|
||||||
|
bool down = (gamepadState.digitalButton[buttonidx] != 0);
|
||||||
SDL_SendJoystickButton(timestamp, item->joystick, i, down);
|
SDL_SendJoystickButton(timestamp, item->joystick, i, down);
|
||||||
}
|
}
|
||||||
|
|
||||||
// store values to compare them in the next update
|
// store values to compare them in the next update
|
||||||
item->analogButton[i] = gamepadState.analogButton[i];
|
item->analogButton[i] = gamepadState.analogButton[buttonidx];
|
||||||
item->digitalButton[i] = gamepadState.digitalButton[i];
|
item->digitalButton[i] = gamepadState.digitalButton[buttonidx];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < item->naxes; i++) {
|
for (i = 0; i < item->naxes; i++) {
|
||||||
@@ -383,6 +418,27 @@ static void EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick)
|
|||||||
item->axis[i] = gamepadState.axis[i];
|
item->axis[i] = gamepadState.axis[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_assert(item->nhats <= 1); // there is (currently) only ever one of these, faked from the d-pad buttons.
|
||||||
|
if (item->nhats) {
|
||||||
|
Uint8 value = SDL_HAT_CENTERED;
|
||||||
|
// this currently expects the first button to be up, then down, then left, then right.
|
||||||
|
if (gamepadState.digitalButton[first_hat_button + 0]) {
|
||||||
|
value |= SDL_HAT_UP;
|
||||||
|
} else if (gamepadState.digitalButton[first_hat_button + 1]) {
|
||||||
|
value |= SDL_HAT_DOWN;
|
||||||
|
}
|
||||||
|
if (gamepadState.digitalButton[first_hat_button + 2]) {
|
||||||
|
value |= SDL_HAT_LEFT;
|
||||||
|
} else if (gamepadState.digitalButton[first_hat_button + 3]) {
|
||||||
|
value |= SDL_HAT_RIGHT;
|
||||||
|
}
|
||||||
|
if (item->hat != value) {
|
||||||
|
item->hat = value;
|
||||||
|
SDL_SendJoystickHat(timestamp, item->joystick, 0, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
item->timestamp = gamepadState.timestamp;
|
item->timestamp = gamepadState.timestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -34,12 +34,15 @@ typedef struct SDL_joylist_item
|
|||||||
char *mapping;
|
char *mapping;
|
||||||
SDL_JoystickID device_instance;
|
SDL_JoystickID device_instance;
|
||||||
SDL_Joystick *joystick;
|
SDL_Joystick *joystick;
|
||||||
|
int first_hat_button;
|
||||||
|
int nhats;
|
||||||
int nbuttons;
|
int nbuttons;
|
||||||
int naxes;
|
int naxes;
|
||||||
double timestamp;
|
double timestamp;
|
||||||
double axis[64];
|
double axis[64];
|
||||||
double analogButton[64];
|
double analogButton[64];
|
||||||
EM_BOOL digitalButton[64];
|
EM_BOOL digitalButton[64];
|
||||||
|
Uint8 hat; // there is (currently) only ever one of these, faked from the d-pad buttons.
|
||||||
|
|
||||||
struct SDL_joylist_item *next;
|
struct SDL_joylist_item *next;
|
||||||
} SDL_joylist_item;
|
} SDL_joylist_item;
|
||||||
|
Reference in New Issue
Block a user