From 842b7fd4db44d85308afbb401023429621d9c586 Mon Sep 17 00:00:00 2001
From: ewewukek <ewewukek@gmail.com>
Date: Thu, 11 Jan 2024 15:04:28 +0300
Subject: Make sticks/triggers behave like regular buttons

---
 src/gui/sdlinput.cpp       |  1 +
 src/input/inputmanager.cpp | 33 ++++++++++++++++++++++++-
 src/input/joystick.cpp     | 61 +++++++++++++++++++++++++++++++++++++++++++---
 src/input/joystick.h       | 15 ++++++++++--
 4 files changed, 103 insertions(+), 7 deletions(-)

diff --git a/src/gui/sdlinput.cpp b/src/gui/sdlinput.cpp
index bf6f0536c..8f3ca8bff 100644
--- a/src/gui/sdlinput.cpp
+++ b/src/gui/sdlinput.cpp
@@ -173,6 +173,7 @@ void SDLInput::pushInput(const SDL_Event &event)
 
         case SDL_JOYBUTTONDOWN:
         case SDL_JOYHATMOTION:
+        case SDL_JOYAXISMOTION:
         {
             const InputActionT actionId = inputManager.getActionByKey(event);
             if (actionId > InputAction::NO_VALUE)
diff --git a/src/input/inputmanager.cpp b/src/input/inputmanager.cpp
index ac5325e3b..fc2815b5e 100644
--- a/src/input/inputmanager.cpp
+++ b/src/input/inputmanager.cpp
@@ -441,6 +441,20 @@ std::string InputManager::getKeyStringLong(const InputActionT index) const
                 // TRANSLATORS: joystick right button. must be short.
                 str = _("JRight");
             }
+            else if (key.value >= Joystick::KEY_NEGATIVE_AXIS_FIRST
+                     && key.value < Joystick::KEY_POSITIVE_AXIS_FIRST)
+            {
+                // TRANSLATORS: joystick negative axis. must be short.
+                str = strprintf(_("JAxis%dMinus"),
+                    key.value - Joystick::KEY_NEGATIVE_AXIS_FIRST);
+            }
+            else if (key.value >= Joystick::KEY_POSITIVE_AXIS_FIRST
+                     && key.value < Joystick::KEY_END)
+            {
+                // TRANSLATORS: joystick positive axis. must be short.
+                str = strprintf(_("JAxis%dPlus"),
+                    key.value - Joystick::KEY_POSITIVE_AXIS_FIRST);
+            }
         }
         if (!str.empty())
         {
@@ -507,6 +521,20 @@ void InputManager::updateKeyString(const InputFunction &ki,
                 // TRANSLATORS: joystick right button. must be very short
                 str = _("JRt");
             }
+            else if (key.value >= Joystick::KEY_NEGATIVE_AXIS_FIRST
+                     && key.value < Joystick::KEY_POSITIVE_AXIS_FIRST)
+            {
+                // TRANSLATORS: joystick negative axis. must be very short.
+                str = strprintf(_("JA%d-"),
+                    key.value - Joystick::KEY_NEGATIVE_AXIS_FIRST);
+            }
+            else if (key.value >= Joystick::KEY_POSITIVE_AXIS_FIRST
+                     && key.value < Joystick::KEY_END)
+            {
+                // TRANSLATORS: joystick positive axis. must be very short.
+                str = strprintf(_("JA%d+"),
+                    key.value - Joystick::KEY_POSITIVE_AXIS_FIRST);
+            }
         }
         if (!str.empty())
         {
@@ -697,10 +725,12 @@ bool InputManager::handleEvent(const SDL_Event &restrict event) restrict2
         }
         case SDL_JOYBUTTONDOWN:
         case SDL_JOYHATMOTION:
