[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
This commit is contained in:
Bill Currie 2021-07-23 02:25:16 +09:00
parent 30dc82f290
commit 3b586fc0a6
10 changed files with 167 additions and 114 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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");

View File

@ -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 ();

View File

@ -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));

View File

@ -59,7 +59,7 @@ GIB_Key_Init (void)
}
void
Key_KeydestCallback (keydest_callback_t *callback)
Key_KeydestCallback (keydest_callback_t *callback, void *data)
{
}

View File

@ -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);
}

View File

@ -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));