summaryrefslogtreecommitdiff
path: root/src/input_common/sdl/sdl_impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/sdl/sdl_impl.cpp')
-rw-r--r--src/input_common/sdl/sdl_impl.cpp47
1 files changed, 45 insertions, 2 deletions
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 7827e324c..d56b7587b 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -1014,11 +1014,44 @@ public:
1014 } 1014 }
1015 return {}; 1015 return {};
1016 } 1016 }
1017 [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const { 1017 [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(SDL_Event& event) {
1018 switch (event.type) { 1018 switch (event.type) {
1019 case SDL_JOYAXISMOTION: 1019 case SDL_JOYAXISMOTION:
1020 if (std::abs(event.jaxis.value / 32767.0) < 0.5) { 1020 if (!axis_memory.count(event.jaxis.which) ||
1021 !axis_memory[event.jaxis.which].count(event.jaxis.axis)) {
1022 axis_memory[event.jaxis.which][event.jaxis.axis] = event.jaxis.value;
1023 axis_event_count[event.jaxis.which][event.jaxis.axis] = 1;
1021 break; 1024 break;
1025 } else {
1026 axis_event_count[event.jaxis.which][event.jaxis.axis]++;
1027 // The joystick and axis exist in our map if we take this branch, so no checks
1028 // needed
1029 if (std::abs(
1030 (event.jaxis.value - axis_memory[event.jaxis.which][event.jaxis.axis]) /
1031 32767.0) < 0.5) {
1032 break;
1033 } else {
1034 if (axis_event_count[event.jaxis.which][event.jaxis.axis] == 2 &&
1035 IsAxisAtPole(event.jaxis.value) &&
1036 IsAxisAtPole(axis_memory[event.jaxis.which][event.jaxis.axis])) {
1037 // If we have exactly two events and both are near a pole, this is
1038 // likely a digital input masquerading as an analog axis; Instead of
1039 // trying to look at the direction the axis travelled, assume the first
1040 // event was press and the second was release; This should handle most
1041 // digital axes while deferring to the direction of travel for analog
1042 // axes
1043 event.jaxis.value = static_cast<Sint16>(
1044 std::copysign(32767, axis_memory[event.jaxis.which][event.jaxis.axis]));
1045 } else {
1046 // There are more than two events, so this is likely a true analog axis,
1047 // check the direction it travelled
1048 event.jaxis.value = static_cast<Sint16>(std::copysign(
1049 32767,
1050 event.jaxis.value - axis_memory[event.jaxis.which][event.jaxis.axis]));
1051 }
1052 axis_memory.clear();
1053 axis_event_count.clear();
1054 }
1022 } 1055 }
1023 [[fallthrough]]; 1056 [[fallthrough]];
1024 case SDL_JOYBUTTONUP: 1057 case SDL_JOYBUTTONUP:
@@ -1027,6 +1060,16 @@ public:
1027 } 1060 }
1028 return std::nullopt; 1061 return std::nullopt;
1029 } 1062 }
1063
1064private:
1065 // Determine whether an axis value is close to an extreme or center
1066 // Some controllers have a digital D-Pad as a pair of analog sticks, with 3 possible values per
1067 // axis, which is why the center must be considered a pole
1068 bool IsAxisAtPole(int16_t value) const {
1069 return std::abs(value) >= 32767 || std::abs(value) < 327;
1070 }
1071 std::unordered_map<SDL_JoystickID, std::unordered_map<uint8_t, int16_t>> axis_memory;
1072 std::unordered_map<SDL_JoystickID, std::unordered_map<uint8_t, uint32_t>> axis_event_count;
1030}; 1073};
1031 1074
1032class SDLMotionPoller final : public SDLPoller { 1075class SDLMotionPoller final : public SDLPoller {