Gamepad Improvements
* Cleanup: Alignment, long lines, Replace 0 with SDLK_UNKNOWN * Gamecontroller api analogue input * Added some button handling * Added mapping for other buttons * Added trigger events * Added force_joystick flag * Removed force_joystick flag Rationale: 1. It was actually broken lol 2. I cannot think of a case where enabling this would be a useful thing for gzdoom. If the user is using a gamecontroller, it is pointless. If they are not using a gamecontroller, it will just default to using the joystick api. If they are not using a gamecontroller, but SDL thinks they are, it is an SDL bug, and will be reported and fixed * Modified default mapping * Added analogue to digital threshold * Added analogue response curve * Per axis settings * Fixed controller reconnect * Added threshold and curve to IJoystickConfig Enabled saving of settings * Added stubs * Cleanup Constants are no longer defines. Constants are mostly shared between backends. Moved some logic to m_joy * Implemented xinput stubs * Implemented dinput stubs * Implemented ps2 stubs (untested) * Fixed inclusive check * Implemented osx stubs (untested) * Fixed curve implementation No longer savable, I screwed the curve function up. I though it needed 2 control points, but it needs 4. Need to re-do controller settings :( * Now using CubicBezier struct * Fixed SetDefaultConfig to match xinput behavior * Expanded gamepad CCMD * Rename enum JoyResponseCurve to EJoyCurve * Initial menu implementation * Fixed SDL controller setting saving * SDL gamepads can now actually be disabled * Fixed initial controller connect of some versions of SDL * Spelling error * Enable gamepad by default * Fixed segfault on some versions of SDL * Only block keydown
This commit is contained in:
parent
672a21f533
commit
2a5cce543b
16 changed files with 1613 additions and 215 deletions
|
|
@ -147,7 +147,9 @@ const char *KeyNames[NUM_KEYS] =
|
|||
"DPadUp","DPadDown","DPadLeft","DPadRight", // Gamepad buttons
|
||||
"Pad_Start","Pad_Back","LThumb","RThumb",
|
||||
"LShoulder","RShoulder","LTrigger","RTrigger",
|
||||
"Pad_A", "Pad_B", "Pad_X", "Pad_Y"
|
||||
"Pad_A", "Pad_B", "Pad_X", "Pad_Y",
|
||||
"Paddle_1", "Paddle_2", "Paddle_3", "Paddle_4",
|
||||
"Guide", "Pad_Misc", "Pad_Touchpad"
|
||||
};
|
||||
|
||||
FKeyBindings Bindings;
|
||||
|
|
|
|||
|
|
@ -134,8 +134,15 @@ enum EKeyCodes
|
|||
KEY_PAD_B = 0x1C1,
|
||||
KEY_PAD_X = 0x1C2,
|
||||
KEY_PAD_Y = 0x1C3,
|
||||
KEY_PAD_PADDLE1 = 0x1C4,
|
||||
KEY_PAD_PADDLE2 = 0x1C5,
|
||||
KEY_PAD_PADDLE3 = 0x1C6,
|
||||
KEY_PAD_PADDLE4 = 0x1C7,
|
||||
KEY_PAD_GUIDE = 0x1C8,
|
||||
KEY_PAD_MISC1 = 0x1C9,
|
||||
KEY_PAD_TOUCHPAD = 0x1CA,
|
||||
|
||||
NUM_KEYS = 0x1C4,
|
||||
NUM_KEYS = 0x1CB,
|
||||
|
||||
NUM_JOYAXISBUTTONS = 8,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@
|
|||
// HEADER FILES ------------------------------------------------------------
|
||||
|
||||
#include <math.h>
|
||||
#include "c_dispatch.h"
|
||||
#include "gain_analysis.h"
|
||||
#include "keydef.h"
|
||||
#include "name.h"
|
||||
#include "tarray.h"
|
||||
#include "vectors.h"
|
||||
#include "m_joy.h"
|
||||
#include "configfile.h"
|
||||
|
|
@ -40,6 +45,7 @@
|
|||
#include "d_eventbase.h"
|
||||
#include "cmdlib.h"
|
||||
#include "printf.h"
|
||||
#include "zstring.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
|
@ -57,9 +63,26 @@ EXTERN_CVAR(Bool, joy_ps2raw)
|
|||
EXTERN_CVAR(Bool, joy_dinput)
|
||||
EXTERN_CVAR(Bool, joy_xinput)
|
||||
|
||||
extern const float JOYDEADZONE_DEFAULT = 0.1; // reduced from 0.25
|
||||
|
||||
extern const float JOYSENSITIVITY_DEFAULT = 1.0;
|
||||
|
||||
extern const float JOYTHRESH_DEFAULT = 0.05;
|
||||
extern const float JOYTHRESH_TRIGGER = 0.05;
|
||||
extern const float JOYTHRESH_STICK_X = 0.65;
|
||||
extern const float JOYTHRESH_STICK_Y = 0.35;
|
||||
|
||||
extern const CubicBezier JOYCURVE[NUM_JOYCURVE] = {
|
||||
{{0.3, 0.0, 0.7, 0.4}}, // DEFAULT -> QUADRATIC
|
||||
|
||||
{{0.0, 0.0, 1.0, 1.0}}, // LINEAR
|
||||
{{0.3, 0.0, 0.7, 0.4}}, // QUADRATIC
|
||||
{{0.5, 0.0, 0.7, 0.2}}, // CUBIC
|
||||
};
|
||||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
CUSTOM_CVARD(Bool, use_joystick, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL, "enables input from the joystick if it is present")
|
||||
CUSTOM_CVARD(Bool, use_joystick, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL, "enables input from the joystick if it is present")
|
||||
{
|
||||
#ifdef _WIN32
|
||||
joy_ps2raw->Callback();
|
||||
|
|
@ -163,6 +186,48 @@ bool M_LoadJoystickConfig(IJoystickConfig *joy)
|
|||
joy->SetAxisScale(i, (float)atof(value));
|
||||
}
|
||||
|
||||
mysnprintf(key + axislen, countof(key) - axislen, "threshold");
|
||||
value = GameConfig->GetValueForKey(key);
|
||||
if (value)
|
||||
{
|
||||
joy->SetAxisDigitalThreshold(i, (float)atof(value));
|
||||
}
|
||||
|
||||
mysnprintf(key + axislen, countof(key) - axislen, "curve");
|
||||
value = GameConfig->GetValueForKey(key);
|
||||
if (value)
|
||||
{
|
||||
joy->SetAxisResponseCurve(i, (EJoyCurve)clamp(atoi(value), (int)JOYCURVE_CUSTOM, (int)NUM_JOYCURVE-1));
|
||||
}
|
||||
|
||||
mysnprintf(key + axislen, countof(key) - axislen, "curve-x1");
|
||||
value = GameConfig->GetValueForKey(key);
|
||||
if (value)
|
||||
{
|
||||
joy->SetAxisResponseCurvePoint(i, 0, (float)atof(value));
|
||||
}
|
||||
|
||||
mysnprintf(key + axislen, countof(key) - axislen, "curve-y1");
|
||||
value = GameConfig->GetValueForKey(key);
|
||||
if (value)
|
||||
{
|
||||
joy->SetAxisResponseCurvePoint(i, 1, (float)atof(value));
|
||||
}
|
||||
|
||||
mysnprintf(key + axislen, countof(key) - axislen, "curve-x2");
|
||||
value = GameConfig->GetValueForKey(key);
|
||||
if (value)
|
||||
{
|
||||
joy->SetAxisResponseCurvePoint(i, 2, (float)atof(value));
|
||||
}
|
||||
|
||||
mysnprintf(key + axislen, countof(key) - axislen, "curve-y2");
|
||||
value = GameConfig->GetValueForKey(key);
|
||||
if (value)
|
||||
{
|
||||
joy->SetAxisResponseCurvePoint(i, 3, (float)atof(value));
|
||||
}
|
||||
|
||||
mysnprintf(key + axislen, countof(key) - axislen, "map");
|
||||
value = GameConfig->GetValueForKey(key);
|
||||
if (value)
|
||||
|
|
@ -227,6 +292,33 @@ void M_SaveJoystickConfig(IJoystickConfig *joy)
|
|||
mysnprintf(value, countof(value), "%g", joy->GetAxisScale(i));
|
||||
GameConfig->SetValueForKey(key, value);
|
||||
}
|
||||
if (!joy->IsAxisDigitalThresholdDefault(i))
|
||||
{
|
||||
mysnprintf(key + axislen, countof(key) - axislen, "threshold");
|
||||
mysnprintf(value, countof(value), "%g", joy->GetAxisDigitalThreshold(i));
|
||||
GameConfig->SetValueForKey(key, value);
|
||||
}
|
||||
if (!joy->IsAxisResponseCurveDefault(i))
|
||||
{
|
||||
mysnprintf(key + axislen, countof(key) - axislen, "curve");
|
||||
mysnprintf(value, countof(value), "%d", joy->GetAxisResponseCurve(i));
|
||||
GameConfig->SetValueForKey(key, value);
|
||||
}
|
||||
if (joy->GetAxisResponseCurve(i) == JOYCURVE_CUSTOM)
|
||||
{
|
||||
mysnprintf(key + axislen, countof(key) - axislen, "curve-x1");
|
||||
mysnprintf(value, countof(value), "%g", joy->GetAxisResponseCurvePoint(i, 0));
|
||||
GameConfig->SetValueForKey(key, value);
|
||||
mysnprintf(key + axislen, countof(key) - axislen, "curve-y1");
|
||||
mysnprintf(value, countof(value), "%g", joy->GetAxisResponseCurvePoint(i, 1));
|
||||
GameConfig->SetValueForKey(key, value);
|
||||
mysnprintf(key + axislen, countof(key) - axislen, "curve-x2");
|
||||
mysnprintf(value, countof(value), "%g", joy->GetAxisResponseCurvePoint(i, 2));
|
||||
GameConfig->SetValueForKey(key, value);
|
||||
mysnprintf(key + axislen, countof(key) - axislen, "curve-y2");
|
||||
mysnprintf(value, countof(value), "%g", joy->GetAxisResponseCurvePoint(i, 3));
|
||||
GameConfig->SetValueForKey(key, value);
|
||||
}
|
||||
if (!joy->IsAxisMapDefault(i))
|
||||
{
|
||||
mysnprintf(key + axislen, countof(key) - axislen, "map");
|
||||
|
|
@ -243,6 +335,174 @@ void M_SaveJoystickConfig(IJoystickConfig *joy)
|
|||
}
|
||||
}
|
||||
|
||||
CCMD (gamepad)
|
||||
{
|
||||
int COMMAND = 1, IDENTIFIER = 2, VALUE = 3;
|
||||
int argc = argv.argc()-1;
|
||||
|
||||
TArray<IJoystickConfig *> sticks;
|
||||
I_GetJoysticks(sticks);
|
||||
|
||||
auto usage = []()
|
||||
{
|
||||
Printf(
|
||||
"usage:"
|
||||
"\n\tgamepad list"
|
||||
"\n\tgamepad reset pad"
|
||||
"\n\tgamepad enabled pad [0|1]"
|
||||
"\n\tgamepad background pad [0|1]"
|
||||
"\n\tgamepad sensitivity pad [float]"
|
||||
"\n\tgamepad deadzone pad.axis [float]"
|
||||
"\n\tgamepad scale pad.axis [float]"
|
||||
"\n\tgamepad threshold pad.axis [float]"
|
||||
"\n\tgamepad curve pad.axis [-1|0|1|2|3]"
|
||||
"\n\tgamepad curve-x1 pad.axis [float]"
|
||||
"\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"
|
||||
);
|
||||
};
|
||||
|
||||
if (argc < COMMAND)
|
||||
{
|
||||
return usage();
|
||||
};
|
||||
|
||||
FName command = argv[COMMAND];
|
||||
|
||||
if (argc < IDENTIFIER)
|
||||
{
|
||||
if (command == "list")
|
||||
{
|
||||
for (int i = 0; i < sticks.SSize(); i++)
|
||||
{
|
||||
Printf("%d: '%s'\n", i, sticks[i]->GetName().GetChars());
|
||||
for (int j = 0; j < sticks[i]->GetNumAxes(); j++)
|
||||
{
|
||||
Printf(" %d.%d: '%s'\n", i, j, sticks[i]->GetAxisName(j));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
return usage();
|
||||
}
|
||||
|
||||
const char * id = argv[IDENTIFIER];
|
||||
const char * hasAxis = strchr(id, '.');
|
||||
|
||||
int pad, axis;
|
||||
|
||||
try {
|
||||
pad = (int)std::stod(id);
|
||||
|
||||
if (pad < 0 || pad >= sticks.SSize())
|
||||
{
|
||||
return (void) Printf("Pad # out of range\n");
|
||||
}
|
||||
} catch (...) {
|
||||
return (void) Printf("Failed to parse pad #\n");
|
||||
}
|
||||
|
||||
if (hasAxis)
|
||||
{
|
||||
try {
|
||||
axis = (int)std::stod(hasAxis+1);
|
||||
|
||||
if (axis < 0 || axis >= sticks[pad]->GetNumAxes())
|
||||
{
|
||||
return (void) Printf("Axis # out of range\n");
|
||||
}
|
||||
} catch (...) {
|
||||
return (void) Printf("Failed to parse axis #\n");
|
||||
}
|
||||
}
|
||||
|
||||
float value = 0;
|
||||
bool set = argc >= VALUE;
|
||||
|
||||
if (set)
|
||||
{
|
||||
try {
|
||||
value = std::stod(argv[VALUE]);
|
||||
} catch (...) {
|
||||
return (void) Printf("Failed to parse args\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (command == "reset")
|
||||
{
|
||||
if (set) return usage();
|
||||
sticks[pad]->SetDefaultConfig();
|
||||
sticks[pad]->SetEnabled(true);
|
||||
sticks[pad]->SetEnabledInBackground(sticks[pad]->AllowsEnabledInBackground());
|
||||
sticks[pad]->SetSensitivity(1);
|
||||
return;
|
||||
}
|
||||
if (command == "enabled")
|
||||
{
|
||||
if (set) sticks[pad]->SetEnabled((int)value);
|
||||
return (void) Printf("%d\n", sticks[pad]->GetEnabled());
|
||||
}
|
||||
if (command == "background")
|
||||
{
|
||||
if (set) sticks[pad]->SetEnabledInBackground((int)value);
|
||||
return (void) Printf("%d\n", sticks[pad]->GetEnabledInBackground());
|
||||
}
|
||||
if (command == "sensitivity")
|
||||
{
|
||||
if (set) sticks[pad]->SetSensitivity(value);
|
||||
return (void) Printf("%g\n", sticks[pad]->GetSensitivity());
|
||||
}
|
||||
if (command == "deadzone")
|
||||
{
|
||||
if (set) sticks[pad]->SetAxisDeadZone(axis, value);
|
||||
return (void) Printf("%g\n", sticks[pad]->GetAxisDeadZone(axis));
|
||||
}
|
||||
if (command == "scale")
|
||||
{
|
||||
if (set) sticks[pad]->SetAxisScale(axis, value);
|
||||
return (void) Printf("%g\n", sticks[pad]->GetAxisScale(axis));
|
||||
}
|
||||
if (command == "threshold")
|
||||
{
|
||||
if (set) sticks[pad]->SetAxisDigitalThreshold(axis, value);
|
||||
return (void) Printf("%g\n", sticks[pad]->GetAxisDigitalThreshold(axis));
|
||||
}
|
||||
if (command == "curve")
|
||||
{
|
||||
if (set) sticks[pad]->SetAxisResponseCurve(axis, (EJoyCurve)value);
|
||||
return (void) Printf("%d\n", sticks[pad]->GetAxisResponseCurve(axis));
|
||||
}
|
||||
if (command == "curve-x1")
|
||||
{
|
||||
if (set) sticks[pad]->SetAxisResponseCurvePoint(axis, 0, value);
|
||||
return (void) Printf("%g\n", sticks[pad]->GetAxisResponseCurvePoint(axis, 0));
|
||||
}
|
||||
if (command == "curve-y1")
|
||||
{
|
||||
if (set) sticks[pad]->SetAxisResponseCurvePoint(axis, 1, value);
|
||||
return (void) Printf("%g\n", sticks[pad]->GetAxisResponseCurvePoint(axis, 1));
|
||||
}
|
||||
if (command == "curve-x2")
|
||||
{
|
||||
if (set) sticks[pad]->SetAxisResponseCurvePoint(axis, 2, value);
|
||||
return (void) Printf("%g\n", sticks[pad]->GetAxisResponseCurvePoint(axis, 2));
|
||||
}
|
||||
if (command == "curve-y2")
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
|
@ -278,6 +538,48 @@ double Joy_RemoveDeadZone(double axisval, double deadzone, uint8_t *buttons)
|
|||
return axisval;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Joy_ApplyResponseCurveBezier
|
||||
//
|
||||
// Applies cubic bezier easing function
|
||||
// Curve is defined by control points [(0,0) (x1,y1) (x2,y2) (1,1)]
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function/cubic-bezier
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
double Joy_ApplyResponseCurveBezier(const CubicBezier &curve, double input)
|
||||
{
|
||||
// clamp + trivial cases
|
||||
if (input == 0) return 0;
|
||||
double sign = (input >= 0)? 1.0: -1.0;
|
||||
input = abs(input);
|
||||
input = (input > 1.0)? 1.0: input;
|
||||
if (input == 1.0) return sign*input;
|
||||
|
||||
double t = input, T;
|
||||
float x1 = curve.x1, y1 = curve.y1, x2 = curve.x2, y2 = curve.y2;
|
||||
|
||||
const int max_iter = 4;
|
||||
for (auto i = 0; i < max_iter; i++)
|
||||
{
|
||||
T = 1-t;
|
||||
|
||||
double x = 3*T*T*t*x1 + 3*T*t*t*x2 + t*t*t;
|
||||
double dx = 3*T*T*x1 + 6*T*t*(x2-x1) + 3*t*t*(1-x2);
|
||||
|
||||
// no div by 0
|
||||
if (abs(dx) < 0.00001) break;
|
||||
|
||||
t = clamp(t - (x-input)/dx, 0.0, 1.0);
|
||||
}
|
||||
|
||||
T = 1-t;
|
||||
t = 3*T*T*t*y1 + 3*T*t*t*y2 + t*t*t;
|
||||
|
||||
return sign*t;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Joy_XYAxesToButtons
|
||||
|
|
@ -315,6 +617,22 @@ int Joy_XYAxesToButtons(double x, double y)
|
|||
return JoyAngleButtons[int(rad) & 7];
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Joy_GenerateButtonEvent
|
||||
//
|
||||
// Send either a button up or button down event for supplied key code
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void Joy_GenerateButtonEvent(bool down, EKeyCodes which)
|
||||
{
|
||||
event_t event = { 0,0,0,0,0,0,0 };
|
||||
event.type = down ? EV_KeyDown : EV_KeyUp;
|
||||
event.data1 = which;
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Joy_GenerateButtonEvents
|
||||
|
|
@ -330,15 +648,12 @@ void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, in
|
|||
int changed = oldbuttons ^ newbuttons;
|
||||
if (changed != 0)
|
||||
{
|
||||
event_t ev = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
int mask = 1;
|
||||
for (int j = 0; j < numbuttons; mask <<= 1, ++j)
|
||||
{
|
||||
if (changed & mask)
|
||||
{
|
||||
ev.data1 = base + j;
|
||||
ev.type = (newbuttons & mask) ? EV_KeyDown : EV_KeyUp;
|
||||
D_PostEvent(&ev);
|
||||
Joy_GenerateButtonEvent(newbuttons & mask, static_cast<EKeyCodes>(base + j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -349,15 +664,12 @@ void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, co
|
|||
int changed = oldbuttons ^ newbuttons;
|
||||
if (changed != 0)
|
||||
{
|
||||
event_t ev = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
int mask = 1;
|
||||
for (int j = 0; j < numbuttons; mask <<= 1, ++j)
|
||||
{
|
||||
if (changed & mask)
|
||||
{
|
||||
ev.data1 = keys[j];
|
||||
ev.type = (newbuttons & mask) ? EV_KeyDown : EV_KeyUp;
|
||||
D_PostEvent(&ev);
|
||||
Joy_GenerateButtonEvent(newbuttons & mask, static_cast<EKeyCodes>(keys[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,30 @@
|
|||
#define M_JOY_H
|
||||
|
||||
#include "basics.h"
|
||||
#include "keydef.h"
|
||||
#include "tarray.h"
|
||||
#include "c_cvars.h"
|
||||
|
||||
union CubicBezier {
|
||||
struct {
|
||||
float x1;
|
||||
float y1;
|
||||
float x2;
|
||||
float y2;
|
||||
};
|
||||
float pts[4];
|
||||
};
|
||||
|
||||
enum EJoyCurve {
|
||||
JOYCURVE_CUSTOM = -1,
|
||||
JOYCURVE_DEFAULT,
|
||||
JOYCURVE_LINEAR,
|
||||
JOYCURVE_QUADRATIC,
|
||||
JOYCURVE_CUBIC,
|
||||
|
||||
NUM_JOYCURVE
|
||||
};
|
||||
|
||||
enum EJoyAxis
|
||||
{
|
||||
JOYAXIS_None = -1,
|
||||
|
|
@ -13,10 +34,22 @@ enum EJoyAxis
|
|||
JOYAXIS_Forward,
|
||||
JOYAXIS_Side,
|
||||
JOYAXIS_Up,
|
||||
// JOYAXIS_Roll, // Ha ha. No roll for you.
|
||||
// JOYAXIS_Roll, // Ha ha. No roll for you.
|
||||
NUM_JOYAXIS,
|
||||
};
|
||||
|
||||
extern const float JOYDEADZONE_DEFAULT;
|
||||
|
||||
extern const float JOYSENSITIVITY_DEFAULT;
|
||||
|
||||
extern const float JOYTHRESH_DEFAULT;
|
||||
|
||||
extern const float JOYTHRESH_TRIGGER;
|
||||
extern const float JOYTHRESH_STICK_X;
|
||||
extern const float JOYTHRESH_STICK_Y;
|
||||
|
||||
extern const CubicBezier JOYCURVE[NUM_JOYCURVE];
|
||||
|
||||
// Generic configuration interface for a controller.
|
||||
struct IJoystickConfig
|
||||
{
|
||||
|
|
@ -31,10 +64,16 @@ struct IJoystickConfig
|
|||
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;
|
||||
virtual EJoyCurve GetAxisResponseCurve(int axis) = 0;
|
||||
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;
|
||||
virtual void SetAxisResponseCurvePoint(int axis, int point, float value) = 0;
|
||||
|
||||
virtual bool GetEnabled() = 0;
|
||||
virtual void SetEnabled(bool enabled) = 0;
|
||||
|
|
@ -48,6 +87,8 @@ struct IJoystickConfig
|
|||
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;
|
||||
|
||||
virtual void SetDefaultConfig() = 0;
|
||||
virtual FString GetIdentifier() = 0;
|
||||
|
|
@ -58,10 +99,12 @@ EXTERN_CVAR(Bool, use_joystick);
|
|||
bool M_LoadJoystickConfig(IJoystickConfig *joy);
|
||||
void M_SaveJoystickConfig(IJoystickConfig *joy);
|
||||
|
||||
void Joy_GenerateButtonEvent(bool down, EKeyCodes which);
|
||||
void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, int base);
|
||||
void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, const int *keys);
|
||||
int Joy_XYAxesToButtons(double x, double y);
|
||||
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]);
|
||||
|
|
|
|||
|
|
@ -84,6 +84,56 @@ DEFINE_ACTION_FUNCTION(IJoystickConfig, SetAxisDeadZone)
|
|||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetAxisDigitalThreshold)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||
PARAM_INT(axis);
|
||||
ACTION_RETURN_FLOAT(self->GetAxisDigitalThreshold(axis));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(IJoystickConfig, SetAxisDigitalThreshold)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||
PARAM_INT(axis);
|
||||
PARAM_FLOAT(dt);
|
||||
self->SetAxisDigitalThreshold(axis, (float)dt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetAxisResponseCurve)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||
PARAM_INT(axis);
|
||||
ACTION_RETURN_INT(self->GetAxisResponseCurve(axis));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(IJoystickConfig, SetAxisResponseCurve)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||
PARAM_INT(axis);
|
||||
PARAM_INT(curve);
|
||||
self->SetAxisResponseCurve(axis, (EJoyCurve)curve);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetAxisResponseCurvePoint)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||
PARAM_INT(axis);
|
||||
PARAM_INT(point);
|
||||
ACTION_RETURN_INT(self->GetAxisResponseCurvePoint(axis, point));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(IJoystickConfig, SetAxisResponseCurvePoint)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||
PARAM_INT(axis);
|
||||
PARAM_INT(point);
|
||||
PARAM_FLOAT(value);
|
||||
self->SetAxisResponseCurvePoint(axis, point, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetAxisMap)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
|
||||
|
|
|
|||
|
|
@ -680,7 +680,7 @@ bool M_Responder (event_t *ev)
|
|||
else if (menuactive != MENU_WaitKey && (ev->type == EV_KeyDown || ev->type == EV_KeyUp))
|
||||
{
|
||||
// eat blocked controller events without dispatching them.
|
||||
if (ev->data1 >= KEY_FIRSTJOYBUTTON && m_blockcontrollers) return true;
|
||||
if (ev->data1 >= KEY_FIRSTJOYBUTTON && m_blockcontrollers && ev->type == EV_KeyDown) return true;
|
||||
|
||||
keyup = ev->type == EV_KeyUp;
|
||||
|
||||
|
|
|
|||
|
|
@ -94,15 +94,23 @@ public:
|
|||
virtual EJoyAxis GetAxisMap(int axis);
|
||||
virtual const char* GetAxisName(int axis);
|
||||
virtual float GetAxisScale(int axis);
|
||||
float GetAxisDigitalThreshold(int axis);
|
||||
EJoyCurve GetAxisResponseCurve(int axis);
|
||||
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);
|
||||
void SetAxisResponseCurvePoint(int axis, int point, float value);
|
||||
|
||||
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);
|
||||
|
||||
virtual bool GetEnabled();
|
||||
virtual void SetEnabled(bool enabled);
|
||||
|
|
@ -146,6 +154,11 @@ private:
|
|||
float defaultDeadZone;
|
||||
float sensitivity;
|
||||
float defaultSensitivity;
|
||||
float digitalThreshold;
|
||||
float defaultDigitalThreshold;
|
||||
EJoyCurve responseCurvePreset;
|
||||
EJoyCurve defaultResponseCurvePreset;
|
||||
CubicBezier responseCurve;
|
||||
|
||||
EJoyAxis gameAxis;
|
||||
EJoyAxis defaultGameAxis;
|
||||
|
|
@ -177,10 +190,6 @@ private:
|
|||
|
||||
io_object_t m_notification;
|
||||
|
||||
|
||||
static const float DEFAULT_DEADZONE;
|
||||
static const float DEFAULT_SENSITIVITY;
|
||||
|
||||
void ProcessAxes();
|
||||
bool ProcessAxis (const IOHIDEventStruct& event);
|
||||
bool ProcessButton(const IOHIDEventStruct& event);
|
||||
|
|
@ -200,10 +209,6 @@ private:
|
|||
};
|
||||
|
||||
|
||||
const float IOKitJoystick::DEFAULT_DEADZONE = 0.25f;
|
||||
const float IOKitJoystick::DEFAULT_SENSITIVITY = 1.0f;
|
||||
|
||||
|
||||
IOHIDDeviceInterface** CreateDeviceInterface(const io_object_t device)
|
||||
{
|
||||
IOCFPlugInInterface** plugInInterface = NULL;
|
||||
|
|
@ -286,7 +291,7 @@ IOHIDQueueInterface** CreateDeviceQueue(IOHIDDeviceInterface** const interface)
|
|||
IOKitJoystick::IOKitJoystick(const io_object_t device)
|
||||
: m_interface(CreateDeviceInterface(device))
|
||||
, m_queue(CreateDeviceQueue(m_interface))
|
||||
, m_sensitivity(DEFAULT_SENSITIVITY)
|
||||
, m_sensitivity(JOYSENSITIVITY_DEFAULT)
|
||||
, m_enabled(true)
|
||||
, m_useAxesPolling(true)
|
||||
, m_notification(0)
|
||||
|
|
@ -386,6 +391,21 @@ float IOKitJoystick::GetAxisScale(int axis)
|
|||
return IS_AXIS_VALID ? m_axes[axis].sensitivity : 0.0f;
|
||||
}
|
||||
|
||||
float IOKitJoystick::GetAxisDigitalThreshold(int axis)
|
||||
{
|
||||
return IS_AXIS_VALID ? m_axes[axis].digitalThreshold : JOYTHRESH_DEFAULT;
|
||||
}
|
||||
|
||||
EJoyCurve IOKitJoystick::GetAxisResponseCurve(int axis)
|
||||
{
|
||||
return IS_AXIS_VALID ? m_axes[axis].responseCurvePreset : JOYCURVE_DEFAULT;
|
||||
}
|
||||
|
||||
float IOKitJoystick::GetAxisResponseCurvePoint(int axis, int point)
|
||||
{
|
||||
return ( IS_AXIS_VALID && unsigned(point) < 4 )? m_axes[axis].responseCurve.pts[point] : 0;
|
||||
}
|
||||
|
||||
void IOKitJoystick::SetAxisDeadZone(int axis, float deadZone)
|
||||
{
|
||||
if (IS_AXIS_VALID)
|
||||
|
|
@ -412,10 +432,37 @@ void IOKitJoystick::SetAxisScale(int axis, float scale)
|
|||
}
|
||||
}
|
||||
|
||||
void IOKitJoystick::SetAxisDigitalThreshold(int axis, float threshold)
|
||||
{
|
||||
if (IS_AXIS_VALID)
|
||||
{
|
||||
m_axes[axis].digitalThreshold = threshold;
|
||||
}
|
||||
}
|
||||
|
||||
void IOKitJoystick::SetAxisResponseCurve(int axis, EJoyCurve preset)
|
||||
{
|
||||
if (IS_AXIS_VALID)
|
||||
{
|
||||
if (preset >= NUM_JOYCURVE || preset < JOYCURVE_CUSTOM) return;
|
||||
m_axes[axis].responseCurvePreset = preset;
|
||||
if (preset == JOYCURVE_CUSTOM) return;
|
||||
m_axes[axis].responseCurve = JOYCURVE[preset];
|
||||
}
|
||||
}
|
||||
|
||||
void IOKitJoystick::SetAxisResponseCurvePoint(int axis, int point, float value)
|
||||
{
|
||||
if (IS_AXIS_VALID && unsigned(point) < 4)
|
||||
{
|
||||
m_axes[axis].responseCurvePreset = JOYCURVE_CUSTOM;
|
||||
m_axes[axis].responseCurve.pts[point] = value;
|
||||
}
|
||||
}
|
||||
|
||||
bool IOKitJoystick::IsSensitivityDefault()
|
||||
{
|
||||
return DEFAULT_SENSITIVITY == m_sensitivity;
|
||||
return JOYSENSITIVITY_DEFAULT == m_sensitivity;
|
||||
}
|
||||
|
||||
bool IOKitJoystick::IsAxisDeadZoneDefault(int axis)
|
||||
|
|
@ -439,7 +486,19 @@ bool IOKitJoystick::IsAxisScaleDefault(int axis)
|
|||
: true;
|
||||
}
|
||||
|
||||
bool IOKitJoystick::IsAxisDigitalThresholdDefault(int axis)
|
||||
{
|
||||
return IS_AXIS_VALID
|
||||
? (m_axes[axis].digitalThreshold == m_axes[axis].defaultDigitalThreshold)
|
||||
: true;
|
||||
}
|
||||
|
||||
bool IOKitJoystick::IsAxisResponseCurveDefault(int axis)
|
||||
{
|
||||
return IS_AXIS_VALID
|
||||
? m_axes[axis].responseCurvePreset == m_axes[axis].defaultResponseCurvePreset
|
||||
: true;
|
||||
}
|
||||
|
||||
bool IOKitJoystick::GetEnabled()
|
||||
{
|
||||
|
|
@ -454,15 +513,18 @@ void IOKitJoystick::SetEnabled(bool enabled)
|
|||
|
||||
void IOKitJoystick::SetDefaultConfig()
|
||||
{
|
||||
m_sensitivity = DEFAULT_SENSITIVITY;
|
||||
m_sensitivity = JOYSENSITIVITY_DEFAULT;
|
||||
|
||||
const size_t axisCount = m_axes.Size();
|
||||
|
||||
for (size_t i = 0; i < axisCount; ++i)
|
||||
{
|
||||
m_axes[i].deadZone = DEFAULT_DEADZONE;
|
||||
m_axes[i].sensitivity = DEFAULT_SENSITIVITY;
|
||||
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];
|
||||
}
|
||||
|
||||
// Two axes? Horizontal is yaw and vertical is forward.
|
||||
|
|
@ -470,7 +532,10 @@ 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;
|
||||
}
|
||||
|
||||
// Three axes? First two are movement, third is yaw.
|
||||
|
|
@ -478,8 +543,13 @@ 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.
|
||||
|
||||
|
|
@ -487,12 +557,14 @@ void IOKitJoystick::SetDefaultConfig()
|
|||
{
|
||||
m_axes[3].gameAxis = JOYAXIS_Pitch;
|
||||
// ??? m_axes[3].sensitivity = 0.75f;
|
||||
m_axes[3].digitalThreshold = JOYTHRESH_STICK_Y;
|
||||
|
||||
// Five axes? Use the fifth one for moving up and down.
|
||||
|
||||
if (axisCount >= 5)
|
||||
{
|
||||
m_axes[4].gameAxis = JOYAXIS_Up;
|
||||
m_axes[4].digitalThreshold = JOYTHRESH_STICK_Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -504,9 +576,11 @@ void IOKitJoystick::SetDefaultConfig()
|
|||
|
||||
for (size_t i = 0; i < axisCount; ++i)
|
||||
{
|
||||
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].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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -602,8 +676,9 @@ 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 smoothedValue = Joy_ApplyResponseCurveBezier(axis.responseCurve, filteredValue);
|
||||
|
||||
axis.value = static_cast<float>(filteredValue * m_sensitivity * axis.sensitivity);
|
||||
axis.value = static_cast<float>(smoothedValue * m_sensitivity * axis.sensitivity);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -635,8 +710,9 @@ bool IOKitJoystick::ProcessAxis(const IOHIDEventStruct& event)
|
|||
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 smoothedValue = Joy_ApplyResponseCurveBezier(axis.responseCurve, filteredValue);
|
||||
|
||||
axis.value = static_cast<float>(filteredValue * m_sensitivity * axis.sensitivity);
|
||||
axis.value = static_cast<float>(smoothedValue * m_sensitivity * axis.sensitivity);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,11 +31,14 @@
|
|||
**
|
||||
*/
|
||||
#include <SDL.h>
|
||||
#include <SDL_events.h>
|
||||
#include "i_input.h"
|
||||
#include "c_cvars.h"
|
||||
#include "dobject.h"
|
||||
#include "m_argv.h"
|
||||
#include "m_joy.h"
|
||||
#include "v_video.h"
|
||||
|
||||
#include "d_eventbase.h"
|
||||
#include "d_gui.h"
|
||||
#include "c_buttons.h"
|
||||
#include "c_console.h"
|
||||
|
|
@ -47,88 +50,147 @@
|
|||
#include "engineerrors.h"
|
||||
#include "i_interface.h"
|
||||
|
||||
|
||||
static void I_CheckGUICapture ();
|
||||
static void I_CheckNativeMouse ();
|
||||
|
||||
bool GUICapture;
|
||||
static bool NativeMouse = true;
|
||||
|
||||
CVAR (Bool, use_mouse, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
|
||||
extern int WaitingForKey;
|
||||
|
||||
static const SDL_Keycode DIKToKeySym[256] =
|
||||
{
|
||||
0, SDLK_ESCAPE, SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5, SDLK_6,
|
||||
SDLK_7, SDLK_8, SDLK_9, SDLK_0,SDLK_MINUS, SDLK_EQUALS, SDLK_BACKSPACE, SDLK_TAB,
|
||||
SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_t, SDLK_y, SDLK_u, SDLK_i,
|
||||
SDLK_o, SDLK_p, SDLK_LEFTBRACKET, SDLK_RIGHTBRACKET, SDLK_RETURN, SDLK_LCTRL, SDLK_a, SDLK_s,
|
||||
SDLK_d, SDLK_f, SDLK_g, SDLK_h, SDLK_j, SDLK_k, SDLK_l, SDLK_SEMICOLON,
|
||||
SDLK_QUOTE, SDLK_BACKQUOTE, SDLK_LSHIFT, SDLK_BACKSLASH, SDLK_z, SDLK_x, SDLK_c, SDLK_v,
|
||||
SDLK_b, SDLK_n, SDLK_m, SDLK_COMMA, SDLK_PERIOD, SDLK_SLASH, SDLK_RSHIFT, SDLK_KP_MULTIPLY,
|
||||
SDLK_LALT, SDLK_SPACE, SDLK_CAPSLOCK, SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5,
|
||||
SDLK_F6, SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_NUMLOCKCLEAR, SDLK_SCROLLLOCK, SDLK_KP_7,
|
||||
SDLK_KP_8, SDLK_KP_9, SDLK_KP_MINUS, SDLK_KP_4, SDLK_KP_5, SDLK_KP_6, SDLK_KP_PLUS, SDLK_KP_1,
|
||||
SDLK_KP_2, SDLK_KP_3, SDLK_KP_0, SDLK_KP_PERIOD, 0, 0, 0, SDLK_F11,
|
||||
SDLK_F12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, SDLK_F13, SDLK_F14, SDLK_F15, SDLK_F16,
|
||||
SDLK_F17, SDLK_F18, SDLK_F19, SDLK_F20, SDLK_F21, SDLK_F22, SDLK_F23, SDLK_F24,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, SDLK_KP_EQUALS, 0, 0,
|
||||
0, SDLK_AT, SDLK_COLON, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, SDLK_KP_ENTER, SDLK_RCTRL, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, SDLK_KP_COMMA, 0, SDLK_KP_DIVIDE, 0, SDLK_SYSREQ,
|
||||
SDLK_RALT, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, SDLK_PAUSE, 0, SDLK_HOME,
|
||||
SDLK_UP, SDLK_PAGEUP, 0, SDLK_LEFT, 0, SDLK_RIGHT, 0, SDLK_END,
|
||||
SDLK_DOWN, SDLK_PAGEDOWN, SDLK_INSERT, SDLK_DELETE, 0, 0, 0, 0,
|
||||
0, 0, 0, SDLK_LGUI, SDLK_RGUI, SDLK_MENU, SDLK_POWER, SDLK_SLEEP,
|
||||
0, 0, 0, 0, 0, SDLK_AC_SEARCH, SDLK_AC_BOOKMARKS, SDLK_AC_REFRESH,
|
||||
SDLK_AC_STOP, SDLK_AC_FORWARD, SDLK_AC_BACK, SDLK_COMPUTER, SDLK_MAIL, SDLK_MEDIASELECT, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
SDLK_UNKNOWN, SDLK_ESCAPE, SDLK_1, SDLK_2,
|
||||
SDLK_3, SDLK_4, SDLK_5, SDLK_6,
|
||||
SDLK_7, SDLK_8, SDLK_9, SDLK_0,
|
||||
SDLK_MINUS, SDLK_EQUALS, SDLK_BACKSPACE, SDLK_TAB,
|
||||
SDLK_q, SDLK_w, SDLK_e, SDLK_r,
|
||||
SDLK_t, SDLK_y, SDLK_u, SDLK_i,
|
||||
SDLK_o, SDLK_p, SDLK_LEFTBRACKET, SDLK_RIGHTBRACKET,
|
||||
SDLK_RETURN, SDLK_LCTRL, SDLK_a, SDLK_s,
|
||||
SDLK_d, SDLK_f, SDLK_g, SDLK_h,
|
||||
SDLK_j, SDLK_k, SDLK_l, SDLK_SEMICOLON,
|
||||
SDLK_QUOTE, SDLK_BACKQUOTE, SDLK_LSHIFT, SDLK_BACKSLASH,
|
||||
SDLK_z, SDLK_x, SDLK_c, SDLK_v,
|
||||
SDLK_b, SDLK_n, SDLK_m, SDLK_COMMA,
|
||||
SDLK_PERIOD, SDLK_SLASH, SDLK_RSHIFT, SDLK_KP_MULTIPLY,
|
||||
SDLK_LALT, SDLK_SPACE, SDLK_CAPSLOCK, SDLK_F1,
|
||||
SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5,
|
||||
SDLK_F6, SDLK_F7, SDLK_F8, SDLK_F9,
|
||||
SDLK_F10, SDLK_NUMLOCKCLEAR, SDLK_SCROLLLOCK, SDLK_KP_7,
|
||||
SDLK_KP_8, SDLK_KP_9, SDLK_KP_MINUS, SDLK_KP_4,
|
||||
SDLK_KP_5, SDLK_KP_6, SDLK_KP_PLUS, SDLK_KP_1,
|
||||
SDLK_KP_2, SDLK_KP_3, SDLK_KP_0, SDLK_KP_PERIOD,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_F11,
|
||||
SDLK_F12, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_F13, SDLK_F14, SDLK_F15, SDLK_F16,
|
||||
SDLK_F17, SDLK_F18, SDLK_F19, SDLK_F20,
|
||||
SDLK_F21, SDLK_F22, SDLK_F23, SDLK_F24,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_KP_EQUALS, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_AT, SDLK_COLON, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_KP_ENTER, SDLK_RCTRL, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_KP_COMMA,
|
||||
SDLK_UNKNOWN, SDLK_KP_DIVIDE, SDLK_UNKNOWN, SDLK_SYSREQ,
|
||||
SDLK_RALT, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_PAUSE, SDLK_UNKNOWN, SDLK_HOME,
|
||||
SDLK_UP, SDLK_PAGEUP, SDLK_UNKNOWN, SDLK_LEFT,
|
||||
SDLK_UNKNOWN, SDLK_RIGHT, SDLK_UNKNOWN, SDLK_END,
|
||||
SDLK_DOWN, SDLK_PAGEDOWN, SDLK_INSERT, SDLK_DELETE,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_LGUI,
|
||||
SDLK_RGUI, SDLK_MENU, SDLK_POWER, SDLK_SLEEP,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_AC_SEARCH, SDLK_AC_BOOKMARKS, SDLK_AC_REFRESH,
|
||||
SDLK_AC_STOP, SDLK_AC_FORWARD, SDLK_AC_BACK, SDLK_COMPUTER,
|
||||
SDLK_MAIL, SDLK_MEDIASELECT, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN,
|
||||
SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN, SDLK_UNKNOWN
|
||||
};
|
||||
|
||||
static const SDL_Scancode DIKToKeyScan[256] =
|
||||
{
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_ESCAPE, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, SDL_SCANCODE_5, SDL_SCANCODE_6,
|
||||
SDL_SCANCODE_7, SDL_SCANCODE_8, SDL_SCANCODE_9, SDL_SCANCODE_0 ,SDL_SCANCODE_MINUS, SDL_SCANCODE_EQUALS, SDL_SCANCODE_BACKSPACE, SDL_SCANCODE_TAB,
|
||||
SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_E, SDL_SCANCODE_R, SDL_SCANCODE_T, SDL_SCANCODE_Y, SDL_SCANCODE_U, SDL_SCANCODE_I,
|
||||
SDL_SCANCODE_O, SDL_SCANCODE_P, SDL_SCANCODE_LEFTBRACKET, SDL_SCANCODE_RIGHTBRACKET, SDL_SCANCODE_RETURN, SDL_SCANCODE_LCTRL, SDL_SCANCODE_A, SDL_SCANCODE_S,
|
||||
SDL_SCANCODE_D, SDL_SCANCODE_F, SDL_SCANCODE_G, SDL_SCANCODE_H, SDL_SCANCODE_J, SDL_SCANCODE_K, SDL_SCANCODE_L, SDL_SCANCODE_SEMICOLON,
|
||||
SDL_SCANCODE_APOSTROPHE, SDL_SCANCODE_GRAVE, SDL_SCANCODE_LSHIFT, SDL_SCANCODE_BACKSLASH, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_C, SDL_SCANCODE_V,
|
||||
SDL_SCANCODE_B, SDL_SCANCODE_N, SDL_SCANCODE_M, SDL_SCANCODE_COMMA, SDL_SCANCODE_PERIOD, SDL_SCANCODE_SLASH, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_KP_MULTIPLY,
|
||||
SDL_SCANCODE_LALT, SDL_SCANCODE_SPACE, SDL_SCANCODE_CAPSLOCK, SDL_SCANCODE_F1, SDL_SCANCODE_F2, SDL_SCANCODE_F3, SDL_SCANCODE_F4, SDL_SCANCODE_F5,
|
||||
SDL_SCANCODE_F6, SDL_SCANCODE_F7, SDL_SCANCODE_F8, SDL_SCANCODE_F9, SDL_SCANCODE_F10, SDL_SCANCODE_NUMLOCKCLEAR, SDL_SCANCODE_SCROLLLOCK, SDL_SCANCODE_KP_7,
|
||||
SDL_SCANCODE_KP_8, SDL_SCANCODE_KP_9, SDL_SCANCODE_KP_MINUS, SDL_SCANCODE_KP_4, SDL_SCANCODE_KP_5, SDL_SCANCODE_KP_6, SDL_SCANCODE_KP_PLUS, SDL_SCANCODE_KP_1,
|
||||
SDL_SCANCODE_KP_2, SDL_SCANCODE_KP_3, SDL_SCANCODE_KP_0, SDL_SCANCODE_KP_PERIOD, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_F11,
|
||||
SDL_SCANCODE_F12, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_F13, SDL_SCANCODE_F14, SDL_SCANCODE_F15, SDL_SCANCODE_F16,
|
||||
SDL_SCANCODE_F17, SDL_SCANCODE_F18, SDL_SCANCODE_F19, SDL_SCANCODE_F20, SDL_SCANCODE_F21, SDL_SCANCODE_F22, SDL_SCANCODE_F23, SDL_SCANCODE_F24,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_EQUALS, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_ENTER, SDL_SCANCODE_RCTRL, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_COMMA, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_DIVIDE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_SYSREQ,
|
||||
SDL_SCANCODE_RALT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_PAUSE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_HOME,
|
||||
SDL_SCANCODE_UP, SDL_SCANCODE_PAGEUP, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_RIGHT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_END,
|
||||
SDL_SCANCODE_DOWN, SDL_SCANCODE_PAGEDOWN, SDL_SCANCODE_INSERT, SDL_SCANCODE_DELETE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_LGUI, SDL_SCANCODE_RGUI, SDL_SCANCODE_MENU, SDL_SCANCODE_POWER, SDL_SCANCODE_SLEEP,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_AC_SEARCH, SDL_SCANCODE_AC_BOOKMARKS, SDL_SCANCODE_AC_REFRESH,
|
||||
SDL_SCANCODE_AC_STOP, SDL_SCANCODE_AC_FORWARD, SDL_SCANCODE_AC_BACK, SDL_SCANCODE_COMPUTER, SDL_SCANCODE_MAIL, SDL_SCANCODE_MEDIASELECT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_ESCAPE, SDL_SCANCODE_1, SDL_SCANCODE_2,
|
||||
SDL_SCANCODE_3, SDL_SCANCODE_4, SDL_SCANCODE_5, SDL_SCANCODE_6,
|
||||
SDL_SCANCODE_7, SDL_SCANCODE_8, SDL_SCANCODE_9, SDL_SCANCODE_0,
|
||||
SDL_SCANCODE_MINUS, SDL_SCANCODE_EQUALS, SDL_SCANCODE_BACKSPACE, SDL_SCANCODE_TAB,
|
||||
SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_E, SDL_SCANCODE_R,
|
||||
SDL_SCANCODE_T, SDL_SCANCODE_Y, SDL_SCANCODE_U, SDL_SCANCODE_I,
|
||||
SDL_SCANCODE_O, SDL_SCANCODE_P, SDL_SCANCODE_LEFTBRACKET, SDL_SCANCODE_RIGHTBRACKET,
|
||||
SDL_SCANCODE_RETURN, SDL_SCANCODE_LCTRL, SDL_SCANCODE_A, SDL_SCANCODE_S,
|
||||
SDL_SCANCODE_D, SDL_SCANCODE_F, SDL_SCANCODE_G, SDL_SCANCODE_H,
|
||||
SDL_SCANCODE_J, SDL_SCANCODE_K, SDL_SCANCODE_L, SDL_SCANCODE_SEMICOLON,
|
||||
SDL_SCANCODE_APOSTROPHE, SDL_SCANCODE_GRAVE, SDL_SCANCODE_LSHIFT, SDL_SCANCODE_BACKSLASH,
|
||||
SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_C, SDL_SCANCODE_V,
|
||||
SDL_SCANCODE_B, SDL_SCANCODE_N, SDL_SCANCODE_M, SDL_SCANCODE_COMMA,
|
||||
SDL_SCANCODE_PERIOD, SDL_SCANCODE_SLASH, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_KP_MULTIPLY,
|
||||
SDL_SCANCODE_LALT, SDL_SCANCODE_SPACE, SDL_SCANCODE_CAPSLOCK, SDL_SCANCODE_F1,
|
||||
SDL_SCANCODE_F2, SDL_SCANCODE_F3, SDL_SCANCODE_F4, SDL_SCANCODE_F5,
|
||||
SDL_SCANCODE_F6, SDL_SCANCODE_F7, SDL_SCANCODE_F8, SDL_SCANCODE_F9,
|
||||
SDL_SCANCODE_F10, SDL_SCANCODE_NUMLOCKCLEAR, SDL_SCANCODE_SCROLLLOCK, SDL_SCANCODE_KP_7,
|
||||
SDL_SCANCODE_KP_8, SDL_SCANCODE_KP_9, SDL_SCANCODE_KP_MINUS, SDL_SCANCODE_KP_4,
|
||||
SDL_SCANCODE_KP_5, SDL_SCANCODE_KP_6, SDL_SCANCODE_KP_PLUS, SDL_SCANCODE_KP_1,
|
||||
SDL_SCANCODE_KP_2, SDL_SCANCODE_KP_3, SDL_SCANCODE_KP_0, SDL_SCANCODE_KP_PERIOD,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_F11,
|
||||
SDL_SCANCODE_F12, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_F13, SDL_SCANCODE_F14, SDL_SCANCODE_F15, SDL_SCANCODE_F16,
|
||||
SDL_SCANCODE_F17, SDL_SCANCODE_F18, SDL_SCANCODE_F19, SDL_SCANCODE_F20,
|
||||
SDL_SCANCODE_F21, SDL_SCANCODE_F22, SDL_SCANCODE_F23, SDL_SCANCODE_F24,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_EQUALS, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_KP_ENTER, SDL_SCANCODE_RCTRL, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_COMMA,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_DIVIDE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_SYSREQ,
|
||||
SDL_SCANCODE_RALT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_PAUSE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_HOME,
|
||||
SDL_SCANCODE_UP, SDL_SCANCODE_PAGEUP, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_LEFT,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_RIGHT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_END,
|
||||
SDL_SCANCODE_DOWN, SDL_SCANCODE_PAGEDOWN, SDL_SCANCODE_INSERT, SDL_SCANCODE_DELETE,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_LGUI,
|
||||
SDL_SCANCODE_RGUI, SDL_SCANCODE_MENU, SDL_SCANCODE_POWER, SDL_SCANCODE_SLEEP,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_AC_SEARCH, SDL_SCANCODE_AC_BOOKMARKS, SDL_SCANCODE_AC_REFRESH,
|
||||
SDL_SCANCODE_AC_STOP, SDL_SCANCODE_AC_FORWARD, SDL_SCANCODE_AC_BACK, SDL_SCANCODE_COMPUTER,
|
||||
SDL_SCANCODE_MAIL, SDL_SCANCODE_MEDIASELECT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN
|
||||
};
|
||||
|
||||
static TMap<SDL_Keycode, uint8_t> InitKeySymMap ()
|
||||
|
|
@ -463,14 +525,60 @@ void MessagePump (const SDL_Event &sev)
|
|||
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
case SDL_JOYBUTTONUP:
|
||||
if (SDL_GameControllerFromInstanceID(sev.jdevice.which))
|
||||
break; // let SDL_CONTROLLERBUTTON* handle this
|
||||
event.type = sev.type == SDL_JOYBUTTONDOWN ? EV_KeyDown : EV_KeyUp;
|
||||
event.data1 = KEY_FIRSTJOYBUTTON + sev.jbutton.button;
|
||||
if(event.data1 != 0)
|
||||
D_PostEvent(&event);
|
||||
I_JoyConsumeEvent(sev.jdevice.which, &event);
|
||||
break;
|
||||
|
||||
case SDL_CONTROLLERBUTTONDOWN:
|
||||
case SDL_CONTROLLERBUTTONUP:
|
||||
event.type = sev.type == SDL_CONTROLLERBUTTONDOWN ? EV_KeyDown : EV_KeyUp;
|
||||
switch (sev.cbutton.button)
|
||||
{
|
||||
case SDL_CONTROLLER_BUTTON_A: event.data1 = KEY_PAD_A; break;
|
||||
case SDL_CONTROLLER_BUTTON_B: event.data1 = KEY_PAD_B; break;
|
||||
case SDL_CONTROLLER_BUTTON_X: event.data1 = KEY_PAD_X; break;
|
||||
case SDL_CONTROLLER_BUTTON_Y: event.data1 = KEY_PAD_Y; break;
|
||||
case SDL_CONTROLLER_BUTTON_BACK: event.data1 = KEY_PAD_BACK; break;
|
||||
case SDL_CONTROLLER_BUTTON_GUIDE: event.data1 = KEY_PAD_GUIDE; break;
|
||||
case SDL_CONTROLLER_BUTTON_START: event.data1 = KEY_PAD_START; break;
|
||||
case SDL_CONTROLLER_BUTTON_LEFTSTICK: event.data1 = KEY_PAD_LTHUMB; break;
|
||||
case SDL_CONTROLLER_BUTTON_RIGHTSTICK: event.data1 = KEY_PAD_RTHUMB; break;
|
||||
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: event.data1 = KEY_PAD_LSHOULDER; break;
|
||||
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: event.data1 = KEY_PAD_RSHOULDER; break;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_UP: event.data1 = KEY_PAD_DPAD_UP; break;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: event.data1 = KEY_PAD_DPAD_DOWN; break;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_LEFT: event.data1 = KEY_PAD_DPAD_LEFT; break;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: event.data1 = KEY_PAD_DPAD_RIGHT; break;
|
||||
case SDL_CONTROLLER_BUTTON_MISC1: event.data1 = KEY_PAD_MISC1; break;
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE1: event.data1 = KEY_PAD_PADDLE1; break;
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE2: event.data1 = KEY_PAD_PADDLE2; break;
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE3: event.data1 = KEY_PAD_PADDLE3; break;
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE4: event.data1 = KEY_PAD_PADDLE4; break;
|
||||
case SDL_CONTROLLER_BUTTON_TOUCHPAD: event.data1 = KEY_PAD_TOUCHPAD; break;
|
||||
default: event.data1 = 0;
|
||||
}
|
||||
if(event.data1 != 0)
|
||||
I_JoyConsumeEvent(sev.cbutton.which, &event);
|
||||
break;
|
||||
|
||||
case SDL_JOYDEVICEADDED:
|
||||
case SDL_CONTROLLERDEVICEADDED:
|
||||
if (sev.type == SDL_JOYDEVICEADDED && SDL_IsGameController(sev.jdevice.which)) // DeviceIndex Here
|
||||
break; // skip double event
|
||||
I_UpdateDeviceList();
|
||||
event.type = EV_DeviceChange;
|
||||
D_PostEvent (&event);
|
||||
break;
|
||||
|
||||
case SDL_JOYDEVICEREMOVED:
|
||||
case SDL_CONTROLLERDEVICEREMOVED:
|
||||
case SDL_CONTROLLERDEVICEREMAPPED:
|
||||
if (sev.type == SDL_JOYDEVICEREMOVED && SDL_GameControllerFromInstanceID(sev.jdevice.which))
|
||||
break; // skip double event
|
||||
I_UpdateDeviceList();
|
||||
event.type = EV_DeviceChange;
|
||||
D_PostEvent (&event);
|
||||
|
|
|
|||
13
src/common/platform/posix/sdl/i_input.h
Normal file
13
src/common/platform/posix/sdl/i_input.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef I_INPUT_H
|
||||
#define I_INPUT_H
|
||||
|
||||
#include "d_eventbase.h"
|
||||
|
||||
extern int WaitingForKey;
|
||||
|
||||
static void I_CheckGUICapture ();
|
||||
static void I_CheckNativeMouse ();
|
||||
|
||||
void I_JoyConsumeEvent(int instanceID, event_t * event);
|
||||
|
||||
#endif
|
||||
|
|
@ -31,47 +31,80 @@
|
|||
**
|
||||
*/
|
||||
#include <SDL.h>
|
||||
#include <SDL_gamecontroller.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "basics.h"
|
||||
#include "cmdlib.h"
|
||||
|
||||
#include "d_eventbase.h"
|
||||
#include "i_input.h"
|
||||
#include "m_joy.h"
|
||||
#include "keydef.h"
|
||||
|
||||
#define DEFAULT_DEADZONE 0.25f;
|
||||
|
||||
// Very small deadzone so that floating point magic doesn't happen
|
||||
#define MIN_DEADZONE 0.000001f
|
||||
|
||||
class SDLInputJoystick: public IJoystickConfig
|
||||
{
|
||||
public:
|
||||
SDLInputJoystick(int DeviceIndex) : DeviceIndex(DeviceIndex), Multiplier(1.0f) , Enabled(true)
|
||||
SDLInputJoystick(int DeviceIndex) :
|
||||
DeviceIndex(DeviceIndex),
|
||||
InstanceID(SDL_JoystickGetDeviceInstanceID(DeviceIndex)),
|
||||
Multiplier(JOYSENSITIVITY_DEFAULT),
|
||||
Enabled(true),
|
||||
SettingsChanged(false)
|
||||
{
|
||||
Device = SDL_JoystickOpen(DeviceIndex);
|
||||
if(Device != NULL)
|
||||
if (SDL_IsGameController(DeviceIndex))
|
||||
{
|
||||
NumAxes = SDL_JoystickNumAxes(Device);
|
||||
NumHats = SDL_JoystickNumHats(Device);
|
||||
Mapping = SDL_GameControllerOpen(DeviceIndex);
|
||||
Device = NULL;
|
||||
|
||||
SetDefaultConfig();
|
||||
DefaultAxes = DefaultControllerAxes;
|
||||
DefaultAxesCount = sizeof(DefaultControllerAxes) / sizeof(DefaultAxisConfig);
|
||||
|
||||
if(Mapping != NULL)
|
||||
{
|
||||
NumAxes = SDL_CONTROLLER_AXIS_MAX;
|
||||
NumHats = 0;
|
||||
|
||||
SetDefaultConfig();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Device = SDL_JoystickOpen(DeviceIndex);
|
||||
Mapping = NULL;
|
||||
|
||||
DefaultAxes = DefaultJoystickAxes;
|
||||
DefaultAxesCount = sizeof(DefaultJoystickAxes) / sizeof(DefaultAxisConfig);
|
||||
|
||||
if(Device != NULL)
|
||||
{
|
||||
NumAxes = SDL_JoystickNumAxes(Device);
|
||||
NumHats = SDL_JoystickNumHats(Device);
|
||||
|
||||
SetDefaultConfig();
|
||||
}
|
||||
}
|
||||
M_LoadJoystickConfig(this);
|
||||
}
|
||||
~SDLInputJoystick()
|
||||
{
|
||||
if(Device != NULL)
|
||||
if(IsValid() && SettingsChanged)
|
||||
M_SaveJoystickConfig(this);
|
||||
SDL_JoystickClose(Device);
|
||||
if (Mapping)
|
||||
SDL_GameControllerClose(Mapping);
|
||||
if (Device)
|
||||
SDL_JoystickClose(Device);
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return Device != NULL;
|
||||
return Device != NULL || Mapping != NULL;
|
||||
}
|
||||
|
||||
FString GetName()
|
||||
{
|
||||
return SDL_JoystickName(Device);
|
||||
return (Mapping)
|
||||
? SDL_GameControllerName(Mapping)
|
||||
: SDL_JoystickName(Device);
|
||||
}
|
||||
float GetSensitivity()
|
||||
{
|
||||
|
|
@ -79,6 +112,7 @@ public:
|
|||
}
|
||||
void SetSensitivity(float scale)
|
||||
{
|
||||
SettingsChanged = true;
|
||||
Multiplier = scale;
|
||||
}
|
||||
|
||||
|
|
@ -102,58 +136,145 @@ public:
|
|||
{
|
||||
return Axes[axis].Multiplier;
|
||||
}
|
||||
float GetAxisDigitalThreshold(int axis)
|
||||
{
|
||||
return Axes[axis].DigitalThreshold;
|
||||
}
|
||||
EJoyCurve GetAxisResponseCurve(int axis)
|
||||
{
|
||||
return Axes[axis].ResponseCurvePreset;
|
||||
}
|
||||
float GetAxisResponseCurvePoint(int axis, int point)
|
||||
{
|
||||
return unsigned(point) < 4
|
||||
? Axes[axis].ResponseCurve.pts[point]
|
||||
: 0;
|
||||
};
|
||||
|
||||
void SetAxisDeadZone(int axis, float zone)
|
||||
{
|
||||
Axes[axis].DeadZone = clamp(zone, MIN_DEADZONE, 1.f);
|
||||
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;
|
||||
Axes[axis].Multiplier = scale;
|
||||
}
|
||||
void SetAxisDigitalThreshold(int axis, float threshold)
|
||||
{
|
||||
SettingsChanged = true;
|
||||
Axes[axis].DigitalThreshold = threshold;
|
||||
}
|
||||
void SetAxisResponseCurve(int axis, EJoyCurve preset)
|
||||
{
|
||||
if (preset >= NUM_JOYCURVE || preset < JOYCURVE_CUSTOM) return;
|
||||
SettingsChanged = true;
|
||||
Axes[axis].ResponseCurvePreset = preset;
|
||||
if (preset == JOYCURVE_CUSTOM) return;
|
||||
Axes[axis].ResponseCurve = JOYCURVE[preset];
|
||||
}
|
||||
void SetAxisResponseCurvePoint(int axis, int point, float value)
|
||||
{
|
||||
if (unsigned(point) < 4)
|
||||
{
|
||||
SettingsChanged = true;
|
||||
Axes[axis].ResponseCurvePreset = JOYCURVE_CUSTOM;
|
||||
Axes[axis].ResponseCurve.pts[point] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Used by the saver to not save properties that are at their defaults.
|
||||
bool IsSensitivityDefault()
|
||||
{
|
||||
return Multiplier == 1.0f;
|
||||
return Multiplier == JOYSENSITIVITY_DEFAULT;
|
||||
}
|
||||
bool IsAxisDeadZoneDefault(int axis)
|
||||
{
|
||||
return Axes[axis].DeadZone <= MIN_DEADZONE;
|
||||
if(axis >= DefaultAxesCount)
|
||||
return Axes[axis].DeadZone == JOYDEADZONE_DEFAULT;
|
||||
return Axes[axis].DeadZone == DefaultAxes[axis].DeadZone;
|
||||
}
|
||||
bool IsAxisMapDefault(int axis)
|
||||
{
|
||||
if(axis >= 5)
|
||||
if(axis >= DefaultAxesCount)
|
||||
return Axes[axis].GameAxis == JOYAXIS_None;
|
||||
return Axes[axis].GameAxis == DefaultAxes[axis];
|
||||
return Axes[axis].GameAxis == DefaultAxes[axis].GameAxis;
|
||||
}
|
||||
bool IsAxisScaleDefault(int axis)
|
||||
{
|
||||
return Axes[axis].Multiplier == 1.0f;
|
||||
if(axis >= DefaultAxesCount)
|
||||
return Axes[axis].Multiplier == JOYSENSITIVITY_DEFAULT;
|
||||
return Axes[axis].Multiplier == DefaultAxes[axis].Multiplier;
|
||||
}
|
||||
bool IsAxisDigitalThresholdDefault(int axis)
|
||||
{
|
||||
if(axis >= DefaultAxesCount)
|
||||
return Axes[axis].DigitalThreshold == JOYTHRESH_DEFAULT;
|
||||
return Axes[axis].DigitalThreshold == DefaultAxes[axis].DigitalThreshold;
|
||||
}
|
||||
bool IsAxisResponseCurveDefault(int axis)
|
||||
{
|
||||
if(axis >= DefaultAxesCount)
|
||||
return Axes[axis].ResponseCurvePreset == JOYCURVE_DEFAULT;
|
||||
return Axes[axis].ResponseCurvePreset == DefaultAxes[axis].ResponseCurvePreset;
|
||||
}
|
||||
|
||||
void SetDefaultConfig()
|
||||
{
|
||||
if (Axes.size() == 0)
|
||||
{
|
||||
for(int i = 0;i < GetNumAxes();i++)
|
||||
{
|
||||
Axes.Push({});
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0;i < GetNumAxes();i++)
|
||||
{
|
||||
AxisInfo info;
|
||||
if(i < NumAxes)
|
||||
info.Name.Format("Axis %d", i+1);
|
||||
if (Mapping) {
|
||||
switch(i) {
|
||||
case SDL_CONTROLLER_AXIS_LEFTX: Axes[i].Name = "Left Stick X"; break;
|
||||
case SDL_CONTROLLER_AXIS_LEFTY: Axes[i].Name = "Left Stick Y"; break;
|
||||
case SDL_CONTROLLER_AXIS_RIGHTX: Axes[i].Name = "Right Stick X"; break;
|
||||
case SDL_CONTROLLER_AXIS_RIGHTY: Axes[i].Name = "Right Stick Y"; break;
|
||||
case SDL_CONTROLLER_AXIS_TRIGGERLEFT: Axes[i].Name = "Left Trigger"; break;
|
||||
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: Axes[i].Name = "Right Trigger"; break;
|
||||
default: Axes[i].Name.Format("Axis %d", i+1); break;
|
||||
}
|
||||
} else {
|
||||
if(i < NumAxes)
|
||||
Axes[i].Name.Format("Axis %d", i+1);
|
||||
else
|
||||
Axes[i].Name.Format("Hat %d (%c)", (i-NumAxes)/2 + 1, (i-NumAxes)%2 == 0 ? 'x' : 'y');
|
||||
}
|
||||
|
||||
Axes[i].Value = 0.0;
|
||||
Axes[i].ButtonValue = 0;
|
||||
|
||||
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;
|
||||
Axes[i].ResponseCurvePreset = DefaultAxes[i].ResponseCurvePreset;
|
||||
Axes[i].ResponseCurve = JOYCURVE[DefaultAxes[i].ResponseCurvePreset];
|
||||
}
|
||||
else
|
||||
info.Name.Format("Hat %d (%c)", (i-NumAxes)/2 + 1, (i-NumAxes)%2 == 0 ? 'x' : 'y');
|
||||
info.DeadZone = DEFAULT_DEADZONE;
|
||||
info.Multiplier = 1.0f;
|
||||
info.Value = 0.0;
|
||||
info.ButtonValue = 0;
|
||||
if(i >= 5)
|
||||
info.GameAxis = JOYAXIS_None;
|
||||
else
|
||||
info.GameAxis = DefaultAxes[i];
|
||||
Axes.Push(info);
|
||||
{
|
||||
Axes[i].GameAxis = JOYAXIS_None;
|
||||
Axes[i].DeadZone = JOYDEADZONE_DEFAULT;
|
||||
Axes[i].Multiplier = JOYSENSITIVITY_DEFAULT;
|
||||
Axes[i].DigitalThreshold = JOYTHRESH_DEFAULT;
|
||||
Axes[i].ResponseCurvePreset = JOYCURVE_DEFAULT;
|
||||
Axes[i].ResponseCurve = JOYCURVE[JOYCURVE_DEFAULT];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -161,9 +282,10 @@ public:
|
|||
{
|
||||
return Enabled;
|
||||
}
|
||||
|
||||
|
||||
void SetEnabled(bool enabled)
|
||||
{
|
||||
SettingsChanged = true;
|
||||
Enabled = enabled;
|
||||
}
|
||||
|
||||
|
|
@ -188,63 +310,101 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void ProcessInput()
|
||||
{
|
||||
void ProcessInput() {
|
||||
uint8_t buttonstate;
|
||||
|
||||
for (int i = 0; i < NumAxes; ++i)
|
||||
if (Mapping)
|
||||
{
|
||||
buttonstate = 0;
|
||||
// GameController API available
|
||||
|
||||
Axes[i].Value = SDL_JoystickGetAxis(Device, i)/32767.0;
|
||||
Axes[i].Value = Joy_RemoveDeadZone(Axes[i].Value, Axes[i].DeadZone, &buttonstate);
|
||||
auto lastTriggerL = Axes[SDL_CONTROLLER_AXIS_TRIGGERLEFT].Value > Axes[SDL_CONTROLLER_AXIS_TRIGGERLEFT].DigitalThreshold;
|
||||
auto lastTriggerR = Axes[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].Value > Axes[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].DigitalThreshold;
|
||||
|
||||
// Map button to axis
|
||||
// X and Y are handled differently so if we have 2 or more axes then we'll use that code instead.
|
||||
if (NumAxes == 1 || (i >= 2 && i < NUM_JOYAXISBUTTONS))
|
||||
for (auto i = 0; i < SDL_CONTROLLER_AXIS_MAX && i < NumAxes; ++i)
|
||||
{
|
||||
Joy_GenerateButtonEvents(Axes[i].ButtonValue, buttonstate, 2, KEY_JOYAXIS1PLUS + i*2);
|
||||
Axes[i].ButtonValue = buttonstate;
|
||||
}
|
||||
}
|
||||
buttonstate = 0;
|
||||
|
||||
if(NumAxes > 1)
|
||||
{
|
||||
buttonstate = Joy_XYAxesToButtons(Axes[0].Value, Axes[1].Value);
|
||||
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);
|
||||
}
|
||||
|
||||
auto currTriggerL = Axes[SDL_CONTROLLER_AXIS_TRIGGERLEFT].Value > Axes[SDL_CONTROLLER_AXIS_TRIGGERLEFT].DigitalThreshold;
|
||||
auto currTriggerR = Axes[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].Value > Axes[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].DigitalThreshold;
|
||||
|
||||
if (lastTriggerL != currTriggerL) Joy_GenerateButtonEvent(currTriggerL, KEY_PAD_LTRIGGER);
|
||||
if (lastTriggerR != currTriggerR) Joy_GenerateButtonEvent(currTriggerR, KEY_PAD_RTRIGGER);
|
||||
|
||||
// todo: right stick
|
||||
buttonstate = Joy_XYAxesToButtons(
|
||||
abs(Axes[0].Value) < Axes[0].DigitalThreshold ? 0 : Axes[0].Value,
|
||||
abs(Axes[1].Value) < Axes[1].DigitalThreshold ? 0 : Axes[1].Value
|
||||
);
|
||||
Joy_GenerateButtonEvents(Axes[0].ButtonValue, buttonstate, 4, KEY_JOYAXIS1PLUS);
|
||||
Axes[0].ButtonValue = buttonstate;
|
||||
}
|
||||
|
||||
// Map POV hats to buttons and axes. Why axes? Well apparently I have
|
||||
// a gamepad where the left control stick is a POV hat (instead of the
|
||||
// d-pad like you would expect, no that's pressure sensitive). Also
|
||||
// KDE's joystick dialog maps them to axes as well.
|
||||
for (int i = 0; i < NumHats; ++i)
|
||||
else
|
||||
{
|
||||
AxisInfo &x = Axes[NumAxes + i*2];
|
||||
AxisInfo &y = Axes[NumAxes + i*2 + 1];
|
||||
// Joystick API fallback
|
||||
|
||||
buttonstate = SDL_JoystickGetHat(Device, i);
|
||||
|
||||
// If we're going to assume that we can pass SDL's value into
|
||||
// Joy_GenerateButtonEvents then we might as well assume the format here.
|
||||
if(buttonstate & 0x1) // Up
|
||||
y.Value = -1.0;
|
||||
else if(buttonstate & 0x4) // Down
|
||||
y.Value = 1.0;
|
||||
else
|
||||
y.Value = 0.0;
|
||||
if(buttonstate & 0x2) // Left
|
||||
x.Value = 1.0;
|
||||
else if(buttonstate & 0x8) // Right
|
||||
x.Value = -1.0;
|
||||
else
|
||||
x.Value = 0.0;
|
||||
|
||||
if(i < 4)
|
||||
for (int i = 0; i < NumAxes; ++i)
|
||||
{
|
||||
Joy_GenerateButtonEvents(x.ButtonValue, buttonstate, 4, KEY_JOYPOV1_UP + i*4);
|
||||
x.ButtonValue = buttonstate;
|
||||
buttonstate = 0;
|
||||
|
||||
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);
|
||||
|
||||
// Map button to axis
|
||||
// X and Y are handled differently so if we have 2 or more axes then we'll use that code instead.
|
||||
if (NumAxes == 1 || (i >= 2 && i < NUM_JOYAXISBUTTONS))
|
||||
{
|
||||
Joy_GenerateButtonEvents(Axes[i].ButtonValue, buttonstate, 2, KEY_JOYAXIS1PLUS + i*2);
|
||||
Axes[i].ButtonValue = buttonstate;
|
||||
}
|
||||
}
|
||||
|
||||
if(NumAxes > 1)
|
||||
{
|
||||
buttonstate = Joy_XYAxesToButtons(
|
||||
abs(Axes[0].Value) < Axes[0].DigitalThreshold ? 0 : Axes[0].Value,
|
||||
abs(Axes[1].Value) < Axes[1].DigitalThreshold ? 0 : Axes[1].Value
|
||||
);
|
||||
Joy_GenerateButtonEvents(Axes[0].ButtonValue, buttonstate, 4, KEY_JOYAXIS1PLUS);
|
||||
Axes[0].ButtonValue = buttonstate;
|
||||
}
|
||||
|
||||
// Map POV hats to buttons and axes. Why axes? Well apparently I have
|
||||
// a gamepad where the left control stick is a POV hat (instead of the
|
||||
// d-pad like you would expect, no that's pressure sensitive). Also
|
||||
// KDE's joystick dialog maps them to axes as well.
|
||||
for (int i = 0; i < NumHats; ++i)
|
||||
{
|
||||
AxisInfo &x = Axes[NumAxes + i*2];
|
||||
AxisInfo &y = Axes[NumAxes + i*2 + 1];
|
||||
|
||||
buttonstate = SDL_JoystickGetHat(Device, i);
|
||||
|
||||
// If we're going to assume that we can pass SDL's value into
|
||||
// Joy_GenerateButtonEvents then we might as well assume the format here.
|
||||
if(buttonstate & 0x1) // Up
|
||||
y.Value = -1.0;
|
||||
else if(buttonstate & 0x4) // Down
|
||||
y.Value = 1.0;
|
||||
else
|
||||
y.Value = 0.0;
|
||||
if(buttonstate & 0x2) // Left
|
||||
x.Value = 1.0;
|
||||
else if(buttonstate & 0x8) // Right
|
||||
x.Value = -1.0;
|
||||
else
|
||||
x.Value = 0.0;
|
||||
|
||||
if(i < 4)
|
||||
{
|
||||
Joy_GenerateButtonEvents(x.ButtonValue, buttonstate, 4, KEY_JOYPOV1_UP + i*4);
|
||||
x.ButtonValue = buttonstate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -255,33 +415,66 @@ protected:
|
|||
FString Name;
|
||||
float DeadZone;
|
||||
float Multiplier;
|
||||
float DigitalThreshold;
|
||||
EJoyCurve ResponseCurvePreset;
|
||||
CubicBezier ResponseCurve;
|
||||
EJoyAxis GameAxis;
|
||||
double Value;
|
||||
uint8_t ButtonValue;
|
||||
};
|
||||
static const EJoyAxis DefaultAxes[5];
|
||||
struct DefaultAxisConfig
|
||||
{
|
||||
float DeadZone;
|
||||
EJoyAxis GameAxis;
|
||||
float Multiplier;
|
||||
float DigitalThreshold;
|
||||
EJoyCurve ResponseCurvePreset;
|
||||
};
|
||||
static const DefaultAxisConfig DefaultJoystickAxes[5];
|
||||
static const DefaultAxisConfig DefaultControllerAxes[6];
|
||||
const DefaultAxisConfig * DefaultAxes;
|
||||
int DefaultAxesCount;
|
||||
|
||||
int DeviceIndex;
|
||||
int InstanceID;
|
||||
SDL_Joystick *Device;
|
||||
SDL_GameController *Mapping;
|
||||
|
||||
float Multiplier;
|
||||
bool Enabled;
|
||||
TArray<AxisInfo> Axes;
|
||||
int NumAxes;
|
||||
int NumHats;
|
||||
bool SettingsChanged;
|
||||
|
||||
friend class SDLInputJoystickManager;
|
||||
};
|
||||
|
||||
// [Nash 4 Feb 2024] seems like on Linux, the third axis is actually the Left Trigger, resulting in the player uncontrollably looking upwards.
|
||||
const EJoyAxis SDLInputJoystick::DefaultAxes[5] = {JOYAXIS_Side, JOYAXIS_Forward, JOYAXIS_None, JOYAXIS_Yaw, JOYAXIS_Pitch};
|
||||
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}
|
||||
};
|
||||
|
||||
// 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},
|
||||
};
|
||||
|
||||
class SDLInputJoystickManager
|
||||
{
|
||||
public:
|
||||
SDLInputJoystickManager()
|
||||
{
|
||||
this->UpdateDeviceList();
|
||||
UpdateDeviceList();
|
||||
}
|
||||
|
||||
void UpdateDeviceList()
|
||||
|
|
@ -318,6 +511,19 @@ public:
|
|||
if(Joysticks[i]->Enabled) Joysticks[i]->ProcessInput();
|
||||
}
|
||||
|
||||
bool IsJoystickEnabled(int instanceID)
|
||||
{
|
||||
for(unsigned int i = 0; i < Joysticks.Size(); i++)
|
||||
{
|
||||
if (Joysticks[i]->InstanceID != instanceID)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return Joysticks[i]->Enabled;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
TDeletingArray<SDLInputJoystick *> Joysticks;
|
||||
};
|
||||
|
|
@ -326,7 +532,7 @@ static SDLInputJoystickManager *JoystickManager;
|
|||
void I_StartupJoysticks()
|
||||
{
|
||||
#ifndef NO_SDL_JOYSTICK
|
||||
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) >= 0)
|
||||
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) >= 0)
|
||||
JoystickManager = new SDLInputJoystickManager();
|
||||
#endif
|
||||
}
|
||||
|
|
@ -335,7 +541,7 @@ void I_ShutdownInput()
|
|||
if(JoystickManager)
|
||||
{
|
||||
delete JoystickManager;
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -365,6 +571,16 @@ void I_ProcessJoysticks()
|
|||
JoystickManager->ProcessInput();
|
||||
}
|
||||
|
||||
void I_JoyConsumeEvent(int instanceID, event_t * event)
|
||||
{
|
||||
if (event->type == EV_KeyDown)
|
||||
{
|
||||
bool okay = use_joystick && JoystickManager && JoystickManager->IsJoystickEnabled(instanceID);
|
||||
if (!okay) return;
|
||||
}
|
||||
D_PostEvent(event);
|
||||
}
|
||||
|
||||
IJoystickConfig *I_UpdateDeviceList()
|
||||
{
|
||||
JoystickManager->UpdateDeviceList();
|
||||
|
|
|
|||
|
|
@ -146,7 +146,6 @@ public:
|
|||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
#define DEFAULT_DEADZONE 0.25f
|
||||
|
||||
// TYPES -------------------------------------------------------------------
|
||||
|
||||
|
|
@ -170,15 +169,23 @@ public:
|
|||
EJoyAxis GetAxisMap(int axis);
|
||||
const char *GetAxisName(int axis);
|
||||
float GetAxisScale(int axis);
|
||||
float GetAxisDigitalThreshold(int axis);
|
||||
EJoyCurve GetAxisResponseCurve(int axis);
|
||||
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);
|
||||
void SetAxisResponseCurvePoint(int axis, int point, float value);
|
||||
|
||||
bool IsSensitivityDefault();
|
||||
bool IsAxisDeadZoneDefault(int axis);
|
||||
bool IsAxisMapDefault(int axis);
|
||||
bool IsAxisScaleDefault(int axis);
|
||||
bool IsAxisDigitalThresholdDefault(int axis);
|
||||
bool IsAxisResponseCurveDefault(int axis);
|
||||
|
||||
bool GetEnabled();
|
||||
void SetEnabled(bool enabled);
|
||||
|
|
@ -201,6 +208,9 @@ protected:
|
|||
float Value;
|
||||
float DeadZone, DefaultDeadZone;
|
||||
float Multiplier, DefaultMultiplier;
|
||||
float DigitalThreshold, DefaultDigitalThreshold;
|
||||
EJoyCurve ResponseCurvePreset, DefaultResponseCurvePreset;
|
||||
CubicBezier ResponseCurve;
|
||||
EJoyAxis GameAxis, DefaultGameAxis;
|
||||
uint8_t ButtonValue;
|
||||
};
|
||||
|
|
@ -454,16 +464,21 @@ void FDInputJoystick::ProcessInput()
|
|||
axisval = (value - info->Min) * 2.0 / (info->Max - info->Min) - 1.0;
|
||||
// Cancel out dead zone
|
||||
axisval = Joy_RemoveDeadZone(axisval, info->DeadZone, &buttonstate);
|
||||
axisval = Joy_ApplyResponseCurveBezier(info->ResponseCurve, axisval);
|
||||
info->Value = float(axisval);
|
||||
if (i < NUM_JOYAXISBUTTONS && (i > 2 || Axes.Size() == 1))
|
||||
{
|
||||
if (abs(axisval) < info->DigitalThreshold) buttonstate = 0;
|
||||
Joy_GenerateButtonEvents(info->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(Axes[0].Value, axisval);
|
||||
buttonstate = Joy_XYAxesToButtons(
|
||||
(abs(Axes[0].Value) < Axes[0].DigitalThreshold) ? 0 : Axes[0].Value,
|
||||
(abs(axisval) < info->DigitalThreshold) ? 0 : axisval
|
||||
);
|
||||
Joy_GenerateButtonEvents(info->ButtonValue, buttonstate, 4, KEY_JOYAXIS1PLUS);
|
||||
}
|
||||
info->ButtonValue = buttonstate;
|
||||
|
|
@ -761,38 +776,54 @@ void FDInputJoystick::SetDefaultConfig()
|
|||
{
|
||||
unsigned i;
|
||||
|
||||
Multiplier = 1;
|
||||
Multiplier = JOYSENSITIVITY_DEFAULT;
|
||||
for (i = 0; i < Axes.Size(); ++i)
|
||||
{
|
||||
Axes[i].DeadZone = DEFAULT_DEADZONE;
|
||||
Axes[i].Multiplier = 1;
|
||||
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];
|
||||
}
|
||||
// Triggers on a 360 controller have a much smaller deadzone.
|
||||
if (Axes.Size() == 5 && Axes[4].Guid == GUID_ZAxis)
|
||||
{
|
||||
Axes[4].DeadZone = 30 / 256.f;
|
||||
Axes[4].DigitalThreshold = JOYTHRESH_TRIGGER;
|
||||
}
|
||||
// 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].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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -805,6 +836,8 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -849,7 +882,7 @@ void FDInputJoystick::SetSensitivity(float scale)
|
|||
|
||||
bool FDInputJoystick::IsSensitivityDefault()
|
||||
{
|
||||
return Multiplier == 1;
|
||||
return Multiplier == JOYSENSITIVITY_DEFAULT;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
@ -923,6 +956,51 @@ float FDInputJoystick::GetAxisScale(int axis)
|
|||
return Axes[axis].Multiplier;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDInputJoystick :: GetAxisDigitalThreshold
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
float FDInputJoystick::GetAxisDigitalThreshold(int axis)
|
||||
{
|
||||
if (unsigned(axis) >= Axes.Size())
|
||||
{
|
||||
return JOYTHRESH_DEFAULT;
|
||||
}
|
||||
return Axes[axis].DigitalThreshold;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDInputJoystick :: GetAxisResponseCurve
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
EJoyCurve FDInputJoystick::GetAxisResponseCurve(int axis)
|
||||
{
|
||||
if (unsigned(axis) >= Axes.Size())
|
||||
{
|
||||
return JOYCURVE_DEFAULT;
|
||||
}
|
||||
return Axes[axis].ResponseCurvePreset;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDInputJoystick :: GetAxisResponseCurvePoint
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
float FDInputJoystick::GetAxisResponseCurvePoint(int axis, int point)
|
||||
{
|
||||
if (unsigned(axis) >= Axes.Size() || unsigned(point) >= 4)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return Axes[axis].ResponseCurve.pts[point];
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDInputJoystick :: SetAxisDeadZone
|
||||
|
|
@ -965,6 +1043,52 @@ void FDInputJoystick::SetAxisScale(int axis, float scale)
|
|||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDInputJoystick :: SetAxisDigitalThreshold
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FDInputJoystick::SetAxisDigitalThreshold(int axis, float threshold)
|
||||
{
|
||||
if (unsigned(axis) < Axes.Size())
|
||||
{
|
||||
Axes[axis].DigitalThreshold = threshold;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDInputJoystick :: SetAxisResponseCurve
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FDInputJoystick::SetAxisResponseCurve(int axis, EJoyCurve preset)
|
||||
{
|
||||
if (unsigned(axis) < Axes.Size())
|
||||
{
|
||||
if (preset >= NUM_JOYCURVE || preset < JOYCURVE_CUSTOM) return;
|
||||
Axes[axis].ResponseCurvePreset = preset;
|
||||
if (preset == JOYCURVE_CUSTOM) return;
|
||||
Axes[axis].ResponseCurve = JOYCURVE[preset];
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDInputJoystick :: SetAxisResponseCurvePoint
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FDInputJoystick::SetAxisResponseCurvePoint(int axis, int point, float value)
|
||||
{
|
||||
if (unsigned(axis) < Axes.Size() && unsigned(point) < 4)
|
||||
{
|
||||
Axes[axis].ResponseCurvePreset = JOYCURVE_CUSTOM;
|
||||
Axes[axis].ResponseCurve.pts[point] = value;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDInputJoystick :: IsAxisDeadZoneDefault
|
||||
|
|
@ -995,6 +1119,36 @@ bool FDInputJoystick::IsAxisScaleDefault(int axis)
|
|||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDInputJoystick :: IsAxisDigitalThresholdDefault
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FDInputJoystick::IsAxisDigitalThresholdDefault(int axis)
|
||||
{
|
||||
if (unsigned(axis) < Axes.Size())
|
||||
{
|
||||
return Axes[axis].DigitalThreshold == Axes[axis].DefaultDigitalThreshold;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDInputJoystick :: IsAxisResponseCurveDefault
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FDInputJoystick::IsAxisResponseCurveDefault(int axis)
|
||||
{
|
||||
if (unsigned(axis) < Axes.Size())
|
||||
{
|
||||
return Axes[axis].ResponseCurvePreset == Axes[axis].DefaultResponseCurvePreset;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FDInputJoystick :: GetEnabled
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@
|
|||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
#define DEFAULT_DEADZONE 0.25f
|
||||
#define STATUS_SWITCH_TIME 3
|
||||
|
||||
#define VID_PLAY_COM 0x0b43
|
||||
|
|
@ -104,15 +103,23 @@ public:
|
|||
EJoyAxis GetAxisMap(int axis);
|
||||
const char *GetAxisName(int axis);
|
||||
float GetAxisScale(int axis);
|
||||
float GetAxisDigitalThreshold(int axis);
|
||||
EJoyCurve GetAxisResponseCurve(int axis);
|
||||
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);
|
||||
void SetAxisResponseCurvePoint(int axis, int point, float value);
|
||||
|
||||
bool IsSensitivityDefault();
|
||||
bool IsAxisDeadZoneDefault(int axis);
|
||||
bool IsAxisMapDefault(int axis);
|
||||
bool IsAxisScaleDefault(int axis);
|
||||
bool IsAxisDigitalThresholdDefault(int axis);
|
||||
bool IsAxisResponseCurveDefault(int axis);
|
||||
|
||||
bool GetEnabled();
|
||||
void SetEnabled(bool enabled);
|
||||
|
|
@ -130,6 +137,9 @@ protected:
|
|||
float Value;
|
||||
float DeadZone;
|
||||
float Multiplier;
|
||||
float DigitalThreshold;
|
||||
EJoyCurve ResponseCurvePreset;
|
||||
CubicBezier ResponseCurve;
|
||||
EJoyAxis GameAxis;
|
||||
uint8_t ButtonValue;
|
||||
};
|
||||
|
|
@ -137,6 +147,8 @@ protected:
|
|||
{
|
||||
EJoyAxis GameAxis;
|
||||
float Multiplier;
|
||||
float DigitalThreshold;
|
||||
EJoyCurve ResponseCurvePreset;
|
||||
};
|
||||
enum
|
||||
{
|
||||
|
|
@ -357,11 +369,11 @@ static const char *AxisNames[] =
|
|||
|
||||
FRawPS2Controller::DefaultAxisConfig FRawPS2Controller::DefaultAxes[NUM_AXES] =
|
||||
{
|
||||
// Game axis, multiplier
|
||||
{ JOYAXIS_Side, 1 }, // ThumbLX
|
||||
{ JOYAXIS_Forward, 1 }, // ThumbLY
|
||||
{ JOYAXIS_Yaw, 1 }, // ThumbRX
|
||||
{ JOYAXIS_Pitch, 0.75 }, // ThumbRY
|
||||
// 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
|
||||
};
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
|
@ -552,11 +564,16 @@ void FRawPS2Controller::ProcessThumbstick(int value1, AxisInfo *axis1, int value
|
|||
axisval2 = value2 * (2.0 / 255) - 1.0;
|
||||
axisval1 = Joy_RemoveDeadZone(axisval1, axis1->DeadZone, NULL);
|
||||
axisval2 = Joy_RemoveDeadZone(axisval2, axis2->DeadZone, NULL);
|
||||
axisval1 = Joy_ApplyResponseCurveBezier(axis1->ResponseCurve, axisval1);
|
||||
axisval2 = Joy_ApplyResponseCurveBezier(axis2->ResponseCurve, axisval2);
|
||||
axis1->Value = float(axisval1);
|
||||
axis2->Value = float(axisval2);
|
||||
|
||||
// We store all four buttons in the first axis and ignore the second.
|
||||
buttonstate = Joy_XYAxesToButtons(axisval1, axisval2);
|
||||
buttonstate = Joy_XYAxesToButtons(
|
||||
(abs(axisval1) < axis1->DigitalThreshold) ? 0 : axisval1,
|
||||
(abs(axisval2) < axis2->DigitalThreshold) ? 0 : axisval2
|
||||
);
|
||||
Joy_GenerateButtonEvents(axis1->ButtonValue, buttonstate, 4, base);
|
||||
axis1->ButtonValue = buttonstate;
|
||||
}
|
||||
|
|
@ -644,10 +661,10 @@ void FRawPS2Controller::AddAxes(float axes[NUM_JOYAXIS])
|
|||
|
||||
void FRawPS2Controller::SetDefaultConfig()
|
||||
{
|
||||
Multiplier = 1;
|
||||
Multiplier = JOYSENSITIVITY_DEFAULT;
|
||||
for (int i = 0; i < NUM_AXES; ++i)
|
||||
{
|
||||
Axes[i].DeadZone = DEFAULT_DEADZONE;
|
||||
Axes[i].DeadZone = JOYDEADZONE_DEFAULT;
|
||||
Axes[i].GameAxis = DefaultAxes[i].GameAxis;
|
||||
Axes[i].Multiplier = DefaultAxes[i].Multiplier;
|
||||
}
|
||||
|
|
@ -712,7 +729,7 @@ void FRawPS2Controller::SetSensitivity(float scale)
|
|||
|
||||
bool FRawPS2Controller::IsSensitivityDefault()
|
||||
{
|
||||
return Multiplier == 1;
|
||||
return Multiplier == JOYSENSITIVITY_DEFAULT;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -786,6 +803,51 @@ float FRawPS2Controller::GetAxisScale(int axis)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FRawPS2Controller :: GetAxisDigitalThreshold
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
float FRawPS2Controller::GetAxisDigitalThreshold(int axis)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES)
|
||||
{
|
||||
return Axes[axis].DigitalThreshold;
|
||||
}
|
||||
return JOYTHRESH_DEFAULT;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FRawPS2Controller :: GetAxisResponseCurve
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
EJoyCurve FRawPS2Controller::GetAxisResponseCurve(int axis)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES)
|
||||
{
|
||||
return Axes[axis].ResponseCurvePreset;
|
||||
}
|
||||
return JOYCURVE_DEFAULT;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FRawPS2Controller :: GetAxisResponseCurvePoint
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
float FRawPS2Controller::GetAxisResponseCurvePoint(int axis, int point)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES && unsigned(point) < 4)
|
||||
{
|
||||
return Axes[axis].ResponseCurve.pts[point];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FRawPS2Controller :: SetAxisDeadZone
|
||||
|
|
@ -828,6 +890,52 @@ void FRawPS2Controller::SetAxisScale(int axis, float scale)
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FRawPS2Controller :: SetAxisDigitalThreshold
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FRawPS2Controller::SetAxisDigitalThreshold(int axis, float threshold)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES)
|
||||
{
|
||||
Axes[axis].DigitalThreshold = threshold;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FRawPS2Controller :: SetAxisResponseCurve
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FRawPS2Controller::SetAxisResponseCurve(int axis, EJoyCurve preset)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES)
|
||||
{
|
||||
if (preset >= NUM_JOYCURVE || preset < JOYCURVE_CUSTOM) return;
|
||||
Axes[axis].ResponseCurvePreset = preset;
|
||||
if (preset == JOYCURVE_CUSTOM) return;
|
||||
Axes[axis].ResponseCurve = JOYCURVE[preset];
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FRawPS2Controller :: SetAxisResponseCurvePoint
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FRawPS2Controller::SetAxisResponseCurvePoint(int axis, int point, float value)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES && unsigned(point) < 4)
|
||||
{
|
||||
Axes[axis].ResponseCurvePreset = JOYCURVE_CUSTOM;
|
||||
Axes[axis].ResponseCurve.pts[point] = value;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FRawPS2Controller :: IsAxisDeadZoneDefault
|
||||
|
|
@ -838,7 +946,7 @@ bool FRawPS2Controller::IsAxisDeadZoneDefault(int axis)
|
|||
{
|
||||
if (unsigned(axis) < NUM_AXES)
|
||||
{
|
||||
return Axes[axis].DeadZone == DEFAULT_DEADZONE;
|
||||
return Axes[axis].DeadZone == JOYDEADZONE_DEFAULT;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -858,6 +966,36 @@ bool FRawPS2Controller::IsAxisScaleDefault(int axis)
|
|||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FRawPS2Controller :: IsAxisDigitalThresholdDefault
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FRawPS2Controller::IsAxisDigitalThresholdDefault(int axis)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES)
|
||||
{
|
||||
return Axes[axis].DigitalThreshold == DefaultAxes[axis].DigitalThreshold;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FRawPS2Controller :: IsAxisResponseCurveDefault
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FRawPS2Controller::IsAxisResponseCurveDefault(int axis)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES)
|
||||
{
|
||||
return Axes[axis].ResponseCurvePreset == DefaultAxes[axis].ResponseCurvePreset;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FRawPS2Controller :: GetEnabled
|
||||
|
|
|
|||
|
|
@ -94,15 +94,23 @@ public:
|
|||
EJoyAxis GetAxisMap(int axis);
|
||||
const char *GetAxisName(int axis);
|
||||
float GetAxisScale(int axis);
|
||||
float GetAxisDigitalThreshold(int axis);
|
||||
EJoyCurve GetAxisResponseCurve(int axis);
|
||||
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);
|
||||
void SetAxisResponseCurvePoint(int axis, int point, float value);
|
||||
|
||||
bool IsSensitivityDefault();
|
||||
bool IsAxisDeadZoneDefault(int axis);
|
||||
bool IsAxisMapDefault(int axis);
|
||||
bool IsAxisScaleDefault(int axis);
|
||||
bool IsAxisDigitalThresholdDefault(int axis);
|
||||
bool IsAxisResponseCurveDefault(int axis);
|
||||
|
||||
bool GetEnabled();
|
||||
void SetEnabled(bool enabled);
|
||||
|
|
@ -122,12 +130,17 @@ protected:
|
|||
float Multiplier;
|
||||
EJoyAxis GameAxis;
|
||||
uint8_t ButtonValue;
|
||||
float DigitalThreshold;
|
||||
EJoyCurve ResponseCurvePreset;
|
||||
CubicBezier ResponseCurve;
|
||||
};
|
||||
struct DefaultAxisConfig
|
||||
{
|
||||
float DeadZone;
|
||||
EJoyAxis GameAxis;
|
||||
float Multiplier;
|
||||
float DigitalThreshold;
|
||||
EJoyCurve ResponseCurvePreset;
|
||||
};
|
||||
enum
|
||||
{
|
||||
|
|
@ -211,13 +224,13 @@ static const char *AxisNames[] =
|
|||
|
||||
FXInputController::DefaultAxisConfig FXInputController::DefaultAxes[NUM_AXES] =
|
||||
{
|
||||
// Dead zone, game axis, multiplier
|
||||
{ XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE / 32768.f, JOYAXIS_Side, 1 }, // ThumbLX
|
||||
{ XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE / 32768.f, JOYAXIS_Forward, 1 }, // ThumbLY
|
||||
{ XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE / 32768.f, JOYAXIS_Yaw, 1 }, // ThumbRX
|
||||
{ XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE / 32768.f, JOYAXIS_Pitch, 0.75 }, // ThumbRY
|
||||
{ XINPUT_GAMEPAD_TRIGGER_THRESHOLD / 256.f, JOYAXIS_None, 0 }, // LeftTrigger
|
||||
{ XINPUT_GAMEPAD_TRIGGER_THRESHOLD / 256.f, JOYAXIS_None, 0 } // RightTrigger
|
||||
// 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
|
||||
};
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
|
@ -327,11 +340,16 @@ void FXInputController::ProcessThumbstick(int value1, AxisInfo *axis1,
|
|||
axisval2 = (value2 - SHRT_MIN) * 2.0 / 65536 - 1.0;
|
||||
axisval1 = Joy_RemoveDeadZone(axisval1, axis1->DeadZone, NULL);
|
||||
axisval2 = Joy_RemoveDeadZone(axisval2, axis2->DeadZone, NULL);
|
||||
axisval1 = Joy_ApplyResponseCurveBezier(axis1->ResponseCurve, axisval1);
|
||||
axisval2 = Joy_ApplyResponseCurveBezier(axis2->ResponseCurve, axisval2);
|
||||
axis1->Value = float(axisval1);
|
||||
axis2->Value = float(axisval2);
|
||||
|
||||
// We store all four buttons in the first axis and ignore the second.
|
||||
buttonstate = Joy_XYAxesToButtons(axisval1, axisval2);
|
||||
buttonstate = Joy_XYAxesToButtons(
|
||||
abs(axisval1) < axis1->DigitalThreshold ? 0: axisval1,
|
||||
abs(axisval2) < axis2->DigitalThreshold ? 0: axisval2
|
||||
);
|
||||
Joy_GenerateButtonEvents(axis1->ButtonValue, buttonstate, 4, base);
|
||||
axis1->ButtonValue = buttonstate;
|
||||
}
|
||||
|
|
@ -351,6 +369,11 @@ void FXInputController::ProcessTrigger(int value, AxisInfo *axis, int base)
|
|||
double axisval;
|
||||
|
||||
axisval = Joy_RemoveDeadZone(value / 256.0, axis->DeadZone, &buttonstate);
|
||||
axisval = Joy_ApplyResponseCurveBezier(axis->ResponseCurve, axisval);
|
||||
|
||||
// TODO: probably just put this into Joy_RemoveDeadZone
|
||||
if (abs(axisval) < axis->DigitalThreshold) buttonstate = 0;
|
||||
|
||||
Joy_GenerateButtonEvents(axis->ButtonValue, buttonstate, 1, base);
|
||||
axis->ButtonValue = buttonstate;
|
||||
axis->Value = float(axisval);
|
||||
|
|
@ -431,12 +454,15 @@ void FXInputController::AddAxes(float axes[NUM_JOYAXIS])
|
|||
|
||||
void FXInputController::SetDefaultConfig()
|
||||
{
|
||||
Multiplier = 1;
|
||||
Multiplier = JOYSENSITIVITY_DEFAULT;
|
||||
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];
|
||||
Axes[i].ResponseCurvePreset = DefaultAxes[i].ResponseCurvePreset;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -494,7 +520,7 @@ void FXInputController::SetSensitivity(float scale)
|
|||
|
||||
bool FXInputController::IsSensitivityDefault()
|
||||
{
|
||||
return Multiplier == 1;
|
||||
return Multiplier == JOYSENSITIVITY_DEFAULT;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -565,6 +591,51 @@ float FXInputController::GetAxisScale(int axis)
|
|||
{
|
||||
return Axes[axis].Multiplier;
|
||||
}
|
||||
return JOYSENSITIVITY_DEFAULT;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FXInputController :: GetAxisDigitalThreshold
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
float FXInputController::GetAxisDigitalThreshold(int axis)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES)
|
||||
{
|
||||
return Axes[axis].DigitalThreshold;
|
||||
}
|
||||
return JOYTHRESH_DEFAULT;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FXInputController :: GetAxisResponseCurve
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
EJoyCurve FXInputController::GetAxisResponseCurve(int axis)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES)
|
||||
{
|
||||
return Axes[axis].ResponseCurvePreset;
|
||||
}
|
||||
return JOYCURVE_DEFAULT;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FXInputController :: GetAxisResponseCurvePoint
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
float FXInputController::GetAxisResponseCurvePoint(int axis, int point)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES && unsigned(point) < 4)
|
||||
{
|
||||
return Axes[axis].ResponseCurve.pts[point];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -610,6 +681,52 @@ void FXInputController::SetAxisScale(int axis, float scale)
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FXInputController :: SetAxisDigitalThreshold
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FXInputController::SetAxisDigitalThreshold(int axis, float threshold)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES)
|
||||
{
|
||||
Axes[axis].DigitalThreshold = threshold;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FXInputController :: SetAxisResponseCurve
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FXInputController::SetAxisResponseCurve(int axis, EJoyCurve preset)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES)
|
||||
{
|
||||
if (preset >= NUM_JOYCURVE || preset < JOYCURVE_CUSTOM) return;
|
||||
Axes[axis].ResponseCurvePreset = preset;
|
||||
if (preset == JOYCURVE_CUSTOM) return;
|
||||
Axes[axis].ResponseCurve = JOYCURVE[preset];
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FXInputController :: SetAxisResponseCurvePoint
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FXInputController::SetAxisResponseCurvePoint(int axis, int point, float value)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES && unsigned(point) < 4)
|
||||
{
|
||||
Axes[axis].ResponseCurvePreset = JOYCURVE_CUSTOM;
|
||||
Axes[axis].ResponseCurve.pts[point] = value;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FXInputController :: IsAxisDeadZoneDefault
|
||||
|
|
@ -640,6 +757,36 @@ bool FXInputController::IsAxisScaleDefault(int axis)
|
|||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FXInputController :: IsAxisDigitalThresholdDefault
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FXInputController::IsAxisDigitalThresholdDefault(int axis)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES)
|
||||
{
|
||||
return Axes[axis].DigitalThreshold == DefaultAxes[axis].DigitalThreshold;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FXInputController :: IsAxisResponseCurveDefault
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FXInputController::IsAxisResponseCurveDefault(int axis)
|
||||
{
|
||||
if (unsigned(axis) < NUM_AXES)
|
||||
{
|
||||
return Axes[axis].ResponseCurvePreset == DefaultAxes[axis].ResponseCurvePreset;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FXInputController :: GetEnabled
|
||||
|
|
|
|||
|
|
@ -837,6 +837,15 @@ OptionMenu "JoystickOptions" protected
|
|||
Title "$JOYMNU_OPTIONS"
|
||||
}
|
||||
|
||||
OptionValue "JoyAxisCurveNames"
|
||||
{
|
||||
-1, "$OPTVAL_CUSTOM"
|
||||
0, "$OPTVAL_DEFAULT"
|
||||
1, "$OPTVAL_LINEAR"
|
||||
2, "$OPTVAL_QUADRATIC"
|
||||
3, "$OPTVAL_CUBIC"
|
||||
}
|
||||
|
||||
OptionValue "JoyAxisMapNames"
|
||||
{
|
||||
-1, "$OPTVAL_NONE"
|
||||
|
|
|
|||
|
|
@ -130,7 +130,94 @@ class OptionMenuSliderJoyDeadZone : OptionMenuSliderBase
|
|||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class OptionMenuSliderJoyDigitalThreshold : OptionMenuSliderBase
|
||||
{
|
||||
int mAxis;
|
||||
int mNeg;
|
||||
JoystickConfig mJoy;
|
||||
|
||||
OptionMenuSliderJoyDigitalThreshold Init(String label, int axis, double min, double max, double step, int showval, JoystickConfig joy)
|
||||
{
|
||||
Super.Init(label, min, max, step, showval);
|
||||
mAxis = axis;
|
||||
mNeg = 1;
|
||||
mJoy = joy;
|
||||
return self;
|
||||
}
|
||||
|
||||
override double GetSliderValue()
|
||||
{
|
||||
double d = mJoy.GetAxisDigitalThreshold(mAxis);
|
||||
mNeg = d < 0? -1:1;
|
||||
return d;
|
||||
}
|
||||
|
||||
override void SetSliderValue(double val)
|
||||
{
|
||||
mJoy.SetAxisDigitalThreshold(mAxis, val * mNeg);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class OptionMenuItemJoyCurve : OptionMenuItemOptionBase
|
||||
{
|
||||
int mAxis;
|
||||
JoystickConfig mJoy;
|
||||
|
||||
OptionMenuItemJoyCurve Init(String label, int axis, Name values, int center, JoystickConfig joy)
|
||||
{
|
||||
Super.Init(label, 'none', values, null, center);
|
||||
mAxis = axis;
|
||||
mJoy = joy;
|
||||
return self;
|
||||
}
|
||||
|
||||
override int GetSelection()
|
||||
{
|
||||
double f = mJoy.GetAxisResponseCurve(mAxis);
|
||||
let opt = OptionValues.GetCount(mValues);
|
||||
if (opt > 0)
|
||||
{
|
||||
// Map from joystick curve to menu selection.
|
||||
for(int i = 0; i < opt; i++)
|
||||
{
|
||||
if (f ~== OptionValues.GetValue(mValues, i))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return JoystickConfig.JOYCURVE_CUSTOM;
|
||||
}
|
||||
|
||||
override void SetSelection(int selection)
|
||||
{
|
||||
let opt = OptionValues.GetCount(mValues);
|
||||
// Map from menu selection to joystick curve.
|
||||
if (opt == 0 || selection >= opt)
|
||||
{
|
||||
selection = JoystickConfig.JOYCURVE_DEFAULT;
|
||||
}
|
||||
else
|
||||
{
|
||||
selection = int(OptionValues.GetValue(mValues, selection));
|
||||
}
|
||||
mJoy.setAxisResponseCurve(mAxis, selection);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
|
|
@ -340,8 +427,25 @@ class OptionMenuItemJoyConfigMenu : OptionMenuItemSubmenu
|
|||
opt.mItems.Push(it);
|
||||
it = new("OptionMenuItemInverter").Init("$JOYMNU_INVERT", i, false, joy);
|
||||
opt.mItems.Push(it);
|
||||
it = new("OptionMenuItemJoyCurve").Init("$JOYMNU_CURVE", i, "JoyAxisCurveNames", false, joy);
|
||||
opt.mItems.Push(it);
|
||||
// // is there a way to do something like this?
|
||||
// // add extra options if the selected value is something specific?
|
||||
// if (joy.GetAxisResponseCurve(i) == JoystickConfig.JOYCURVE_CUSTOM)
|
||||
// {
|
||||
// it = new("OptionMenuItemStaticText").Init("$JOYMNU_CURVE_X1", false);
|
||||
// opt.mItems.Push(it);
|
||||
// it = new("OptionMenuItemStaticText").Init("$JOYMNU_CURVE_Y1", false);
|
||||
// opt.mItems.Push(it);
|
||||
// it = new("OptionMenuItemStaticText").Init("$JOYMNU_CURVE_X2", false);
|
||||
// opt.mItems.Push(it);
|
||||
// it = new("OptionMenuItemStaticText").Init("$JOYMNU_CURVE_Y2", false);
|
||||
// opt.mItems.Push(it);
|
||||
// }
|
||||
it = new("OptionMenuSliderJoyDeadZone").Init("$JOYMNU_DEADZONE", i, 0, 0.9, 0.05, 3, joy);
|
||||
opt.mItems.Push(it);
|
||||
it = new("OptionMenuSliderJoyDigitalThreshold").Init("$JOYMNU_THRESHOLD", i, 0, 0.9, 0.05, 3, joy);
|
||||
opt.mItems.Push(it);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -68,6 +68,16 @@ struct JoystickConfig native version("2.4")
|
|||
NUM_JOYAXIS,
|
||||
};
|
||||
|
||||
enum EJoyCurve {
|
||||
JOYCURVE_CUSTOM = -1,
|
||||
JOYCURVE_DEFAULT,
|
||||
JOYCURVE_LINEAR,
|
||||
JOYCURVE_QUADRATIC,
|
||||
JOYCURVE_CUBIC,
|
||||
|
||||
NUM_JOYCURVE
|
||||
};
|
||||
|
||||
native float GetSensitivity();
|
||||
native void SetSensitivity(float scale);
|
||||
|
||||
|
|
@ -77,6 +87,15 @@ struct JoystickConfig native version("2.4")
|
|||
native float GetAxisDeadZone(int axis);
|
||||
native void SetAxisDeadZone(int axis, float zone);
|
||||
|
||||
native float GetAxisDigitalThreshold(int axis);
|
||||
native void SetAxisDigitalThreshold(int axis, float thresh);
|
||||
|
||||
native int GetAxisResponseCurve(int axis);
|
||||
native void SetAxisResponseCurve(int axis, int preset);
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue