Esempio n. 1
0
/*
===================
Key_Event

Called by the system for both key up and key down events
===================
*/
void Key_Event( int key, qboolean down )
{
	const char	*kb;
	char		cmd[1024];
	//Con_Printf( "Keycode %d\n", key );
	if ( key > 255 || key < 0) 
	{
		Con_Printf ("Keynum %d out of range\n", key);
		return;
	}
	// update auto-repeat status and BUTTON_ANY status
	keys[key].down = down;

	if( down )
	{
		//keys[key].repeats++;

		if( key != K_BACKSPACE && key != K_PAUSE && keys[key].repeats > 1 )
		{
			if( cls.key_dest == key_game )
			{
				// ignore most autorepeats
				return;
			}
		}
	}
	else
	{
		keys[key].repeats = 0;
	}

	// console key is hardcoded, so the user can never unbind it
	if( key == '`' || key == '~' )
	{
		// we are in typing mode, so don't switch to console
		if( cls.key_dest == key_message || !down )
			return;

		Con_ToggleConsole_f();
		return;
	}

	// escape is always handled specially
	if( key == K_ESCAPE && down )
	{
		switch( cls.key_dest )
		{
		case key_game:
			if( host.mouse_visible && cls.state != ca_cinematic )
			{
				clgame.dllFuncs.pfnKey_Event( down, key, keys[key].binding );
				return; // handled in client.dll
			}
			break;
		case key_message:
			Key_Message( key );
			return;
		case key_console:
			if( cls.state == ca_active && !cl.background )
				Key_SetKeyDest( key_game );
			else UI_SetActiveMenu( true );
			return;
		case key_menu:
			UI_KeyEvent( key, true );
			return;
		default:
			MsgDev( D_ERROR, "Key_Event: bad cls.key_dest\n" );
			return;
		}
	}

	if( cls.key_dest == key_menu )
	{
		// only non printable keys passed
		UI_KeyEvent( key, down );
		return;
	}

	// key up events only perform actions if the game key binding is
	// a button command (leading + sign).  These will be processed even in
	// console mode and menu mode, to keep the character from continuing 
	// an action started before a mode switch.
	if( !down )
	{
		kb = keys[key].binding;

		if( cls.key_dest == key_game && ( key != K_ESCAPE ))
			clgame.dllFuncs.pfnKey_Event( down, key, kb );

		Key_AddKeyUpCommands( key, kb );
		return;
	}

	// distribute the key down event to the apropriate handler
	if( cls.key_dest == key_game )
	{
		if( cls.state == ca_cinematic )
		{
			// only escape passed when cinematic is playing
			// HLFX 0.6 bug: crash in vgui3.dll while press +attack during movie playback
			if( key != K_ESCAPE || !down )
				return;
		}
		else if( host.mouse_visible )
			return;

		// send the bound action
		kb = keys[key].binding;

		if( !clgame.dllFuncs.pfnKey_Event( down, key, keys[key].binding ))
		{
			// handled in client.dll
		}
		else if( kb != NULL )
		{
			if( kb[0] == '+' )
			{	
				int	i;
				char	button[1024], *buttonPtr;

				for( i = 0, buttonPtr = button; ; i++ )
				{
					if( kb[i] == ';' || !kb[i] )
					{
						*buttonPtr = '\0';
						if( button[0] == '+' )
						{
							Q_sprintf( cmd, "%s %i\n", button, key );
							Cbuf_AddText( cmd );
						}
						else
						{
							// down-only command
							Cbuf_AddText( button );
							Cbuf_AddText( "\n" );
						}

						buttonPtr = button;
						while (( kb[i] <= ' ' || kb[i] == ';' ) && kb[i] != 0 )
							i++;
					}

					*buttonPtr++ = kb[i];
					if( !kb[i] ) break;
				}
			}
			else
			{
				// down-only command
				Cbuf_AddText( kb );
				Cbuf_AddText( "\n" );
			}
		}
	}
	else if( cls.key_dest == key_console )
	{
		Key_Console( key );
	}
	else if( cls.key_dest == key_message )
	{
		Key_Message( key );
	}
}
Esempio n. 2
0
/**
 * @brief Called by the system between frames for both key up and key down events
 * @note Should NOT be called during an interrupt!
 * @sa Key_Message
 */
