commit 7ad0f991beb544f57b00668f6bdfbd60331ae32f
Author: Michael Day <contact@michaelcday.com>
AuthorDate: Wed Nov 29 16:08:15 2023 -0500
Commit: Michael Day <contact@michaelcday.com>
CommitDate: Sun Dec 3 22:50:09 2023 -0500
doom: Gamepad dpad or stick can navigate menu
---
src/d_event.h | 3 +-
src/doom/m_menu.c | 23 ++++++--
src/i_joystick.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++----
src/i_joystick.h | 18 +++++++
4 files changed, 183 insertions(+), 16 deletions(-)
diff --git a/src/d_event.h b/src/d_event.h
index 7cc390a9..bc1050ae 100644
--- a/src/d_event.h
+++ b/src/d_event.h
@@ -60,6 +60,7 @@ typedef enum
// data3: Y axis mouse movement (forward/backward).
// data4: Third axis mouse movement (strafe).
// data5: Fourth axis mouse movement (look)
+ // data6: Dpad and analog stick direction.
ev_joystick,
// Quit event. Triggered when the user clicks the "close" button
@@ -73,7 +74,7 @@ typedef struct
evtype_t type;
// Event-specific data; see the descriptions given above.
- int data1, data2, data3, data4, data5;
+ int data1, data2, data3, data4, data5, data6;
} event_t;
diff --git a/src/doom/m_menu.c b/src/doom/m_menu.c
index 073b8a12..5cb0274f 100644
--- a/src/doom/m_menu.c
+++ b/src/doom/m_menu.c
@@ -30,6 +30,7 @@
#include "deh_main.h"
#include "i_input.h"
+#include "i_joystick.h"
#include "i_swap.h"
#include "i_system.h"
#include "i_timer.h"
@@ -1357,6 +1358,7 @@ boolean M_Responder (event_t* ev)
static int lasty = 0;
static int mousex = 0;
static int lastx = 0;
+ int dir;
// In testcontrols mode, none of the function keys should do anything
// - the only key is escape to quit.
@@ -1404,22 +1406,35 @@ boolean M_Responder (event_t* ev)
if (menuactive)
{
- if (ev->data3 < 0)
+ if (JOY_GET_DPAD(ev->data6) != JOY_DIR_NONE)
+ {
+ dir = JOY_GET_DPAD(ev->data6);
+ }
+ else if (JOY_GET_LSTICK(ev->data6) != JOY_DIR_NONE)
+ {
+ dir = JOY_GET_LSTICK(ev->data6);
+ }
+ else
+ {
+ dir = JOY_GET_RSTICK(ev->data6);
+ }
+
+ if (dir & JOY_DIR_UP)
{
key = key_menu_up;
joywait = I_GetTime() + 5;
}
- else if (ev->data3 > 0)
+ else if (dir & JOY_DIR_DOWN)
{
key = key_menu_down;
joywait = I_GetTime() + 5;
}
- if (ev->data2 < 0)
+ if (dir & JOY_DIR_LEFT)
{
key = key_menu_left;
joywait = I_GetTime() + 2;
}
- else if (ev->data2 > 0)
+ else if (dir & JOY_DIR_RIGHT)
{
key = key_menu_right;
joywait = I_GetTime() + 2;
diff --git a/src/i_joystick.c b/src/i_joystick.c
index 575073bd..5ebaca7e 100644
--- a/src/i_joystick.c
+++ b/src/i_joystick.c
@@ -283,7 +283,8 @@ static int GetButtonsStateGamepad(void)
// Read the state of an axis, inverting if necessary.
-static int GetAxisStateGamepad(int axis, int invert, int dead_zone)
+static int GetAxisStateGamepad(const int *axis_values, int axis, int invert,
+ int dead_zone)
{
int result;
@@ -297,7 +298,7 @@ static int GetAxisStateGamepad(int axis, int invert, int dead_zone)
// Dead zone is expressed as percentage of axis max value
dead_zone = 32768 * dead_zone / 100;
- result = SDL_GameControllerGetAxis(gamepad, axis);
+ result = axis_values[axis];
if (result < dead_zone && result > -dead_zone)
{
@@ -314,23 +315,130 @@ static int GetAxisStateGamepad(int axis, int invert, int dead_zone)
return result;
}
+#define DIRECTION_DEADZONE (50 * 32768 / 100)
+
+static int GetDirectionalInputGamepad(const int *axis_values)
+{
+ int value;
+ int dpad = JOY_DIR_NONE;
+ int leftstick = JOY_DIR_NONE;
+ int rightstick = JOY_DIR_NONE;
+
+ // Dpad.
+ if (SDL_GameControllerGetButton(gamepad, SDL_CONTROLLER_BUTTON_DPAD_UP))
+ {
+ dpad |= JOY_DIR_UP;
+ }
+
+ if (SDL_GameControllerGetButton(gamepad, SDL_CONTROLLER_BUTTON_DPAD_DOWN))
+ {
+ dpad |= JOY_DIR_DOWN;
+ }
+
+ if (SDL_GameControllerGetButton(gamepad, SDL_CONTROLLER_BUTTON_DPAD_LEFT))
+ {
+ dpad |= JOY_DIR_LEFT;
+ }
+
+ if (SDL_GameControllerGetButton(gamepad, SDL_CONTROLLER_BUTTON_DPAD_RIGHT))
+ {
+ dpad |= JOY_DIR_RIGHT;
+ }
+
+ // Left stick.
+ value = axis_values[SDL_CONTROLLER_AXIS_LEFTY];
+
+ if (value > DIRECTION_DEADZONE || value < -DIRECTION_DEADZONE)
+ {
+ if (value > 0)
+ {
+ leftstick |= JOY_DIR_DOWN;
+ }
+ else
+ {
+ leftstick |= JOY_DIR_UP;
+ }
+ }
+
+ value = axis_values[SDL_CONTROLLER_AXIS_LEFTX];
+
+ if (value > DIRECTION_DEADZONE || value < -DIRECTION_DEADZONE)
+ {
+ if (value > 0)
+ {
+ leftstick |= JOY_DIR_RIGHT;
+ }
+ else
+ {
+ leftstick |= JOY_DIR_LEFT;
+ }
+ }
+
+ // Right stick.
+ value = axis_values[SDL_CONTROLLER_AXIS_RIGHTX];
+
+ if (value > DIRECTION_DEADZONE || value < -DIRECTION_DEADZONE)
+ {
+ if (value > 0)
+ {
+ rightstick |= JOY_DIR_RIGHT;
+ }
+ else
+ {
+ rightstick |= JOY_DIR_LEFT;
+ }
+ }
+
+ value = axis_values[SDL_CONTROLLER_AXIS_RIGHTY];
+
+ if (value > DIRECTION_DEADZONE || value < -DIRECTION_DEADZONE)
+ {
+ if (value > 0)
+ {
+ rightstick |= JOY_DIR_DOWN;
+ }
+ else
+ {
+ rightstick |= JOY_DIR_UP;
+ }
+ }
+
+ return ((dpad << DPAD_SHIFT) | (leftstick << LSTICK_SHIFT) |
+ (rightstick << RSTICK_SHIFT));
+}
+
void I_UpdateGamepad(void)
{
if (gamepad != NULL)
{
event_t ev;
+ int axis_values[SDL_CONTROLLER_AXIS_MAX];
+
+ axis_values[SDL_CONTROLLER_AXIS_LEFTX] =
+ SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_LEFTX);
+
+ axis_values[SDL_CONTROLLER_AXIS_LEFTY] =
+ SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_LEFTY);
+
+ axis_values[SDL_CONTROLLER_AXIS_RIGHTX] =
+ SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_RIGHTX);
+
+ axis_values[SDL_CONTROLLER_AXIS_RIGHTY] =
+ SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_RIGHTY);
ev.type = ev_joystick;
ev.data1 = GetButtonsStateGamepad();
- ev.data2 = GetAxisStateGamepad(joystick_x_axis, joystick_x_invert,
- joystick_x_dead_zone);
- ev.data3 = GetAxisStateGamepad(joystick_y_axis, joystick_y_invert,
- joystick_y_dead_zone);
- ev.data4 =
- GetAxisStateGamepad(joystick_strafe_axis, joystick_strafe_invert,
- joystick_strafe_dead_zone);
- ev.data5 = GetAxisStateGamepad(joystick_look_axis, joystick_look_invert,
+ ev.data2 = GetAxisStateGamepad(axis_values, joystick_x_axis,
+ joystick_x_invert, joystick_x_dead_zone);
+ ev.data3 = GetAxisStateGamepad(axis_values, joystick_y_axis,
+ joystick_y_invert, joystick_y_dead_zone);
+ ev.data4 = GetAxisStateGamepad(axis_values, joystick_strafe_axis,
+ joystick_strafe_invert,
+ joystick_strafe_dead_zone);
+ ev.data5 = GetAxisStateGamepad(axis_values, joystick_look_axis,
+ joystick_look_invert,
joystick_look_dead_zone);
+ ev.data6 = GetDirectionalInputGamepad(axis_values);
D_PostEvent(&ev);
}
@@ -630,6 +738,31 @@ static int GetAxisState(int axis, int invert, int dead_zone)
return result;
}
+static int GetDirectionalInput(int x, int y)
+{
+ int retval = JOY_DIR_NONE;
+
+ if (x > 0)
+ {
+ retval |= JOY_DIR_RIGHT;
+ }
+ else if (x < 0)
+ {
+ retval |= JOY_DIR_LEFT;
+ }
+
+ if (y > 0)
+ {
+ retval |= JOY_DIR_DOWN;
+ }
+ else if (y < 0)
+ {
+ retval |= JOY_DIR_UP;
+ }
+
+ return (retval << DPAD_SHIFT);
+}
+
void I_UpdateJoystick(void)
{
if (use_gamepad)
@@ -652,7 +785,7 @@ void I_UpdateJoystick(void)
joystick_strafe_dead_zone);
ev.data5 = GetAxisState(joystick_look_axis, joystick_look_invert,
joystick_look_dead_zone);
-
+ ev.data6 = GetDirectionalInput(ev.data2, ev.data3);
D_PostEvent(&ev);
}
}
diff --git a/src/i_joystick.h b/src/i_joystick.h
index 9831ee1c..a50c5309 100644
--- a/src/i_joystick.h
+++ b/src/i_joystick.h
@@ -74,6 +74,24 @@
// To be used with SDL_JoystickGetGUIDString; see SDL_joystick.h
#define GUID_STRING_BUF_SIZE 33
+// Helper macros for bitpacked directional data from gamepad inputs.
+#define DPAD_SHIFT 0
+#define LSTICK_SHIFT 4
+#define RSTICK_SHIFT 8
+#define JOY_GET_DPAD(x) (((x) >> DPAD_SHIFT) & 0xf)
+#define JOY_GET_LSTICK(x) (((x) >> LSTICK_SHIFT) & 0xf)
+#define JOY_GET_RSTICK(x) (((x) >> RSTICK_SHIFT) & 0xf)
+
+// 4-way direction data for gamepad directional inputs.
+enum
+{
+ JOY_DIR_NONE = 0x0,
+ JOY_DIR_UP = 0x1,
+ JOY_DIR_DOWN = 0x2,
+ JOY_DIR_LEFT = 0x4,
+ JOY_DIR_RIGHT = 0x8
+};
+
// Extend the SDL_GameControllerButton enum to include the triggers.
enum
{