diff --git a/include/QF/keys.h b/include/QF/keys.h index 50dc7ff0f..0159d80bc 100644 --- a/include/QF/keys.h +++ b/include/QF/keys.h @@ -537,7 +537,6 @@ typedef struct { int state; // low bit is down state } kbutton_t; -extern knum_t key_togglemenu; extern knum_t key_toggleconsole; typedef struct keybind_s { @@ -571,8 +570,8 @@ extern int keydown[QFK_LAST]; \param down True if a press event, false if a release event. \param data Callback specific data pointer as passed to Key_SetKeyDest */ -typedef void (*key_event_t) (knum_t key, short unicode, qboolean down, - void *data); +typedef void key_event_t (knum_t key, short unicode, qboolean down, + void *data); /** Set the fallback key event handler callback for the specified keydest. @@ -585,9 +584,25 @@ typedef void (*key_event_t) (knum_t key, short unicode, qboolean down, \param keydest The keydest for which the callback will be set. \param callback The function to be called when an event occurs. - \param data Opaque data pointerer passed to the callback. + \param data Opaque data pointer passed to the callback. */ -void Key_SetKeyEvent (keydest_t keydest, key_event_t callback, void *data); +void Key_SetKeyEvent (keydest_t keydest, key_event_t *callback, void *data); + +/** Callback for handling the escape key. + \param data Callback specific data pointer as passed to Key_PushEscape +*/ +typedef void key_escape_t (void *data); + +/** Push an escape key event handler callback. + + \param callback The function to be called when the escape key is pressed. + \param data Opaque data pointer passed to the callback. +*/ +void Key_PushEscape (key_escape_t *callback, void *data); + +/** Push an escape key event handler callback. +*/ +void Key_PopEscape (void); struct cbuf_s; @@ -687,14 +702,17 @@ keydest_t Key_GetKeyDest(void) __attribute__((pure)); /** keydest callback signature. \param kd The new current keydest target. + \param data Callback specific data pointer as passed to + Key_KeydestCallback */ -typedef void keydest_callback_t (keydest_t kd); +typedef void keydest_callback_t (keydest_t kd, void *data); /** Add a callback for when the keydest target changes. \param callback The callback to be added. + \param data Opaque data pointer passed to the callback. */ -void Key_KeydestCallback (keydest_callback_t *callback); +void Key_KeydestCallback (keydest_callback_t *callback, void *data); /** Get the string representation of a key. diff --git a/libs/console/client.c b/libs/console/client.c index 32dbb4a62..186d2a509 100644 --- a/libs/console/client.c +++ b/libs/console/client.c @@ -106,7 +106,8 @@ static view_t *hud_view; static qboolean con_initialized; -static keydest_t con_keydest; +static keydest_t con_curr_keydest; +static keydest_t con_prev_keydest; static void ClearNotify (void) @@ -123,9 +124,10 @@ ToggleConsole_f (void) { Con_ClearTyping (input_line, 0); - if (con_keydest == key_console && !con_data.force_commandline) { - Key_SetKeyDest (key_game); + if (con_curr_keydest == key_console && !con_data.force_commandline) { + Key_SetKeyDest (con_prev_keydest); } else { + con_prev_keydest = Key_GetKeyDest (); Key_SetKeyDest (key_console); } @@ -137,7 +139,7 @@ ToggleChat_f (void) { Con_ClearTyping (input_line, 0); - if (con_keydest == key_console && !con_data.force_commandline) { + if (con_curr_keydest == key_console && !con_data.force_commandline) { Key_SetKeyDest (key_game); } else { Key_SetKeyDest (key_console); @@ -453,49 +455,19 @@ C_KeyEvent (knum_t key, short unicode, qboolean down, void *data) if (!down) return; - if (con_keydest == key_menu) { + if (con_curr_keydest == key_menu) { if (Menu_KeyEvent (key, unicode, down)) return; } if (down) { - if (key == key_togglemenu) { - switch (con_keydest) { - case key_menu: - Menu_Leave (); - return; - case key_message: - if (chat_team) { - Con_ClearTyping (say_team_line, 1); - } else { - Con_ClearTyping (say_line, 1); - } - Key_SetKeyDest (key_game); - return; - case key_console: - if (!con_data.force_commandline) { - Cbuf_AddText (con_data.cbuf, "toggleconsole\n"); - return; - } - case key_game: - case key_demo: - Menu_Enter (); - return; - case key_unfocused: - return; - case key_last: - break; // should not happen, so hit error - } - Sys_Error ("Bad con_keydest"); - } else if (key == key_toggleconsole) { + if (key == key_toggleconsole) { ToggleConsole_f (); return; } } - if (con_keydest == key_menu) { - return; - } else if (con_keydest == key_message) { + if (con_curr_keydest == key_message) { if (chat_team) { il = say_team_line; } else { @@ -579,7 +551,7 @@ C_DrawInputLine (inputline_t *il) static void draw_input (view_t *view) { - if (con_keydest != key_console)// && !con_data.force_commandline) + if (con_curr_keydest != key_console)// && !con_data.force_commandline) return; // don't draw anything (always draw if not active) DrawInputLine (view->xabs + 8, view->yabs, 1, input_line); @@ -734,7 +706,7 @@ setup_console (void) if (con_data.force_commandline) { lines = con_data.lines = r_data->vid->conview->ylen; - } else if (con_keydest == key_console) { + } else if (con_curr_keydest == key_console) { lines = r_data->vid->conview->ylen * bound (0.2, con_size->value, 1); } else { lines = 0; @@ -763,9 +735,9 @@ C_DrawConsole (void) if (console_view->ylen != con_data.lines) view_resize (console_view, console_view->xlen, con_data.lines); - say_view->visible = con_keydest == key_message; + say_view->visible = con_curr_keydest == key_message; console_view->visible = con_data.lines != 0; - menu_view->visible = con_keydest == key_menu; + menu_view->visible = con_curr_keydest == key_menu; con_data.view->draw (con_data.view); } @@ -806,10 +778,50 @@ exec_line (inputline_t *il) } static void -con_keydest_callback (keydest_t kd) +con_end_message (void *line) { - // simply cache the value - con_keydest = kd; + Key_PopEscape (); + Con_ClearTyping (line, 1); + Key_SetKeyDest (key_game); +} + +static void +con_leave_console (void *data) +{ + ToggleConsole_f (); +} + +static void +con_keydest_callback (keydest_t kd, void *data) +{ + if (kd == key_unfocused || kd == con_curr_keydest) { + return; + } + if (kd != key_console && con_curr_keydest == key_console) { + Key_PopEscape (); + } + switch (kd) { + case key_last: + case key_game: + case key_demo: + case key_unfocused: + case key_menu: + break; + case key_message: + Key_PushEscape (con_end_message, + chat_team ? say_team_line : say_line); + break; + case key_console: + Key_PushEscape (con_leave_console, 0); + break; + } + con_curr_keydest = kd; +} + +static void +con_enter_menu (void *data) +{ + Menu_Enter (); } static void @@ -821,7 +833,8 @@ C_Init (void) setlocale (LC_ALL, "C-TRADITIONAL"); #endif - Key_KeydestCallback (con_keydest_callback); + Key_PushEscape (con_enter_menu, 0); + Key_KeydestCallback (con_keydest_callback, 0); Key_SetKeyEvent (key_message, C_KeyEvent, 0); Key_SetKeyEvent (key_menu, C_KeyEvent, 0); Key_SetKeyEvent (key_console, C_KeyEvent, 0); diff --git a/libs/console/menu.c b/libs/console/menu.c index b635fcfaa..d7c48df60 100644 --- a/libs/console/menu.c +++ b/libs/console/menu.c @@ -779,6 +779,12 @@ Menu_KeyEvent (knum_t key, short unicode, qboolean down) } } +static void +menu_leave (void *data) +{ + Menu_Leave (); +} + void Menu_Enter () { @@ -789,6 +795,7 @@ Menu_Enter () menu = Hash_Find (menu_hash, top_menu); if (menu) { menu_keydest = Key_GetKeyDest (); + Key_PushEscape (menu_leave, 0); Key_SetKeyDest (key_menu); if (menu->enter_hook) { run_menu_pre (); @@ -809,6 +816,7 @@ Menu_Leave () } menu = menu->parent; if (!menu) { + Key_PopEscape (); Key_SetKeyDest (menu_keydest); } } diff --git a/libs/input/keys.c b/libs/input/keys.c index 1f860f081..2a61122fd 100644 --- a/libs/input/keys.c +++ b/libs/input/keys.c @@ -42,6 +42,7 @@ #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" @@ -53,13 +54,25 @@ static keydest_t key_dest = key_console; static keytarget_t key_targets[key_last]; -VISIBLE knum_t key_togglemenu = QFK_ESCAPE; VISIBLE knum_t key_toggleconsole = QFK_BACKQUOTE; -#define KEYDEST_CALLBACK_CHUNK 16 -static keydest_callback_t **keydest_callbacks; -static int num_keydest_callbacks; -static int max_keydest_callbacks; +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]; @@ -614,10 +627,10 @@ Key_SetBinding (imt_t *imt, knum_t keynum, const char *binding) static void Key_CallDestCallbacks (keydest_t kd) { - int i; - - for (i = 0; i < num_keydest_callbacks; i++) - keydest_callbacks[i] (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 @@ -934,23 +947,6 @@ Key_Bind_f (void) } } -static void -in_key_togglemenu_f (cvar_t *var) -{ - int k; - - if (!*var->string) { - key_togglemenu = QFK_ESCAPE; - return; - } - if ((k = Key_StringToKeynum (var->string)) == -1) { - k = QFK_ESCAPE; - Sys_Printf ("\"%s\" is not a valid key. setting to \"K_ESCAPE\"\n", - var->string); - } - key_togglemenu = k; -} - static void in_key_toggleconsole_f (cvar_t *var) { @@ -1116,11 +1112,11 @@ keyhelp_f (void) keyhelp = 1; } -static key_event_t key_event_handlers[key_last] = { }; +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) +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); @@ -1152,15 +1148,20 @@ Key_Event (knum_t key, short unicode, qboolean down) keydown[key] = 0; } - // handle menu and console toggle keys specially so the user can never - // override or unbind them + // 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_menu && key == key_togglemenu && keydown[key] == 1) { - Cbuf_AddText (cbuf, "togglemenu"); - return; - } else if (key_dest != key_console && key == key_toggleconsole - && keydown[key] == 1) { + if (key_dest != key_console && key == key_toggleconsole + && keydown[key] == 1) { Cbuf_AddText (cbuf, "toggleconsole"); return; } @@ -1310,8 +1311,6 @@ Key_Init (cbuf_t *cb) void Key_Init_Cvars (void) { - Cvar_Get ("in_key_togglemenu", "", CVAR_NONE, in_key_togglemenu_f, - "Key for toggling the menu."); Cvar_Get ("in_key_toggleconsole", "K_BACKQUOTE", CVAR_NONE, in_key_toggleconsole_f, "Key for toggling the console."); @@ -1333,8 +1332,10 @@ Key_SetKeyDest(keydest_t kd) Sys_Error ("Bad key_dest: %d", kd); } Sys_MaskPrintf (SYS_input, "Key_SetKeyDest: %s\n", keydest_names[kd]); - key_dest = kd; - Key_CallDestCallbacks (key_dest); + if (key_dest != kd) { + key_dest = kd; + Key_CallDestCallbacks (key_dest); + } } VISIBLE keydest_t @@ -1344,19 +1345,32 @@ Key_GetKeyDest (void) } VISIBLE void -Key_KeydestCallback (keydest_callback_t *callback) +Key_KeydestCallback (keydest_callback_t *callback, void *data) { - if (num_keydest_callbacks == max_keydest_callbacks) { - size_t size = (max_keydest_callbacks + KEYDEST_CALLBACK_CHUNK) - * sizeof (keydest_callback_t *); - keydest_callbacks = realloc (keydest_callbacks, size); - if (!keydest_callbacks) - Sys_Error ("Too many keydest callbacks!"); - max_keydest_callbacks += KEYDEST_CALLBACK_CHUNK; + if (!callback) { + Sys_Error ("null keydest callback"); } - if (!callback) - Sys_Error ("null keydest callback"); - - keydest_callbacks[num_keydest_callbacks++] = 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); } diff --git a/libs/video/targets/in_x11.c b/libs/video/targets/in_x11.c index a2e2a35ce..1cb682416 100644 --- a/libs/video/targets/in_x11.c +++ b/libs/video/targets/in_x11.c @@ -597,7 +597,7 @@ XLateKey (XKeyEvent * ev, int *k, int *u) } static void -x11_keydest_callback (keydest_t key_dest) +x11_keydest_callback (keydest_t key_dest, void *data) { // if (key_dest == key_game) { // XAutoRepeatOff (x_disp); @@ -842,7 +842,7 @@ IN_LL_Init (void) in_mouse_avail = 1; } - Key_KeydestCallback (x11_keydest_callback); + Key_KeydestCallback (x11_keydest_callback, 0); Cmd_AddCommand ("in_paste_buffer", in_paste_buffer_f, "Paste the contents of X's C&P buffer to the console"); diff --git a/nq/source/host.c b/nq/source/host.c index 53c1e3311..69870013d 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -849,7 +849,7 @@ Host_Init_Memory (void) } static void -host_keydest_callback (keydest_t kd) +host_keydest_callback (keydest_t kd, void *data) { host_in_game = kd == key_game; } @@ -888,7 +888,7 @@ Host_Init (void) Mod_Init (); - Key_KeydestCallback (host_keydest_callback); + Key_KeydestCallback (host_keydest_callback, 0); SV_Init (); diff --git a/nq/source/sbar.c b/nq/source/sbar.c index c51e99ec8..5cbf233b9 100644 --- a/nq/source/sbar.c +++ b/nq/source/sbar.c @@ -1644,7 +1644,7 @@ Sbar_GIB_Print_Center_f (void) } static void -sbar_keydest_callback (keydest_t kd) +sbar_keydest_callback (keydest_t kd, void *data) { overlay_view->visible = kd == key_game; } @@ -1656,7 +1656,7 @@ Sbar_Init (void) init_views (); - Key_KeydestCallback (sbar_keydest_callback); + Key_KeydestCallback (sbar_keydest_callback, 0); for (i = 0; i < 10; i++) { sb_nums[0][i] = r_funcs->Draw_PicFromWad (va (0, "num_%i", i)); diff --git a/nq/source/sv_ded.c b/nq/source/sv_ded.c index 0d80842e2..6a854084a 100644 --- a/nq/source/sv_ded.c +++ b/nq/source/sv_ded.c @@ -59,7 +59,7 @@ GIB_Key_Init (void) } void -Key_KeydestCallback (keydest_callback_t *callback) +Key_KeydestCallback (keydest_callback_t *callback, void *data) { } diff --git a/qw/source/cl_chat.c b/qw/source/cl_chat.c index fbc26b983..da3b5f9e8 100644 --- a/qw/source/cl_chat.c +++ b/qw/source/cl_chat.c @@ -250,7 +250,7 @@ CL_ChatInfo (int val) } static void -cl_chat_keydest (keydest_t keydest) +cl_chat_keydest (keydest_t keydest, void *data) { switch (keydest) { case key_game: @@ -277,5 +277,5 @@ CL_Chat_Init (void) Cmd_AddCommand ("ignore", CL_Ignore_f, "Ignores chat and name-change messages from a user."); Cmd_AddCommand ("unignore", CL_Unignore_f, "Removes a previously ignored user from the ignore list."); - Key_KeydestCallback (cl_chat_keydest); + Key_KeydestCallback (cl_chat_keydest, 0); } diff --git a/qw/source/sbar.c b/qw/source/sbar.c index ca8d7b74d..373b108c6 100644 --- a/qw/source/sbar.c +++ b/qw/source/sbar.c @@ -1941,7 +1941,7 @@ Sbar_GIB_Print_Center_f (void) } static void -sbar_keydest_callback (keydest_t kd) +sbar_keydest_callback (keydest_t kd, void *data) { overlay_view->visible = kd == key_game; } @@ -1953,7 +1953,7 @@ Sbar_Init (void) init_views (); - Key_KeydestCallback (sbar_keydest_callback); + Key_KeydestCallback (sbar_keydest_callback, 0); for (i = 0; i < 10; i++) { sb_nums[0][i] = r_funcs->Draw_PicFromWad (va (0, "num_%i", i));