void Key_Event (unsigned int key, unsigned short unicode, qboolean down, unsigned time)
{
	char cmd[MAX_STRING_CHARS];

	/* unbindable key */
	if (key >= K_KEY_SIZE)
		return;

	/* any key (except F1-F12) during the sequence mode will bring up the menu */

	if (cls.keyDest == key_game && down) {
		if (UI_KeyPressed(key, unicode))
			return;
	}

	/* menu key is hardcoded, so the user can never unbind it */
	if (key == K_ESCAPE) {
		if (!down)
			return;

		switch (cls.keyDest) {
		case key_console:
			Con_ToggleConsole_f();
			break;
		default:
			Com_Error(ERR_FATAL, "Bad cls.key_dest");
		}
		return;
	}

	/* track if any key is down for BUTTON_ANY */
	keyDown[key] = down;
	if (!down) {
		int i;
		/* key up events only generate commands if the game key binding is
		 * a button command (leading + sign).  These will occur even in console mode,
		 * to keep the character from continuing an action started before a console
		 * switch.  Button commands include the kenum as a parameter, so multiple
		 * downs can be matched with ups */
		const char *kb = menuKeyBindings[key];
		/* this loop ensures, that every down event reaches it's proper kbutton_t */
		for (i = 0; i < 3; i++) {
			if (kb && kb[0] == '+') {
				/* '-' means we have released the key
				 * the key number is used to determine whether the kbutton_t is really
				 * released or whether any other bound key will still ensure that the
				 * kbutton_t is pressed
				 * the time is the msec value when the key was released */
				Com_sprintf(cmd, sizeof(cmd), "-%s %i %i\n", kb + 1, key, time);
				Cbuf_AddText(cmd);
			}
			if (i == 0)
				kb = keyBindings[key];
			else
				kb = battleKeyBindings[key];
		}
		return;
	}

	/* if not a consolekey, send to the interpreter no matter what mode is */
	if (cls.keyDest == key_game || (key >= K_MOUSE1 && key <= K_MWHEELUP)) {
		/* Some keyboards need modifiers to access key values that are
		 * present as bare keys on other keyboards. Smooth over the difference
		 * here by using the translated value if there is a binding for it. */
		const char *kb = NULL;
		if (mouseSpace == MS_UI && unicode >= 32 && unicode < 127)
			kb = menuKeyBindings[unicode];
		if (!kb && mouseSpace == MS_UI)
			kb = menuKeyBindings[key];
		if (!kb && unicode >= 32 && unicode < 127)
			kb = keyBindings[unicode];
		if (!kb)
			kb = keyBindings[key];
		if (!kb && CL_OnBattlescape())
			kb = battleKeyBindings[key];
		if (kb) {
			if (kb[0] == '+') {	/* button commands add keynum and time as a parm */
				/* '+' means we have pressed the key
				 * the key number is used because the kbutton_t can be 'pressed' by several keys
				 * the time is the msec value when the key was pressed */
				Com_sprintf(cmd, sizeof(cmd), "%s %i %i\n", kb, key, time);
				Cbuf_AddText(cmd);
			} else {
				Cbuf_AddText(kb);
				Cbuf_AddText("\n");
			}
			if (cls.keyDest == key_game)
				return;
		}
	}

	if (!down)
		return;	/* other systems only care about key down events */

	switch (cls.keyDest) {
	case key_game:
	case key_console:
		Key_Console(key, unicode);
		break;
	default:
		Com_Error(ERR_FATAL, "Bad cls.key_dest");
	}
}
Esempio n. 3
0
/*
===================
Key_Event

Called by the system between frames for both key up and key down events
Should NOT be called during an interrupt!
===================
*/
void Key_Event(unsigned key, qboolean down, unsigned time)
{
    char    *kb;
    char    cmd[MAX_STRING_CHARS];

    if (key >= 256) {
        Com_Error(ERR_FATAL, "%s: bad key", __func__);
    }

    Com_DDDPrintf("%u: %c%s\n", time,
                  down ? '+' : '-', Key_KeynumToString(key));

    // hack for menu key binding
    if (key_wait_cb && down && !key_wait_cb(key_wait_arg, key)) {
        return;
    }

    // update key down and auto-repeat status
    if (down) {
        if (keydown[key] < 255)
            keydown[key]++;
    } else {
        keydown[key] = 0;
    }

    // console key is hardcoded, so the user can never unbind it
    if (!Key_IsDown(K_SHIFT) && (key == '`' || key == '~')) {
        if (keydown[key] == 1) {
            Con_ToggleConsole_f();
        }
        return;
    }

    // Alt+Enter is hardcoded for all systems
    if (Key_IsDown(K_ALT) && key == K_ENTER) {
        if (keydown[key] == 1) {
            VID_ToggleFullscreen();
        }
        return;
    }

    // menu key is hardcoded, so the user can never unbind it
    if (key == K_ESCAPE) {
        if (!down) {
            return;
        }

        if (cls.key_dest == KEY_GAME &&
            cl.frame.ps.stats[STAT_LAYOUTS] &&
            cls.demo.playback == qfalse) {
            if (keydown[key] == 2) {
                // force main menu if escape is held
                UI_OpenMenu(UIMENU_GAME);
            } else if (keydown[key] == 1) {
                // put away help computer / inventory
                CL_ClientCommand("putaway");
            }
            return;
        }

        // ignore autorepeats
        if (keydown[key] > 1) {
            return;
        }

        if (cls.key_dest & KEY_CONSOLE) {
            if (cls.state < ca_active && !(cls.key_dest & KEY_MENU)) {
                UI_OpenMenu(UIMENU_MAIN);
            } else {
                Con_Close(qtrue);
            }
        } else if (cls.key_dest & KEY_MENU) {
            UI_Keydown(key);
        } else if (cls.key_dest & KEY_MESSAGE) {
            Key_Message(key);
        } else if (cls.state == ca_active) {
            UI_OpenMenu(UIMENU_GAME);
        } else {
            UI_OpenMenu(UIMENU_MAIN);
        }
        return;
    }

    // track if any key is down for BUTTON_ANY
    if (down) {
        if (keydown[key] == 1)
            anykeydown++;
    } else {
        anykeydown--;
        if (anykeydown < 0)
            anykeydown = 0;
    }

    // hack for demo freelook in windowed mode
    if (cls.key_dest == KEY_GAME && cls.demo.playback && key == K_SHIFT && keydown[key] <= 1) {
        IN_Activate();
    }

//
// if not a consolekey, send to the interpreter no matter what mode is
//
    if ((cls.key_dest == KEY_GAME) ||
        ((cls.key_dest & KEY_CONSOLE) && !Q_IsBitSet(consolekeys, key)) ||
        ((cls.key_dest & KEY_MENU) && (key >= K_F1 && key <= K_F12)) ||
        (!down && Q_IsBitSet(buttondown, key))) {
//
// Key up events only generate commands if the game key binding is a button
// command (leading + sign). These will occur even in console mode, to keep the
// character from continuing an action started before a console switch. Button
// commands include the kenum as a parameter, so multiple downs can be matched
// with ups.
//
        if (!down) {
            kb = keybindings[key];
            if (kb && kb[0] == '+') {
                Q_snprintf(cmd, sizeof(cmd), "-%s %i %i\n",
                           kb + 1, key, time);
                Cbuf_AddText(&cmd_buffer, cmd);
            }
            Q_ClearBit(buttondown, key);
            return;
        }

        // ignore autorepeats
        if (keydown[key] > 1) {
            return;
        }

        // generate button up command when released
        Q_SetBit(buttondown, key);

        kb = keybindings[key];
        if (kb) {
            if (kb[0] == '+') {
                // button commands add keynum and time as a parm
                Q_snprintf(cmd, sizeof(cmd), "%s %i %i\n", kb, key, time);
                Cbuf_AddText(&cmd_buffer, cmd);
            } else {
                Cbuf_AddText(&cmd_buffer, kb);
                Cbuf_AddText(&cmd_buffer, "\n");
            }
        }
        return;
    }

    if (cls.key_dest == KEY_GAME)
        return;

    if (!down)
        return;     // other subsystems only care about key down events

    if (cls.key_dest & KEY_CONSOLE) {
        Key_Console(key);
    } else if (cls.key_dest & KEY_MENU) {
        UI_Keydown(key);
    } else if (cls.key_dest & KEY_MESSAGE) {
        Key_Message(key);
    }

    if (Key_IsDown(K_CTRL) || Key_IsDown(K_ALT)) {
        return;
    }

    switch (key) {
    case K_KP_SLASH:
        key = '/';
        break;
    case K_KP_MULTIPLY:
        key = '*';
        break;
    case K_KP_MINUS:
        key = '-';
        break;
    case K_KP_PLUS:
        key = '+';
        break;
    case K_KP_HOME:
        key = '7';
        break;
    case K_KP_UPARROW:
        key = '8';
        break;
    case K_KP_PGUP:
        key = '9';
        break;
    case K_KP_LEFTARROW:
        key = '4';
        break;
    case K_KP_5:
        key = '5';
        break;
    case K_KP_RIGHTARROW:
        key = '6';
        break;
    case K_KP_END:
        key = '1';
        break;
    case K_KP_DOWNARROW:
        key = '2';
        break;
    case K_KP_PGDN:
        key = '3';
        break;
    case K_KP_INS:
        key = '0';
        break;
    case K_KP_DEL:
        key = '.';
        break;
    }

    // if key is printable, generate char events
    if (key < 32 || key >= 127) {
        return;
    }

    if (Key_IsDown(K_SHIFT)) {
        key = keyshift[key];
    }

    if (cls.key_dest & KEY_CONSOLE) {
        Char_Console(key);
    } else if (cls.key_dest & KEY_MENU) {
        UI_CharEvent(key);
    } else if (cls.key_dest & KEY_MESSAGE) {
        Char_Message(key);
    }
}
Esempio n. 4
0
File: keys.c Progetto: Slipyx/r1q2
/*
===================
Key_Event

Called by the system between frames for both key up and key down events
Should NOT be called during an interrupt!
===================
*/
void Key_Event (int key, qboolean down, uint32 time)
{
	char		*kb;
	char		cmd[1024];

	// hack for modal presses
	/*if (key_waiting == -1)
	{
		if (down)
			key_waiting = key;
		return;
		}*/

	//Com_Printf ("%d is %d for %u\n", LOG_GENERAL, key, down, time);

	// update auto-repeat status
	if (down)
	{
		key_repeats[key]++;
		if (cls.key_dest != key_console && key != K_BACKSPACE && key != K_DEL && key != K_LEFTARROW && key != K_RIGHTARROW
			&& key != K_PAUSE 
			&& key != K_PGUP 
			&& key != K_KP_PGUP 
			&& key != K_PGDN
			&& key != K_KP_PGDN
			&& key_repeats[key] > 1)
			return;	// ignore most autorepeats
			
		if (key >= 200 && !keybindings[key])
			Com_Printf ("%s is unbound, hit F4 to set.\n", LOG_CLIENT, Key_KeynumToString (key) );
	}
	else
	{
		key_repeats[key] = 0;
	}

	//for dinput
	if (down && keydown[K_ALT])
	{
		if (key == K_ENTER)
		{
			Com_Printf ("ALT+Enter, setting fullscreen %d.\n", LOG_CLIENT, !vid_fullscreen->intvalue);
			Cvar_SetValue( "vid_fullscreen", (float)!vid_fullscreen->intvalue );
			return;
		}
		else if (key == K_TAB)
		{
			//prevent executing action on alt+tab
			return;
		}
	}

	if (key == K_SHIFT)
		shift_down = down;

	// console key is hardcoded, so the user can never unbind it
	if ((key == '`' || key == '~') && !shift_down)
	{
		if (!down)
			return;
		Con_ToggleConsole_f ();
		return;
	}

	// any key during the attract mode will bring up the menu
	/*if (cl.attractloop && cls.key_dest != key_menu &&
		!(key >= K_F1 && key <= K_F12))
		key = K_ESCAPE;*/

	// menu key is hardcoded, so the user can never unbind it
	if (key == K_ESCAPE)
	{
		if (!down)
			return;

		if (cl.frame.playerstate.stats[STAT_LAYOUTS] && cls.key_dest == key_game)
		{	// put away help computer / inventory
			Cbuf_AddText ("cmd putaway\n");
			return;
		}
		switch (cls.key_dest)
		{
		case key_message:
			Key_Message (key);
			break;
		case key_menu:
			M_Keydown (key);
			break;
		case key_game:
		case key_console:
			M_Menu_Main_f ();
			break;
		default:
			Com_Error (ERR_FATAL, "Bad cls.key_dest");
		}
		return;
	}

	if (!keydown[key])
		key_lastrepeat[key] = curtime + key_repeatdelay;

	// track if any key is down for BUTTON_ANY
	keydown[key] = down;
	if (down)
	{
		if (key_repeats[key] == 1)
			anykeydown++;
	}
	else
	{
		key_lastrepeat[key] = 0;

		anykeydown--;
		if (anykeydown < 0)
			anykeydown = 0;
	}

//
// key up events only generate commands if the game key binding is
// a button command (leading + sign).  These will occur even in console mode,
// to keep the character from continuing an action started before a console
// switch.  Button commands include the kenum as a parameter, so multiple
// downs can be matched with ups
//
	if (!down)
	{
		//r1ch: only generate -events if key was down (prevents -binds in menu / messagemode)
		if (buttondown[key])
		{
			kb = keybindings[key];
			if (kb && kb[0] == '+')
			{
				Com_sprintf (cmd, sizeof(cmd), "-%s %i %u\n", kb+1, key, time);
				Cbuf_AddText (cmd);
			}
			if (keyshift[key] != key)
			{
				kb = keybindings[keyshift[key]];
				if (kb && kb[0] == '+')
				{
					Com_sprintf (cmd, sizeof(cmd), "-%s %i %u\n", kb+1, key, time);
					Cbuf_AddText (cmd);
				}
			}
			buttondown[key] = false;
		}
		return;
	}

//
// if not a consolekey, send to the interpreter no matter what mode is
//
	if ( (cls.key_dest == key_menu && menubound[key])
	|| (cls.key_dest == key_console && !consolekeys[key])
	|| (cls.key_dest == key_game && ( cls.state == ca_active || !consolekeys[key] ) ) )
	{
		kb = keybindings[key];
		if (kb && kb[0])
		{
			if (kb[0] == '+')
			{	
				// button commands add keynum and time as a parm
				if (cls.key_dest != key_game) //r1: don't run buttons in console
					return;
				Com_sprintf (cmd, sizeof(cmd), "%s %i %u\n", kb, key, time);
				Cbuf_AddText (cmd);
				buttondown[key] = true;
			}
			else
			{
				Cbuf_AddText (kb);
				Cbuf_AddText ("\n");
			}
		}
		return;
	}

	//if (!down)
	//	return;		// other systems only care about key down events

	if (shift_down)
		key = keyshift[key];

	switch (cls.key_dest)
	{
	case key_message:
		Key_Message (key);
		break;
	case key_menu:
		M_Keydown (key);
		break;

	case key_game:
	case key_console:
		Key_Console (key);
		break;
	default:
		Com_Error (ERR_FATAL, "Bad cls.key_dest");
	}
}
Esempio n. 5
0
/*
===================
Key_Event

Called by the system between frames for both key up and key down events
Should NOT be called during an interrupt!
===================
*/
void Key_Event (int key, qboolean down)
{
	char	*kb;
	char	cmd[1024];

	keydown[key] = down;

	if (!down)
		key_repeats[key] = 0;

	key_lastpress = key;
	key_count++;
	if (key_count <= 0)
		return;		// just catching keys for Con_NotifyBox

// update auto-repeat status
	if (down)
	{
		/* Pause key doesn't generate a scancode when released,
		 * never increment its auto-repeat status.
		 */
		if (key != K_PAUSE && key != K_KP_NUMLOCK)
			key_repeats[key]++;
#if 0
		if (key != K_BACKSPACE && key != K_PGUP && key != K_PGDN &&
					key_repeats[key] > 1)
			return;	// ignore most autorepeats
#endif
		if (key_repeats[key] > 1)
		{
			if (key_dest == key_game && !con_forcedup)
				return;	// ignore autorepeats in game mode
		}
		else if (key >= 200 && !keybindings[key])
			Con_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString(key));
	}

	if (key == K_SHIFT)
		shift_down = down;

