Tie axis data to the button map

The main benefit of this is to remove the requirement of going to the gamepad menu for binding analog sticks, and going to a keybinds menu for binding literally everything else; now it's all bound in the same location.

This also means that axes can both register as a digital button press, and be used as an analog value for movement separately. Before, using analog movement would not register BT_FORWARD, BT_BACK, etc
This commit is contained in:
Sally Coolatta 2025-01-30 22:42:13 -05:00 committed by Rachael Alexanderson
commit ca562829c5
17 changed files with 439 additions and 376 deletions

View file

@ -39,6 +39,8 @@
#include "printf.h"
#include "cmdlib.h"
#include "c_console.h"
#include "m_joy.h"
#include "c_bind.h"
ButtonMap buttonMap;
@ -150,6 +152,26 @@ void ButtonMap::ResetButtonStates ()
//
//=============================================================================
void ButtonMap::GetAxes ()
{
float joyaxes[NUM_AXIS_CODES];
I_GetAxes(joyaxes);
for (int i = 0; i < Buttons.Size(); i++)
{
FButtonStatus &btn = Buttons[i];
FString &btn_name = NumToName[i];
btn.AddAxes(btn_name, joyaxes);
}
}
//=============================================================================
//
//
//
//=============================================================================
bool FButtonStatus::PressKey (int keynum)
{
int i, open;
@ -246,6 +268,53 @@ bool FButtonStatus::ReleaseKey (int keynum)
//
//=============================================================================
void FButtonStatus::AddAxes (FString &btn_name, float joyaxes[NUM_AXIS_CODES])
{
int i;
bIsAxis = false;
Axis = 0.0f;
char cmd_name[16];
strcpy(&cmd_name[1], btn_name.GetChars());
cmd_name[0] = '+';
TArray<int> positive_keys = Bindings.GetKeysForCommand(cmd_name);
cmd_name[0] = '-';
TArray<int> negative_keys = Bindings.GetKeysForCommand(cmd_name);
for (i = 0; i < NUM_AXIS_CODES; i++)
{
float axis_value = joyaxes[i];
if (axis_value > 0.0)
{
int key_code = KeyAxisMapping[i];
if (positive_keys.Contains(key_code))
{
Axis += axis_value;
bIsAxis = true;
}
if (negative_keys.Contains(key_code))
{
Axis -= axis_value;
bIsAxis = true;
}
}
}
Axis = clamp<float>(Axis, 0.0f, 1.0f);
}
//=============================================================================
//
//
//
//=============================================================================
void ButtonMap::AddButtonTabCommands()
{
// Add all the action commands for tab completion

View file

@ -3,6 +3,7 @@
#include <stdint.h>
#include "tarray.h"
#include "name.h"
#include "keydef.h"
// Actions
struct FButtonStatus
@ -14,13 +15,18 @@ struct FButtonStatus
bool bWentDown; // Button went down this tic
bool bWentUp; // Button went up this tic
bool bReleaseLock; // Lock ReleaseKey call in ResetButtonStates
bool bIsAxis; // Whenever or not this button is being controlled by any axis.
float Axis; // How far the button has been pressed. Updated by I_GetAxes.
void (*PressHandler)(); // for optional game-side customization
void (*ReleaseHandler)();
bool PressKey (int keynum); // Returns true if this key caused the button to be pressed.
bool ReleaseKey (int keynum); // Returns true if this key is no longer pressed.
void AddAxes (FString &btn_name, float joyaxes[NUM_AXIS_CODES]); // Update joystick axis information.
void ResetTriggers () { bWentDown = bWentUp = false; }
void Reset () { bDown = bWentDown = bWentUp = false; }
void Reset () { bDown = bWentDown = bWentUp = bIsAxis = false; Axis = 0.0f; }
};
class ButtonMap
@ -53,6 +59,7 @@ public:
void ResetButtonTriggers(); // Call ResetTriggers for all buttons
void ResetButtonStates(); // Same as above, but also clear bDown
void GetAxes(); // Call AddAxes for all buttons
int ListActionCommands(const char* pattern);
void AddButtonTabCommands();
@ -62,6 +69,28 @@ public:
return Buttons[x].bDown;
}
bool ButtonDownDigital(int x) const
{
// Like ButtonDown, but only for digital buttons.
// This is necessary, because of how the game runs different
// code for both digital and analog, and they can't be rolled
// together without introducing some subtle gameplay differences.
return (Buttons[x].bIsAxis == false && Buttons[x].bDown == true);
}
float ButtonAnalog(int x) const
{
// Get the analog value of a button.
// This is 0.0 (not 1.0) for digital presses, because again,
// of how the game logic is split between the two.
if (Buttons[x].bIsAxis == true)
{
return Buttons[x].Axis;
}
return 0.0f;
}
bool ButtonPressed(int x) const
{
return Buttons[x].bWentDown;

View file

@ -147,3 +147,77 @@ enum EKeyCodes
NUM_JOYAXISBUTTONS = 8,
};
// Axes are provided per-key now, but passing around
// an entire NUM_KEYS-sized array is overkill. These
// codes are used for translating between axes and keys.
enum EAxisCodes
{
AXIS_CODE_NULL = -1,
AXIS_CODE_JOY1_PLUS = 0,
AXIS_CODE_JOY1_MINUS,
AXIS_CODE_JOY2_PLUS,
AXIS_CODE_JOY2_MINUS,
AXIS_CODE_JOY3_PLUS,
AXIS_CODE_JOY3_MINUS,
AXIS_CODE_JOY4_PLUS,
AXIS_CODE_JOY4_MINUS,
AXIS_CODE_JOY5_PLUS,
AXIS_CODE_JOY5_MINUS,
AXIS_CODE_JOY6_PLUS,
AXIS_CODE_JOY6_MINUS,
AXIS_CODE_JOY7_PLUS,
AXIS_CODE_JOY7_MINUS,
AXIS_CODE_JOY8_PLUS,
AXIS_CODE_JOY8_MINUS,
AXIS_CODE_PAD_LTHUMB_RIGHT,
AXIS_CODE_PAD_LTHUMB_LEFT,
AXIS_CODE_PAD_LTHUMB_DOWN,
AXIS_CODE_PAD_LTHUMB_UP,
AXIS_CODE_PAD_RTHUMB_RIGHT,
AXIS_CODE_PAD_RTHUMB_LEFT,
AXIS_CODE_PAD_RTHUMB_DOWN,
AXIS_CODE_PAD_RTHUMB_UP,
AXIS_CODE_PAD_LTRIGGER,
AXIS_CODE_PAD_RTRIGGER,
NUM_AXIS_CODES,
};
static const int KeyAxisMapping[NUM_AXIS_CODES] = {
KEY_JOYAXIS1PLUS,
KEY_JOYAXIS1MINUS,
KEY_JOYAXIS2PLUS,
KEY_JOYAXIS2MINUS,
KEY_JOYAXIS3PLUS,
KEY_JOYAXIS3MINUS,
KEY_JOYAXIS4PLUS,
KEY_JOYAXIS4MINUS,
KEY_JOYAXIS5PLUS,
KEY_JOYAXIS5MINUS,
KEY_JOYAXIS6PLUS,
KEY_JOYAXIS6MINUS,
KEY_JOYAXIS7PLUS,
KEY_JOYAXIS7MINUS,
KEY_JOYAXIS8PLUS,
KEY_JOYAXIS8MINUS,
KEY_PAD_LTHUMB_RIGHT,
KEY_PAD_LTHUMB_LEFT,
KEY_PAD_LTHUMB_DOWN,
KEY_PAD_LTHUMB_UP,
KEY_PAD_RTHUMB_RIGHT,
KEY_PAD_RTHUMB_LEFT,
KEY_PAD_RTHUMB_DOWN,
KEY_PAD_RTHUMB_UP,
KEY_PAD_LTRIGGER,
KEY_PAD_RTRIGGER,
};

View file

