Tutorial: Fixing annoying -alias keypress in standard Quake

Post tutorials on how to do certain tasks within game or engine code here.
Post Reply
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Tutorial: Fixing annoying -alias keypress in standard Quake

Post by Baker »

I think Inside3d should serve as the central depot for engine code now that Quakesrc.org is dead and it is clear it won't ever be back. Here is a tutorial I made a while back @ QuakeOne.com (original thread) and I think this is needs to be here:

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 (if you are using an engine that supports that).

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.

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 ();
}
And the Key_ClearStates from GLQuake:
/*
===================
Key_ClearStates
===================
*/
void Key_ClearStates (void)
{
int i;

for (i=0 ; i<256 ; i++)
{
keydown = false;
key_repeats = 0;
}
}


Note that the above is setting the down state to false.

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;
}
}


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.

Code: Select all

/*
==================
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 ();
}
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.
//At the top of keys.c

qboolean keygamedown[256];
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.
//keys.c in Key_Event
qboolean wasgamekey = false;
And we need to set this variable immediately after "keydown[key] = down;"

Code: Select all

//keys.c in Key_Event 

	wasgamekey = keygamedown[key]; // Baker: to prevent -aliases being triggered in-console needlessly		
	if (!down) {
		keygamedown[key] = false;
	}
Now we need to find this to make it only execute the -alias if the key was triggered in the game:
if (!down)
{
// Baker: we only want to trigger -alias if appropriate
// but we ALWAYS want to exit if 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;
}
And finally, we need to have it set the keygamedown ONLY when the +alias is executed:
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;
Post Reply