// handle escape specialy, so the user can never unbind it
	if (key == K_ESCAPE)
	{
		if (!down)
			return;
		switch (key_dest)
		{
		case key_message:
			Key_Message (key);
			break;
		case key_menu:
			M_Keydown (key);
			break;
		case key_menubind:
			M_Keybind (key);
			break;
		case key_game:
		case key_console:
			M_ToggleMenu_f ();
			break;
		default:
			Sys_Error ("Bad key_dest");
		}
		return;
	}

// key up events only generate commands if the game key binding is
// a button command (leading + sign).  These will occur even in console mode,
// to keep the character from continuing an action started before a console
// switch.  Button commands include the kenum as a parameter, so multiple
// downs can be matched with ups
	if (!down)
	{
		kb = keybindings[key];
		if (kb && kb[0] == '+')
		{
			sprintf (cmd, "-%s %i\n", kb+1, key);
			Cbuf_AddText (cmd);
		}
		if (keyshift[key] != key)
		{
			kb = keybindings[keyshift[key]];
			if (kb && kb[0] == '+')
			{
				sprintf (cmd, "-%s %i\n", kb+1, key);
				Cbuf_AddText (cmd);
			}
		}
		return;
	}

// during demo playback, most keys bring up the main menu
	if (cls.demoplayback && down && consolekeys[key] && key_dest == key_game)
	{
		M_ToggleMenu_f ();
		return;
	}

