/* keys.c (description) Copyright (C) 1996-1997 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: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #include #include #include #include "QF/cbuf.h" #include "QF/cmd.h" #include "QF/cvar.h" #include "QF/darray.h" #include "QF/dstring.h" #include "QF/keys.h" #include "QF/sys.h" #include "compat.h" #include "old_keys.h" /* key up events are sent even if in console mode */ static keydest_t key_dest = key_console; static keytarget_t key_targets[key_last]; VISIBLE knum_t key_toggleconsole = QFK_BACKQUOTE; typedef struct { keydest_callback_t *func; void *data; } keydest_callback_item_t; typedef struct { key_escape_t *func; void *data; } key_escape_item_t; #define CALLBACK_CHUNK 16 static struct DARRAY_TYPE(keydest_callback_item_t) keydest_callbacks = { .grow = CALLBACK_CHUNK }; static struct DARRAY_TYPE(key_escape_item_t) key_escape_callbacks = { .grow = CALLBACK_CHUNK }; VISIBLE int keydown[QFK_LAST]; static int keyhelp; static cbuf_t *cbuf; static const char *keydest_names[] = { "key_unfocused", "key_game", "key_demo", "key_console", "key_message", "key_menu", "key_last" }; typedef struct { const char *name; imt_t imtnum; } imtname_t; typedef struct { const char *name; knum_t keynum; } keyname_t; keyname_t keynames[] = { { "K_UNKNOWN", QFK_UNKNOWN }, { "K_FIRST", QFK_FIRST }, { "K_BACKSPACE", QFK_BACKSPACE }, { "K_TAB", QFK_TAB }, { "K_CLEAR", QFK_CLEAR }, { "K_RETURN", QFK_RETURN }, { "K_PAUSE", QFK_PAUSE }, { "K_ESCAPE", QFK_ESCAPE }, { "K_SPACE", QFK_SPACE }, { "K_EXCLAIM", QFK_EXCLAIM }, { "K_QUOTEDBL", QFK_QUOTEDBL }, { "K_HASH", QFK_HASH }, { "K_DOLLAR", QFK_DOLLAR }, { "K_PERCENT", QFK_PERCENT }, { "K_AMPERSAND", QFK_AMPERSAND }, { "K_QUOTE", QFK_QUOTE }, { "K_LEFTPAREN", QFK_LEFTPAREN }, { "K_RIGHTPAREN", QFK_RIGHTPAREN }, { "K_ASTERISK", QFK_ASTERISK }, { "K_PLUS", QFK_PLUS }, { "K_COMMA", QFK_COMMA }, { "K_MINUS", QFK_MINUS }, { "K_PERIOD", QFK_PERIOD }, { "K_SLASH", QFK_SLASH }, { "K_0", QFK_0 }, { "K_1", QFK_1 }, { "K_2", QFK_2 }, { "K_3", QFK_3 }, { "K_4", QFK_4 }, { "K_5", QFK_5 }, { "K_6", QFK_6 }, { "K_7", QFK_7 }, { "K_8", QFK_8 }, { "K_9", QFK_9 }, { "K_COLON", QFK_COLON }, { "K_SEMICOLON", QFK_SEMICOLON }, { "K_LESS", QFK_LESS }, { "K_EQUALS", QFK_EQUALS }, { "K_GREATER", QFK_GREATER }, { "K_QUESTION", QFK_QUESTION }, { "K_AT", QFK_AT }, { "K_LEFTBRACKET", QFK_LEFTBRACKET }, { "K_BACKSLASH", QFK_BACKSLASH }, { "K_RIGHTBRACKET", QFK_RIGHTBRACKET }, { "K_CARET", QFK_CARET }, { "K_UNDERSCORE", QFK_UNDERSCORE }, { "K_BACKQUOTE", QFK_BACKQUOTE }, { "K_a", QFK_a }, { "K_b", QFK_b }, { "K_c", QFK_c }, { "K_d", QFK_d }, { "K_e", QFK_e }, { "K_f", QFK_f }, { "K_g", QFK_g }, { "K_h", QFK_h }, { "K_i", QFK_i }, { "K_j", QFK_j }, { "K_k", QFK_k }, { "K_l", QFK_l }, { "K_m", QFK_m }, { "K_n", QFK_n }, { "K_o", QFK_o }, { "K_p", QFK_p }, { "K_q", QFK_q }, { "K_r", QFK_r }, { "K_s", QFK_s }, { "K_t", QFK_t }, { "K_u", QFK_u }, { "K_v", QFK_v }, { "K_w", QFK_w }, { "K_x", QFK_x }, { "K_y", QFK_y }, { "K_z", QFK_z }, { "K_BRACELEFT", QFK_BRACELEFT }, { "K_BAR", QFK_BAR }, { "K_BRACERIGHT", QFK_BRACERIGHT }, { "K_ASCIITILDE", QFK_ASCIITILDE }, { "K_DELETE", QFK_DELETE }, { "K_WORLD_0", QFK_WORLD_0 }, { "K_WORLD_1", QFK_WORLD_1 }, { "K_WORLD_2", QFK_WORLD_2 }, { "K_WORLD_3", QFK_WORLD_3 }, { "K_WORLD_4", QFK_WORLD_4 }, { "K_WORLD_5", QFK_WORLD_5 }, { "K_WORLD_6", QFK_WORLD_6 }, { "K_WORLD_7", QFK_WORLD_7 }, { "K_WORLD_8", QFK_WORLD_8 }, { "K_WORLD_9", QFK_WORLD_9 }, { "K_WORLD_10", QFK_WORLD_10 }, { "K_WORLD_11", QFK_WORLD_11 }, { "K_WORLD_12", QFK_WORLD_12 }, { "K_WORLD_13", QFK_WORLD_13 }, { "K_WORLD_14", QFK_WORLD_14 }, { "K_WORLD_15", QFK_WORLD_15 }, { "K_WORLD_16", QFK_WORLD_16 }, { "K_WORLD_17", QFK_WORLD_17 }, { "K_WORLD_18", QFK_WORLD_18 }, { "K_WORLD_19", QFK_WORLD_19 }, { "K_WORLD_20", QFK_WORLD_20 }, { "K_WORLD_21", QFK_WORLD_21 }, { "K_WORLD_22", QFK_WORLD_22 }, { "K_WORLD_23", QFK_WORLD_23 }, { "K_WORLD_24", QFK_WORLD_24 }, { "K_WORLD_25", QFK_WORLD_25 }, { "K_WORLD_26", QFK_WORLD_26 }, { "K_WORLD_27", QFK_WORLD_27 }, { "K_WORLD_28", QFK_WORLD_28 }, { "K_WORLD_29", QFK_WORLD_29 }, { "K_WORLD_30", QFK_WORLD_30 }, { "K_WORLD_31", QFK_WORLD_31 }, { "K_WORLD_32", QFK_WORLD_32 }, { "K_WORLD_33", QFK_WORLD_33 }, { "K_WORLD_34", QFK_WORLD_34 }, { "K_WORLD_35", QFK_WORLD_35 }, { "K_WORLD_36", QFK_WORLD_36 }, { "K_WORLD_37", QFK_WORLD_37 }, { "K_WORLD_38", QFK_WORLD_38 }, { "K_WORLD_39", QFK_WORLD_39 }, { "K_WORLD_40", QFK_WORLD_40 }, { "K_WORLD_41", QFK_WORLD_41 }, { "K_WORLD_42", QFK_WORLD_42 }, { "K_WORLD_43", QFK_WORLD_43 }, { "K_WORLD_44", QFK_WORLD_44 }, { "K_WORLD_45", QFK_WORLD_45 }, { "K_WORLD_46", QFK_WORLD_46 }, { "K_WORLD_47", QFK_WORLD_47 }, { "K_WORLD_48", QFK_WORLD_48 }, { "K_WORLD_49", QFK_WORLD_49 }, { "K_WORLD_50", QFK_WORLD_50 }, { "K_WORLD_51", QFK_WORLD_51 }, { "K_WORLD_52", QFK_WORLD_52 }, { "K_WORLD_53", QFK_WORLD_53 }, { "K_WORLD_54", QFK_WORLD_54 }, { "K_WORLD_55", QFK_WORLD_55 }, { "K_WORLD_56", QFK_WORLD_56 }, { "K_WORLD_57", QFK_WORLD_57 }, { "K_WORLD_58", QFK_WORLD_58 }, { "K_WORLD_59", QFK_WORLD_59 }, { "K_WORLD_60", QFK_WORLD_60 }, { "K_WORLD_61", QFK_WORLD_61 }, { "K_WORLD_62", QFK_WORLD_62 }, { "K_WORLD_63", QFK_WORLD_63 }, { "K_WORLD_64", QFK_WORLD_64 }, { "K_WORLD_65", QFK_WORLD_65 }, { "K_WORLD_66", QFK_WORLD_66 }, { "K_WORLD_67", QFK_WORLD_67 }, { "K_WORLD_68", QFK_WORLD_68 }, { "K_WORLD_69", QFK_WORLD_69 }, { "K_WORLD_70", QFK_WORLD_70 }, { "K_WORLD_71", QFK_WORLD_71 }, { "K_WORLD_72", QFK_WORLD_72 }, { "K_WORLD_73", QFK_WORLD_73 }, { "K_WORLD_74", QFK_WORLD_74 }, { "K_WORLD_75", QFK_WORLD_75 }, { "K_WORLD_76", QFK_WORLD_76 }, { "K_WORLD_77", QFK_WORLD_77 }, { "K_WORLD_78", QFK_WORLD_78 }, { "K_WORLD_79", QFK_WORLD_79 }, { "K_WORLD_80", QFK_WORLD_80 }, { "K_WORLD_81", QFK_WORLD_81 }, { "K_WORLD_82", QFK_WORLD_82 }, { "K_WORLD_83", QFK_WORLD_83 }, { "K_WORLD_84", QFK_WORLD_84 }, { "K_WORLD_85", QFK_WORLD_85 }, { "K_WORLD_86", QFK_WORLD_86 }, { "K_WORLD_87", QFK_WORLD_87 }, { "K_WORLD_88", QFK_WORLD_88 }, { "K_WORLD_89", QFK_WORLD_89 }, { "K_WORLD_90", QFK_WORLD_90 }, { "K_WORLD_91", QFK_WORLD_91 }, { "K_WORLD_92", QFK_WORLD_92 }, { "K_WORLD_93", QFK_WORLD_93 }, { "K_WORLD_94", QFK_WORLD_94 }, { "K_WORLD_95", QFK_WORLD_95 }, { "K_KP0", QFK_KP0 }, { "K_KP1", QFK_KP1 }, { "K_KP2", QFK_KP2 }, { "K_KP3", QFK_KP3 }, { "K_KP4", QFK_KP4 }, { "K_KP5", QFK_KP5 }, { "K_KP6", QFK_KP6 }, { "K_KP7", QFK_KP7 }, { "K_KP8", QFK_KP8 }, { "K_KP9", QFK_KP9 }, { "K_KP_PERIOD", QFK_KP_PERIOD }, { "K_KP_DIVIDE", QFK_KP_DIVIDE }, { "K_KP_MULTIPLY", QFK_KP_MULTIPLY }, { "K_KP_MINUS", QFK_KP_MINUS }, { "K_KP_PLUS", QFK_KP_PLUS }, { "K_KP_ENTER", QFK_KP_ENTER }, { "K_KP_EQUALS", QFK_KP_EQUALS }, { "K_UP", QFK_UP }, { "K_DOWN", QFK_DOWN }, { "K_RIGHT", QFK_RIGHT }, { "K_LEFT", QFK_LEFT }, { "K_INSERT", QFK_INSERT }, { "K_HOME", QFK_HOME }, { "K_END", QFK_END }, { "K_PAGEUP", QFK_PAGEUP }, { "K_PAGEDOWN", QFK_PAGEDOWN }, { "K_F1", QFK_F1 }, { "K_F2", QFK_F2 }, { "K_F3", QFK_F3 }, { "K_F4", QFK_F4 }, { "K_F5", QFK_F5 }, { "K_F6", QFK_F6 }, { "K_F7", QFK_F7 }, { "K_F8", QFK_F8 }, { "K_F9", QFK_F9 }, { "K_F10", QFK_F10 }, { "K_F11", QFK_F11 }, { "K_F12", QFK_F12 }, { "K_F13", QFK_F13 }, { "K_F14", QFK_F14 }, { "K_F15", QFK_F15 }, { "K_F16", QFK_F16 }, { "K_F17", QFK_F17 }, { "K_F18", QFK_F18 }, { "K_F19", QFK_F19 }, { "K_F20", QFK_F20 }, { "K_F21", QFK_F21 }, { "K_F22", QFK_F22 }, { "K_F23", QFK_F23 }, { "K_F24", QFK_F24 }, { "K_F25", QFK_F25 }, { "K_F26", QFK_F26 }, { "K_F27", QFK_F27 }, { "K_F28", QFK_F28 }, { "K_F29", QFK_F29 }, { "K_F30", QFK_F30 }, { "K_F31", QFK_F31 }, { "K_F32", QFK_F32 }, { "K_F33", QFK_F33 }, { "K_F34", QFK_F34 }, { "K_F35", QFK_F35 }, { "K_F36", QFK_F36 }, { "K_F37", QFK_F37 }, { "K_F38", QFK_F38 }, { "K_F39", QFK_F39 }, { "K_F40", QFK_F40 }, { "K_F41", QFK_F41 }, { "K_F42", QFK_F42 }, { "K_F43", QFK_F43 }, { "K_F44", QFK_F44 }, { "K_F45", QFK_F45 }, { "K_F46", QFK_F46 }, { "K_F47", QFK_F47 }, { "K_F48", QFK_F48 }, { "K_NUMLOCK", QFK_NUMLOCK }, { "K_CAPSLOCK", QFK_CAPSLOCK }, { "K_SCROLLOCK", QFK_SCROLLOCK }, { "K_RSHIFT", QFK_RSHIFT }, { "K_LSHIFT", QFK_LSHIFT }, { "K_RCTRL", QFK_RCTRL }, { "K_LCTRL", QFK_LCTRL }, { "K_RALT", QFK_RALT }, { "K_LALT", QFK_LALT }, { "K_RMETA", QFK_RMETA }, { "K_LMETA", QFK_LMETA }, { "K_LSUPER", QFK_LSUPER }, { "K_RSUPER", QFK_RSUPER }, { "K_MODE", QFK_MODE }, { "K_COMPOSE", QFK_COMPOSE }, { "K_HELP", QFK_HELP }, { "K_PRINT", QFK_PRINT }, { "K_SYSREQ", QFK_SYSREQ }, { "K_BREAK", QFK_BREAK }, { "K_MENU", QFK_MENU }, { "K_POWER", QFK_POWER }, { "K_EURO", QFK_EURO }, { "K_KANJI", QFK_KANJI }, { "K_MUHENKAN", QFK_MUHENKAN }, { "K_HENKAN", QFK_HENKAN }, { "K_ROMAJI", QFK_ROMAJI }, { "K_HIRAGANA", QFK_HIRAGANA }, { "K_KATAKANA", QFK_KATAKANA }, { "K_HIRAGANA_KATAKANA", QFK_HIRAGANA_KATAKANA }, { "K_ZENKAKU", QFK_ZENKAKU }, { "K_HANKAKU", QFK_HANKAKU }, { "K_ZENKAKU_HANKAKU", QFK_ZENKAKU_HANKAKU }, { "K_TOUROKU", QFK_TOUROKU }, { "K_MASSYO", QFK_MASSYO }, { "K_KANA_LOCK", QFK_KANA_LOCK }, { "K_KANA_SHIFT", QFK_KANA_SHIFT }, { "K_EISU_SHIFT", QFK_EISU_SHIFT }, { "K_EISU_TOGGLE", QFK_EISU_TOGGLE }, { "K_KANJI_BANGOU", QFK_KANJI_BANGOU }, { "K_ZEN_KOHO", QFK_ZEN_KOHO }, { "K_MAE_KOHO", QFK_MAE_KOHO }, { "K_HOMEPAGE", QFK_HOMEPAGE }, { "K_SEARCH", QFK_SEARCH }, { "K_MAIL", QFK_MAIL }, { "K_FAVORITES", QFK_FAVORITES }, { "K_AUDIOMUTE", QFK_AUDIOMUTE }, { "K_AUDIOLOWERVOLUME", QFK_AUDIOLOWERVOLUME }, { "K_AUDIORAISEVOLUME", QFK_AUDIORAISEVOLUME }, { "K_AUDIOPLAY", QFK_AUDIOPLAY }, { "K_CALCULATOR", QFK_CALCULATOR }, { "K_UNDO", QFK_UNDO }, { "K_REDO", QFK_REDO }, { "K_NEW", QFK_NEW }, { "K_RELOAD", QFK_RELOAD }, { "K_OPEN", QFK_OPEN }, { "K_CLOSE", QFK_CLOSE }, { "K_REPLY", QFK_REPLY }, { "K_MAILFORWARD", QFK_MAILFORWARD }, { "K_SEND", QFK_SEND }, { "K_SAVE", QFK_SAVE }, { "K_BACK", QFK_BACK }, { "K_FORWARD", QFK_FORWARD }, { "M_BUTTON1", QFM_BUTTON1 }, { "M_BUTTON2", QFM_BUTTON2 }, { "M_BUTTON3", QFM_BUTTON3 }, { "M_WHEEL_UP", QFM_WHEEL_UP }, { "M_WHEEL_DOWN", QFM_WHEEL_DOWN }, { "M_BUTTON6", QFM_BUTTON6 }, { "M_BUTTON7", QFM_BUTTON7 }, { "M_BUTTON8", QFM_BUTTON8 }, { "M_BUTTON9", QFM_BUTTON9 }, { "M_BUTTON10", QFM_BUTTON10 }, { "M_BUTTON11", QFM_BUTTON11 }, { "M_BUTTON12", QFM_BUTTON12 }, { "M_BUTTON13", QFM_BUTTON13 }, { "M_BUTTON14", QFM_BUTTON14 }, { "M_BUTTON15", QFM_BUTTON15 }, { "M_BUTTON16", QFM_BUTTON16 }, { "M_BUTTON17", QFM_BUTTON17 }, { "M_BUTTON18", QFM_BUTTON18 }, { "M_BUTTON19", QFM_BUTTON19 }, { "M_BUTTON20", QFM_BUTTON20 }, { "M_BUTTON21", QFM_BUTTON21 }, { "M_BUTTON22", QFM_BUTTON22 }, { "M_BUTTON23", QFM_BUTTON23 }, { "M_BUTTON24", QFM_BUTTON24 }, { "M_BUTTON25", QFM_BUTTON25 }, { "M_BUTTON26", QFM_BUTTON26 }, { "M_BUTTON27", QFM_BUTTON27 }, { "M_BUTTON28", QFM_BUTTON28 }, { "M_BUTTON29", QFM_BUTTON29 }, { "M_BUTTON30", QFM_BUTTON30 }, { "M_BUTTON31", QFM_BUTTON31 }, { "M_BUTTON32", QFM_BUTTON32 }, { "J_BUTTON1", QFJ_BUTTON1 }, { "J_BUTTON2", QFJ_BUTTON2 }, { "J_BUTTON3", QFJ_BUTTON3 }, { "J_BUTTON4", QFJ_BUTTON4 }, { "J_BUTTON5", QFJ_BUTTON5 }, { "J_BUTTON6", QFJ_BUTTON6 }, { "J_BUTTON7", QFJ_BUTTON7 }, { "J_BUTTON8", QFJ_BUTTON8 }, { "J_BUTTON9", QFJ_BUTTON9 }, { "J_BUTTON10", QFJ_BUTTON10 }, { "J_BUTTON11", QFJ_BUTTON11 }, { "J_BUTTON12", QFJ_BUTTON12 }, { "J_BUTTON13", QFJ_BUTTON13 }, { "J_BUTTON14", QFJ_BUTTON14 }, { "J_BUTTON15", QFJ_BUTTON15 }, { "J_BUTTON16", QFJ_BUTTON16 }, { "J_BUTTON17", QFJ_BUTTON17 }, { "J_BUTTON18", QFJ_BUTTON18 }, { "J_BUTTON19", QFJ_BUTTON19 }, { "J_BUTTON20", QFJ_BUTTON20 }, { "J_BUTTON21", QFJ_BUTTON21 }, { "J_BUTTON22", QFJ_BUTTON22 }, { "J_BUTTON23", QFJ_BUTTON23 }, { "J_BUTTON24", QFJ_BUTTON24 }, { "J_BUTTON25", QFJ_BUTTON25 }, { "J_BUTTON26", QFJ_BUTTON26 }, { "J_BUTTON27", QFJ_BUTTON27 }, { "J_BUTTON28", QFJ_BUTTON28 }, { "J_BUTTON29", QFJ_BUTTON29 }, { "J_BUTTON30", QFJ_BUTTON30 }, { "J_BUTTON31", QFJ_BUTTON31 }, { "J_BUTTON32", QFJ_BUTTON32 }, { "J_BUTTON33", QFJ_BUTTON33 }, { "J_BUTTON34", QFJ_BUTTON34 }, { "J_BUTTON35", QFJ_BUTTON35 }, { "J_BUTTON36", QFJ_BUTTON36 }, { "J_BUTTON37", QFJ_BUTTON37 }, { "J_BUTTON38", QFJ_BUTTON38 }, { "J_BUTTON39", QFJ_BUTTON39 }, { "J_BUTTON40", QFJ_BUTTON40 }, { "J_BUTTON41", QFJ_BUTTON41 }, { "J_BUTTON42", QFJ_BUTTON42 }, { "J_BUTTON43", QFJ_BUTTON43 }, { "J_BUTTON44", QFJ_BUTTON44 }, { "J_BUTTON45", QFJ_BUTTON45 }, { "J_BUTTON46", QFJ_BUTTON46 }, { "J_BUTTON47", QFJ_BUTTON47 }, { "J_BUTTON48", QFJ_BUTTON48 }, { "J_BUTTON49", QFJ_BUTTON49 }, { "J_BUTTON50", QFJ_BUTTON50 }, { "J_BUTTON51", QFJ_BUTTON51 }, { "J_BUTTON52", QFJ_BUTTON52 }, { "J_BUTTON53", QFJ_BUTTON53 }, { "J_BUTTON54", QFJ_BUTTON54 }, { "J_BUTTON55", QFJ_BUTTON55 }, { "J_BUTTON56", QFJ_BUTTON56 }, { "J_BUTTON57", QFJ_BUTTON57 }, { "J_BUTTON58", QFJ_BUTTON58 }, { "J_BUTTON59", QFJ_BUTTON59 }, { "J_BUTTON60", QFJ_BUTTON60 }, { "J_BUTTON61", QFJ_BUTTON61 }, { "J_BUTTON62", QFJ_BUTTON62 }, { "J_BUTTON63", QFJ_BUTTON63 }, { "J_BUTTON64", QFJ_BUTTON64 }, { "J_AXIS1", QFJ_AXIS1 }, { "J_AXIS2", QFJ_AXIS2 }, { "J_AXIS3", QFJ_AXIS3 }, { "J_AXIS4", QFJ_AXIS4 }, { "J_AXIS5", QFJ_AXIS5 }, { "J_AXIS6", QFJ_AXIS6 }, { "J_AXIS7", QFJ_AXIS7 }, { "J_AXIS8", QFJ_AXIS8 }, { "J_AXIS9", QFJ_AXIS9 }, { "J_AXIS10", QFJ_AXIS10 }, { "J_AXIS11", QFJ_AXIS11 }, { "J_AXIS12", QFJ_AXIS12 }, { "J_AXIS13", QFJ_AXIS13 }, { "J_AXIS14", QFJ_AXIS14 }, { "J_AXIS15", QFJ_AXIS15 }, { "J_AXIS16", QFJ_AXIS16 }, { "J_AXIS17", QFJ_AXIS17 }, { "J_AXIS18", QFJ_AXIS18 }, { "J_AXIS19", QFJ_AXIS19 }, { "J_AXIS20", QFJ_AXIS20 }, { "J_AXIS21", QFJ_AXIS21 }, { "J_AXIS22", QFJ_AXIS22 }, { "J_AXIS23", QFJ_AXIS23 }, { "J_AXIS24", QFJ_AXIS24 }, { "J_AXIS25", QFJ_AXIS25 }, { "J_AXIS26", QFJ_AXIS26 }, { "J_AXIS27", QFJ_AXIS27 }, { "J_AXIS28", QFJ_AXIS28 }, { "J_AXIS29", QFJ_AXIS29 }, { "J_AXIS30", QFJ_AXIS30 }, { "J_AXIS31", QFJ_AXIS31 }, { "J_AXIS32", QFJ_AXIS32 }, {NULL, 0} }; static __attribute__((pure)) imt_t * key_target_find_imt (keytarget_t *kt, const char *imt_name) { imt_t *imt; for (imt = kt->imts; imt; imt = imt->next) { if (!strcasecmp (imt->name, imt_name)) { return imt; } } return 0; } VISIBLE imt_t * Key_FindIMT (const char *imt_name) { keydest_t kd; imt_t *imt = 0; for (kd = key_unfocused; !imt && kd < key_last; kd++) { imt = key_target_find_imt (&key_targets[kd], imt_name); } return imt; } void Key_CreateIMT (keydest_t kd, const char *imt_name, const char *chain_imt_name) { imt_t *imt; imt_t *chain_imt = 0; keytarget_t *kt = &key_targets[kd]; imt = Key_FindIMT (imt_name); if (imt) { Sys_Printf ("imt error: imt %s already exists\n", imt_name); return; } if (chain_imt_name) { chain_imt = Key_FindIMT (chain_imt_name); if (!chain_imt) { Sys_Printf ("imt error: chain imt %s does not exist\n", chain_imt_name); return; } imt = key_target_find_imt (kt, chain_imt_name); if (!imt) { Sys_Printf ("imt error: chain imt %s not on target key " "destination\n", chain_imt_name); return; } } imt = calloc (1, sizeof (imt_t)); imt->name = strdup (imt_name); imt->chain = chain_imt; imt->next = kt->imts; kt->imts = imt; if (!kt->active) { kt->active = imt; } } VISIBLE void Key_SetBinding (imt_t *imt, knum_t keynum, const char *binding) { if (keynum == (knum_t) -1) return; if (imt->bindings[keynum].str) { free (imt->bindings[keynum].str); imt->bindings[keynum].str = NULL; } if (binding) { imt->bindings[keynum].str = strdup(binding); } } static void Key_CallDestCallbacks (keydest_t kd) { for (size_t i = 0; i < keydest_callbacks.size; i++) { keydest_callback_item_t *cb = &keydest_callbacks.a[i]; cb->func (kd, cb->data); } } static void process_binding (knum_t key, const char *kb) { char cmd[1024]; if (kb[0] == '+') { if (keydown[key]) snprintf (cmd, sizeof (cmd), "%s %d\n", kb, key); else snprintf (cmd, sizeof (cmd), "-%s %d\n", kb + 1, key); } else { if (!keydown[key]) return; snprintf (cmd, sizeof (cmd), "%s\n", kb); } Cbuf_AddText (cbuf, cmd); } /* Key_Game Game key handling. */ static qboolean Key_Game (knum_t key, short unicode) { const char *kb; imt_t *imt = key_targets[key_dest].active; while (imt) { kb = imt->bindings[key].str; if (kb) { if (keydown[key] <= 1) process_binding (key, kb); return true; } imt = imt->chain; } return false; } VISIBLE int Key_StringToKeynum (const char *str) { keyname_t *kn; if (!str || !str[0]) return -1; for (kn = keynames; kn->name; kn++) { if (!strcasecmp (str, kn->name)) return kn->keynum; } return -1; } VISIBLE const char * Key_KeynumToString (knum_t keynum) { keyname_t *kn; if (keynum == (knum_t) -1) return ""; for (kn = keynames; kn->name; kn++) if (keynum == kn->keynum) return kn->name; return ""; } static void Key_In_Unbind (const char *imt_name, const char *key_name) { imt_t *imt; int key; imt = Key_FindIMT (imt_name); if (!imt) { Sys_Printf ("\"%s\" is not a valid imt\n", imt_name); return; } key = Key_StringToKeynum (key_name); if (key == -1) { Sys_Printf ("\"%s\" is not a valid key\n", key_name); return; } Key_SetBinding (imt, key, NULL); } static void Key_In_Unbind_f (void) { if (Cmd_Argc () != 3) { Sys_Printf ("in_unbind : remove commands from a key\n"); return; } Key_In_Unbind (Cmd_Argv (1), Cmd_Argv (2)); } static void Key_Unbindall_f (void) { imt_t *imt; int i; imt = Key_FindIMT ("imt_mod"); if (imt) { for (i = 0; i < QFK_LAST; i++) { Key_SetBinding (imt, i, 0); } } } static void Key_In_Type_f (void) { const char *str, *p; if (Cmd_Argc () != 2) { Sys_Printf ("in_type \n"); Sys_Printf (" Send the given string as simulated key presses.\n"); return; } str = Cmd_Argv (1); for (p = str; *p; p++) { Key_Event (QFK_UNKNOWN, *p, 1); Key_Event (QFK_UNKNOWN, 0, 0); } } static void Key_In_Clear (void) { int err = 0; imt_t *imt; int i, j; if (Cmd_Argc () == 1) { Sys_Printf ("in_clear ...\n"); return; } for (i = 1; i < Cmd_Argc (); i++) { if (!Key_FindIMT (Cmd_Argv (i))) { Sys_Printf ("\"%s\" is not a valid imt\n", Cmd_Argv (i)); err = 1; } } if (err) return; for (i = 1; i < Cmd_Argc (); i++) { imt = Key_FindIMT (Cmd_Argv (i)); for (j = 0; j < QFK_LAST; j++) Key_SetBinding (imt, j, NULL); } } static void Key_IMT_Create_f (void) { const char *keydest; const char *imt_name; const char *chain_imt_name = 0; keydest_t kd; if (Cmd_Argc () < 3 || Cmd_Argc () > 4) { Sys_Printf ("see help imt_create\n"); return; } keydest = Cmd_Argv (1); imt_name = Cmd_Argv (2); if (Cmd_Argc () == 4) { chain_imt_name = Cmd_Argv (3); } for (kd = key_game; kd < key_last; kd++) { if (!strcasecmp (keydest_names[kd], keydest)) { break; } } if (kd == key_last) { Sys_Printf ("imt error: invalid keydest: %s\n", keydest); return; } Key_CreateIMT (kd, imt_name, chain_imt_name); } static void Key_IMT_Drop_All_f (void) { keydest_t kd; imt_t *imt; for (kd = key_unfocused; kd < key_last; kd++) { while (key_targets[kd].imts) { imt = key_targets[kd].imts; key_targets[kd].imts = imt->next; for (int i = 0; i < QFK_LAST; i++) { if (imt->bindings[i].str) { free (imt->bindings[i].str); } } free ((char *) imt->name); free (imt); } key_targets[kd].active = 0; } } static void Key_In_Bind (const char *imt_name, const char *key_name, const char *cmd) { imt_t *imt; int key; imt = Key_FindIMT (imt_name); if (!imt) { Sys_Printf ("\"%s\" is not a valid imt\n", imt_name); return; } key = Key_StringToKeynum (key_name); if (key == -1) { Sys_Printf ("\"%s\" is not a valid key\n", key_name); return; } if (!cmd) { if (imt->bindings[key].str) Sys_Printf ("%s %s \"%s\"\n", imt_name, key_name, imt->bindings[key].str); else Sys_Printf ("%s %s is not bound\n", imt_name, key_name); return; } Key_SetBinding (imt, key, cmd); } static void Key_In_Bind_f (void) { int c, i; const char *imt, *key, *cmd = 0; dstring_t *cmd_buf = 0; c = Cmd_Argc (); if (c < 3) { Sys_Printf ("in_bind [command] : attach a command to a " "key\n"); return; } imt = Cmd_Argv (1); key = Cmd_Argv (2); if (c >= 4) { cmd_buf = dstring_newstr (); for (i = 3; i < c; i++) { dasprintf (cmd_buf, "%s%s", i > 3 ? " " : "", Cmd_Argv (i)); } cmd = cmd_buf->str; } Key_In_Bind (imt, key, cmd); if (cmd_buf) { dstring_delete (cmd_buf); } } static void Key_Unbind_f (void) { const char *key; if (Cmd_Argc () != 2) { Sys_Printf ("unbind : remove commands from a key\n"); return; } key = OK_TranslateKeyName (Cmd_Argv (1)); Key_In_Unbind ("imt_mod", key); } static void Key_Bind_f (void) { int c, i; const char *key, *cmd = 0; dstring_t *cmd_buf = 0; c = Cmd_Argc (); if (c < 2) { Sys_Printf ("bind [command] : attach a command to a key\n"); return; } key = OK_TranslateKeyName (Cmd_Argv (1)); if (c >= 3) { cmd_buf = dstring_newstr (); for (i = 2; i < c; i++) { dasprintf (cmd_buf, "%s%s", i > 2 ? " " : "", Cmd_Argv (i)); } cmd = cmd_buf->str; } Key_In_Bind ("imt_mod", key, cmd); if (cmd_buf) { dstring_delete (cmd_buf); } } static void in_key_toggleconsole_f (cvar_t *var) { int k; if (!*var->string) { key_toggleconsole = -1; return; } if ((k = Key_StringToKeynum (var->string)) == -1) { Sys_Printf ("\"%s\" is not a valid key. not setting\n", var->string); return; } key_toggleconsole = k; } static void Key_InputMappingTable_f (void) { int c; imt_t *imt; c = Cmd_Argc (); if (c != 2) { Sys_Printf ("Current imt is %s\n", key_targets[key_game].active->name); Sys_Printf ("imt : set to a specific input mapping table\n"); return; } imt = Key_FindIMT (Cmd_Argv (1)); if (!imt) { Sys_Printf ("\"%s\" is not a valid imt\n", Cmd_Argv (1)); return; } key_targets[key_game].active = imt; } static void Key_IMT_Keydest_f (void) { int c; imt_t *imt; const char *imt_name = 0; const char *keydest; keydest_t kd; c = Cmd_Argc (); switch (c) { case 3: imt_name = Cmd_Argv (2); case 2: keydest = Cmd_Argv (1); break; default: return; } for (kd = key_game; kd < key_last; kd++) { if (!strcasecmp (keydest_names[kd], keydest)) { break; } } if (kd == key_last) { Sys_Printf ("imt error: invalid keydest: %s\n", keydest); return; } if (!imt_name) { Sys_Printf ("Current imt is %s\n", key_targets[key_game].active->name); Sys_Printf ("imt : set to a specific input mapping table\n"); return; } imt = key_target_find_imt (&key_targets[kd], imt_name); if (!imt) { Sys_Printf ("\"%s\" is not an imt on %s\n", imt_name, keydest); return; } key_targets[kd].active = imt; } static void __attribute__((format(PRINTF,2,3))) key_printf (QFile *f, const char *fmt, ...) { va_list args; static dstring_t *string; if (!string) { string = dstring_new (); } va_start (args, fmt); dvsprintf (string, fmt, args); va_end (args); if (f) { Qprintf (f, "%s", string->str); } else { Sys_Printf ("%s", string->str); } } static void key_write_imt (QFile *f, keydest_t kd, imt_t *imt) { int i; const char *bind; if (!imt || imt->written) { return; } imt->written = 1; key_write_imt (f, kd, imt->chain); if (imt->chain) { key_printf (f, "imt_create %s %s %s\n", keydest_names[kd], imt->name, imt->chain->name); } else { key_printf (f, "imt_create %s %s\n", keydest_names[kd], imt->name); } for (i = 0; i < QFK_LAST; i++) { bind = imt->bindings[i].str; if (bind) { key_printf (f, "in_bind %s %s \"%s\"\n", imt->name, Key_KeynumToString (i), bind); } } } void Key_WriteBindings (QFile *f) { keydest_t kd; imt_t *imt; for (kd = key_unfocused; kd < key_last; kd++) { for (imt = key_targets[kd].imts; imt; imt = imt->next) { imt->written = 0; } } key_printf (f, "imt_drop_all\n"); for (kd = key_unfocused; kd < key_last; kd++) { if (key_targets[kd].imts) { for (imt = key_targets[kd].imts; imt; imt = imt->next) { key_write_imt (f, kd, imt); } key_printf (f, "imt_keydest %s %s\n", keydest_names[kd], key_targets[kd].active->name); } } } static void Key_Bindlist_f (void) { Key_WriteBindings (0); } static void keyhelp_f (void) { keyhelp = 1; } static key_event_t *key_event_handlers[key_last] = { }; static void *key_event_data[key_last] = { }; VISIBLE void Key_SetKeyEvent (keydest_t keydest, key_event_t *callback, void *data) { if (keydest < 0 || keydest >= key_last) { Sys_Error ("Key_SetKeyEvent: invalid keydest: %d", keydest); } key_event_handlers[keydest] = callback; key_event_data[keydest] = data; } /* Key_Event Called by the system between frames for both key up and key down events Should NOT be called during an interrupt! */ VISIBLE void Key_Event (knum_t key, short unicode, qboolean down) { // Sys_Printf ("%d %d %d : %d\n", key_target, key_dest, key, down); //@@@ if (down) { keydown[key]++; if (keyhelp) { Sys_Printf ("Key name for that key is \"%s\"\n", Key_KeynumToString (key)); keyhelp = 0; return; // gobble the key } } else { keydown[key] = 0; } // handle the escape key specially so it can never be overridden or // unbound if (key == QFK_ESCAPE && keydown[key] == 1) { if (key_escape_callbacks.size) { int ind = key_escape_callbacks.size - 1; key_escape_item_t cb = key_escape_callbacks.a[ind]; cb.func (cb.data); } return; } //FIXME maybe still a tad over-coupled. Use callbacks for menu and console //toggles? Should keys know anything about menu and console? if (key_dest != key_console && key == key_toggleconsole && keydown[key] == 1) { Cbuf_AddText (cbuf, "toggleconsole"); return; } if (key_dest < 0 || key_dest >= key_last) { Sys_Error ("Bad key_dest"); } if (!Key_Game (key, unicode)) { if (key_event_handlers[key_dest]) { key_event_handlers[key_dest] (key, unicode, down, key_event_data[key_dest]); } } } VISIBLE void Key_FocusEvent (int gain) { if (gain) { Key_CallDestCallbacks (key_dest); } else { Key_CallDestCallbacks (key_unfocused); } } void Key_ClearStates (void) { int i; for (i = 0; i < QFK_LAST; i++) { if (keydown[i]) Key_Event (i, 0, false); keydown[i] = false; } } static struct { keydest_t kd; const char *imt_name; const char *chain_imt_name; } default_imts[] = { {key_game, "imt_mod", 0}, {key_game, "imt_0", "imt_mod"}, {key_game, "imt_1", "imt_0"}, {key_game, "imt_2", "imt_0"}, {key_game, "imt_3", "imt_0"}, {key_game, "imt_4", "imt_0"}, {key_game, "imt_5", "imt_0"}, {key_game, "imt_6", "imt_0"}, {key_game, "imt_7", "imt_0"}, {key_game, "imt_8", "imt_0"}, {key_game, "imt_9", "imt_0"}, {key_game, "imt_10", "imt_0"}, {key_game, "imt_11", "imt_0"}, {key_game, "imt_12", "imt_0"}, {key_game, "imt_13", "imt_0"}, {key_game, "imt_14", "imt_0"}, {key_game, "imt_15", "imt_0"}, {key_game, "imt_16", "imt_0"}, {key_demo, "imt_demo", 0}, {key_console, "imt_console", 0}, {key_message, "imt_message", 0}, {key_menu, "imt_menu", 0}, {key_last, 0, 0}, }; static struct { const char *imt; const char *key; const char *command; } default_bindings[] = { {"imt_mod", "K_F10", "quit"}, {"imt_mod", "K_BACKQUOTE", "toggleconsole"}, {"imt_0", "K_F10", "quit"}, {"imt_0", "K_BACKQUOTE", "toggleconsole"}, {"imt_demo", "K_F10", "quit"}, {"imt_demo", "K_BACKQUOTE", "toggleconsole"}, {"imt_console", "K_F10", "quit"}, {"imt_console", "K_BACKQUOTE", "toggleconsole"}, {"imt_menu", "K_F10", "quit"}, {"imt_console", "K_BACKQUOTE", "toggleconsole"}, { } }; static void Key_CreateDefaultIMTs (void) { int i; for (i = 0; default_imts[i].kd != key_last; i++) { Key_CreateIMT (default_imts[i].kd, default_imts[i].imt_name, default_imts[i].chain_imt_name); } for (i = 0; default_bindings[i].imt; i++) { Key_In_Bind (default_bindings[i].imt, default_bindings[i].key, default_bindings[i].command); } } void Key_Init (cbuf_t *cb) { cbuf = cb; Key_CreateDefaultIMTs (); OK_Init (); // register our functions Cmd_AddCommand ("in_bind", Key_In_Bind_f, "Assign a command or a set of " "commands to a key.\n" "Note: To bind multiple commands to a key, enclose the " "commands in quotes and separate with semi-colons."); Cmd_AddCommand ("in_unbind", Key_In_Unbind_f, "Remove the bind from the the selected key"); Cmd_AddCommand ("unbindall", Key_Unbindall_f, "Remove all binds (USE CAUTIOUSLY!!!)"); Cmd_AddCommand ("in_clear", Key_In_Clear, "Remove all binds from the specified imts"); Cmd_AddCommand ("in_type", Key_In_Type_f, "Send the given string as simulated key presses."); Cmd_AddCommand ("imt", Key_InputMappingTable_f, ""); Cmd_AddCommand ("imt_keydest", Key_IMT_Keydest_f, ""); Cmd_AddCommand ("imt_create", Key_IMT_Create_f, "create a new imt table:\n" " imt_create [chain_name]\n" "\n" "The new table will be attached to the specified keydest\n" "imt_name must not already exist.\n" "If given, chain_name must already exist and be on " "keydest.\n"); Cmd_AddCommand ("imt_drop_all", Key_IMT_Drop_All_f, "delete all imt tables\n"); Cmd_AddCommand ("bind", Key_Bind_f, "wrapper for in_bind that uses " "in_bind_imt for the imt parameter"); Cmd_AddCommand ("unbind", Key_Unbind_f, "wrapper for in_unbind that uses in_bind_imt for the imt " "parameter"); Cmd_AddCommand ("bindlist", Key_Bindlist_f, "list all of the key bindings"); Cmd_AddCommand ("keyhelp", keyhelp_f, "display the keyname for the next " "RECOGNIZED key-press. If the key pressed produces no " "output, " PACKAGE_NAME " does not recognise that key."); } void Key_Init_Cvars (void) { Cvar_Get ("in_key_toggleconsole", "K_BACKQUOTE", CVAR_NONE, in_key_toggleconsole_f, "Key for toggling the console."); } const char * Key_GetBinding (imt_t *imt, knum_t key) { if (imt) { return imt->bindings[key].str; } return 0; } VISIBLE void Key_SetKeyDest(keydest_t kd) { if (kd < 0 || kd >= key_last) { Sys_Error ("Bad key_dest: %d", kd); } Sys_MaskPrintf (SYS_input, "Key_SetKeyDest: %s\n", keydest_names[kd]); if (key_dest != kd) { key_dest = kd; Key_CallDestCallbacks (key_dest); } } VISIBLE keydest_t Key_GetKeyDest (void) { return key_dest; } VISIBLE void Key_KeydestCallback (keydest_callback_t *callback, void *data) { if (!callback) { Sys_Error ("null keydest callback"); } keydest_callback_item_t cb = { callback, data }; DARRAY_APPEND (&keydest_callbacks, cb); } VISIBLE void Key_PushEscape (key_escape_t *callback, void *data) { if (!callback) { Sys_Error ("null escape callback"); } key_escape_item_t cb = { callback, data }; DARRAY_APPEND (&key_escape_callbacks, cb); } VISIBLE void Key_PopEscape (void) { if (!key_escape_callbacks.size) { Sys_Error ("no escape callback to pop"); } DARRAY_REMOVE (&key_escape_callbacks); }