From 3b586fc0a6ef54801b30a791cda5f736ed5a6f86 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 23 Jul 2021 02:25:16 +0900 Subject: [PATCH] [console] Untangle console and menu toggling The recent changes to key handling broke using escape to get out of the console (escape would toggle between console and menu). Thus take care of the menu (escape) part of the coupling FIXME by implementing a callback for the escape key (and removing key_togglemenu) and sorting out the escape key handling in console. Seems to work nicely --- include/QF/keys.h | 32 +++++++--- libs/console/client.c | 103 ++++++++++++++++++-------------- libs/console/menu.c | 8 +++ libs/input/keys.c | 116 ++++++++++++++++++++---------------- libs/video/targets/in_x11.c | 4 +- nq/source/host.c | 4 +- nq/source/sbar.c | 4 +- nq/source/sv_ded.c | 2 +- qw/source/cl_chat.c | 4 +- qw/source/sbar.c | 4 +- 10 files changed, 167 insertions(+), 114 deletions(-) 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));