// if not a consolekey, send to the interpreter no matter what mode is
	if (((key_dest & key_menu) && menubound[key]) ||
	    (key_dest == key_console && !consolekeys[key]) ||
	    (key_dest == key_game && (!con_forcedup || !consolekeys[key])))
	{
		kb = keybindings[key];
		if (kb)
		{
			if (kb[0] == '+')
			{	// button commands add keynum as a parm
				sprintf (cmd, "%s %i\n", kb, key);
				Cbuf_AddText (cmd);
			}
			else
			{
				Cbuf_AddText (kb);
				Cbuf_AddText ("\n");
			}
		}
		return;
	}

	if (!down)
		return;		// other systems only care about key down events

	if (shift_down)
		key = keyshift[key];

	switch (key_dest)
	{
	case key_message:
		Key_Message (key);
		break;
	case key_menu:
		M_Keydown (key);
		break;
	case key_menubind:
		M_Keybind (key);
		break;
	case key_game:
	case key_console:
		Key_Console (key);
		break;
	default:
		Sys_Error ("Bad key_dest");
	}
}
Esempio n. 6
0
/**
 * \brief Called by the system between frames for both key up and key down events.
 * \param[in] key Key mapping
 * \param[in] down Is key being pressed?
 * \param[in] time
 * \note Should NOT be called during an interrupt!
 */
