From 3ef3789f58270a89c7a046a17654a1b022d84c13 Mon Sep 17 00:00:00 2001
From: toaster <rollerorbital@gmail.com>
Date: Fri, 26 Aug 2022 19:09:46 +0100
Subject: [PATCH] Gamepad improvements for menus

* For left stick up/down/left/right input, allow holding a direction down to move continuously in a direction at a rate of 7 steps per second per axis
* Now supports accel axis being used for the Enter key/"accept" in menus, to mirror how an accel BUTTON bind will be used as an Enter event.
---
 src/m_menu.c | 91 ++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 63 insertions(+), 28 deletions(-)

diff --git a/src/m_menu.c b/src/m_menu.c
index 2fd5bc217..29585827d 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -2517,8 +2517,8 @@ boolean M_Responder(event_t *ev)
 {
 	INT32 ch = -1;
 //	INT32 i;
-	static tic_t joywait = 0, mousewait = 0;
-	static INT32 pjoyx = 0, pjoyy = 0;
+	static tic_t joywaitx = 0, joywaity = 0, joywaitaccel = 0, mousewait = 0;
+	static INT32 pjoyx = 0, pjoyy = 0, pjoyaccel = 0;
 	static INT32 pmousex = 0, pmousey = 0;
 	static INT32 lastx = 0, lasty = 0;
 	void (*routine)(INT32 choice); // for some casting problem
@@ -2569,48 +2569,83 @@ boolean M_Responder(event_t *ev)
 	}
 	else if (menuactive)
 	{
-		if (ev->type == ev_joystick  && ev->data1 == 0 && joywait < I_GetTime())
+		tic_t thistime = I_GetTime();
+		if (ev->type == ev_joystick)
 		{
 			const INT32 jxdeadzone = ((JOYAXISRANGE-1) * max(cv_xdeadzone.value, FRACUNIT/2)) >> FRACBITS;
 			const INT32 jydeadzone = ((JOYAXISRANGE-1) * max(cv_ydeadzone.value, FRACUNIT/2)) >> FRACBITS;
-			if (ev->data3 != INT32_MAX)
+			INT32 accelaxis = abs(cv_moveaxis.value);
+			if (ev->data1 == 0)
 			{
-				if (Joystick.bGamepadStyle || abs(ev->data3) > jydeadzone)
+				if (ev->data3 != INT32_MAX)
 				{
-					if (ev->data3 < 0 && pjoyy >= 0)
+					if (Joystick.bGamepadStyle || abs(ev->data3) > jydeadzone)
 					{
-						ch = KEY_UPARROW;
-						joywait = I_GetTime() + NEWTICRATE/7;
+						if (joywaity < thistime)
+						{
+							ch = (ev->data3 < 0) ? KEY_UPARROW : KEY_DOWNARROW;
+							joywaity = thistime;
+							if (pjoyy == 0 // no previous input?
+							|| ((ev->data3 < 0) == (pjoyy < 0))) // same direction as the current one?
+								joywaity += NEWTICRATE/7;
+						}
+						pjoyy = ev->data3;
 					}
-					else if (ev->data3 > 0 && pjoyy <= 0)
+					else
+						pjoyy = 0;
+				}
+
+				if (ev->data2 != INT32_MAX && joywaitx < thistime)
+				{
+					if (Joystick.bGamepadStyle || abs(ev->data2) > jxdeadzone)
 					{
-						ch = KEY_DOWNARROW;
-						joywait = I_GetTime() + NEWTICRATE/7;
+						if (joywaity < thistime)
+						{
+							ch = (ev->data2 < 0) ? KEY_LEFTARROW : KEY_RIGHTARROW;
+							joywaity = thistime;
+							if (pjoyx == 0 // no previous input?
+							|| ((ev->data2 < 0) == (pjoyx < 0))) // same direction as the current one?
+								joywaity += NEWTICRATE/7;
+						}
+						pjoyx = ev->data2;
 					}
-					pjoyy = ev->data3;
+					else
+						pjoyx = 0;
 				}
-				else
-					pjoyy = 0;
 			}
-
-			if (ev->data2 != INT32_MAX)
+			else if (!(accelaxis > JOYAXISSET*2 || accelaxis == 0))
 			{
-				if (Joystick.bGamepadStyle || abs(ev->data2) > jxdeadzone)
+				// The following borrows heavily from Joy1Axis.
+				const boolean xmode = (accelaxis%2);
+				INT32 retaxis = 0;
+				if (!xmode)
+					accelaxis--;
+				accelaxis /= 2;
+				if (ev->data1 == accelaxis)
 				{
-					if (ev->data2 < 0 && pjoyx >= 0)
-					{
-						ch = KEY_LEFTARROW;
-						joywait = I_GetTime() + NEWTICRATE/17;
-					}
-					else if (ev->data2 > 0 && pjoyx <= 0)
+					const INT32 jacceldeadzone = xmode ? jxdeadzone : jydeadzone;
+					retaxis = xmode ? ev->data2 : ev->data3;
+					if (retaxis != INT32_MAX)
 					{
-						ch = KEY_RIGHTARROW;
-						joywait = I_GetTime() + NEWTICRATE/17;
+						if (cv_moveaxis.value < 0)
+							retaxis = -retaxis;
+
+						if (Joystick.bGamepadStyle || abs(retaxis) > jacceldeadzone)
+						{
+							if (joywaitaccel < thistime)
+							{
+								ch = KEY_ENTER;
+								joywaitaccel = thistime;
+								if (pjoyaccel == 0 // no previous input?
+								|| ((retaxis < 0) == (pjoyaccel > 0))) // same direction as the current one?
+									joywaitaccel += NEWTICRATE/3;
+							}
+							pjoyaccel = retaxis;
+						}
+						else
+							pjoyaccel = 0;
 					}
-					pjoyx = ev->data2;
 				}
-				else
-					pjoyx = 0;
 			}
 		}
 		else if (ev->type == ev_mouse && mousewait < I_GetTime())
-- 
GitLab