+        case SDL_JOYAXISMOTION:
         {
             updateConditionMask(true);
 //            joystick.handleActicateButton(event);
-            if (handleAssignKey(event, InputType::JOYSTICK))
+            if (joystick != nullptr && joystick->isActionEvent(event)
+                && handleAssignKey(event, InputType::JOYSTICK))
             {
                 BLOCK_END("InputManager::handleEvent")
                 return true;
@@ -774,6 +804,7 @@ bool InputManager::handleEvent(const SDL_Event &restrict event) restrict2
 
         case SDL_JOYBUTTONDOWN:
         case SDL_JOYHATMOTION:
+        case SDL_JOYAXISMOTION:
             if ((joystick != nullptr) && joystick->validate())
             {
                 if (triggerAction(joystick->getActionVector(event)))
diff --git a/src/input/joystick.cpp b/src/input/joystick.cpp
index 1e375cb0a..21de2ad3d 100644
--- a/src/input/joystick.cpp
+++ b/src/input/joystick.cpp
@@ -51,6 +51,7 @@ Joystick::Joystick(const int no) :
     mJoystick(nullptr),
     mTolerance(0),
     mNumber(no >= joystickCount ? joystickCount : no),
+    mAxesNumber(MAX_AXES),
     mButtonsNumber(MAX_BUTTONS),
     mUseHatForMovement(true),
     mUseInactive(false),
@@ -59,6 +60,8 @@ Joystick::Joystick(const int no) :
     mKeyToId(),
     mKeyTimeMap()
 {
+    for (int i = 0; i < MAX_AXES; i++)
+        mAxesPositions[i] = 0;
     for (int i = 0; i < MAX_BUTTONS; i++)
         mActiveButtons[i] = false;
 }
@@ -127,7 +130,9 @@ bool Joystick::open()
         return false;
     }
 
+    mAxesNumber = SDL_JoystickNumAxes(mJoystick);
     mButtonsNumber = SDL_JoystickNumButtons(mJoystick);
+
     logger->log("Joystick: %i ", mNumber);
 #ifdef USE_SDL2
     logger->log("Name: %s", SDL_JoystickName(mJoystick));
@@ -186,13 +191,16 @@ bool Joystick::open()
     logger->log("Name: %s", SDL_JoystickName(mNumber));
 #endif  // USE_SDL2
 
-    logger->log("Axes: %i ", SDL_JoystickNumAxes(mJoystick));
+    logger->log("Axes: %i ", mAxesNumber);
     logger->log("Balls: %i", SDL_JoystickNumBalls(mJoystick));
     logger->log("Hats: %i", SDL_JoystickNumHats(mJoystick));
     logger->log("Buttons: %i", mButtonsNumber);
 
     mHaveHats = (SDL_JoystickNumHats(mJoystick) > 0);
 
+    if (mAxesNumber > MAX_AXES)
+        mAxesNumber = mAxesNumber;
+
     if (mButtonsNumber > MAX_BUTTONS)
         mButtonsNumber = MAX_BUTTONS;
 
@@ -244,15 +252,18 @@ void Joystick::logic()
     if (mUseInactive ||
         settings.inputFocused != KeyboardFocus::Unfocused)
     {
+        for (int i = 0; i < mAxesNumber; i++)
+            mAxesPositions[i] = SDL_JoystickGetAxis(mJoystick, i);
+
         // X-Axis
-        int position = SDL_JoystickGetAxis(mJoystick, 0);
+        int position = mAxesPositions[0];
         if (position >= mTolerance * SDL_JOYSTICK_AXIS_MAX)
             mDirection |= RIGHT;
         else if (position <= mTolerance * SDL_JOYSTICK_AXIS_MIN)
             mDirection |= LEFT;
 
         // Y-Axis
-        position = SDL_JoystickGetAxis(mJoystick, 1);
+        position = mAxesPositions[1];
         if (position <= mTolerance * SDL_JOYSTICK_AXIS_MIN)
             mDirection |= UP;
         else if (position >= mTolerance * SDL_JOYSTICK_AXIS_MAX)
@@ -300,6 +311,8 @@ void Joystick::logic()
     else
     {
         mHatPosition = 0;
+        for (int i = 0; i < mAxesNumber; i++)
+            mAxesPositions[i] = 0;
         for (int i = 0; i < mButtonsNumber; i++)
             mActiveButtons[i] = false;
     }
@@ -325,6 +338,20 @@ bool Joystick::buttonPressed(const int no) const
         if (no == KEY_RIGHT)
             return (mHatPosition & RIGHT) != 0;
     }
+    if (KEY_NEGATIVE_AXIS_FIRST <= no && no < KEY_POSITIVE_AXIS_FIRST)
+    {
+        const int axis = no - KEY_NEGATIVE_AXIS_FIRST;
+        if (axis < RESERVED_AXES || axis >= mAxesNumber)
+            return false;
+        return mAxesPositions[axis] < mTolerance * SDL_JOYSTICK_AXIS_MIN;
+    }
+    if (KEY_POSITIVE_AXIS_FIRST <= no && no < KEY_END)
+    {
+        const int axis = no - KEY_POSITIVE_AXIS_FIRST;
+        if (axis < RESERVED_AXES || axis >= mAxesNumber)
+            return false;
+        return mAxesPositions[axis] > mTolerance * SDL_JOYSTICK_AXIS_MAX;
+    }
     return false;
 }
 
@@ -354,7 +381,7 @@ KeysVector *Joystick::getActionVector(const SDL_Event &event)
 
 KeysVector *Joystick::getActionVectorByKey(const int i)
 {
-    if (i < 0 || (i >= mButtonsNumber && i < MAX_BUTTONS) || i > KEY_LAST)
+    if (i < 0 || (i >= mButtonsNumber && i < MAX_BUTTONS) || i >= KEY_END)
         return nullptr;
 //    logger->log("button triggerAction: %d", i);
     if (mKeyToAction.find(i) != mKeyToAction.end())
@@ -397,6 +424,20 @@ int Joystick::getButtonFromEvent(const SDL_Event &event) const
         if ((mHatPosition & RIGHT) == 0 && (value & SDL_HAT_RIGHT) != 0)
             return KEY_RIGHT;
     }
+    if (event.type == SDL_JOYAXISMOTION)
+    {
+        if (event.jaxis.which != mNumber)
+            return -1;
+        const int axis = event.jaxis.axis;
+        if (axis < RESERVED_AXES)
+            return -1;
+        if (event.jaxis.value < mTolerance * SDL_JOYSTICK_AXIS_MIN
+            && mAxesPositions[axis] > mTolerance * SDL_JOYSTICK_AXIS_MIN)
+            return KEY_NEGATIVE_AXIS_FIRST + axis;
+        if (event.jaxis.value > mTolerance * SDL_JOYSTICK_AXIS_MAX
+            && mAxesPositions[axis] < mTolerance * SDL_JOYSTICK_AXIS_MAX)
+            return KEY_POSITIVE_AXIS_FIRST + axis;
+    }
     return -1;
 }
 