@ -222,18 +222,6 @@ bool M_LoadJoystickConfig(IJoystickConfig *joy)
{
joy->SetAxisResponseCurvePoint(i, 3, (float)atof(value));
}
mysnprintf(key + axislen, countof(key) - axislen, "map");
value = GameConfig->GetValueForKey(key);
if (value)
{
EJoyAxis gameaxis = (EJoyAxis)atoi(value);
if (gameaxis < JOYAXIS_None || gameaxis >= NUM_JOYAXIS)
{
gameaxis = JOYAXIS_None;
}
joy->SetAxisMap(i, gameaxis);
}
}
return true;
}
@ -314,12 +302,6 @@ void M_SaveJoystickConfig(IJoystickConfig *joy)
mysnprintf(value, countof(value), "%g", joy->GetAxisResponseCurvePoint(i, 3));
GameConfig->SetValueForKey(key, value);
}
if (!joy->IsAxisMapDefault(i))
{
mysnprintf(key + axislen, countof(key) - axislen, "map");
mysnprintf(value, countof(value), "%d", joy->GetAxisMap(i));
GameConfig->SetValueForKey(key, value);
}
}
// If the joystick is entirely at its defaults, delete this section
// so that we don't write out a lone section header.
@ -355,7 +337,6 @@ CCMD (gamepad)
"\n\tgamepad curve-y1 pad.axis [float]"
"\n\tgamepad curve-x2 pad.axis [float]"
"\n\tgamepad curve-y2 pad.axis [float]"
"\n\tgamepad map pad.axis [-1|0|1|2|3|4]"
"\n"
);
};
@ -490,11 +471,6 @@ CCMD (gamepad)
if (set) sticks[pad]->SetAxisResponseCurvePoint(axis, 3, value);
return (void) Printf("%g\n", sticks[pad]->GetAxisResponseCurvePoint(axis, 3));
}
if (command == "map")
{
if (set) sticks[pad]->SetAxisMap(axis, (EJoyAxis)value);
return (void) Printf("%d\n", sticks[pad]->GetAxisMap(axis));
}
return usage();
}

View file

@ -5,6 +5,7 @@
#include "keydef.h"
#include "tarray.h"
#include "c_cvars.h"
#include "keydef.h"
union CubicBezier {
struct {
@ -26,18 +27,6 @@ enum EJoyCurve {
NUM_JOYCURVE
};
enum EJoyAxis
{
JOYAXIS_None = -1,
JOYAXIS_Yaw,
JOYAXIS_Pitch,
JOYAXIS_Forward,
JOYAXIS_Side,
JOYAXIS_Up,
// JOYAXIS_Roll, // Ha ha. No roll for you.
NUM_JOYAXIS,
};
extern const float JOYDEADZONE_DEFAULT;
extern const float JOYSENSITIVITY_DEFAULT;
@ -61,7 +50,6 @@ struct IJoystickConfig
virtual int GetNumAxes() = 0;
virtual float GetAxisDeadZone(int axis) = 0;
virtual EJoyAxis GetAxisMap(int axis) = 0;
virtual const char *GetAxisName(int axis) = 0;
virtual float GetAxisScale(int axis) = 0;
virtual float GetAxisDigitalThreshold(int axis) = 0;
@ -69,7 +57,6 @@ struct IJoystickConfig
virtual float GetAxisResponseCurvePoint(int axis, int point) = 0;
virtual void SetAxisDeadZone(int axis, float zone) = 0;
virtual void SetAxisMap(int axis, EJoyAxis gameaxis) = 0;
virtual void SetAxisScale(int axis, float scale) = 0;
virtual void SetAxisDigitalThreshold(int axis, float threshold) = 0;
virtual void SetAxisResponseCurve(int axis, EJoyCurve preset) = 0;
@ -85,7 +72,6 @@ struct IJoystickConfig
// Used by the saver to not save properties that are at their defaults.
virtual bool IsSensitivityDefault() = 0;
virtual bool IsAxisDeadZoneDefault(int axis) = 0;
virtual bool IsAxisMapDefault(int axis) = 0;
virtual bool IsAxisScaleDefault(int axis) = 0;
virtual bool IsAxisDigitalThresholdDefault(int axis) = 0;
virtual bool IsAxisResponseCurveDefault(int axis) = 0;
@ -107,7 +93,7 @@ double Joy_RemoveDeadZone(double axisval, double deadzone, uint8_t *buttons);
double Joy_ApplyResponseCurveBezier(const CubicBezier &curve, double input);
// These ought to be provided by a system-specific i_input.cpp.
void I_GetAxes(float axes[NUM_JOYAXIS]);
void I_GetAxes(float axes[NUM_AXIS_CODES]);
void I_GetJoysticks(TArray<IJoystickConfig *> &sticks);
IJoystickConfig *I_UpdateDeviceList();
extern void UpdateJoystickMenu(IJoystickConfig *);

View file

@ -134,22 +134,6 @@ DEFINE_ACTION_FUNCTION(IJoystickConfig, SetAxisResponseCurvePoint)
return 0;
}
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetAxisMap)
{
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
PARAM_INT(axis);
ACTION_RETURN_INT(self->GetAxisMap(axis));
}
DEFINE_ACTION_FUNCTION(IJoystickConfig, SetAxisMap)
{
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
PARAM_INT(axis);
PARAM_INT(map);
self->SetAxisMap(axis, (EJoyAxis)map);
return 0;
}
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetName)
{
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);

View file

