diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c index f3f4b57c0..9bf688acf 100644 --- a/src/joystick/SDL_gamecontroller.c +++ b/src/joystick/SDL_gamecontroller.c @@ -1089,6 +1089,91 @@ static ControllerMapping_t *SDL_PrivateGetControllerMappingForNameAndGUID(const return mapping; } +static void SDL_PrivateAppendToMappingString(char *mapping_string, + size_t mapping_string_len, + const char *input_name, + SDL_InputMapping *mapping) +{ + char buffer[16]; + if (mapping->kind == EMappingKind_None) { + return; + } + + SDL_strlcat(mapping_string, input_name, mapping_string_len); + SDL_strlcat(mapping_string, ":", mapping_string_len); + switch (mapping->kind) { + case EMappingKind_Button: + SDL_snprintf(buffer, sizeof(buffer), "b%i", mapping->target); + break; + case EMappingKind_Axis: + SDL_snprintf(buffer, sizeof(buffer), "a%i", mapping->target); + break; + case EMappingKind_Hat: + SDL_snprintf(buffer, sizeof(buffer), "h%i.%i", mapping->target >> 4, mapping->target & 0x0F); + break; + default: + SDL_assert(SDL_FALSE); + } + + SDL_strlcat(mapping_string, buffer, mapping_string_len); + SDL_strlcat(mapping_string, ",", mapping_string_len); +} + +static ControllerMapping_t *SDL_PrivateGenerateAutomaticControllerMapping(const char *name, + SDL_JoystickGUID guid, + SDL_GamepadMapping *raw_map) +{ + SDL_bool existing; + char name_string[128]; + char mapping[1024]; + + /* Remove any commas in the name */ + SDL_strlcpy(name_string, name, sizeof(name_string)); + { + char *spot; + for (spot = name_string; *spot; ++spot) { + if (*spot == ',') { + *spot = ' '; + } + } + } + SDL_snprintf(mapping, sizeof(mapping), "none,%s,", name_string); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "a", &raw_map->a); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "b", &raw_map->b); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "x", &raw_map->x); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "y", &raw_map->y); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "back", &raw_map->back); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "guide", &raw_map->guide); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "start", &raw_map->start); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "leftstick", &raw_map->leftstick); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "rightstick", &raw_map->rightstick); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "leftshoulder", &raw_map->leftshoulder); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "rightshoulder", &raw_map->rightshoulder); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpup", &raw_map->dpup); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpdown", &raw_map->dpdown); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpleft", &raw_map->dpleft); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpright", &raw_map->dpright); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "leftx", &raw_map->leftx); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "lefty", &raw_map->lefty); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "rightx", &raw_map->rightx); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "righty", &raw_map->righty); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "lefttrigger", &raw_map->lefttrigger); + SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "righttrigger", &raw_map->righttrigger); + + /* Remove trailing comma */ + { + int pos = (int)SDL_strlen(mapping) - 1; + if (pos >= 0) { + if (mapping[pos] == ',') { + mapping[pos] = '\0'; + } + } + } + + return SDL_PrivateAddMappingForGUID(guid, mapping, + &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT); +} + static ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index) { const char *name; @@ -1106,6 +1191,13 @@ static ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index) name = SDL_JoystickNameForIndex(device_index); guid = SDL_JoystickGetDeviceGUID(device_index); mapping = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid); + if (!mapping) { + SDL_GamepadMapping raw_map; + if (SDL_PrivateJoystickGetAutoGamepadMapping(device_index, &raw_map)) { + mapping = SDL_PrivateGenerateAutomaticControllerMapping(name, guid, &raw_map); + } + } + SDL_UnlockJoysticks(); return mapping; } diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 4722b602e..1ac8d5e94 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -584,6 +584,21 @@ SDL_PrivateJoystickValid(SDL_Joystick * joystick) return valid; } +SDL_bool +SDL_PrivateJoystickGetAutoGamepadMapping(int device_index, SDL_GamepadMapping * out) +{ + SDL_JoystickDriver *driver; + SDL_bool is_ok = SDL_FALSE; + + SDL_LockJoysticks(); + if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) { + is_ok = driver->GetGamepadMapping(device_index, out); + } + SDL_UnlockJoysticks(); + + return is_ok; +} + /* * Get the number of multi-dimensional axis controls on a joystick */ diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h index 392a5f807..02bf2b5a9 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/src/joystick/SDL_joystick_c.h @@ -111,6 +111,49 @@ extern void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, /* Internal sanity checking functions */ extern SDL_bool SDL_PrivateJoystickValid(SDL_Joystick * joystick); +typedef enum +{ + EMappingKind_None = 0, + EMappingKind_Button = 1, + EMappingKind_Axis = 2, + EMappingKind_Hat = 3 +} EMappingKind; + +typedef struct _SDL_InputMapping +{ + EMappingKind kind; + Uint8 target; +} SDL_InputMapping; + +typedef struct _SDL_GamepadMapping +{ + SDL_InputMapping a; + SDL_InputMapping b; + SDL_InputMapping x; + SDL_InputMapping y; + SDL_InputMapping back; + SDL_InputMapping guide; + SDL_InputMapping start; + SDL_InputMapping leftstick; + SDL_InputMapping rightstick; + SDL_InputMapping leftshoulder; + SDL_InputMapping rightshoulder; + SDL_InputMapping dpup; + SDL_InputMapping dpdown; + SDL_InputMapping dpleft; + SDL_InputMapping dpright; + SDL_InputMapping leftx; + SDL_InputMapping lefty; + SDL_InputMapping rightx; + SDL_InputMapping righty; + SDL_InputMapping lefttrigger; + SDL_InputMapping righttrigger; +} SDL_GamepadMapping; + +/* Function to get autodetected gamepad controller mapping from the driver */ +extern SDL_bool SDL_PrivateJoystickGetAutoGamepadMapping(int device_index, + SDL_GamepadMapping *out); + #endif /* SDL_joystick_c_h_ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index e0ac96726..982e953a3 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -136,6 +136,9 @@ typedef struct _SDL_JoystickDriver /* Function to perform any system-specific joystick related cleanup */ void (*Quit)(void); + /* Function to get the autodetected controller mapping; returns false if there isn't any. */ + SDL_bool (*GetGamepadMapping)(int device_index, SDL_GamepadMapping * out); + } SDL_JoystickDriver; /* Windows and Mac OSX has a limit of MAX_DWORD / 1000, Linux kernel has a limit of 0xFFFF */ diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c index 6ea044682..1ff322ec2 100644 --- a/src/joystick/android/SDL_sysjoystick.c +++ b/src/joystick/android/SDL_sysjoystick.c @@ -693,6 +693,12 @@ ANDROID_JoystickQuit(void) #endif /* 0 */ } +static SDL_bool +ANDROID_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) +{ + return SDL_FALSE; +} + SDL_JoystickDriver SDL_ANDROID_JoystickDriver = { ANDROID_JoystickInit, @@ -708,6 +714,7 @@ SDL_JoystickDriver SDL_ANDROID_JoystickDriver = ANDROID_JoystickUpdate, ANDROID_JoystickClose, ANDROID_JoystickQuit, + ANDROID_JoystickGetGamepadMapping }; #endif /* SDL_JOYSTICK_ANDROID */ diff --git a/src/joystick/bsd/SDL_sysjoystick.c b/src/joystick/bsd/SDL_sysjoystick.c index 057f93b4a..e47557df3 100644 --- a/src/joystick/bsd/SDL_sysjoystick.c +++ b/src/joystick/bsd/SDL_sysjoystick.c @@ -762,6 +762,12 @@ BSD_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 return SDL_Unsupported(); } +static SDL_bool +BSD_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) +{ + return SDL_FALSE; +} + SDL_JoystickDriver SDL_BSD_JoystickDriver = { BSD_JoystickInit, @@ -777,6 +783,7 @@ SDL_JoystickDriver SDL_BSD_JoystickDriver = BSD_JoystickUpdate, BSD_JoystickClose, BSD_JoystickQuit, + BSD_JoystickGetGamepadMapping }; #endif /* SDL_JOYSTICK_USBHID */ diff --git a/src/joystick/darwin/SDL_sysjoystick.c b/src/joystick/darwin/SDL_sysjoystick.c index fbee787ca..637975ff8 100644 --- a/src/joystick/darwin/SDL_sysjoystick.c +++ b/src/joystick/darwin/SDL_sysjoystick.c @@ -1051,6 +1051,12 @@ DARWIN_JoystickQuit(void) } } +static SDL_bool +DARWIN_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) +{ + return SDL_FALSE; +} + SDL_JoystickDriver SDL_DARWIN_JoystickDriver = { DARWIN_JoystickInit, @@ -1066,6 +1072,7 @@ SDL_JoystickDriver SDL_DARWIN_JoystickDriver = DARWIN_JoystickUpdate, DARWIN_JoystickClose, DARWIN_JoystickQuit, + DARWIN_JoystickGetGamepadMapping }; #endif /* SDL_JOYSTICK_IOKIT */ diff --git a/src/joystick/dummy/SDL_sysjoystick.c b/src/joystick/dummy/SDL_sysjoystick.c index 4fcceaf85..4ca2a9f50 100644 --- a/src/joystick/dummy/SDL_sysjoystick.c +++ b/src/joystick/dummy/SDL_sysjoystick.c @@ -104,6 +104,12 @@ DUMMY_JoystickQuit(void) { } +static SDL_bool +DUMMY_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) +{ + return SDL_FALSE; +} + SDL_JoystickDriver SDL_DUMMY_JoystickDriver = { DUMMY_JoystickInit, @@ -119,6 +125,7 @@ SDL_JoystickDriver SDL_DUMMY_JoystickDriver = DUMMY_JoystickUpdate, DUMMY_JoystickClose, DUMMY_JoystickQuit, + DUMMY_JoystickGetGamepadMapping }; #endif /* SDL_JOYSTICK_DUMMY || SDL_JOYSTICK_DISABLED */ diff --git a/src/joystick/emscripten/SDL_sysjoystick.c b/src/joystick/emscripten/SDL_sysjoystick.c index 02d08746c..6ddb06753 100644 --- a/src/joystick/emscripten/SDL_sysjoystick.c +++ b/src/joystick/emscripten/SDL_sysjoystick.c @@ -403,6 +403,12 @@ EMSCRIPTEN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, return SDL_Unsupported(); } +static SDL_bool +EMSCRIPTEN_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) +{ + return SDL_FALSE; +} + SDL_JoystickDriver SDL_EMSCRIPTEN_JoystickDriver = { EMSCRIPTEN_JoystickInit, @@ -418,6 +424,7 @@ SDL_JoystickDriver SDL_EMSCRIPTEN_JoystickDriver = EMSCRIPTEN_JoystickUpdate, EMSCRIPTEN_JoystickClose, EMSCRIPTEN_JoystickQuit, + EMSCRIPTEN_JoystickGetGamepadMapping }; #endif /* SDL_JOYSTICK_EMSCRIPTEN */ diff --git a/src/joystick/haiku/SDL_haikujoystick.cc b/src/joystick/haiku/SDL_haikujoystick.cc index c34db5370..370e9e148 100644 --- a/src/joystick/haiku/SDL_haikujoystick.cc +++ b/src/joystick/haiku/SDL_haikujoystick.cc @@ -259,6 +259,12 @@ extern "C" return SDL_Unsupported(); } + static SDL_bool + HAIKU_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) + { + return SDL_FALSE; + } + SDL_JoystickDriver SDL_HAIKU_JoystickDriver = { HAIKU_JoystickInit, @@ -274,6 +280,7 @@ extern "C" HAIKU_JoystickUpdate, HAIKU_JoystickClose, HAIKU_JoystickQuit, + HAIKU_JoystickGetGamepadMapping }; } // extern "C" diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c index 9ed82d850..d5aea3e15 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick.c +++ b/src/joystick/hidapi/SDL_hidapijoystick.c @@ -1101,6 +1101,12 @@ HIDAPI_JoystickQuit(void) initialized = SDL_FALSE; } +static SDL_bool +HIDAPI_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) +{ + return SDL_FALSE; +} + SDL_JoystickDriver SDL_HIDAPI_JoystickDriver = { HIDAPI_JoystickInit, @@ -1116,6 +1122,7 @@ SDL_JoystickDriver SDL_HIDAPI_JoystickDriver = HIDAPI_JoystickUpdate, HIDAPI_JoystickClose, HIDAPI_JoystickQuit, + HIDAPI_JoystickGetGamepadMapping }; #endif /* SDL_JOYSTICK_HIDAPI */ diff --git a/src/joystick/iphoneos/SDL_sysjoystick.m b/src/joystick/iphoneos/SDL_sysjoystick.m index 4f413e976..b8b029a02 100644 --- a/src/joystick/iphoneos/SDL_sysjoystick.m +++ b/src/joystick/iphoneos/SDL_sysjoystick.m @@ -850,6 +850,12 @@ IOS_JoystickQuit(void) numjoysticks = 0; } +static SDL_bool +IOS_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) +{ + return SDL_FALSE; +} + SDL_JoystickDriver SDL_IOS_JoystickDriver = { IOS_JoystickInit, @@ -865,6 +871,7 @@ SDL_JoystickDriver SDL_IOS_JoystickDriver = IOS_JoystickUpdate, IOS_JoystickClose, IOS_JoystickQuit, + IOS_JoystickGetGamepadMapping }; /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c index 28bccd8ea..2ffb4eb47 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -656,6 +656,7 @@ ConfigJoystick(SDL_Joystick * joystick, int fd) printf("Joystick has button: 0x%x\n", i); #endif joystick->hwdata->key_map[i] = joystick->nbuttons; + joystick->hwdata->has_key[i] = SDL_TRUE; ++joystick->nbuttons; } } @@ -665,6 +666,7 @@ ConfigJoystick(SDL_Joystick * joystick, int fd) printf("Joystick has button: 0x%x\n", i); #endif joystick->hwdata->key_map[i] = joystick->nbuttons; + joystick->hwdata->has_key[i] = SDL_TRUE; ++joystick->nbuttons; } } @@ -687,6 +689,7 @@ ConfigJoystick(SDL_Joystick * joystick, int fd) absinfo.fuzz, absinfo.flat); #endif /* DEBUG_INPUT_EVENTS */ joystick->hwdata->abs_map[i] = joystick->naxes; + joystick->hwdata->has_abs[i] = SDL_TRUE; if (absinfo.minimum == absinfo.maximum) { joystick->hwdata->abs_correct[i].used = 0; } else { @@ -721,6 +724,7 @@ ConfigJoystick(SDL_Joystick * joystick, int fd) absinfo.fuzz, absinfo.flat); #endif /* DEBUG_INPUT_EVENTS */ joystick->hwdata->hats_indices[hat_index] = joystick->nhats++; + joystick->hwdata->has_hat[hat_index] = SDL_TRUE; } } if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) { @@ -1100,6 +1104,181 @@ LINUX_JoystickQuit(void) SDL_QuitSteamControllers(); } +/* + This is based on the Linux Gamepad Specification + available at: https://www.kernel.org/doc/html/v4.15/input/gamepad.html + */ +static SDL_bool +LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) +{ + SDL_Joystick * joystick; + + joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1); + if (joystick == NULL) { + SDL_OutOfMemory(); + return SDL_FALSE; + } + + /* We temporarily open the device to check how it's configured. */ + if (LINUX_JoystickOpen(joystick, device_index) < 0) { + SDL_free(joystick); + return SDL_FALSE; + } + + if (!joystick->hwdata->has_key[BTN_GAMEPAD]) { + /* Not a gamepad according to the specs. */ + LINUX_JoystickClose(joystick); + SDL_free(joystick); + return SDL_FALSE; + } + + /* We have a gamepad; start filling out the mappings. */ + memset(out, 0, sizeof(SDL_GamepadMapping)); + + if (joystick->hwdata->has_key[BTN_SOUTH]) { + out->a.kind = EMappingKind_Button; + out->a.target = joystick->hwdata->key_map[BTN_SOUTH]; + } + + if (joystick->hwdata->has_key[BTN_EAST]) { + out->b.kind = EMappingKind_Button; + out->b.target = joystick->hwdata->key_map[BTN_EAST]; + } + + if (joystick->hwdata->has_key[BTN_NORTH]) { + out->y.kind = EMappingKind_Button; + out->y.target = joystick->hwdata->key_map[BTN_NORTH]; + } + + if (joystick->hwdata->has_key[BTN_WEST]) { + out->x.kind = EMappingKind_Button; + out->x.target = joystick->hwdata->key_map[BTN_WEST]; + } + + if (joystick->hwdata->has_key[BTN_SELECT]) { + out->back.kind = EMappingKind_Button; + out->back.target = joystick->hwdata->key_map[BTN_SELECT]; + } + + if (joystick->hwdata->has_key[BTN_START]) { + out->start.kind = EMappingKind_Button; + out->start.target = joystick->hwdata->key_map[BTN_START]; + } + + if (joystick->hwdata->has_key[BTN_THUMBL]) { + out->leftstick.kind = EMappingKind_Button; + out->leftstick.target = joystick->hwdata->key_map[BTN_THUMBL]; + } + + if (joystick->hwdata->has_key[BTN_THUMBR]) { + out->rightstick.kind = EMappingKind_Button; + out->rightstick.target = joystick->hwdata->key_map[BTN_THUMBR]; + } + + if (joystick->hwdata->has_key[BTN_MODE]) { + out->guide.kind = EMappingKind_Button; + out->guide.target = joystick->hwdata->key_map[BTN_MODE]; + } + + /* + According to the specs the D-Pad, the shoulder buttons and the triggers + can be digital, or analog, or both at the same time. + */ + + /* Prefer digital shoulder buttons, but settle for analog if missing. */ + if (joystick->hwdata->has_key[BTN_TL]) { + out->leftshoulder.kind = EMappingKind_Button; + out->leftshoulder.target = joystick->hwdata->key_map[BTN_TL]; + } + + if (joystick->hwdata->has_key[BTN_TR]) { + out->rightshoulder.kind = EMappingKind_Button; + out->rightshoulder.target = joystick->hwdata->key_map[BTN_TR]; + } + + if (joystick->hwdata->has_hat[1] && /* Check if ABS_HAT1{X, Y} is available. */ + (!joystick->hwdata->has_key[BTN_TL] || !joystick->hwdata->has_key[BTN_TR])) { + int hat = joystick->hwdata->hats_indices[1] << 4; + out->leftshoulder.kind = EMappingKind_Hat; + out->rightshoulder.kind = EMappingKind_Hat; + out->leftshoulder.target = hat | 0x4; + out->rightshoulder.target = hat | 0x2; + } + + /* Prefer analog triggers, but settle for digital if missing. */ + if (joystick->hwdata->has_hat[2]) { /* Check if ABS_HAT2{X,Y} is available. */ + int hat = joystick->hwdata->hats_indices[2] << 4; + out->lefttrigger.kind = EMappingKind_Hat; + out->righttrigger.kind = EMappingKind_Hat; + out->lefttrigger.target = hat | 0x4; + out->righttrigger.target = hat | 0x2; + } else { + if (joystick->hwdata->has_key[BTN_TL2]) { + out->lefttrigger.kind = EMappingKind_Button; + out->lefttrigger.target = joystick->hwdata->key_map[BTN_TL2]; + } + + if (joystick->hwdata->has_key[BTN_TR2]) { + out->righttrigger.kind = EMappingKind_Button; + out->righttrigger.target = joystick->hwdata->key_map[BTN_TR2]; + } + } + + /* Prefer digital D-Pad, but settle for analog if missing. */ + if (joystick->hwdata->has_key[BTN_DPAD_UP]) { + out->dpup.kind = EMappingKind_Button; + out->dpup.target = joystick->hwdata->key_map[BTN_DPAD_UP]; + } + + if (joystick->hwdata->has_key[BTN_DPAD_DOWN]) { + out->dpdown.kind = EMappingKind_Button; + out->dpdown.target = joystick->hwdata->key_map[BTN_DPAD_DOWN]; + } + + if (joystick->hwdata->has_key[BTN_DPAD_LEFT]) { + out->dpleft.kind = EMappingKind_Button; + out->dpleft.target = joystick->hwdata->key_map[BTN_DPAD_LEFT]; + } + + if (joystick->hwdata->has_key[BTN_DPAD_RIGHT]) { + out->dpright.kind = EMappingKind_Button; + out->dpright.target = joystick->hwdata->key_map[BTN_DPAD_RIGHT]; + } + + if (joystick->hwdata->has_hat[0] && /* Check if ABS_HAT0{X,Y} is available. */ + (!joystick->hwdata->has_key[BTN_DPAD_LEFT] || !joystick->hwdata->has_key[BTN_DPAD_RIGHT] || + !joystick->hwdata->has_key[BTN_DPAD_UP] || !joystick->hwdata->has_key[BTN_DPAD_DOWN])) { + int hat = joystick->hwdata->hats_indices[0] << 4; + out->dpleft.kind = EMappingKind_Hat; + out->dpright.kind = EMappingKind_Hat; + out->dpup.kind = EMappingKind_Hat; + out->dpdown.kind = EMappingKind_Hat; + out->dpleft.target = hat | 0x8; + out->dpright.target = hat | 0x2; + out->dpup.target = hat | 0x1; + out->dpdown.target = hat | 0x4; + } + + if (joystick->hwdata->has_abs[ABS_X] && joystick->hwdata->has_abs[ABS_Y]) { + out->leftx.kind = EMappingKind_Axis; + out->lefty.kind = EMappingKind_Axis; + out->leftx.target = joystick->hwdata->abs_map[ABS_X]; + out->lefty.target = joystick->hwdata->abs_map[ABS_Y]; + } + + if (joystick->hwdata->has_abs[ABS_RX] && joystick->hwdata->has_abs[ABS_RY]) { + out->rightx.kind = EMappingKind_Axis; + out->righty.kind = EMappingKind_Axis; + out->rightx.target = joystick->hwdata->abs_map[ABS_RX]; + out->righty.target = joystick->hwdata->abs_map[ABS_RY]; + } + + LINUX_JoystickClose(joystick); + SDL_free(joystick); + + return SDL_TRUE; +} + SDL_JoystickDriver SDL_LINUX_JoystickDriver = { LINUX_JoystickInit, @@ -1115,6 +1294,7 @@ SDL_JoystickDriver SDL_LINUX_JoystickDriver = LINUX_JoystickUpdate, LINUX_JoystickClose, LINUX_JoystickQuit, + LINUX_JoystickGetGamepadMapping }; #endif /* SDL_JOYSTICK_LINUX */ diff --git a/src/joystick/linux/SDL_sysjoystick_c.h b/src/joystick/linux/SDL_sysjoystick_c.h index a92429bcc..6f162ae9c 100644 --- a/src/joystick/linux/SDL_sysjoystick_c.h +++ b/src/joystick/linux/SDL_sysjoystick_c.h @@ -53,6 +53,9 @@ struct joystick_hwdata /* Support for the Linux 2.4 unified input interface */ Uint8 key_map[KEY_MAX]; Uint8 abs_map[ABS_MAX]; + SDL_bool has_key[KEY_MAX]; + SDL_bool has_abs[ABS_MAX]; + struct axis_correct { int used; @@ -65,6 +68,7 @@ struct joystick_hwdata SDL_bool m_bSteamController; /* 4 = (ABS_HAT3X-ABS_HAT0X)/2 (see input-event-codes.h in kernel) */ int hats_indices[4]; + SDL_bool has_hat[4]; /* Set when gamepad is pending removal due to ENODEV read error */ SDL_bool gone; diff --git a/src/joystick/virtual/SDL_virtualjoystick.c b/src/joystick/virtual/SDL_virtualjoystick.c index 623ed1c97..ce075b075 100644 --- a/src/joystick/virtual/SDL_virtualjoystick.c +++ b/src/joystick/virtual/SDL_virtualjoystick.c @@ -391,6 +391,11 @@ VIRTUAL_JoystickQuit(void) } } +static SDL_bool +VIRTUAL_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) +{ + return SDL_FALSE; +} SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver = { @@ -407,6 +412,7 @@ SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver = VIRTUAL_JoystickUpdate, VIRTUAL_JoystickClose, VIRTUAL_JoystickQuit, + VIRTUAL_JoystickGetGamepadMapping }; #endif /* SDL_JOYSTICK_VIRTUAL || SDL_JOYSTICK_DISABLED */ diff --git a/src/joystick/windows/SDL_rawinputjoystick.c b/src/joystick/windows/SDL_rawinputjoystick.c index f17e8526a..4134e4ceb 100644 --- a/src/joystick/windows/SDL_rawinputjoystick.c +++ b/src/joystick/windows/SDL_rawinputjoystick.c @@ -725,6 +725,11 @@ RAWINPUT_JoystickQuit(void) SDL_RAWINPUT_inited = SDL_FALSE; } +static SDL_bool +RAWINPUT_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) +{ + return SDL_FALSE; +} SDL_JoystickDriver SDL_RAWINPUT_JoystickDriver = { @@ -741,6 +746,7 @@ SDL_JoystickDriver SDL_RAWINPUT_JoystickDriver = RAWINPUT_JoystickUpdate, RAWINPUT_JoystickClose, RAWINPUT_JoystickQuit, + RAWINPUT_JoystickGetGamepadMapping }; #endif /* SDL_JOYSTICK_RAWINPUT */ diff --git a/src/joystick/windows/SDL_windows_gaming_input.c b/src/joystick/windows/SDL_windows_gaming_input.c index 90ab8cd5a..e491d3e41 100644 --- a/src/joystick/windows/SDL_windows_gaming_input.c +++ b/src/joystick/windows/SDL_windows_gaming_input.c @@ -699,6 +699,12 @@ WGI_JoystickQuit(void) WIN_CoUninitialize(); } +static SDL_bool +WGI_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) +{ + return SDL_FALSE; +} + SDL_JoystickDriver SDL_WGI_JoystickDriver = { WGI_JoystickInit, @@ -714,6 +720,7 @@ SDL_JoystickDriver SDL_WGI_JoystickDriver = WGI_JoystickUpdate, WGI_JoystickClose, WGI_JoystickQuit, + WGI_JoystickGetGamepadMapping }; #endif /* SDL_JOYSTICK_WGI */ diff --git a/src/joystick/windows/SDL_windowsjoystick.c b/src/joystick/windows/SDL_windowsjoystick.c index df8fdf165..042676000 100644 --- a/src/joystick/windows/SDL_windowsjoystick.c +++ b/src/joystick/windows/SDL_windowsjoystick.c @@ -555,6 +555,12 @@ WINDOWS_JoystickQuit(void) s_bDeviceRemoved = SDL_FALSE; } +static SDL_bool +WINDOWS_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) +{ + return SDL_FALSE; +} + SDL_JoystickDriver SDL_WINDOWS_JoystickDriver = { WINDOWS_JoystickInit, @@ -570,6 +576,7 @@ SDL_JoystickDriver SDL_WINDOWS_JoystickDriver = WINDOWS_JoystickUpdate, WINDOWS_JoystickClose, WINDOWS_JoystickQuit, + WINDOWS_JoystickGetGamepadMapping }; #endif /* SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT */