Summary:
This short tutorial fixes a couple of really annoying problems in Quake that have to do with all sorts of aliases and keybinds being triggered inappropriately in situations in-game, in the console and when using ALT-TAB or changing video mode.
Walkthrough:
This part fixes the ALT-TAB and video mode changing issues. Later on, the console and messagemode fixes are addressed.
For starters, some of the code is not really in the right place in Quake.
In ProQuake, I moved Key_ClearAllStates from gl_vidnt.c/vid_win.c into keys.c. There is no Windows-only code in Key_ClearAllStates, so it is just a more sensible location.
Here is the ClearAllStates from GLQuake:
And the Key_ClearStates from GLQuake:
Note that the above is setting the down state to false.
And here is the IN_ClearStates from GLQuake in in_win.c:
This is reseting the mouse coordinates.
What is wrong with the way GLQuake does it
First, it is triggering -aliases FOR all keys. It doesn't matter if the key was depressed or not. This can have undesirable effects when ALT-TAB is done or if the client supports video mode changing.
Second, only ClearAllStates in gl_vidnt.c/vid_win.c calls Key_ClearStates. Why have 2 procedures separate and 1 of them in clearly the wrong source file.
What I did to fix this ...
Only ClearAllStates calls Key_ClearStates and it's in the wrong place. I deleted ClearAllStates from gl_vidnt.c and vid_win.c. Then renamed Key_ClearStates to Key_ClearAllStates.
And instead of triggering every key with a release event, it only triggers key events for keys that were actually down.
The Key_Event with the down=false is going to set keydown[key] to false and keyrepeats[key] to 0 anyway.
Extra Credit
The above doesn't address another issue. Minus -aliases are triggered in the console or even in messagemode! This is annoying.
My console, for instance, gets spammed with "-hook isn't a valid alias" and weird impulses gets trigger when I'm in message mode because I have a weapon changing binds with both +aliases and -aliases. I've had other oddball things happen while typing, I even ruined a tournament game once when logged in as admin from this because all sorts of things can get triggered by -aliases being executed while chatting.
The Fix For That
First, we are going to mark whether a key was depressed while in-game.
Second, in Key_Event we need a temp variable to store this value. This is because Key_Event will need to set the down state to false if exiting.
And we need to set this variable immediately after "keydown[key] = down;"
Now we need to find this to make it only execute the -alias if the key was triggered in the game:
And finally, we need to have it set the keygamedown ONLY when the +alias is executed:
This short tutorial fixes a couple of really annoying problems in Quake that have to do with all sorts of aliases and keybinds being triggered inappropriately in situations in-game, in the console and when using ALT-TAB or changing video mode.
Walkthrough:
This part fixes the ALT-TAB and video mode changing issues. Later on, the console and messagemode fixes are addressed.
For starters, some of the code is not really in the right place in Quake.
In ProQuake, I moved Key_ClearAllStates from gl_vidnt.c/vid_win.c into keys.c. There is no Windows-only code in Key_ClearAllStates, so it is just a more sensible location.
Here is the ClearAllStates from GLQuake:
/*
================
ClearAllStates
================
*/
void ClearAllStates (void)
{
int i;
// send an up event for each key, to make sure the server clears them all
for (i=0 ; i<256 ; i++)
{
Key_Event (i, false);
}
Key_ClearStates ();
IN_ClearStates ();
}
================
ClearAllStates
================
*/
void ClearAllStates (void)
{
int i;
// send an up event for each key, to make sure the server clears them all
for (i=0 ; i<256 ; i++)
{
Key_Event (i, false);
}
Key_ClearStates ();
IN_ClearStates ();
}
/*
===================
Key_ClearStates
===================
*/
void Key_ClearStates (void)
{
int i;
for (i=0 ; i<256 ; i++)
{
keydown[i] = false;
key_repeats[i] = 0;
}
}
===================
Key_ClearStates
===================
*/
void Key_ClearStates (void)
{
int i;
for (i=0 ; i<256 ; i++)
{
keydown[i] = false;
key_repeats[i] = 0;
}
}
And here is the IN_ClearStates from GLQuake in in_win.c:
/*
===================
IN_ClearStates
===================
*/
void IN_ClearStates (void)
{
if (mouseactive)
{
mx_accum = 0;
my_accum = 0;
mouse_oldbuttonstate = 0;
}
}
===================
IN_ClearStates
===================
*/
void IN_ClearStates (void)
{
if (mouseactive)
{
mx_accum = 0;
my_accum = 0;
mouse_oldbuttonstate = 0;
}
}
What is wrong with the way GLQuake does it
First, it is triggering -aliases FOR all keys. It doesn't matter if the key was depressed or not. This can have undesirable effects when ALT-TAB is done or if the client supports video mode changing.
Second, only ClearAllStates in gl_vidnt.c/vid_win.c calls Key_ClearStates. Why have 2 procedures separate and 1 of them in clearly the wrong source file.