@ -91,7 +91,6 @@ public:
virtual int GetNumAxes();
virtual float GetAxisDeadZone(int axis);
virtual EJoyAxis GetAxisMap(int axis);
virtual const char* GetAxisName(int axis);
virtual float GetAxisScale(int axis);
float GetAxisDigitalThreshold(int axis);
@ -99,7 +98,6 @@ public:
float GetAxisResponseCurvePoint(int axis, int point);
virtual void SetAxisDeadZone(int axis, float deadZone);
virtual void SetAxisMap(int axis, EJoyAxis gameAxis);
virtual void SetAxisScale(int axis, float scale);
void SetAxisDigitalThreshold(int axis, float threshold);
void SetAxisResponseCurve(int axis, EJoyCurve preset);
@ -107,7 +105,6 @@ public:
virtual bool IsSensitivityDefault();
virtual bool IsAxisDeadZoneDefault(int axis);
virtual bool IsAxisMapDefault(int axis);
virtual bool IsAxisScaleDefault(int axis);
bool IsAxisDigitalThresholdDefault(int axis);
bool IsAxisResponseCurveDefault(int axis);
@ -122,7 +119,7 @@ public:
virtual void SetDefaultConfig();
virtual FString GetIdentifier();
void AddAxes(float axes[NUM_JOYAXIS]) const;
void AddAxes(float axes[NUM_AXIS_CODES]) const;
void Update();
@ -160,8 +157,7 @@ private:
EJoyCurve defaultResponseCurvePreset;
CubicBezier responseCurve;
EJoyAxis gameAxis;
EJoyAxis defaultGameAxis;
uint8_t buttonValue;
AnalogAxis()
{
@ -376,11 +372,6 @@ float IOKitJoystick::GetAxisDeadZone(int axis)
return IS_AXIS_VALID ? m_axes[axis].deadZone : 0.0f;
}
EJoyAxis IOKitJoystick::GetAxisMap(int axis)
{
return IS_AXIS_VALID ? m_axes[axis].gameAxis : JOYAXIS_None;
}
const char* IOKitJoystick::GetAxisName(int axis)
{
return IS_AXIS_VALID ? m_axes[axis].name : "Invalid";
@ -414,16 +405,6 @@ void IOKitJoystick::SetAxisDeadZone(int axis, float deadZone)
}
}
void IOKitJoystick::SetAxisMap(int axis, EJoyAxis gameAxis)
{
if (IS_AXIS_VALID)
{
m_axes[axis].gameAxis = (gameAxis> JOYAXIS_None && gameAxis <NUM_JOYAXIS)
? gameAxis
: JOYAXIS_None;
}
}
void IOKitJoystick::SetAxisScale(int axis, float scale)
{
if (IS_AXIS_VALID)
@ -472,13 +453,6 @@ bool IOKitJoystick::IsAxisDeadZoneDefault(int axis)
: true;
}
bool IOKitJoystick::IsAxisMapDefault(int axis)
{
return IS_AXIS_VALID
? (m_axes[axis].gameAxis == m_axes[axis].defaultGameAxis)
: true;
}
bool IOKitJoystick::IsAxisScaleDefault(int axis)
{
return IS_AXIS_VALID
@ -521,7 +495,6 @@ void IOKitJoystick::SetDefaultConfig()
{
m_axes[i].deadZone = JOYDEADZONE_DEFAULT;
m_axes[i].sensitivity = JOYSENSITIVITY_DEFAULT;
m_axes[i].gameAxis = JOYAXIS_None;
m_axes[i].digitalThreshold = JOYTHRESH_DEFAULT;
m_axes[i].responseCurvePreset = JOYCURVE_DEFAULT;
m_axes[i].responseCurve = JOYCURVE[JOYCURVE_DEFAULT];
@ -531,10 +504,7 @@ void IOKitJoystick::SetDefaultConfig()
if (2 == axisCount)
{
m_axes[0].gameAxis = JOYAXIS_Yaw;
m_axes[0].digitalThreshold = JOYTHRESH_STICK_X;
m_axes[1].gameAxis = JOYAXIS_Forward;
m_axes[1].digitalThreshold = JOYTHRESH_STICK_Y;
}
@ -542,20 +512,14 @@ void IOKitJoystick::SetDefaultConfig()
else if (axisCount >= 3)
{
m_axes[0].gameAxis = JOYAXIS_Side;
m_axes[0].digitalThreshold = JOYTHRESH_STICK_X;
m_axes[1].gameAxis = JOYAXIS_Forward;
m_axes[1].digitalThreshold = JOYTHRESH_STICK_Y;
m_axes[2].gameAxis = JOYAXIS_Yaw;
m_axes[2].digitalThreshold = JOYTHRESH_STICK_X;
// Four axes? First two are movement, last two are looking around.
if (axisCount >= 4)
{
m_axes[3].gameAxis = JOYAXIS_Pitch;
// ??? m_axes[3].sensitivity = 0.75f;
m_axes[3].digitalThreshold = JOYTHRESH_STICK_Y;
@ -563,7 +527,6 @@ void IOKitJoystick::SetDefaultConfig()
if (axisCount >= 5)
{
m_axes[4].gameAxis = JOYAXIS_Up;
m_axes[4].digitalThreshold = JOYTHRESH_STICK_Y;
}
}
@ -578,7 +541,6 @@ void IOKitJoystick::SetDefaultConfig()
{
m_axes[i].defaultDeadZone = m_axes[i].deadZone;
m_axes[i].defaultSensitivity = m_axes[i].sensitivity;
m_axes[i].defaultGameAxis = m_axes[i].gameAxis;
m_axes[i].defaultDigitalThreshold = m_axes[i].digitalThreshold;
m_axes[i].defaultResponseCurvePreset = m_axes[i].responseCurvePreset;
}
@ -591,18 +553,30 @@ FString IOKitJoystick::GetIdentifier()
}
void IOKitJoystick::AddAxes(float axes[NUM_JOYAXIS]) const
void IOKitJoystick::AddAxes(float axes[NUM_AXIS_CODES]) const
{
for (size_t i = 0, count = m_axes.Size(); i < count; ++i)
{
const EJoyAxis axis = m_axes[i].gameAxis;
// Add to the game axis.
float axis_value = m_axes[i].value;
int code = AXIS_CODE_NULL;
if (JOYAXIS_None == axis)
if (i < NUM_JOYAXISBUTTONS)
{
continue;
if (axis_value > 0.0f)
{
code = AXIS_CODE_JOY1_PLUS + (i * 2);
}
else if (axis_value < 0.0f)
{
code = AXIS_CODE_JOY1_PLUS + (i * 2) + 1;
}
}
axes[axis] -= m_axes[i].value;
if (code != AXIS_CODE_NULL)
{
axes[code] += fabs(axis_value);
}
}
}
@ -665,6 +639,7 @@ void IOKitJoystick::ProcessAxes()
for (size_t i = 0, count = m_axes.Size(); i < count; ++i)
{
AnalogAxis& axis = m_axes[i];
uint8_t buttonstate = 0;
static const double scaledMin = -1;
static const double scaledMax = 1;
@ -675,7 +650,7 @@ void IOKitJoystick::ProcessAxes()
{
const double scaledValue = scaledMin +
(event.value - axis.minValue) * (scaledMax - scaledMin) / (axis.maxValue - axis.minValue);
const double filteredValue = Joy_RemoveDeadZone(scaledValue, axis.deadZone, NULL);
const double filteredValue = Joy_RemoveDeadZone(scaledValue, axis.deadZone, &buttonstate);
const double smoothedValue = Joy_ApplyResponseCurveBezier(axis.responseCurve, filteredValue);
axis.value = static_cast<float>(smoothedValue * m_sensitivity * axis.sensitivity);
@ -684,6 +659,19 @@ void IOKitJoystick::ProcessAxes()
{
axis.value = 0.0f;
}
if (i < NUM_JOYAXISBUTTONS && (i > 2 || m_axes.Size() == 1))
{
Joy_GenerateButtonEvents(axis.buttonValue, buttonstate, 2, KEY_JOYAXIS1PLUS + i*2);
}
else if (i == 1)
{
// Since we sorted the axes, we know that the first two are definitely X and Y.
// They are probably a single stick, so use angular position to determine buttons.
buttonstate = Joy_XYAxesToButtons(m_axes[0].value, axis.value);
Joy_GenerateButtonEvents(axis.buttonValue, buttonstate, 4, KEY_JOYAXIS1PLUS);
}
axis.buttonValue = buttonstate;
}
}
@ -703,17 +691,23 @@ bool IOKitJoystick::ProcessAxis(const IOHIDEventStruct& event)
}
AnalogAxis& axis = m_axes[i];
uint8_t buttonstate = 0;
static const double scaledMin = -1;
static const double scaledMax = 1;
const double scaledValue = scaledMin +
(event.value - axis.minValue) * (scaledMax - scaledMin) / (axis.maxValue - axis.minValue);
const double filteredValue = Joy_RemoveDeadZone(scaledValue, axis.deadZone, NULL);
const double filteredValue = Joy_RemoveDeadZone(scaledValue, axis.deadZone, &buttonstate);
const double smoothedValue = Joy_ApplyResponseCurveBezier(axis.responseCurve, filteredValue);
axis.value = static_cast<float>(smoothedValue * m_sensitivity * axis.sensitivity);
if (i < NUM_JOYAXISBUTTONS)
{
Joy_GenerateButtonEvents(axis.buttonValue, buttonstate, 2, KEY_JOYAXIS1PLUS + i*2);
}
axis.buttonValue = buttonstate;
return true;
}
@ -1042,7 +1036,7 @@ public:
void GetJoysticks(TArray<IJoystickConfig*>& joysticks) const;
void AddAxes(float axes[NUM_JOYAXIS]) const;
void AddAxes(float axes[NUM_AXIS_CODES]) const;
// Updates axes/buttons states
void Update();
@ -1133,7 +1127,7 @@ void IOKitJoystickManager::GetJoysticks(TArray<IJoystickConfig*>& joysticks) con
}
}
void IOKitJoystickManager::AddAxes(float axes[NUM_JOYAXIS]) const
void IOKitJoystickManager::AddAxes(float axes[NUM_AXIS_CODES]) const
{
for (size_t i = 0, count = m_joysticks.Size(); i < count; ++i)
{
@ -1296,9 +1290,9 @@ void I_GetJoysticks(TArray<IJoystickConfig*>& sticks)
}
}
void I_GetAxes(float axes[NUM_JOYAXIS])
void I_GetAxes(float axes[NUM_AXIS_CODES])
{
for (size_t i = 0; i < NUM_JOYAXIS; ++i)
for (size_t i = 0; i < NUM_AXIS_CODES; ++i)
{
axes[i] = 0.0f;
}

View file

@ -124,10 +124,6 @@ public:
{
return Axes[axis].DeadZone;
}
EJoyAxis GetAxisMap(int axis)
{
return Axes[axis].GameAxis;
}
const char *GetAxisName(int axis)
{
return Axes[axis].Name.GetChars();
@ -156,11 +152,6 @@ public:
SettingsChanged = true;
Axes[axis].DeadZone = clamp(zone, 0.f, 1.f);
}
void SetAxisMap(int axis, EJoyAxis gameaxis)
{
SettingsChanged = true;
Axes[axis].GameAxis = gameaxis;
}
void SetAxisScale(int axis, float scale)
{
SettingsChanged = true;
@ -200,12 +191,6 @@ public:
return Axes[axis].DeadZone == JOYDEADZONE_DEFAULT;
return Axes[axis].DeadZone == DefaultAxes[axis].DeadZone;
}
bool IsAxisMapDefault(int axis)
{
if(axis >= DefaultAxesCount)
return Axes[axis].GameAxis == JOYAXIS_None;
return Axes[axis].GameAxis == DefaultAxes[axis].GameAxis;
}
bool IsAxisScaleDefault(int axis)
{
if(axis >= DefaultAxesCount)
@ -259,7 +244,6 @@ public:
if (i < DefaultAxesCount)
{
Axes[i].GameAxis = DefaultAxes[i].GameAxis;
Axes[i].DeadZone = DefaultAxes[i].DeadZone;
Axes[i].Multiplier = DefaultAxes[i].Multiplier;
Axes[i].DigitalThreshold = DefaultAxes[i].DigitalThreshold;
@ -268,7 +252,6 @@ public:
}
else
{
Axes[i].GameAxis = JOYAXIS_None;
Axes[i].DeadZone = JOYDEADZONE_DEFAULT;
Axes[i].Multiplier = JOYSENSITIVITY_DEFAULT;
Axes[i].DigitalThreshold = JOYTHRESH_DEFAULT;
@ -300,17 +283,32 @@ public:
return id;
}
void AddAxes(float axes[NUM_JOYAXIS])
void AddAxes(float axes[NUM_AXIS_CODES])
{
// Add to game axes.
for (int i = 0; i < GetNumAxes(); ++i)
{
if(Axes[i].GameAxis != JOYAXIS_None)
axes[Axes[i].GameAxis] -= float(Axes[i].Value * Multiplier * Axes[i].Multiplier);
float axis_value = float(Axes[i].Value * Multiplier * Axes[i].Multiplier);
int code = AXIS_CODE_NULL;
if (axis_value > 0.0f)
{
code = Axes[i].Codes[0];
}
else if (axis_value < 0.0f)
{
code = Axes[i].Codes[1];
}
if (code != AXIS_CODE_NULL)
{
axes[code] += fabs(axis_value);
}
}
}
void ProcessInput() {
void ProcessInput()
{
uint8_t buttonstate;
if (Mapping)
@ -324,6 +322,16 @@ public:
{
buttonstate = 0;
if (i < NUM_JOYAXISBUTTONS)
{
Axes[i].Codes[0] = AXIS_CODE_JOY1_PLUS + (i * 2);
Axes[i].Codes[1] = AXIS_CODE_JOY1_PLUS + (i * 2) + 1;
}
else
{
Axes[i].Codes[0] = Axes[i].Codes[1] = AXIS_CODE_NULL;
}
Axes[i].Value = SDL_GameControllerGetAxis(Mapping, static_cast<SDL_GameControllerAxis>(i))/32767.0;
Axes[i].Value = Joy_RemoveDeadZone(Axes[i].Value, Axes[i].DeadZone, &buttonstate);
Axes[i].Value = Joy_ApplyResponseCurveBezier(Axes[i].ResponseCurve, Axes[i].Value);
@ -351,6 +359,16 @@ public:
{
buttonstate = 0;
if (i < NUM_JOYAXISBUTTONS)
{
Axes[i].Codes[0] = AXIS_CODE_JOY1_PLUS + (i * 2);
Axes[i].Codes[1] = AXIS_CODE_JOY1_PLUS + (i * 2) + 1;
}
else
{
Axes[i].Codes[0] = Axes[i].Codes[1] = AXIS_CODE_NULL;
}
Axes[i].Value = SDL_JoystickGetAxis(Device, i)/32767.0;
Axes[i].Value = Joy_RemoveDeadZone(Axes[i].Value, Axes[i].DeadZone, &buttonstate);
Axes[i].Value = Joy_ApplyResponseCurveBezier(Axes[i].ResponseCurve, Axes[i].Value);
@ -364,7 +382,7 @@ public:
}
}
if(NumAxes > 1)
if (NumAxes > 1)
{
buttonstate = Joy_XYAxesToButtons(
abs(Axes[0].Value) < Axes[0].DigitalThreshold ? 0 : Axes[0].Value,
@ -400,7 +418,7 @@ public:
else
x.Value = 0.0;
if(i < 4)
if (i < 4)
{
Joy_GenerateButtonEvents(x.ButtonValue, buttonstate, 4, KEY_JOYPOV1_UP + i*4);
x.ButtonValue = buttonstate;
@ -418,14 +436,13 @@ protected:
float DigitalThreshold;
EJoyCurve ResponseCurvePreset;
CubicBezier ResponseCurve;
EJoyAxis GameAxis;
int Codes[2]; // 0: positive, 1: negative
double Value;
uint8_t ButtonValue;
};
struct DefaultAxisConfig
{
float DeadZone;
EJoyAxis GameAxis;
float Multiplier;
float DigitalThreshold;
EJoyCurve ResponseCurvePreset;
@ -452,21 +469,21 @@ protected:
// [Nash 4 Feb 2024] seems like on Linux, the third axis is actually the Left Trigger, resulting in the player uncontrollably looking upwards.
const SDLInputJoystick::DefaultAxisConfig SDLInputJoystick::DefaultJoystickAxes[5] = {
{JOYDEADZONE_DEFAULT, JOYAXIS_Side, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYAXIS_Forward, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYAXIS_None, JOYSENSITIVITY_DEFAULT, JOYTHRESH_DEFAULT, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYAXIS_Yaw, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYAXIS_Pitch, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT}
{JOYDEADZONE_DEFAULT, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYSENSITIVITY_DEFAULT, JOYTHRESH_DEFAULT, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT}
};
// Defaults if we have access to the GameController API for this device
const SDLInputJoystick::DefaultAxisConfig SDLInputJoystick::DefaultControllerAxes[6] = {
{JOYDEADZONE_DEFAULT, JOYAXIS_Side, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYAXIS_Forward, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYAXIS_Yaw, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYAXIS_Pitch, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYAXIS_None, JOYSENSITIVITY_DEFAULT, JOYTHRESH_TRIGGER, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYAXIS_None, JOYSENSITIVITY_DEFAULT, JOYTHRESH_TRIGGER, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYSENSITIVITY_DEFAULT, JOYTHRESH_TRIGGER, JOYCURVE_DEFAULT},
{JOYDEADZONE_DEFAULT, JOYSENSITIVITY_DEFAULT, JOYTHRESH_TRIGGER, JOYCURVE_DEFAULT},
};
class SDLInputJoystickManager
@ -490,7 +507,7 @@ public:
}
}
void AddAxes(float axes[NUM_JOYAXIS])
void AddAxes(float axes[NUM_AXIS_CODES])
{
for(unsigned int i = 0;i < Joysticks.Size();i++)
Joysticks[i]->AddAxes(axes);
@ -553,12 +570,13 @@ void I_GetJoysticks(TArray<IJoystickConfig *> &sticks)
JoystickManager->GetDevices(sticks);
}
void I_GetAxes(float axes[NUM_JOYAXIS])
void I_GetAxes(float axes[NUM_AXIS_CODES])
{
for (int i = 0; i < NUM_JOYAXIS; ++i)
for (int i = 0; i < NUM_AXIS_CODES; ++i)
{
axes[i] = 0;
axes[i] = 0.0f;
}
if (use_joystick && JoystickManager)
{
JoystickManager->AddAxes(axes);

View file

@ -157,7 +157,7 @@ public:
bool GetDevice();
void ProcessInput();
void AddAxes(float axes[NUM_JOYAXIS]);
void AddAxes(float axes[NUM_AXIS_CODES]);
// IJoystickConfig interface
FString GetName();
@ -166,7 +166,6 @@ public:
int GetNumAxes();
float GetAxisDeadZone(int axis);
EJoyAxis GetAxisMap(int axis);
const char *GetAxisName(int axis);
float GetAxisScale(int axis);
float GetAxisDigitalThreshold(int axis);
@ -174,7 +173,6 @@ public:
float GetAxisResponseCurvePoint(int axis, int point);
void SetAxisDeadZone(int axis, float deadzone);
void SetAxisMap(int axis, EJoyAxis gameaxis);
void SetAxisScale(int axis, float scale);
void SetAxisDigitalThreshold(int axis, float threshold);
void SetAxisResponseCurve(int axis, EJoyCurve preset);
@ -182,7 +180,6 @@ public:
bool IsSensitivityDefault();
bool IsAxisDeadZoneDefault(int axis);
bool IsAxisMapDefault(int axis);
bool IsAxisScaleDefault(int axis);
bool IsAxisDigitalThresholdDefault(int axis);
bool IsAxisResponseCurveDefault(int axis);
@ -211,7 +208,6 @@ protected:
float DigitalThreshold, DefaultDigitalThreshold;
EJoyCurve ResponseCurvePreset, DefaultResponseCurvePreset;
CubicBezier ResponseCurve;
EJoyAxis GameAxis, DefaultGameAxis;
uint8_t ButtonValue;
};
struct ButtonInfo
@ -254,7 +250,7 @@ public:
bool GetDevice();
void ProcessInput();
void AddAxes(float axes[NUM_JOYAXIS]);
void AddAxes(float axes[NUM_AXIS_CODES]);
void GetDevices(TArray<IJoystickConfig *> &sticks);
IJoystickConfig *Rescan();
@ -527,12 +523,30 @@ void FDInputJoystick::ProcessInput()
//
//===========================================================================
void FDInputJoystick::AddAxes(float axes[NUM_JOYAXIS])
void FDInputJoystick::AddAxes(float axes[NUM_AXIS_CODES])
{
for (unsigned i = 0; i < Axes.Size(); ++i)
{
// Add to the game axis.
axes[Axes[i].GameAxis] -= float(Axes[i].Value * Multiplier * Axes[i].Multiplier);
float axis_value = float(Axes[i].Value * Multiplier * Axes[i].Multiplier);
int code = AXIS_CODE_NULL;
if (i < NUM_JOYAXISBUTTONS)
{
if (axis_value > 0.0f)
{
code = AXIS_CODE_JOY1_PLUS + (i * 2);
}
else if (axis_value < 0.0f)
{
code = AXIS_CODE_JOY1_PLUS + (i * 2) + 1;
}
}
if (code != AXIS_CODE_NULL)
{
axes[code] += fabs(axis_value);
}
}
}
@ -608,7 +622,6 @@ BOOL CALLBACK FDInputJoystick::EnumObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpd
info.Ofs = 0;
info.Min = diprg.lMin;
info.Max = diprg.lMax;
info.GameAxis = JOYAXIS_None;
info.Value = 0;
info.ButtonValue = 0;
joy->Axes.Push(info);
@ -781,7 +794,6 @@ void FDInputJoystick::SetDefaultConfig()
{
Axes[i].DeadZone = JOYDEADZONE_DEFAULT;
Axes[i].Multiplier = JOYSENSITIVITY_DEFAULT;
Axes[i].GameAxis = JOYAXIS_None;
Axes[i].DigitalThreshold = JOYTHRESH_DEFAULT;
Axes[i].ResponseCurvePreset = JOYCURVE_DEFAULT;
Axes[i].ResponseCurve = JOYCURVE[JOYCURVE_DEFAULT];
@ -795,34 +807,24 @@ void FDInputJoystick::SetDefaultConfig()
// Two axes? Horizontal is yaw and vertical is forward.
if (Axes.Size() == 2)
{
Axes[0].GameAxis = JOYAXIS_Yaw;
Axes[0].DigitalThreshold = JOYTHRESH_STICK_X;
Axes[1].GameAxis = JOYAXIS_Forward;
Axes[1].DigitalThreshold = JOYTHRESH_STICK_Y;
}
// Three axes? First two are movement, third is yaw.
else if (Axes.Size() >= 3)
{
Axes[0].GameAxis = JOYAXIS_Side;
Axes[0].DigitalThreshold = JOYTHRESH_STICK_X;
Axes[1].GameAxis = JOYAXIS_Forward;
Axes[1].DigitalThreshold = JOYTHRESH_STICK_Y;
Axes[2].GameAxis = JOYAXIS_Yaw;
Axes[2].DigitalThreshold = JOYTHRESH_STICK_X;
// Four axes? First two are movement, last two are looking around.
if (Axes.Size() >= 4)
{
Axes[3].GameAxis = JOYAXIS_Pitch;
// Axes[3].Multiplier = 0.75f;
Axes[3].DigitalThreshold = JOYTHRESH_STICK_Y;
// Five axes? Use the fifth one for moving up and down.
if (Axes.Size() >= 5)
{
Axes[4].GameAxis = JOYAXIS_Up;
Axes[4].DigitalThreshold = JOYTHRESH_STICK_Y;
}
}
@ -835,7 +837,6 @@ void FDInputJoystick::SetDefaultConfig()
{
Axes[i].DefaultDeadZone = Axes[i].DeadZone;
Axes[i].DefaultMultiplier = Axes[i].Multiplier;
Axes[i].DefaultGameAxis = Axes[i].GameAxis;
Axes[i].DefaultDigitalThreshold = Axes[i].DigitalThreshold;
Axes[i].DefaultResponseCurvePreset = Axes[i].ResponseCurvePreset;
}
@ -911,21 +912,6 @@ float FDInputJoystick::GetAxisDeadZone(int axis)
return Axes[axis].DeadZone;
}
//===========================================================================
//
// FDInputJoystick :: GetAxisMap
//
//===========================================================================
EJoyAxis FDInputJoystick::GetAxisMap(int axis)
{
if (unsigned(axis) >= Axes.Size())
{
return JOYAXIS_None;
}
return Axes[axis].GameAxis;
}
//===========================================================================
//
// FDInputJoystick :: GetAxisName
@ -1015,20 +1001,6 @@ void FDInputJoystick::SetAxisDeadZone(int axis, float deadzone)
}
}
//===========================================================================
//
// FDInputJoystick :: SetAxisMap
//
//===========================================================================
void FDInputJoystick::SetAxisMap(int axis, EJoyAxis gameaxis)
{
if (unsigned(axis) < Axes.Size())
{
Axes[axis].GameAxis = (unsigned(gameaxis) < NUM_JOYAXIS) ? gameaxis : JOYAXIS_None;
}
}
//===========================================================================
//
// FDInputJoystick :: SetAxisScale
@ -1171,21 +1143,6 @@ void FDInputJoystick::SetEnabled(bool enabled)
Enabled = enabled;
}
//===========================================================================
//
// FDInputJoystick :: IsAxisMapDefault
//
//===========================================================================
bool FDInputJoystick::IsAxisMapDefault(int axis)
{
if (unsigned(axis) < Axes.Size())
{
return Axes[axis].GameAxis == Axes[axis].DefaultGameAxis;
}
return true;
}
//===========================================================================
//
// FDInputJoystickManager - Constructor
@ -1253,7 +1210,7 @@ void FDInputJoystickManager::ProcessInput()
//
//===========================================================================
void FDInputJoystickManager :: AddAxes(float axes[NUM_JOYAXIS])
void FDInputJoystickManager :: AddAxes(float axes[NUM_AXIS_CODES])
{
for (unsigned i = 0; i < Devices.Size(); ++i)
{

View file

@ -636,14 +636,15 @@ void I_StartFrame ()
}
}
void I_GetAxes(float axes[NUM_JOYAXIS])
void I_GetAxes(float axes[NUM_AXIS_CODES])
{
int i;
for (i = 0; i < NUM_JOYAXIS; ++i)
for (i = 0; i < NUM_AXIS_CODES; ++i)
{
axes[i] = 0;
axes[i] = 0.0f;
}
if (use_joystick)
{
for (i = 0; i < NUM_JOYDEVICES; ++i)

View file

@ -120,7 +120,7 @@ protected:
class FJoystickCollection : public FInputDevice
{
public:
virtual void AddAxes(float axes[NUM_JOYAXIS]) = 0;
virtual void AddAxes(float axes[NUM_AXIS_CODES]) = 0;
virtual void GetDevices(TArray<IJoystickConfig *> &sticks) = 0;
virtual IJoystickConfig *Rescan() = 0;
};

View file

@ -90,7 +90,7 @@ public:
~FRawPS2Controller();
bool ProcessInput(RAWHID *raw, int code);
void AddAxes(float axes[NUM_JOYAXIS]);
void AddAxes(float axes[NUM_AXIS_CODES]);
bool IsConnected() { return Connected; }
// IJoystickConfig interface
@ -100,7 +100,6 @@ public:
int GetNumAxes();
float GetAxisDeadZone(int axis);
EJoyAxis GetAxisMap(int axis);
const char *GetAxisName(int axis);
float GetAxisScale(int axis);
float GetAxisDigitalThreshold(int axis);
@ -108,7 +107,6 @@ public:
float GetAxisResponseCurvePoint(int axis, int point);
void SetAxisDeadZone(int axis, float deadzone);
void SetAxisMap(int axis, EJoyAxis gameaxis);
void SetAxisScale(int axis, float scale);
void SetAxisDigitalThreshold(int axis, float threshold);
void SetAxisResponseCurve(int axis, EJoyCurve preset);
@ -116,7 +114,6 @@ public:
bool IsSensitivityDefault();
bool IsAxisDeadZoneDefault(int axis);
bool IsAxisMapDefault(int axis);
bool IsAxisScaleDefault(int axis);
bool IsAxisDigitalThresholdDefault(int axis);
bool IsAxisResponseCurveDefault(int axis);
@ -140,12 +137,10 @@ protected:
float DigitalThreshold;
EJoyCurve ResponseCurvePreset;
CubicBezier ResponseCurve;
EJoyAxis GameAxis;
uint8_t ButtonValue;
};
struct DefaultAxisConfig
{
EJoyAxis GameAxis;
float Multiplier;
float DigitalThreshold;
EJoyCurve ResponseCurvePreset;
@ -191,7 +186,7 @@ public:
bool GetDevice();
bool ProcessRawInput(RAWINPUT *raw, int code);
void AddAxes(float axes[NUM_JOYAXIS]);
void AddAxes(float axes[NUM_AXIS_CODES]);
void GetDevices(TArray<IJoystickConfig *> &sticks);
IJoystickConfig *Rescan();
@ -367,13 +362,21 @@ static const char *AxisNames[] =
"Right Thumb Y Axis",
};
static const EAxisCodes AxisCodes[][2] =
{
{ AXIS_CODE_PAD_LTHUMB_RIGHT, AXIS_CODE_PAD_LTHUMB_LEFT },
{ AXIS_CODE_PAD_LTHUMB_DOWN, AXIS_CODE_PAD_LTHUMB_UP },
{ AXIS_CODE_PAD_RTHUMB_RIGHT, AXIS_CODE_PAD_RTHUMB_LEFT },
{ AXIS_CODE_PAD_RTHUMB_DOWN, AXIS_CODE_PAD_RTHUMB_UP }
};
FRawPS2Controller::DefaultAxisConfig FRawPS2Controller::DefaultAxes[NUM_AXES] =
{
// Game axis, multiplier, digital threshold, response curve A, response curve B
{ JOYAXIS_Side, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT }, // ThumbLX
{ JOYAXIS_Forward, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT }, // ThumbLY
{ JOYAXIS_Yaw, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT }, // ThumbRX
{ JOYAXIS_Pitch, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT }, // ThumbRY
// multiplier, digital threshold, response curve A, response curve B
{ JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT }, // ThumbLX
{ JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT }, // ThumbLY
{ JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT }, // ThumbRX
{ JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT }, // ThumbRY
};
// CODE --------------------------------------------------------------------
@ -644,12 +647,27 @@ void FRawPS2Controller::NeutralInput()
//
//==========================================================================
void FRawPS2Controller::AddAxes(float axes[NUM_JOYAXIS])
void FRawPS2Controller::AddAxes(float axes[NUM_AXIS_CODES])
{
// Add to game axes.
for (int i = 0; i < NUM_AXES; ++i)
{
axes[Axes[i].GameAxis] -= float(Axes[i].Value * Multiplier * Axes[i].Multiplier);
// Add to the game axis.
float axis_value = float(Axes[i].Value * Multiplier * Axes[i].Multiplier);
int code = AXIS_CODE_NULL;
if (axis_value > 0.0f)
{
code = AxisCodes[i][0];
}
else if (axis_value < 0.0f)
{
code = AxisCodes[i][1];
}
if (code != AXIS_CODE_NULL)
{
axes[code] += fabs(axis_value);
}
}
}
@ -665,7 +683,6 @@ void FRawPS2Controller::SetDefaultConfig()
for (int i = 0; i < NUM_AXES; ++i)
{
Axes[i].DeadZone = JOYDEADZONE_DEFAULT;
Axes[i].GameAxis = DefaultAxes[i].GameAxis;
Axes[i].Multiplier = DefaultAxes[i].Multiplier;
}
}
@ -758,21 +775,6 @@ float FRawPS2Controller::GetAxisDeadZone(int axis)
return 0;
}
//==========================================================================
//
// FRawPS2Controller :: GetAxisMap
//
//==========================================================================
EJoyAxis FRawPS2Controller::GetAxisMap(int axis)
{
if (unsigned(axis) < NUM_AXES)
{
return Axes[axis].GameAxis;
}
return JOYAXIS_None;
}
//==========================================================================
//
// FRawPS2Controller :: GetAxisName
@ -862,20 +864,6 @@ void FRawPS2Controller::SetAxisDeadZone(int axis, float deadzone)
}
}
//==========================================================================
//
// FRawPS2Controller :: SetAxisMap
//
//==========================================================================
void FRawPS2Controller::SetAxisMap(int axis, EJoyAxis gameaxis)
{
if (unsigned(axis) < NUM_AXES)
{
Axes[axis].GameAxis = (unsigned(gameaxis) < NUM_JOYAXIS) ? gameaxis : JOYAXIS_None;
}
}
//==========================================================================
//
// FRawPS2Controller :: SetAxisScale
@ -1018,21 +1006,6 @@ void FRawPS2Controller::SetEnabled(bool enabled)
Enabled = enabled;
}
//===========================================================================
//
// FRawPS2Controller :: IsAxisMapDefault
//
//===========================================================================
bool FRawPS2Controller::IsAxisMapDefault(int axis)
{
if (unsigned(axis) < NUM_AXES)
{
return Axes[axis].GameAxis == DefaultAxes[axis].GameAxis;
}
return true;
}
//==========================================================================
//
// FRawPS2Manager - Constructor
@ -1094,7 +1067,7 @@ bool FRawPS2Manager::GetDevice()
//
//===========================================================================
void FRawPS2Manager::AddAxes(float axes[NUM_JOYAXIS])
void FRawPS2Manager::AddAxes(float axes[NUM_AXIS_CODES])
{
for (unsigned i = 0; i < Devices.Size(); ++i)
{

View file

@ -81,7 +81,7 @@ public:
~FXInputController();
void ProcessInput();
void AddAxes(float axes[NUM_JOYAXIS]);
void AddAxes(float axes[NUM_AXIS_CODES]);
bool IsConnected() { return Connected; }
// IJoystickConfig interface
@ -91,7 +91,6 @@ public:
int GetNumAxes();
float GetAxisDeadZone(int axis);
EJoyAxis GetAxisMap(int axis);
const char *GetAxisName(int axis);
float GetAxisScale(int axis);
float GetAxisDigitalThreshold(int axis);
@ -99,7 +98,6 @@ public:
float GetAxisResponseCurvePoint(int axis, int point);
void SetAxisDeadZone(int axis, float deadzone);
void SetAxisMap(int axis, EJoyAxis gameaxis);
void SetAxisScale(int axis, float scale);
void SetAxisDigitalThreshold(int axis, float threshold);
void SetAxisResponseCurve(int axis, EJoyCurve preset);
@ -107,7 +105,6 @@ public:
bool IsSensitivityDefault();
bool IsAxisDeadZoneDefault(int axis);
bool IsAxisMapDefault(int axis);
bool IsAxisScaleDefault(int axis);
bool IsAxisDigitalThresholdDefault(int axis);
bool IsAxisResponseCurveDefault(int axis);
@ -128,7 +125,6 @@ protected:
float Value;
float DeadZone;
float Multiplier;
EJoyAxis GameAxis;
uint8_t ButtonValue;
float DigitalThreshold;
EJoyCurve ResponseCurvePreset;
@ -137,7 +133,6 @@ protected:
struct DefaultAxisConfig
{
float DeadZone;
EJoyAxis GameAxis;
float Multiplier;
float DigitalThreshold;
EJoyCurve ResponseCurvePreset;
@ -179,7 +174,7 @@ public:
bool GetDevice();
void ProcessInput();
bool WndProcHook(HWND hWnd, uint32_t message, WPARAM wParam, LPARAM lParam, LRESULT *result);
void AddAxes(float axes[NUM_JOYAXIS]);
void AddAxes(float axes[NUM_AXIS_CODES]);
void GetDevices(TArray<IJoystickConfig *> &sticks);
IJoystickConfig *Rescan();
@ -222,15 +217,25 @@ static const char *AxisNames[] =
"Right Trigger"
};
static const EAxisCodes AxisCodes[][2] =
{
{ AXIS_CODE_PAD_LTHUMB_RIGHT, AXIS_CODE_PAD_LTHUMB_LEFT },
{ AXIS_CODE_PAD_LTHUMB_DOWN, AXIS_CODE_PAD_LTHUMB_UP },
{ AXIS_CODE_PAD_RTHUMB_RIGHT, AXIS_CODE_PAD_RTHUMB_LEFT },
{ AXIS_CODE_PAD_RTHUMB_DOWN, AXIS_CODE_PAD_RTHUMB_UP },
{ AXIS_CODE_PAD_LTRIGGER, AXIS_CODE_NULL },
{ AXIS_CODE_PAD_RTRIGGER, AXIS_CODE_NULL }
};
FXInputController::DefaultAxisConfig FXInputController::DefaultAxes[NUM_AXES] =
{
// Dead zone, game axis, multiplier, digitalthreshold, curveA, curveB
{ XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE / 32768.f, JOYAXIS_Side, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT }, // ThumbLX
{ XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE / 32768.f, JOYAXIS_Forward, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT }, // ThumbLY
{ XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE / 32768.f, JOYAXIS_Yaw, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT }, // ThumbRX
{ XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE / 32768.f, JOYAXIS_Pitch, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT }, // ThumbRY
{ XINPUT_GAMEPAD_TRIGGER_THRESHOLD / 256.f, JOYAXIS_None, JOYSENSITIVITY_DEFAULT, JOYTHRESH_TRIGGER, JOYCURVE_DEFAULT }, // LeftTrigger
{ XINPUT_GAMEPAD_TRIGGER_THRESHOLD / 256.f, JOYAXIS_None, JOYSENSITIVITY_DEFAULT, JOYTHRESH_TRIGGER, JOYCURVE_DEFAULT } // RightTrigger
// Dead zone, multiplier, digitalthreshold, curveA, curveB
{ XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE / 32768.f, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT }, // ThumbLX
{ XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE / 32768.f, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT }, // ThumbLY
{ XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE / 32768.f, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_X, JOYCURVE_DEFAULT }, // ThumbRX
{ XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE / 32768.f, JOYSENSITIVITY_DEFAULT, JOYTHRESH_STICK_Y, JOYCURVE_DEFAULT }, // ThumbRY
{ XINPUT_GAMEPAD_TRIGGER_THRESHOLD / 256.f, JOYSENSITIVITY_DEFAULT, JOYTHRESH_TRIGGER, JOYCURVE_DEFAULT }, // LeftTrigger
{ XINPUT_GAMEPAD_TRIGGER_THRESHOLD / 256.f, JOYSENSITIVITY_DEFAULT, JOYTHRESH_TRIGGER, JOYCURVE_DEFAULT } // RightTrigger
};
// CODE --------------------------------------------------------------------
@ -437,12 +442,27 @@ void FXInputController::Detached()
//
//==========================================================================
void FXInputController::AddAxes(float axes[NUM_JOYAXIS])
void FXInputController::AddAxes(float axes[NUM_AXIS_CODES])
{
// Add to game axes.
for (int i = 0; i < NUM_AXES; ++i)
{
axes[Axes[i].GameAxis] -= float(Axes[i].Value * Multiplier * Axes[i].Multiplier);
// Add to the game axis.
float axis_value = float(Axes[i].Value * Multiplier * Axes[i].Multiplier);
int code = AXIS_CODE_NULL;
if (axis_value > 0.0f)
{
code = AxisCodes[i][0];
}
else if (axis_value < 0.0f)
{
code = AxisCodes[i][1];
}
if (code != AXIS_CODE_NULL)
{
axes[code] += fabs(axis_value);
}
}
}
@ -458,7 +478,6 @@ void FXInputController::SetDefaultConfig()
for (int i = 0; i < NUM_AXES; ++i)
{
Axes[i].DeadZone = DefaultAxes[i].DeadZone;
Axes[i].GameAxis = DefaultAxes[i].GameAxis;
Axes[i].Multiplier = DefaultAxes[i].Multiplier;
Axes[i].DigitalThreshold = DefaultAxes[i].DigitalThreshold;
Axes[i].ResponseCurve = JOYCURVE[DefaultAxes[i].ResponseCurvePreset];
@ -549,21 +568,6 @@ float FXInputController::GetAxisDeadZone(int axis)
return 0;
}
//==========================================================================
//
// FXInputController :: GetAxisMap
//
//==========================================================================
EJoyAxis FXInputController::GetAxisMap(int axis)
{
if (unsigned(axis) < NUM_AXES)
{
return Axes[axis].GameAxis;
}
return JOYAXIS_None;
}
//==========================================================================
//
// FXInputController :: GetAxisName
@ -653,20 +657,6 @@ void FXInputController::SetAxisDeadZone(int axis, float deadzone)
}
}
//==========================================================================
//
// FXInputController :: SetAxisMap
//
//==========================================================================
void FXInputController::SetAxisMap(int axis, EJoyAxis gameaxis)
{
if (unsigned(axis) < NUM_AXES)
{
Axes[axis].GameAxis = (unsigned(gameaxis) < NUM_JOYAXIS) ? gameaxis : JOYAXIS_None;
}
}
//==========================================================================
//
// FXInputController :: SetAxisScale
@ -809,21 +799,6 @@ void FXInputController::SetEnabled(bool enabled)
Enabled = enabled;
}
//===========================================================================
//
// FXInputController :: IsAxisMapDefault
//
//===========================================================================
bool FXInputController::IsAxisMapDefault(int axis)
{
if (unsigned(axis) < NUM_AXES)
{
return Axes[axis].GameAxis == DefaultAxes[axis].GameAxis;
}
return true;
}
//==========================================================================
//
// FXInputManager - Constructor
@ -913,7 +888,7 @@ void FXInputManager::ProcessInput()
//
//===========================================================================
void FXInputManager::AddAxes(float axes[NUM_JOYAXIS])
void FXInputManager::AddAxes(float axes[NUM_AXIS_CODES])
{
for (int i = 0; i < XUSER_MAX_COUNT; ++i)
{

View file

@ -611,6 +611,9 @@ void G_BuildTiccmd (usercmd_t *cmd)
base = G_BaseTiccmd ();
*cmd = *base;
// Update axis polling for the button map
buttonMap.GetAxes();
strafe = buttonMap.ButtonDown(Button_Strafe);
speed = buttonMap.ButtonDown(Button_Speed) ^ (int)cl_run;
@ -619,7 +622,7 @@ void G_BuildTiccmd (usercmd_t *cmd)
// [RH] only use two stage accelerative turning on the keyboard
// and not the joystick, since we treat the joystick as
// the analog device it is.
if (buttonMap.ButtonDown(Button_Left) || buttonMap.ButtonDown(Button_Right))
if (buttonMap.ButtonDownDigital(Button_Left) || buttonMap.ButtonDownDigital(Button_Right))
turnheld += TicDup;
else
turnheld = 0;
@ -627,9 +630,9 @@ void G_BuildTiccmd (usercmd_t *cmd)
// let movement keys cancel each other out
if (strafe)
{
if (buttonMap.ButtonDown(Button_Right))
if (buttonMap.ButtonDownDigital(Button_Right))
side += sidemove[speed];
if (buttonMap.ButtonDown(Button_Left))
if (buttonMap.ButtonDownDigital(Button_Left))
side -= sidemove[speed];
}
else
@ -639,48 +642,48 @@ void G_BuildTiccmd (usercmd_t *cmd)
if (turnheld < SLOWTURNTICS)
tspeed += 2; // slow turn
if (buttonMap.ButtonDown(Button_Right))
if (buttonMap.ButtonDownDigital(Button_Right))
{
G_AddViewAngle (*angleturn[tspeed]);
}
if (buttonMap.ButtonDown(Button_Left))
if (buttonMap.ButtonDownDigital(Button_Left))
{
G_AddViewAngle (-*angleturn[tspeed]);
}
}
if (buttonMap.ButtonDown(Button_LookUp))
if (buttonMap.ButtonDownDigital(Button_LookUp))
{
G_AddViewPitch (lookspeed[speed]);
}
if (buttonMap.ButtonDown(Button_LookDown))
if (buttonMap.ButtonDownDigital(Button_LookDown))
{
G_AddViewPitch (-lookspeed[speed]);
}
if (buttonMap.ButtonDown(Button_MoveUp))
if (buttonMap.ButtonDownDigital(Button_MoveUp))
fly += flyspeed[speed];
if (buttonMap.ButtonDown(Button_MoveDown))
if (buttonMap.ButtonDownDigital(Button_MoveDown))
fly -= flyspeed[speed];
if (buttonMap.ButtonDown(Button_Klook))
{
if (buttonMap.ButtonDown(Button_Forward))
if (buttonMap.ButtonDownDigital(Button_Forward))
G_AddViewPitch (lookspeed[speed]);
if (buttonMap.ButtonDown(Button_Back))
if (buttonMap.ButtonDownDigital(Button_Back))
G_AddViewPitch (-lookspeed[speed]);
}
else
{
if (buttonMap.ButtonDown(Button_Forward))
if (buttonMap.ButtonDownDigital(Button_Forward))
forward += forwardmove[speed];
if (buttonMap.ButtonDown(Button_Back))
if (buttonMap.ButtonDownDigital(Button_Back))
forward -= forwardmove[speed];
}
if (buttonMap.ButtonDown(Button_MoveRight))
if (buttonMap.ButtonDownDigital(Button_MoveRight))
side += sidemove[speed];
if (buttonMap.ButtonDown(Button_MoveLeft))
if (buttonMap.ButtonDownDigital(Button_MoveLeft))
side -= sidemove[speed];
// buttons
@ -712,35 +715,37 @@ void G_BuildTiccmd (usercmd_t *cmd)
if (buttonMap.ButtonDown(Button_ShowScores)) cmd->buttons |= BT_SHOWSCORES;
if (speed) cmd->buttons |= BT_RUN;
// Handle joysticks/game controllers.
float joyaxes[NUM_JOYAXIS];
I_GetAxes(joyaxes);
// Remap some axes depending on button state.
float axis_yaw = buttonMap.ButtonAnalog(Button_Left) - buttonMap.ButtonAnalog(Button_Right);
float axis_pitch = buttonMap.ButtonAnalog(Button_LookUp) - buttonMap.ButtonAnalog(Button_LookDown);
float axis_forward = buttonMap.ButtonAnalog(Button_Forward) - buttonMap.ButtonAnalog(Button_Back);
float axis_side = buttonMap.ButtonAnalog(Button_MoveLeft) - buttonMap.ButtonAnalog(Button_MoveRight);
float axis_up = buttonMap.ButtonAnalog(Button_MoveUp) - buttonMap.ButtonAnalog(Button_MoveDown);
if (buttonMap.ButtonDown(Button_Strafe) || (buttonMap.ButtonDown(Button_Mlook) && lookstrafe))
{
joyaxes[JOYAXIS_Side] = joyaxes[JOYAXIS_Yaw];
joyaxes[JOYAXIS_Yaw] = 0;
axis_side = axis_yaw;
axis_yaw = 0.0f;
}
if (buttonMap.ButtonDown(Button_Mlook))
{
joyaxes[JOYAXIS_Pitch] = joyaxes[JOYAXIS_Forward];
joyaxes[JOYAXIS_Forward] = 0;
axis_pitch = axis_forward;
axis_forward = 0.0f;
}
if (joyaxes[JOYAXIS_Pitch] != 0)
if (axis_pitch != 0)
{
G_AddViewPitch(joyint(joyaxes[JOYAXIS_Pitch] * 2048));
G_AddViewPitch(joyint(axis_pitch * 2048));
}
if (joyaxes[JOYAXIS_Yaw] != 0)
if (axis_yaw != 0)
{
G_AddViewAngle(joyint(-1280 * joyaxes[JOYAXIS_Yaw]));
G_AddViewAngle(joyint(-1280 * axis_yaw));
}
side -= joyint(sidemove[speed] * joyaxes[JOYAXIS_Side]);
forward += joyint(joyaxes[JOYAXIS_Forward] * forwardmove[speed]);
fly += joyint(joyaxes[JOYAXIS_Up] * 2048);
side -= joyint(sidemove[speed] * axis_side);
forward += joyint(axis_forward * forwardmove[speed]);
fly += joyint(axis_up * 2048);
// Handle mice.
if (!buttonMap.ButtonDown(Button_Mlook) && !freelook)

View file

@ -64,6 +64,14 @@ dpadup togglemap
pad_start menu_main
pad_back pause
lthumb crouch
lstickleft +moveleft
lstickright +moveright
lstickup +forward
lstickdown +back
rstickleft +left
rstickright +right
rstickup +lookup
rstickdown +lookdown
// Generic gamepad bindings
joy1 +use
@ -79,6 +87,10 @@ pov1up togglemap
joy8 menu_main
joy7 pause
joy10 crouch
axis1minus +moveleft
axis1plus +moveright
axis2minus +forward
axis2plus +back
/* Default automap bindings */
mapbind f am_togglefollow

View file

@ -267,6 +267,9 @@ class OptionMenuItemJoyCurve : OptionMenuItemOptionBase
class OptionMenuItemJoyMap : OptionMenuItemOptionBase
{
// For backwards compatibility with menu mods, we need to leave this class alone.
// It simply is always set to "None" and does nothing now.
int mAxis;
JoystickConfig mJoy;
@ -465,7 +468,7 @@ class OptionMenuItemJoyConfigMenu : OptionMenuItemSubmenu
it = new("OptionMenuItemStaticText").Init(" ", false);
opt.mItems.Push(it);
it = new("OptionMenuItemJoyMap").Init(joy.GetAxisName(i), i, "JoyAxisMapNames", false, joy);
it = new("OptionMenuItemStaticText").Init(joy.GetAxisName(i), false);
opt.mItems.Push(it);
it = new("OptionMenuSliderJoyScale").Init("$JOYMNU_OVRSENS", i, 0, 4, 0.1, 3, joy);
opt.mItems.Push(it);

View file

@ -96,8 +96,15 @@ struct JoystickConfig native version("2.4")
native float GetAxisResponseCurvePoint(int axis, int point);
native void SetAxisResponseCurvePoint(int axis, int point, float value);
native int GetAxisMap(int axis);
native void SetAxisMap(int axis, int gameaxis);
deprecated("4.15.1", "Axis mapping was replaced with binds; remove this menu item") int GetAxisMap(int axis)
{
return JOYAXIS_None;
}
deprecated("4.15.1", "Axis mapping was replaced with binds; remove this menu item") void SetAxisMap(int axis, int gameaxis)
{
// NOP
}
native String GetName();
native int GetNumAxes();