summaryrefslogtreecommitdiff
path: root/source/cl_keys.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/cl_keys.c')
-rw-r--r--source/cl_keys.c918
1 files changed, 918 insertions, 0 deletions
diff --git a/source/cl_keys.c b/source/cl_keys.c
new file mode 100644
index 0000000..c60e22c
--- /dev/null
+++ b/source/cl_keys.c
@@ -0,0 +1,918 @@
+/*
+Copyright (C) 1997-2001 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+#include "cl_local.h"
+
+/*
+
+key up events are sent even if in console mode
+
+*/
+
+#define MAXCMDLINE 256
+
+keyAPI_t keys;
+
+static int anykeydown;
+
+static int key_waiting;
+static char *keybindings[256];
+
+/* if qtrue, can't be rebound while in console */
+static qboolean consolekeys[256];
+
+/* if qtrue, can't be rebound while in menu */
+static qboolean menubound[256];
+
+#ifndef USE_CHAR_EVENTS
+/* key to map to if shift held down in console
+ * used unless char events are provided by OS */
+static int keyshift[256];
+#endif /* !USE_CHAR_EVENTS */
+
+static int key_repeats[256]; /* if > 1, it is autorepeating */
+static qboolean keydown[256];
+
+static qboolean key_overstrike;
+
+typedef struct keyname_s
+{
+ char *name;
+ int keynum;
+} keyname_t;
+
+static keyname_t keynames[] =
+{
+ {"TAB", K_TAB},
+ {"ENTER", K_ENTER},
+ {"ESCAPE", K_ESCAPE},
+ {"SPACE", K_SPACE},
+ {"BACKSPACE", K_BACKSPACE},
+ {"UPARROW", K_UPARROW},
+ {"DOWNARROW", K_DOWNARROW},
+ {"LEFTARROW", K_LEFTARROW},
+ {"RIGHTARROW", K_RIGHTARROW},
+
+ {"ALT", K_ALT},
+ {"CTRL", K_CTRL},
+ {"SHIFT", K_SHIFT},
+
+ {"F1", K_F1},
+ {"F2", K_F2},
+ {"F3", K_F3},
+ {"F4", K_F4},
+ {"F5", K_F5},
+ {"F6", K_F6},
+ {"F7", K_F7},
+ {"F8", K_F8},
+ {"F9", K_F9},
+ {"F10", K_F10},
+ {"F11", K_F11},
+ {"F12", K_F12},
+
+ {"INS", K_INS},
+ {"DEL", K_DEL},
+ {"PGDN", K_PGDN},
+ {"PGUP", K_PGUP},
+ {"HOME", K_HOME},
+ {"END", K_END},
+
+ {"NUMLOCK", K_NUMLOCK},
+ {"CAPSLOCK", K_CAPSLOCK},
+ {"SCROLLOCK", K_SCROLLOCK},
+ {"LWINKEY", K_LWINKEY},
+ {"RWINKEY", K_RWINKEY},
+ {"MENU", K_MENU},
+
+ {"MOUSE1", K_MOUSE1},
+ {"MOUSE2", K_MOUSE2},
+ {"MOUSE3", K_MOUSE3},
+ {"MOUSE4", K_MOUSE4},
+ {"MOUSE5", K_MOUSE5},
+ {"MOUSE6", K_MOUSE6},
+ {"MOUSE7", K_MOUSE7},
+ {"MOUSE8", K_MOUSE8},
+
+ {"JOY1", K_JOY1},
+ {"JOY2", K_JOY2},
+ {"JOY3", K_JOY3},
+ {"JOY4", K_JOY4},
+
+ {"AUX1", K_AUX1},
+ {"AUX2", K_AUX2},
+ {"AUX3", K_AUX3},
+ {"AUX4", K_AUX4},
+ {"AUX5", K_AUX5},
+ {"AUX6", K_AUX6},
+ {"AUX7", K_AUX7},
+ {"AUX8", K_AUX8},
+ {"AUX9", K_AUX9},
+ {"AUX10", K_AUX10},
+ {"AUX11", K_AUX11},
+ {"AUX12", K_AUX12},
+ {"AUX13", K_AUX13},
+ {"AUX14", K_AUX14},
+ {"AUX15", K_AUX15},
+ {"AUX16", K_AUX16},
+ {"AUX17", K_AUX17},
+ {"AUX18", K_AUX18},
+ {"AUX19", K_AUX19},
+ {"AUX20", K_AUX20},
+ {"AUX21", K_AUX21},
+ {"AUX22", K_AUX22},
+ {"AUX23", K_AUX23},
+ {"AUX24", K_AUX24},
+ {"AUX25", K_AUX25},
+ {"AUX26", K_AUX26},
+ {"AUX27", K_AUX27},
+ {"AUX28", K_AUX28},
+ {"AUX29", K_AUX29},
+ {"AUX30", K_AUX30},
+ {"AUX31", K_AUX31},
+ {"AUX32", K_AUX32},
+
+ {"KP_HOME", K_KP_HOME },
+ {"KP_UPARROW", K_KP_UPARROW },
+ {"KP_PGUP", K_KP_PGUP },
+ {"KP_LEFTARROW", K_KP_LEFTARROW },
+ {"KP_5", K_KP_5 },
+ {"KP_RIGHTARROW", K_KP_RIGHTARROW },
+ {"KP_END", K_KP_END },
+ {"KP_DOWNARROW", K_KP_DOWNARROW },
+ {"KP_PGDN", K_KP_PGDN },
+ {"KP_ENTER", K_KP_ENTER },
+ {"KP_INS", K_KP_INS },
+ {"KP_DEL", K_KP_DEL },
+ {"KP_SLASH", K_KP_SLASH },
+ {"KP_MINUS", K_KP_MINUS },
+ {"KP_PLUS", K_KP_PLUS },
+ {"KP_MULTIPLY", K_KP_MULTIPLY },
+
+ {"MWHEELUP", K_MWHEELUP },
+ {"MWHEELDOWN", K_MWHEELDOWN },
+
+ {"PAUSE", K_PAUSE},
+
+ {"SEMICOLON", ';'}, // because a raw semicolon seperates commands
+
+ {NULL,0}
+};
+
+//============================================================================
+
+/*
+===================
+Key_GetOverstrikeMode
+===================
+*/
+qboolean Key_GetOverstrikeMode( void ) {
+ return key_overstrike;
+}
+
+/*
+===================
+Key_SetOverstrikeMode
+===================
+*/
+void Key_SetOverstrikeMode( qboolean overstrike ) {
+ key_overstrike = overstrike;
+}
+
+/*
+===================
+Key_GetDest
+===================
+*/
+keydest_t Key_GetDest( void ) {
+ return cls.key_dest;
+}
+
+/*
+===================
+Key_SetDest
+===================
+*/
+void Key_SetDest( keydest_t dest ) {
+ int diff = cls.key_dest ^ dest;
+
+ if( diff & KEY_CONSOLE ) {
+ if( dest & KEY_CONSOLE ) {
+// release all keys, to keep the character from continuing an
+// action started before a console switch
+ Key_ClearStates();
+ }
+ }
+
+ cls.key_dest = dest;
+
+// activate or deactivate mouse
+ if( diff & KEY_CONSOLE ) {
+ CL_InputActivate();
+ }
+}
+
+/*
+===================
+Key_IsDown
+===================
+*/
+qboolean Key_IsDown( int key ) {
+ if( key < 0 || key > 255 ) {
+ return qfalse;
+ }
+
+ return keydown[key];
+}
+
+/*
+===================
+Key_AnyKeyDown
+===================
+*/
+qboolean Key_AnyKeyDown( void ) {
+ return anykeydown;
+}
+
+/*
+===================
+Key_StringToKeynum
+
+Returns a key number to be used to index keybindings[] by looking at
+the given string. Single ascii characters return themselves, while
+the K_* names are matched up.
+===================
+*/
+int Key_StringToKeynum( const char *str ) {
+ keyname_t *kn;
+
+ if( !str || !str[0] )
+ return -1;
+ if( !str[1] )
+ return str[0];
+
+ for( kn=keynames ; kn->name ; kn++ ) {
+ if( !Q_stricmp( str, kn->name ) )
+ return kn->keynum;
+ }
+ return -1;
+}
+
+/*
+===================
+Key_KeynumToString
+
+Returns a string (either a single ascii char, or a K_* name) for the
+given keynum.
+FIXME: handle quote special (general escape sequence?)
+===================
+*/
+char *Key_KeynumToString( int keynum ) {
+ keyname_t *kn;
+ static char tinystr[2];
+
+ if( keynum == -1 )
+ return "<KEY NOT FOUND>";
+ if( keynum > 32 && keynum < 127 ) {
+ // printable ascii
+ tinystr[0] = keynum;
+ tinystr[1] = 0;
+ return tinystr;
+ }
+
+ for( kn=keynames ; kn->name ; kn++ )
+ if( keynum == kn->keynum )
+ return kn->name;
+
+ return "<UNKNOWN KEYNUM>";
+}
+
+/*
+===================
+Key_SetBinding
+
+Returns the name of the first key found.
+===================
+*/
+char *Key_GetBinding( const char *binding ) {
+ int key;
+
+ for( key=0 ; key<256 ; key++ ) {
+ if( keybindings[key] ) {
+ if( !Q_stricmp( keybindings[key], binding ) ) {
+ return Key_KeynumToString( key );
+ }
+ }
+ }
+
+ return "";
+}
+
+/*
+===================
+Key_EnumBindings
+===================
+*/
+int Key_EnumBindings( int key, const char *binding ) {
+ if( key < 0 ) {
+ key = 0;
+ }
+ for( ; key < 256; key++ ) {
+ if( keybindings[key] ) {
+ if( !Q_stricmp( keybindings[key], binding ) ) {
+ return key;
+ }
+ }
+ }
+
+ return -1;
+}
+
+/*
+===================
+Key_SetBinding
+===================
+*/
+void Key_SetBinding( int keynum, const char *binding ) {
+ if( keynum < 0 || keynum > 255 )
+ return;
+
+// free old bindings
+ if( keybindings[keynum] ) {
+ Z_Free( keybindings[keynum] );
+ }
+
+// allocate memory for new binding
+ keybindings[keynum] = Z_CopyString( binding );
+}
+
+static const char *Key_Name_g( const char *partial, int state ) {
+ static int length;
+ static keyname_t *k;
+ const char *name;
+
+ if( !state ) {
+ length = strlen( partial );
+ k = keynames;
+ }
+
+ while( k->name ) {
+ name = k->name;
+ k++;
+ if( !strncmp( partial, name, length ) ) {
+ return name;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+===================
+Key_Unbind_f
+===================
+*/
+static void Key_Unbind_f( void ) {
+ int b;
+
+ if( Cmd_Argc() != 2 ) {
+ Com_Printf( "unbind <key> : remove commands from a key\n" );
+ return;
+ }
+
+ b = Key_StringToKeynum( Cmd_Argv( 1 ) );
+ if( b == -1 ) {
+ Com_Printf( "\"%s\" isn't a valid key\n", Cmd_Argv( 1 ) );
+ return;
+ }
+
+ Key_SetBinding( b, NULL );
+}
+
+/*
+===================
+Key_Unbindall_f
+===================
+*/
+static void Key_Unbindall_f( void ) {
+ int i;
+
+ for( i=0 ; i<256 ; i++ )
+ if( keybindings[i] )
+ Key_SetBinding( i, NULL );
+}
+
+
+/*
+===================
+Key_Bind_f
+===================
+*/
+static void Key_Bind_f( void ) {
+ int c, b;
+
+ c = Cmd_Argc();
+
+ if( c < 2 ) {
+ Com_Printf( "bind <key> [command] : attach a command to a key\n" );
+ return;
+ }
+ b = Key_StringToKeynum( Cmd_Argv( 1 ) );
+ if( b == -1 ) {
+ Com_Printf( "\"%s\" isn't a valid key\n", Cmd_Argv( 1 ) );
+ return;
+ }
+
+ if( c == 2 ) {
+ if( keybindings[b] )
+ Com_Printf( "\"%s\" = \"%s\"\n", Cmd_Argv( 1 ), keybindings[b] );
+ else
+ Com_Printf( "\"%s\" is not bound\n", Cmd_Argv( 1 ) );
+ return;
+ }
+
+// copy the rest of the command line
+ Key_SetBinding( b, Cmd_ArgsFrom( 2 ) );
+}
+
+/*
+============
+Key_WriteBindings
+
+Writes lines containing "bind key value"
+============
+*/
+void Key_WriteBindings( fileHandle_t f ) {
+ int i;
+
+ for( i=0 ; i<256 ; i++ ) {
+ if( keybindings[i] && keybindings[i][0] ) {
+ FS_FPrintf( f, "bind %s \"%s\"\n", Key_KeynumToString( i ),
+ keybindings[i] );
+ }
+ }
+}
+
+
+/*
+============
+Key_Bindlist_f
+
+============
+*/
+static void Key_Bindlist_f( void ) {
+ int i;
+
+ for( i=0 ; i<256 ; i++ ) {
+ if( keybindings[i] && keybindings[i][0] ) {
+ Com_Printf( "%s \"%s\"\n", Key_KeynumToString( i ),
+ keybindings[i] );
+ }
+ }
+}
+
+/*
+===================
+Key_FillAPI
+===================
+*/
+void Key_FillAPI( keyAPI_t *api ) {
+ api->GetOverstrikeMode = Key_GetOverstrikeMode;
+ api->SetOverstrikeMode = Key_SetOverstrikeMode;
+ api->GetDest = Key_GetDest;
+ api->SetDest = Key_SetDest;
+
+ api->IsDown = Key_IsDown;
+ api->AnyKeyDown = Key_AnyKeyDown;
+ api->ClearStates = Key_ClearStates;
+
+ api->KeyNumToString = Key_KeynumToString;
+ api->SetBinding = Key_SetBinding;
+ api->GetBinding = Key_GetBinding;
+ api->EnumBindings = Key_EnumBindings;
+}
+
+static cmdreg_t c_keys[] = {
+ { "bind", Key_Bind_f, Key_Name_g, Cmd_Mixed_g },
+ { "unbind", Key_Unbind_f, Key_Name_g },
+ { "unbindall", Key_Unbindall_f },
+ { "bindlist", Key_Bindlist_f },
+
+ { NULL }
+};
+
+/*
+===================
+Key_Init
+===================
+*/
+void Key_Init( void ) {
+ int i;
+
+//
+// init ascii characters in console mode
+//
+ for( i = 32; i < 128; i++ )
+ consolekeys[i] = qtrue;
+ consolekeys[K_ENTER] = qtrue;
+ consolekeys[K_KP_ENTER] = qtrue;
+ consolekeys[K_TAB] = qtrue;
+ consolekeys[K_LEFTARROW] = qtrue;
+ consolekeys[K_KP_LEFTARROW] = qtrue;
+ consolekeys[K_RIGHTARROW] = qtrue;
+ consolekeys[K_KP_RIGHTARROW] = qtrue;
+ consolekeys[K_UPARROW] = qtrue;
+ consolekeys[K_KP_UPARROW] = qtrue;
+ consolekeys[K_DOWNARROW] = qtrue;
+ consolekeys[K_KP_DOWNARROW] = qtrue;
+ consolekeys[K_BACKSPACE] = qtrue;
+ consolekeys[K_HOME] = qtrue;
+ consolekeys[K_KP_HOME] = qtrue;
+ consolekeys[K_END] = qtrue;
+ consolekeys[K_KP_END] = qtrue;
+ consolekeys[K_PGUP] = qtrue;
+ consolekeys[K_KP_PGUP] = qtrue;
+ consolekeys[K_PGDN] = qtrue;
+ consolekeys[K_KP_PGDN] = qtrue;
+ consolekeys[K_SHIFT] = qtrue;
+ consolekeys[K_INS] = qtrue;
+ consolekeys[K_KP_INS] = qtrue;
+ consolekeys[K_KP_DEL] = qtrue;
+ consolekeys[K_KP_SLASH] = qtrue;
+ consolekeys[K_KP_PLUS] = qtrue;
+ consolekeys[K_KP_MINUS] = qtrue;
+ consolekeys[K_KP_5] = qtrue;
+ consolekeys[K_DEL] = qtrue;
+ consolekeys[K_CTRL] = qtrue;
+ consolekeys[K_MWHEELUP] = qtrue;
+ consolekeys[K_MWHEELDOWN] = qtrue;
+ consolekeys[K_MOUSE3] = qtrue;
+
+ consolekeys['`'] = qtrue;
+ consolekeys['~'] = qtrue;
+
+#ifndef USE_CHAR_EVENTS
+
+ for( i = 0; i < 256; i++ )
+ keyshift[i] = i;
+ for( i = 'a'; i <= 'z'; i++ )
+ keyshift[i] = i - 'a' + 'A';
+ keyshift['1'] = '!';
+ keyshift['2'] = '@';
+ keyshift['3'] = '#';
+ keyshift['4'] = '$';
+ keyshift['5'] = '%';
+ keyshift['6'] = '^';
+ keyshift['7'] = '&';
+ keyshift['8'] = '*';
+ keyshift['9'] = '(';
+ keyshift['0'] = ')';
+ keyshift['-'] = '_';
+ keyshift['='] = '+';
+ keyshift[','] = '<';
+ keyshift['.'] = '>';
+ keyshift['/'] = '?';
+ keyshift[';'] = ':';
+ keyshift['\''] = '"';
+ keyshift['['] = '{';
+ keyshift[']'] = '}';
+ keyshift['`'] = '~';
+ keyshift['\\'] = '|';
+
+#endif /* !USE_CHAR_EVENTS */
+
+ menubound[K_ESCAPE] = qtrue;
+ for( i = 0; i < 12; i++ )
+ menubound[K_F1+i] = qtrue;
+
+//
+// register our functions
+//
+ Cmd_Register( c_keys );
+
+ Key_FillAPI( &keys );
+}
+
+/*
+===================
+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( uint32 key, qboolean down, uint32 time ) {
+ char *kb;
+ char cmd[MAX_STRING_CHARS];
+
+ // hack for modal presses
+ if( key_waiting == -1 ) {
+ if( down )
+ key_waiting = key;
+ return;
+ }
+
+ // update auto-repeat status
+ if( down ) {
+ key_repeats[key]++;
+ if( !( cls.key_dest & (KEY_CONSOLE|KEY_MESSAGE|KEY_MENU) )
+ && 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] && !consolekeys[key] ) {
+ Com_Printf( "%s is unbound, hit F4 to set.\n",
+ Key_KeynumToString( key ) );
+ }
+ } else {
+ key_repeats[key] = 0;
+ }
+
+ // console key is hardcoded, so the user can never unbind it
+ if( !keydown[K_SHIFT] && ( key == '`' || key == '~' ) ) {
+ if( down ) {
+ Con_ToggleConsole_f();
+ }
+ return;
+ }
+
+ // Alt+Enter is hardcoded for all systems
+ if( keydown[K_ALT] && key == K_ENTER ) {
+ if( down ) {
+ Cvar_SetInteger( "vid_fullscreen",
+ !Cvar_VariableInteger( "vid_fullscreen" ) );
+ Cbuf_AddText( "vid_restart\n" );
+ }
+ return;
+ }
+
+ // any key during the attract mode will bring up the menu
+ if( cl.attractLoop == ATR_DEMO &&
+ !cls.demoplayback &&
+ !( 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( key_repeats[key] > 1 ) {
+ return;
+ }
+
+ if( cls.key_dest == KEY_GAME &&
+ !cls.demoplayback &&
+ cl.clientNum != -1 &&
+ cl.frame.ps.stats[STAT_LAYOUTS] )
+ {
+ // put away help computer / inventory
+ Cbuf_AddText( "cmd putaway\n" );
+ //return;
+ }
+
+ if( cls.state > ca_disconnected && cls.state < ca_active ) {
+ if( cls.key_dest & KEY_CONSOLE ) {
+ Con_Close();
+ } else {
+ CL_Disconnect( ERR_SILENT, NULL );
+ }
+ return;
+ }
+
+ if( cls.key_dest & KEY_CONSOLE ) {
+ if( cls.state == ca_disconnected && !( cls.key_dest & KEY_MENU ) ) {
+ UI_OpenMenu( UIMENU_MAIN_FORCE );
+ }
+ Con_Close();
+ } 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_INGAME );
+ } else {
+ UI_OpenMenu( UIMENU_MAIN_FORCE );
+ }
+ 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;
+ }
+
+ if( ( cls.key_dest == KEY_GAME ) ||
+ ( ( cls.key_dest & KEY_CONSOLE ) && !consolekeys[key] ) ||
+ ( ( cls.key_dest & KEY_MENU ) && menubound[key] ) )
+ {
+
+//
+// key up events only generate commands if the game key binding is
+// a button command (leading + sign).
+// 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_sprintf( cmd, sizeof( cmd ), "-%s %i %i\n",
+ kb + 1, key, time );
+ Cbuf_InsertText( cmd );
+ }
+#ifndef USE_CHAR_EVENTS
+ if( keyshift[key] != key ) {
+ kb = keybindings[keyshift[key]];
+ if( kb && kb[0] == '+' ) {
+ Com_sprintf( cmd, sizeof( cmd ), "-%s %i %i\n",
+ kb + 1, key, time );
+ Cbuf_InsertText( cmd );
+ }
+ }
+#endif
+ return;
+ }
+
+//
+// if not a consolekey, send to the interpreter no matter what mode is
+//
+ if( key_repeats[key] > 1 ) {
+ return;
+ }
+
+ kb = keybindings[key];
+ if( kb ) {
+ if( kb[0] == '+' ) {
+ // button commands add keynum and time as a parm
+ Com_sprintf( cmd, sizeof( cmd ), "%s %i %i\n", kb, key, time );
+ Cbuf_InsertText( cmd );
+ } else {
+ Cbuf_InsertText( kb );
+ Cbuf_InsertText( "\n" );
+ }
+ }
+ 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 );
+ }
+
+#ifndef USE_CHAR_EVENTS
+
+ if( keydown[K_CTRL] || keydown[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( keydown[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 );
+ }
+
+#endif /* !USE_CHAR_EVENTS */
+
+}
+
+#ifdef USE_CHAR_EVENTS
+
+/*
+===================
+Key_CharEvent
+===================
+*/
+void Key_CharEvent( int key ) {
+ if( key == '`' || key == '~' ) {
+ return;
+ }
+
+ 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 );
+ }
+}
+
+#endif /* USE_CHAR_EVENTS */
+
+/*
+===================
+Key_ClearStates
+===================
+*/
+void Key_ClearStates( void ) {
+ int i;
+
+ for( i = 0; i < 256; i++ ) {
+ if( keydown[i] || key_repeats[i] )
+ Key_Event( i, qfalse, 0 );
+ keydown[i] = 0;
+ key_repeats[i] = 0;
+ }
+
+ anykeydown = 0;
+}
+
+
+
+
+