What I did to fix this ...
Only ClearAllStates calls Key_ClearStates and it's in the wrong place. I deleted ClearAllStates from gl_vidnt.c and vid_win.c. Then renamed Key_ClearStates to Key_ClearAllStates.
And instead of triggering every key with a release event, it only triggers key events for keys that were actually down.
Code:
/* ================== Key_ClearAllStates ================== */ void Key_ClearAllStates (void) { int i; for (i=0 ; i<256 ; i++) { // If the key is down, trigger the up action if, say, +showscores or another +bind is activated if (keydown[i]) Key_Event (i, false); } IN_ClearStates (); }
Extra Credit
The above doesn't address another issue. Minus -aliases are triggered in the console or even in messagemode! This is annoying.
My console, for instance, gets spammed with "-hook isn't a valid alias" and weird impulses gets trigger when I'm in message mode because I have a weapon changing binds with both +aliases and -aliases. I've had other oddball things happen while typing, I even ruined a tournament game once when logged in as admin from this because all sorts of things can get triggered by -aliases being executed while chatting.
The Fix For That
First, we are going to mark whether a key was depressed while in-game.
//At the top of keys.c
qboolean keygamedown[256];
qboolean keygamedown[256];
//keys.c in Key_Event
qboolean wasgamekey = false;
qboolean wasgamekey = false;
Code:
//keys.c in Key_Event wasgamekey = keygamedown[key]; // Baker: to prevent -aliases being triggered in-console needlessly if (!down) { keygamedown[key] = false; }
if (!down)
{
// Baker: we only want to trigger -alias if appropriate
// but we ALWAYS want to exit is key is up
if (wasgamekey) {
kb = keybindings[key];
if (kb && kb[0] == '+')
{
Q_snprintfz (cmd, sizeof(cmd), "-%s %i\n", kb+1, key);
Cbuf_AddText (cmd);
}
if (keyshift[key] != key)
{
kb = keybindings[keyshift[key]];
if (kb && kb[0] == '+')
{
Q_snprintfz (cmd, sizeof(cmd), "-%s %i\n", kb+1, key);
Cbuf_AddText (cmd);
}
}
}
return;
}
{
// Baker: we only want to trigger -alias if appropriate
// but we ALWAYS want to exit is key is up
if (wasgamekey) {
kb = keybindings[key];
if (kb && kb[0] == '+')
{
Q_snprintfz (cmd, sizeof(cmd), "-%s %i\n", kb+1, key);
Cbuf_AddText (cmd);
}
if (keyshift[key] != key)
{
kb = keybindings[keyshift[key]];
if (kb && kb[0] == '+')
{
Q_snprintfz (cmd, sizeof(cmd), "-%s %i\n", kb+1, key);
Cbuf_AddText (cmd);
}
}
}
return;
}
if ((kb = keybindings[key]))
{
// Baker: if we are here, the key is down
// and if it is retrigger a bind
// it must be allowed to trigger the -bind
//
keygamedown[key]=true; // Let it be untriggered anytime
if (kb[0] == '+')
{ // button commands add keynum as a parm
Q_snprintfz (cmd, sizeof(cmd), "%s %i\n", kb, key);
Cbuf_AddText (cmd);
}
else
{
Cbuf_AddText (kb);
Cbuf_AddText ("\n");
}
}
return;
{
// Baker: if we are here, the key is down
// and if it is retrigger a bind
// it must be allowed to trigger the -bind
//
keygamedown[key]=true; // Let it be untriggered anytime
if (kb[0] == '+')
{ // button commands add keynum as a parm
Q_snprintfz (cmd, sizeof(cmd), "%s %i\n", kb, key);
Cbuf_AddText (cmd);
}
else
{
Cbuf_AddText (kb);
Cbuf_AddText ("\n");
}
}
return;
Comment