@@ -448,6 +489,18 @@ void Joystick::handleRepeat(const int time)
             if (key == KEY_RIGHT && (mHatPosition & RIGHT) != 0)
                 repeat = true;
         }
+        if (KEY_NEGATIVE_AXIS_FIRST <= key && key < KEY_POSITIVE_AXIS_FIRST)
+        {
+            const int axis = key - KEY_NEGATIVE_AXIS_FIRST;
+            if (axis >= RESERVED_AXES && mAxesPositions[axis] < mTolerance * SDL_JOYSTICK_AXIS_MIN)
+                repeat = true;
+        }
+        if (KEY_POSITIVE_AXIS_FIRST <= key && key < KEY_END)
+        {
+            const int axis = key - KEY_POSITIVE_AXIS_FIRST;
+            if (axis >= RESERVED_AXES && mAxesPositions[axis] > mTolerance * SDL_JOYSTICK_AXIS_MAX)
+                repeat = true;
+        }
         if (repeat)
         {
             int &keyTime = (*it).second;
diff --git a/src/input/joystick.h b/src/input/joystick.h
index 293e75a22..2a7e0f638 100644
--- a/src/input/joystick.h
+++ b/src/input/joystick.h
@@ -51,8 +51,15 @@ class Joystick final
             MAX_BUTTONS = 64
         };
 
+        enum
+        {
+            RESERVED_AXES = 2,  // reserved for movement
+            MAX_AXES = 8  // number of axes we can handle
+        };
+
         /**
-         * Additional "buttons" for hat 0 (d-pad).
+         * Additional "buttons" for hat 0 (d-pad),
+         * sticks and triggers.
          */
         enum
         {
@@ -60,7 +67,9 @@ class Joystick final
             KEY_DOWN,
             KEY_LEFT,
             KEY_RIGHT,
-            KEY_LAST = KEY_RIGHT
+            KEY_NEGATIVE_AXIS_FIRST,
+            KEY_POSITIVE_AXIS_FIRST = KEY_NEGATIVE_AXIS_FIRST + MAX_AXES,
+            KEY_END = KEY_POSITIVE_AXIS_FIRST + MAX_AXES
         };
 
         /**
@@ -169,12 +178,14 @@ class Joystick final
         unsigned char mDirection;
 
         unsigned char mHatPosition;
+        int mAxesPositions[MAX_AXES];
         bool mActiveButtons[MAX_BUTTONS];
 
         SDL_Joystick *mJoystick;
 
         float mTolerance;
         int mNumber;
+        int mAxesNumber;
         int mButtonsNumber;
         bool mUseHatForMovement;
         bool mUseInactive;
-- 
cgit v1.2.3-70-g09d2