Rework the entire G_PlayerInputAnalog system.
* Previous control checking flow:
* Current controller/keyboard (userbound controls).
* If on a menu:
* Current controller/keyboard (default controls).
* All controllers not in use by a player (default controls).
* New control checking flow:
* Current controller/keyboard (userbound controls).
* If player 0 and just checked a controller, check keyboard (userbound controls).
* If on a menu:
* Check all controllers not in use by a player (userbound controls).
* If keys are inaccessible/unbound and keybind is necessary to navigate menus, repeat eveyrhting with default controls.
* Instead of duplicated code, control the flow in a finer fashion.
* Now able to detect if gamepad inputs are possible to recieve (via checking deviceID), instead of assuming they are.
* If a keybind is set but inaccessible by the above metric, make it flash on the Profile Controls screen.
* Fix out-of-order key mappings for a given bind being invisible on the Profile Controls menu.
This commit is contained in:
parent
a0348420f7
commit
144e967ee5
3 changed files with 106 additions and 51 deletions
103
src/g_game.c
103
src/g_game.c
|
|
@ -786,38 +786,14 @@ bound:
|
|||
return false;
|
||||
}
|
||||
|
||||
static INT32 KeyValue(UINT8 p, INT32 key, boolean menu)
|
||||
{
|
||||
INT32 deviceID;
|
||||
|
||||
if (key <= 0 || key >= NUMINPUTS)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (menu == false)
|
||||
{
|
||||
deviceID = cv_usejoystick[p].value;
|
||||
if (deviceID < 0 || deviceID >= MAXDEVICES)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return gamekeydown[deviceID][key];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use keyboard as alternative for P1 menu.
|
||||
return gamekeydown[0][key];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
INT32 G_PlayerInputAnalog(UINT8 p, INT32 gc, boolean menu)
|
||||
{
|
||||
INT32 deviceID;
|
||||
INT32 i;
|
||||
INT32 deadzone = 0;
|
||||
boolean trydefaults = true;
|
||||
boolean tryingotherID = false;
|
||||
INT32 *controltable = &(gamecontrol[p][gc][0]);
|
||||
|
||||
if (p >= MAXSPLITSCREENPLAYERS)
|
||||
{
|
||||
|
|
@ -829,17 +805,24 @@ INT32 G_PlayerInputAnalog(UINT8 p, INT32 gc, boolean menu)
|
|||
|
||||
deadzone = (JOYAXISRANGE * cv_deadzone[p].value) / FRACUNIT;
|
||||
|
||||
deviceID = cv_usejoystick[p].value;
|
||||
|
||||
retrygetcontrol:
|
||||
for (i = 0; i < MAXINPUTMAPPING; i++)
|
||||
{
|
||||
INT32 key = gamecontrol[p][gc][i];
|
||||
INT32 key = controltable[i];
|
||||
INT32 value = 0;
|
||||
|
||||
if (key <= 0 || key >= NUMINPUTS)
|
||||
// Invalid key number.
|
||||
if (!G_KeyIsAvailable(key, deviceID))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
value = KeyValue(p, key, false);
|
||||
// It's possible to access this control right now, so let's disable the default control backup for later.
|
||||
trydefaults = false;
|
||||
|
||||
value = gamekeydown[deviceID][key];
|
||||
|
||||
if (value >= deadzone)
|
||||
{
|
||||
|
|
@ -847,29 +830,51 @@ INT32 G_PlayerInputAnalog(UINT8 p, INT32 gc, boolean menu)
|
|||
}
|
||||
}
|
||||
|
||||
if (p == 0 && menu == true)
|
||||
// If you're on controller, try your keyboard-based binds as an immediate backup.
|
||||
if (p == 0 && deviceID > 0 && !tryingotherID)
|
||||
{
|
||||
// We don't want menus to become unnavigable if people unbind
|
||||
// all of their controls, so use the default control scheme in
|
||||
// this scenario.
|
||||
deviceID = 0;
|
||||
goto retrygetcontrol;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXINPUTMAPPING; i++)
|
||||
if (menu == false)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We don't want menus to become unnavigable if people unbind
|
||||
// all of their controls, so we do several things in this scenario.
|
||||
// First: try other controllers.
|
||||
|
||||
if (!tryingotherID)
|
||||
{
|
||||
deviceID = MAXDEVICES;
|
||||
tryingotherID = true;
|
||||
}
|
||||
loweringid:
|
||||
deviceID--;
|
||||
if (deviceID > 0)
|
||||
{
|
||||
for (i = 0; i < cv_splitplayers.value-1; i++)
|
||||
{
|
||||
INT32 key = gamecontroldefault[gc][i];
|
||||
INT32 value = 0;
|
||||
|
||||
if (key <= 0 || key >= NUMINPUTS)
|
||||
{
|
||||
if (deviceID != cv_usejoystick[i].value)
|
||||
continue;
|
||||
}
|
||||
|
||||
value = KeyValue(p, key, true);
|
||||
|
||||
if (value >= deadzone)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
// Controller taken? Try again...
|
||||
goto loweringid;
|
||||
}
|
||||
goto retrygetcontrol;
|
||||
}
|
||||
|
||||
if (trydefaults && G_KeyBindIsNecessary(gc))
|
||||
{
|
||||
// If we still haven't found anything and the keybind is necessary,
|
||||
// try it all again but with default binds.
|
||||
trydefaults = false;
|
||||
controltable = &(gamecontroldefault[gc][0]);
|
||||
tryingotherID = false;
|
||||
deviceID = cv_usejoystick[p].value;
|
||||
goto retrygetcontrol;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -418,6 +418,51 @@ static const char *gamecontrolname[num_gamecontrols] =
|
|||
|
||||
#define NUMKEYNAMES (sizeof (keynames)/sizeof (keyname_t))
|
||||
|
||||
// If keybind is necessary to navigate menus, it's on this list.
|
||||
boolean G_KeyBindIsNecessary(INT32 gc)
|
||||
{
|
||||
switch (gc)
|
||||
{
|
||||
case gc_accelerate:
|
||||
case gc_brake:
|
||||
case gc_aimforward:
|
||||
case gc_aimbackward:
|
||||
case gc_turnleft:
|
||||
case gc_turnright:
|
||||
case gc_systemmenu:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns false if a key is deemed unreachable for this device.
|
||||
boolean G_KeyIsAvailable(INT32 key, INT32 deviceID)
|
||||
{
|
||||
// Invalid key number.
|
||||
if (key <= 0 || key >= NUMINPUTS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Valid controller-specific virtual key, but no controller attached for player.
|
||||
if (key >= KEY_JOY1 && key < JOYINPUTEND && deviceID <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Valid mouse-specific virtual key, but no mouse attached for player. TODO HOW TO DETECT ACTIVE MOUSE CONNECTION
|
||||
/*
|
||||
if (key >= KEY_MOUSE1 && key < MOUSEINPUTEND && ????????)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Detach any keys associated to the given game control
|
||||
// - pass the pointer to the gamecontrol table for the player being edited
|
||||
|
|
|
|||
|
|
@ -41,13 +41,15 @@ typedef enum
|
|||
KEY_JOY1 = NUMKEYS,
|
||||
KEY_HAT1 = KEY_JOY1 + JOYBUTTONS,
|
||||
KEY_AXIS1 = KEY_HAT1 + JOYHATS*4,
|
||||
JOYINPUTEND = KEY_AXIS1 + JOYAXISSET*2*2, // 4 sets of 2 axes, each with positive & negative
|
||||
|
||||
KEY_MOUSE1 = KEY_AXIS1 + JOYAXISSET*4,
|
||||
KEY_MOUSE1 = JOYINPUTEND,
|
||||
KEY_MOUSEMOVE = KEY_MOUSE1 + MOUSEBUTTONS,
|
||||
KEY_MOUSEWHEELUP = KEY_MOUSEMOVE + 4,
|
||||
KEY_MOUSEWHEELDOWN = KEY_MOUSEWHEELUP + 1,
|
||||
MOUSEINPUTEND = KEY_MOUSEWHEELDOWN + 1,
|
||||
|
||||
NUMINPUTS = KEY_MOUSEWHEELDOWN + 1,
|
||||
NUMINPUTS = MOUSEINPUTEND,
|
||||
} key_input_e;
|
||||
|
||||
typedef enum
|
||||
|
|
@ -126,6 +128,9 @@ void G_MapEventsToControls(event_t *ev);
|
|||
const char *G_KeynumToString(INT32 keynum);
|
||||
INT32 G_KeyStringtoNum(const char *keystr);
|
||||
|
||||
boolean G_KeyBindIsNecessary(INT32 gc);
|
||||
boolean G_KeyIsAvailable(INT32 key, INT32 deviceID);
|
||||
|
||||
// detach any keys associated to the given game control
|
||||
void G_ClearControlKeys(INT32 (*setupcontrols)[MAXINPUTMAPPING], INT32 control);
|
||||
void G_ClearAllControlKeys(void);
|
||||
|
|
|
|||
Loading…
Reference in a new issue