PUBLIC void Key_Event( int key, _boolean down, unsigned time )
{
    char    *kb;
    char    cmd[ 1024 ];

    // hack for modal presses
    if (key_waiting == -1)
    {
        if (down)
        {
            key_waiting = key;
        }
        return;
    }

    // update auto-repeat status
    if (down)
    {
        key_repeats[key]++;
        if (key != K_BACKSPACE
                && key != K_PAUSE
                && key != K_PGUP
                && key != K_KP_PGUP
                && key != K_PGDN
                && key != K_KP_PGDN
                && key_repeats[key] > 1)
        {
            return; // ignore most autorepeats
        }

        if (key >= 200 && !keybindings[key])
        {
            Com_Printf ( "%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
        }
    }
    else
    {
        key_repeats[ key ] = 0;
    }

	if( key == K_SHIFT )
	{
		shift_down = down;
	}

	// console key is hardcoded, so the user can never unbind it
	if( key == '`' || key == '~' )
	{
		if( ! down )
		{
			return;
		}

		Con_ToggleConsole_f();
		return;
	}

        // any key during the attract mode will bring up the menu
//      if (cl.attractloop && ClientStatic.key_dest != key_menu &&
//              !(key >= K_F1 && key <= K_F12))
//              key = K_ESCAPE;

        // menu key is hardcoded, so the user can never unbind it
    if( key == K_ESCAPE )
    {
        if( ! down )
        {
            return;
        }
//              if (cl.frame.playerstate.stats[STAT_LAYOUTS] && ClientStatic.key_dest == key_game)
//              {       // put away help computer / inventory
//                      Cbuf_AddText ("cmd putaway\n");
//                      return;
//              }

        switch( ClientStatic.key_dest )
        {
            case key_message:
                    Key_Message( key );
                    break;

            case KEY_AUTOMAP:
                    automap_keydown( key );
                    break;

            case key_menu:
                    M_Keydown( key );
                    break;

            case key_game:
            case key_console:
                    M_Menu_Main_f();
                    break;

            default:
                    Com_DPrintf( "Bad ClientStatic.key_dest\n" );
        }
        return;
    }

    // track if any key is down for BUTTON_ANY
    keydown[key] = down;
    if (down)
    {
        if (key_repeats[key] == 1)
        {
            anykeydown++;
        }
    }
    else
    {
        anykeydown--;
        if (anykeydown < 0)
        {
            anykeydown = 0;
        }
    }

//
// key up events only generate commands if the game key binding is
// a button command (leading + sign).  These will occur even in console mode,
// to keep the character from continuing an action started before a console
// switch.  Button commands include the kenum as a parameter, so multiple
// downs can be matched with ups
//
    if( ! down )
    {
        kb = keybindings[key];
        if (kb && kb[0] == '+')
        {
            com_snprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
            Cbuf_AddText (cmd);
        }
        if (keyshift[key] != key)
        {
            kb = keybindings[keyshift[key]];
            if (kb && kb[0] == '+')
            {
                com_snprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
                Cbuf_AddText (cmd);
            }
        }
        return;
    }

//
// if not a consolekey, send to the interpreter no matter what mode is
//
    if ( (ClientStatic.key_dest == key_menu && menubound[key])
        || (ClientStatic.key_dest == key_console && !consolekeys[key])
        || (ClientStatic.key_dest == key_game ) )
    {
        kb = keybindings[key];
        if (kb)
        {
            if (kb[0] == '+')
            {       // button commands add keynum and time as a parm
                com_snprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time);
                Cbuf_AddText (cmd);
            }
            else
            {
                Cbuf_AddText (kb);
                Cbuf_AddText ("\n");
            }
        }
        return;
    }

    if( ! down )
	{
		return;         // other systems only care about key down events
	}

    if (shift_down)
	{
		key = keyshift[ key ];
	}

    switch (ClientStatic.key_dest)
    {
        case KEY_AUTOMAP:
                automap_keydown( key );
                break;

        case key_message:
                Key_Message (key);
                break;
        case key_menu:
                M_Keydown (key);
                break;

        case key_game:
        case key_console:
                Key_Console (key);
                break;

        default:
                Com_DPrintf( "Bad ClientStatic.key_dest\n" );
    }
}