2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
35 char *strId; // localized string id
38 // keys that can be set without a special name
39 static const char unnamedkeys[] = "*,-=./[\\]1234567890abcdefghijklmnopqrstuvwxyz";
42 const char* OSX_GetLocalizedString( const char* );
45 // names not in this list can either be lowercase ascii, or '0xnn' hex sequences
46 keyname_t keynames[] =
48 {"TAB", K_TAB, "#str_07018"},
49 {"ENTER", K_ENTER, "#str_07019"},
50 {"ESCAPE", K_ESCAPE, "#str_07020"},
51 {"SPACE", K_SPACE, "#str_07021"},
52 {"BACKSPACE", K_BACKSPACE, "#str_07022"},
53 {"UPARROW", K_UPARROW, "#str_07023"},
54 {"DOWNARROW", K_DOWNARROW, "#str_07024"},
55 {"LEFTARROW", K_LEFTARROW, "#str_07025"},
56 {"RIGHTARROW", K_RIGHTARROW, "#str_07026"},
58 {"ALT", K_ALT, "#str_07027"},
59 {"RIGHTALT", K_RIGHT_ALT, "#str_07027"},
60 {"CTRL", K_CTRL, "#str_07028"},
61 {"SHIFT", K_SHIFT, "#str_07029"},
63 {"LWIN", K_LWIN, "#str_07030"},
64 {"RWIN", K_RWIN, "#str_07031"},
65 {"MENU", K_MENU, "#str_07032"},
67 {"COMMAND", K_COMMAND, "#str_07033"},
69 {"CAPSLOCK", K_CAPSLOCK, "#str_07034"},
70 {"SCROLL", K_SCROLL, "#str_07035"},
71 {"PRINTSCREEN", K_PRINT_SCR, "#str_07179"},
73 {"F1", K_F1, "#str_07036"},
74 {"F2", K_F2, "#str_07037"},
75 {"F3", K_F3, "#str_07038"},
76 {"F4", K_F4, "#str_07039"},
77 {"F5", K_F5, "#str_07040"},
78 {"F6", K_F6, "#str_07041"},
79 {"F7", K_F7, "#str_07042"},
80 {"F8", K_F8, "#str_07043"},
81 {"F9", K_F9, "#str_07044"},
82 {"F10", K_F10, "#str_07045"},
83 {"F11", K_F11, "#str_07046"},
84 {"F12", K_F12, "#str_07047"},
86 {"INS", K_INS, "#str_07048"},
87 {"DEL", K_DEL, "#str_07049"},
88 {"PGDN", K_PGDN, "#str_07050"},
89 {"PGUP", K_PGUP, "#str_07051"},
90 {"HOME", K_HOME, "#str_07052"},
91 {"END", K_END, "#str_07053"},
93 {"MOUSE1", K_MOUSE1, "#str_07054"},
94 {"MOUSE2", K_MOUSE2, "#str_07055"},
95 {"MOUSE3", K_MOUSE3, "#str_07056"},
96 {"MOUSE4", K_MOUSE4, "#str_07057"},
97 {"MOUSE5", K_MOUSE5, "#str_07058"},
98 {"MOUSE6", K_MOUSE6, "#str_07059"},
99 {"MOUSE7", K_MOUSE7, "#str_07060"},
100 {"MOUSE8", K_MOUSE8, "#str_07061"},
102 {"MWHEELUP", K_MWHEELUP, "#str_07131"},
103 {"MWHEELDOWN", K_MWHEELDOWN, "#str_07132"},
105 {"JOY1", K_JOY1, "#str_07062"},
106 {"JOY2", K_JOY2, "#str_07063"},
107 {"JOY3", K_JOY3, "#str_07064"},
108 {"JOY4", K_JOY4, "#str_07065"},
109 {"JOY5", K_JOY5, "#str_07066"},
110 {"JOY6", K_JOY6, "#str_07067"},
111 {"JOY7", K_JOY7, "#str_07068"},
112 {"JOY8", K_JOY8, "#str_07069"},
113 {"JOY9", K_JOY9, "#str_07070"},
114 {"JOY10", K_JOY10, "#str_07071"},
115 {"JOY11", K_JOY11, "#str_07072"},
116 {"JOY12", K_JOY12, "#str_07073"},
117 {"JOY13", K_JOY13, "#str_07074"},
118 {"JOY14", K_JOY14, "#str_07075"},
119 {"JOY15", K_JOY15, "#str_07076"},
120 {"JOY16", K_JOY16, "#str_07077"},
121 {"JOY17", K_JOY17, "#str_07078"},
122 {"JOY18", K_JOY18, "#str_07079"},
123 {"JOY19", K_JOY19, "#str_07080"},
124 {"JOY20", K_JOY20, "#str_07081"},
125 {"JOY21", K_JOY21, "#str_07082"},
126 {"JOY22", K_JOY22, "#str_07083"},
127 {"JOY23", K_JOY23, "#str_07084"},
128 {"JOY24", K_JOY24, "#str_07085"},
129 {"JOY25", K_JOY25, "#str_07086"},
130 {"JOY26", K_JOY26, "#str_07087"},
131 {"JOY27", K_JOY27, "#str_07088"},
132 {"JOY28", K_JOY28, "#str_07089"},
133 {"JOY29", K_JOY29, "#str_07090"},
134 {"JOY30", K_JOY30, "#str_07091"},
135 {"JOY31", K_JOY31, "#str_07092"},
136 {"JOY32", K_JOY32, "#str_07093"},
138 {"AUX1", K_AUX1, "#str_07094"},
139 {"AUX2", K_AUX2, "#str_07095"},
140 {"AUX3", K_AUX3, "#str_07096"},
141 {"AUX4", K_AUX4, "#str_07097"},
142 {"AUX5", K_AUX5, "#str_07098"},
143 {"AUX6", K_AUX6, "#str_07099"},
144 {"AUX7", K_AUX7, "#str_07100"},
145 {"AUX8", K_AUX8, "#str_07101"},
146 {"AUX9", K_AUX9, "#str_07102"},
147 {"AUX10", K_AUX10, "#str_07103"},
148 {"AUX11", K_AUX11, "#str_07104"},
149 {"AUX12", K_AUX12, "#str_07105"},
150 {"AUX13", K_AUX13, "#str_07106"},
151 {"AUX14", K_AUX14, "#str_07107"},
152 {"AUX15", K_AUX15, "#str_07108"},
153 {"AUX16", K_AUX16, "#str_07109"},
155 {"KP_HOME", K_KP_HOME, "#str_07110"},
156 {"KP_UPARROW", K_KP_UPARROW, "#str_07111"},
157 {"KP_PGUP", K_KP_PGUP, "#str_07112"},
158 {"KP_LEFTARROW", K_KP_LEFTARROW, "#str_07113"},
159 {"KP_5", K_KP_5, "#str_07114"},
160 {"KP_RIGHTARROW", K_KP_RIGHTARROW, "#str_07115"},
161 {"KP_END", K_KP_END, "#str_07116"},
162 {"KP_DOWNARROW", K_KP_DOWNARROW, "#str_07117"},
163 {"KP_PGDN", K_KP_PGDN, "#str_07118"},
164 {"KP_ENTER", K_KP_ENTER, "#str_07119"},
165 {"KP_INS", K_KP_INS, "#str_07120"},
166 {"KP_DEL", K_KP_DEL, "#str_07121"},
167 {"KP_SLASH", K_KP_SLASH, "#str_07122"},
168 {"KP_MINUS", K_KP_MINUS, "#str_07123"},
169 {"KP_PLUS", K_KP_PLUS, "#str_07124"},
170 {"KP_NUMLOCK", K_KP_NUMLOCK, "#str_07125"},
171 {"KP_STAR", K_KP_STAR, "#str_07126"},
172 {"KP_EQUALS", K_KP_EQUALS, "#str_07127"},
174 {"PAUSE", K_PAUSE, "#str_07128"},
176 {"SEMICOLON", ';', "#str_07129"}, // because a raw semicolon separates commands
177 {"APOSTROPHE", '\'', "#str_07130"}, // because a raw apostrophe messes with parsing
184 static const int MAX_KEYS = 256;
188 idKey( void ) { down = false; repeats = 0; usercmdAction = 0; }
190 int repeats; // if > 1, it is autorepeating
192 int usercmdAction; // for testing by the asyncronous usercmd generation
195 bool key_overstrikeMode = false;
198 #define ID_DOOM_LEGACY
200 #ifdef ID_DOOM_LEGACY
202 char * cheatCodes[] = {
203 "iddqd", // Invincibility
204 "idkfa", // All weapons, keys, ammo, and 200% armor
205 "idfa", // Reset ammunition
206 "idspispopd", // Walk through walls
207 "idclip", // Walk through walls
208 "idchoppers", // Chainsaw
210 "idbeholds", // Berserker strength
211 "idbeholdv", // Temporary invincibility
212 "idbeholdi", // Temporary invisibility
213 "idbeholda", // Full automap
214 "idbeholdr", // Anti-radiation suit
215 "idbeholdl", // Light amplification visor
216 "idclev", // Level select
217 "iddt", // Toggle full map; full map and objects; normal map
218 "idmypos", // Display coordinates and heading
219 "idmus", // Change music to indicated level
220 "fhhall", // Kill all enemies in level
221 "fhshh", // Invisible to enemies until attack
232 idKeyInput::ArgCompletion_KeyName
235 void idKeyInput::ArgCompletion_KeyName( const idCmdArgs &args, void(*callback)( const char *s ) ) {
239 for( i = 0; i < sizeof( unnamedkeys ) - 1; i++ ) {
240 callback( va( "%s %c", args.Argv( 0 ), unnamedkeys[ i ] ) );
243 for ( kn = keynames; kn->name; kn++ ) {
244 callback( va( "%s %s", args.Argv( 0 ), kn->name ) );
250 idKeyInput::GetOverstrikeMode
253 bool idKeyInput::GetOverstrikeMode( void ) {
254 return key_overstrikeMode;
259 idKeyInput::SetOverstrikeMode
262 void idKeyInput::SetOverstrikeMode( bool state ) {
263 key_overstrikeMode = state;
271 bool idKeyInput::IsDown( int keynum ) {
272 if ( keynum == -1 ) {
276 return keys[keynum].down;
281 idKeyInput::StringToKeyNum
283 Returns a key number to be used to index keys[] by looking at
284 the given string. Single ascii characters return themselves, while
285 the K_* names are matched up.
287 0x11 will be interpreted as raw hex, which will allow new controlers
288 to be configured even if they don't have defined names.
291 int idKeyInput::StringToKeyNum( const char *str ) {
294 if ( !str || !str[0] ) {
298 return (unsigned char)(str[0]);
301 // check for hex code
302 if ( str[0] == '0' && str[1] == 'x' && strlen( str ) == 4 ) {
306 if ( n1 >= '0' && n1 <= '9' ) {
308 } else if ( n1 >= 'a' && n1 <= 'f' ) {
315 if ( n2 >= '0' && n2 <= '9' ) {
317 } else if ( n2 >= 'a' && n2 <= 'f' ) {
326 // scan for a text match
327 for ( kn = keynames; kn->name; kn++ ) {
328 if ( !idStr::Icmp( str, kn->name ) ) {
338 idKeyInput::KeyNumToString
340 Returns a string (either a single ascii char, a K_* name, or a 0x11 hex string) for the
344 const char *idKeyInput::KeyNumToString( int keynum, bool localized ) {
346 static char tinystr[5];
349 if ( keynum == -1 ) {
350 return "<KEY NOT FOUND>";
353 if ( keynum < 0 || keynum > 255 ) {
354 return "<OUT OF RANGE>";
357 // check for printable ascii (don't use quote)
358 if ( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' && keynum != '\'' ) {
359 tinystr[0] = Sys_MapCharForKey( keynum );
364 // check for a key string
365 for ( kn = keynames; kn->name; kn++ ) {
366 if ( keynum == kn->keynum ) {
367 if ( !localized || kn->strId[0] != '#' ) {
372 switch ( kn->keynum ) {
378 return OSX_GetLocalizedString( kn->name );
381 return common->GetLanguageDict()->GetString( kn->strId ); break;
384 return common->GetLanguageDict()->GetString( kn->strId );
390 // check for European high-ASCII characters
391 if ( localized && keynum >= 161 && keynum <= 255 ) {
403 tinystr[2] = i > 9 ? i - 10 + 'a' : i + '0';
404 tinystr[3] = j > 9 ? j - 10 + 'a' : j + '0';
412 idKeyInput::SetBinding
415 void idKeyInput::SetBinding( int keynum, const char *binding ) {
416 if ( keynum == -1 ) {
420 // Clear out all button states so we aren't stuck forever thinking this key is held down
423 // allocate memory for new binding
424 keys[keynum].binding = binding;
426 // find the action for the async command generation
427 keys[keynum].usercmdAction = usercmdGen->CommandStringUsercmdData( binding );
429 // consider this like modifying an archived cvar, so the
430 // file write will be triggered at the next oportunity
431 cvarSystem->SetModifiedFlags( CVAR_ARCHIVE );
437 idKeyInput::GetBinding
440 const char *idKeyInput::GetBinding( int keynum ) {
441 if ( keynum == -1 ) {
445 return keys[ keynum ].binding;
450 idKeyInput::GetUsercmdAction
453 int idKeyInput::GetUsercmdAction( int keynum ) {
454 return keys[ keynum ].usercmdAction;
462 void Key_Unbind_f( const idCmdArgs &args ) {
465 if ( args.Argc() != 2 ) {
466 common->Printf( "unbind <key> : remove commands from a key\n" );
470 b = idKeyInput::StringToKeyNum( args.Argv(1) );
472 // If it wasn't a key, it could be a command
473 if ( !idKeyInput::UnbindBinding( args.Argv(1) ) ) {
474 common->Printf( "\"%s\" isn't a valid key\n", args.Argv(1) );
477 idKeyInput::SetBinding( b, "" );
486 void Key_Unbindall_f( const idCmdArgs &args ) {
489 for ( i = 0; i < MAX_KEYS; i++ ) {
490 idKeyInput::SetBinding( i, "" );
499 void Key_Bind_f( const idCmdArgs &args ) {
501 char cmd[MAX_STRING_CHARS];
506 common->Printf( "bind <key> [command] : attach a command to a key\n" );
509 b = idKeyInput::StringToKeyNum( args.Argv(1) );
511 common->Printf( "\"%s\" isn't a valid key\n", args.Argv(1) );
516 if ( keys[b].binding.Length() ) {
517 common->Printf( "\"%s\" = \"%s\"\n", args.Argv(1), keys[b].binding.c_str() );
520 common->Printf( "\"%s\" is not bound\n", args.Argv(1) );
525 // copy the rest of the command line
526 cmd[0] = 0; // start out with a null string
527 for ( i = 2; i < c; i++ ) {
528 strcat( cmd, args.Argv( i ) );
534 idKeyInput::SetBinding( b, cmd );
541 binds keynum to bindcommand and unbinds if there are already two binds on the key
544 void Key_BindUnBindTwo_f( const idCmdArgs &args ) {
547 common->Printf( "bindunbindtwo <keynum> [command]\n" );
550 int key = atoi( args.Argv( 1 ) );
551 idStr bind = args.Argv( 2 );
552 if ( idKeyInput::NumBinds( bind ) >= 2 && !idKeyInput::KeyIsBoundTo( key, bind ) ) {
553 idKeyInput::UnbindBinding( bind );
555 idKeyInput::SetBinding( key, bind );
562 idKeyInput::WriteBindings
564 Writes lines containing "bind key value"
567 void idKeyInput::WriteBindings( idFile *f ) {
570 f->Printf( "unbindall\n" );
572 for ( i = 0; i < MAX_KEYS; i++ ) {
573 if ( keys[i].binding.Length() ) {
574 const char *name = KeyNumToString( i, false );
576 // handle the escape character nicely
577 if ( !strcmp( name, "\\" ) ) {
578 f->Printf( "bind \"\\\" \"%s\"\n", keys[i].binding.c_str() );
580 f->Printf( "bind \"%s\" \"%s\"\n", KeyNumToString( i, false ), keys[i].binding.c_str() );
591 void Key_ListBinds_f( const idCmdArgs &args ) {
594 for ( i = 0; i < MAX_KEYS; i++ ) {
595 if ( keys[i].binding.Length() ) {
596 common->Printf( "%s \"%s\"\n", idKeyInput::KeyNumToString( i, false ), keys[i].binding.c_str() );
603 idKeyInput::KeysFromBinding
604 returns the localized name of the key for the binding
607 const char *idKeyInput::KeysFromBinding( const char *bind ) {
609 static char keyName[MAX_STRING_CHARS];
612 if ( bind && *bind ) {
613 for ( i = 0; i < MAX_KEYS; i++ ) {
614 if ( keys[i].binding.Icmp( bind ) == 0 ) {
615 if ( keyName[0] != '\0' ) {
616 idStr::Append( keyName, sizeof( keyName ), common->GetLanguageDict()->GetString( "#str_07183" ) );
618 idStr::Append( keyName, sizeof( keyName ), KeyNumToString( i, true ) );
622 if ( keyName[0] == '\0' ) {
623 idStr::Copynz( keyName, common->GetLanguageDict()->GetString( "#str_07133" ), sizeof( keyName ) );
625 idStr::ToLower( keyName );
631 idKeyInput::BindingFromKey
632 returns the binding for the localized name of the key
635 const char *idKeyInput::BindingFromKey( const char *key ) {
636 const int keyNum = idKeyInput::StringToKeyNum( key );
637 if ( keyNum<0 || keyNum >= MAX_KEYS ) {
640 return keys[keyNum].binding.c_str();
645 idKeyInput::UnbindBinding
648 bool idKeyInput::UnbindBinding( const char *binding ) {
649 bool unbound = false;
652 if ( binding && *binding ) {
653 for ( i = 0; i < MAX_KEYS; i++ ) {
654 if ( keys[i].binding.Icmp( binding ) == 0 ) {
668 int idKeyInput::NumBinds( const char *binding ) {
671 if ( binding && *binding ) {
672 for ( i = 0; i < MAX_KEYS; i++ ) {
673 if ( keys[i].binding.Icmp( binding ) == 0 ) {
683 idKeyInput::KeyIsBountTo
686 bool idKeyInput::KeyIsBoundTo( int keynum, const char *binding ) {
687 if ( keynum >= 0 && keynum < MAX_KEYS ) {
688 return ( keys[keynum].binding.Icmp( binding ) == 0 );
695 idKeyInput::PreliminaryKeyEvent
697 Tracks global key up/down state
698 Called by the system for both key up and key down events
701 void idKeyInput::PreliminaryKeyEvent( int keynum, bool down ) {
702 keys[keynum].down = down;
704 #ifdef ID_DOOM_LEGACY
706 lastKeys[ 0 + ( lastKeyIndex & 15 )] = keynum;
707 lastKeys[16 + ( lastKeyIndex & 15 )] = keynum;
708 lastKeyIndex = ( lastKeyIndex + 1 ) & 15;
709 for ( int i = 0; cheatCodes[i] != NULL; i++ ) {
710 int l = strlen( cheatCodes[i] );
712 if ( idStr::Icmpn( lastKeys + 16 + ( lastKeyIndex & 15 ) - l, cheatCodes[i], l ) == 0 ) {
713 common->Printf( "your memory serves you well!\n" );
723 idKeyInput::ExecKeyBinding
726 bool idKeyInput::ExecKeyBinding( int keynum ) {
727 // commands that are used by the async thread
729 if ( keys[keynum].usercmdAction ) {
733 // send the bound action
734 if ( keys[keynum].binding.Length() ) {
735 cmdSystem->BufferCommandText( CMD_EXEC_APPEND, keys[keynum].binding.c_str() );
736 cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "\n" );
743 idKeyInput::ClearStates
746 void idKeyInput::ClearStates( void ) {
749 for ( i = 0; i < MAX_KEYS; i++ ) {
750 if ( keys[i].down ) {
751 PreliminaryKeyEvent( i, false );
753 keys[i].down = false;
756 // clear the usercommand states
765 void idKeyInput::Init( void ) {
767 keys = new idKey[MAX_KEYS];
769 // register our functions
770 cmdSystem->AddCommand( "bind", Key_Bind_f, CMD_FL_SYSTEM, "binds a command to a key", idKeyInput::ArgCompletion_KeyName );
771 cmdSystem->AddCommand( "bindunbindtwo", Key_BindUnBindTwo_f, CMD_FL_SYSTEM, "binds a key but unbinds it first if there are more than two binds" );
772 cmdSystem->AddCommand( "unbind", Key_Unbind_f, CMD_FL_SYSTEM, "unbinds any command from a key", idKeyInput::ArgCompletion_KeyName );
773 cmdSystem->AddCommand( "unbindall", Key_Unbindall_f, CMD_FL_SYSTEM, "unbinds any commands from all keys" );
774 cmdSystem->AddCommand( "listBinds", Key_ListBinds_f, CMD_FL_SYSTEM, "lists key bindings" );
782 void idKeyInput::Shutdown( void ) {