diff --git a/include/hack.h b/include/hack.h index ad215db96..46721704c 100644 --- a/include/hack.h +++ b/include/hack.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 hack.h $NHDT-Date: 1664837602 2022/10/03 22:53:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.196 $ */ +/* NetHack 3.7 hack.h $NHDT-Date: 1680771353 2023/04/06 08:55:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.215 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -749,10 +749,21 @@ struct sinfo { int in_paniclog; /* writing a panicloc entry */ #endif int wizkit_wishing; /* starting wizard mode game w/ WIZKIT file */ - /* getting_a_command: only used for ALTMETA config to process ESC, but - present and updated unconditionally; set by parse() when requesting - next command keystroke, reset by readchar() as it returns a key */ - int getting_a_command; /* next key pressed will be entering a cmnd */ + /* input_state: used in the core for the 'altmeta' option to process ESC; + used in the curses interface to avoid arrow keys when user is doing + something other than entering a command or direction and in the Qt + interface to suppress menu commands in similar conditions; + readchar() alrways resets it to 'otherInp' prior to returning */ + int input_state; /* whether next key pressed will be entering a command */ +}; + +/* value of program_state.input_state, significant during readchar(); + get_count() expects digits then a command so sets it to commandInp */ +enum InputState { + otherInp = 0, /* 'other' */ + commandInp = 1, /* readchar() */ + getposInp = 2, /* getpos() */ + getdirInp = 3, /* getdir() */ }; /* sortloot() return type; needed before extern.h */ diff --git a/src/cmd.c b/src/cmd.c index a23155505..08ad9efa3 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -5209,7 +5209,7 @@ getdir(const char *s) } retry: - gp.program_state.getting_a_command = 1; /* arrow key support for curses */ + gp.program_state.input_state = getdirInp; if (gi.in_doagain || *readchar_queue) dirsym = readchar(); else @@ -6219,7 +6219,7 @@ get_count( unsigned gc_flags) /* control flags: GC_SAVEHIST, GC_ECHOFIRST */ { char qbuf[QBUFSZ]; - int key; + int key, save_input_state = gp.program_state.input_state; long cnt = 0L, first = inkey ? (long) (inkey - '0') : 0L; boolean backspaced = FALSE, showzero = TRUE, /* should "Count: 123" go into message history? */ @@ -6239,8 +6239,9 @@ get_count( key = inkey; inkey = '\0'; } else { - gp.program_state.getting_a_command = 1; /* readchar altmeta - * compatibility */ + /* if readchar() has already been called in this loop, it will + have reset input_state; put that back to its previous value */ + gp.program_state.input_state = save_input_state; key = readchar(); } @@ -6300,9 +6301,9 @@ parse(void) gc.context.move = TRUE; /* assume next command will take game time */ flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */ - gp.program_state.getting_a_command = 1; /* affects readchar() behavior for - * ESC iff 'altmeta' option is On; - * reset to 0 by readchar() */ + /* affects readchar() behavior for ESC iff 'altmeta' option is On; + reset to 0 by readchar() */ + gp.program_state.input_state = commandInp; if (!gc.Cmd.num_pad || (foo = readchar()) == gc.Cmd.spkeys[NHKF_COUNT]) { foo = get_count((char *) 0, '\0', LARGEST_INT, &gc.command_count, GC_NOFLAGS); @@ -6400,8 +6401,10 @@ readchar_core(coordxy *x, coordxy *y, int *mod) { register int sym; - if (iflags.debug_fuzzer) - return randomkey(); + if (iflags.debug_fuzzer) { + sym = randomkey(); + goto readchar_done; + } if (*readchar_queue) sym = *readchar_queue++; else if (gi.in_doagain) @@ -6431,9 +6434,11 @@ readchar_core(coordxy *x, coordxy *y, int *mod) sym = '\033'; #ifdef ALTMETA } else if (sym == '\033' && iflags.altmeta - && gp.program_state.getting_a_command) { + && gp.program_state.input_state != otherInp) { /* iflags.altmeta: treat two character ``ESC c'' as single `M-c' but - only when we're called by parse() [possibly via get_count()] */ + only when we're called by parse() [possibly via get_count()] + or getpos() [to support Alt+digit] or getdir() [for arrow keys + under curses] */ sym = *readchar_queue ? *readchar_queue++ : pgetchar(); if (sym == EOF || sym == 0) sym = '\033'; @@ -6445,12 +6450,15 @@ readchar_core(coordxy *x, coordxy *y, int *mod) gc.clicklook_cc.x = gc.clicklook_cc.y = -1; click_to_cmd(*x, *y, *mod); } - gp.program_state.getting_a_command = 0; /* next readchar() will be for an - * ordinary char unless parse() - * sets this back to 1 */ + + readchar_done: + /* next readchar() will be for an ordinary char unless parse() + sets this back to non-zero */ + gp.program_state.input_state = otherInp; return (char) sym; } +/* get a character */ char readchar(void) { @@ -6462,11 +6470,13 @@ readchar(void) return ch; } +/* used by getpos() to accept mouse input as well as keyboard input */ char readchar_poskey(coordxy *x, coordxy *y, int *mod) { char ch; + gp.program_state.input_state = getposInp; ch = readchar_core(x, y, mod); return ch; } @@ -6632,6 +6642,8 @@ yn_function( dumplogmsg(dumplog_buf); } #endif + /* in case we're called via getdir() which sets input_state */ + gp.program_state.input_state = otherInp; return res; } diff --git a/src/do_name.c b/src/do_name.c index 3371145de..9ddf98019 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -838,7 +838,6 @@ getpos(coord *ccp, boolean force, const char *goal) rushrun = FALSE; - gp.program_state.getting_a_command = 1; if ((cmdq = cmdq_pop()) != 0) { if (cmdq->typ == CMDQ_KEY) { c = cmdq->key; diff --git a/win/Qt/qt_main.cpp b/win/Qt/qt_main.cpp index 0bbddf9c6..a4c27a903 100644 --- a/win/Qt/qt_main.cpp +++ b/win/Qt/qt_main.cpp @@ -459,7 +459,8 @@ aboutMsg() char *p, vbuf[BUFSZ]; /* nethack's getversionstring() includes a final period but we're using it mid-sentence so strip period off */ - if ((p = strrchr(::getversionstring(vbuf, sizeof vbuf), '.')) != 0 && *(p + 1) == '\0') + if ((p = strrchr(::getversionstring(vbuf, sizeof vbuf), '.')) != 0 + && *(p + 1) == '\0') *p = '\0'; /* it's also long; break it into two pieces */ (void) strsubst(vbuf, " - ", "\n- "); @@ -1001,8 +1002,30 @@ public: }; #endif +/* used by doMenuItem() and for the toolbar buttons */ +bool NetHackQtMainWindow::ok_for_command() +{ + /* + * If the core expects text to be entered (perhaps typing in a wish, + * assigning a name to something, or answering a y/n prompt), or a + * map position or a direction is being picked, don't accept commands + * from the toolbar. + * + * FIXME: it would be much better to gray-out inapplicable entries + * when popping up a command menu instead of needing this. + */ + if (::gp.program_state.input_state != commandInp) { + NetHackQtBind::qt_nhbell(); + // possibly call doKeys("\033"); here? + return false; + } + return true; +} + void NetHackQtMainWindow::doMenuItem(QAction *action) { + if (!ok_for_command()) + return; /* this converts meta characters to '?'; menu processing has been changed to send multi-character "#abc" instead (already needed for commands that didn't have either a regular keystroke or a diff --git a/win/Qt/qt_main.h b/win/Qt/qt_main.h index 6925d156e..3aa5de79c 100644 --- a/win/Qt/qt_main.h +++ b/win/Qt/qt_main.h @@ -98,6 +98,7 @@ private: void ShowIfReady(); void AddToolButton(QToolBar *toolbar, QSignalMapper *sm, const char *name, int (*func)(void), QPixmap xpm); + static bool ok_for_command(); #ifdef KDE KMenuBar* menubar; diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index 916fe6daa..ef07fb602 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -856,7 +856,7 @@ Currently this is limited to arrow keys, but this may be expanded. */ int curses_convert_keys(int key) { - boolean reject = !gp.program_state.getting_a_command, + boolean reject = (gp.program_state.input_state == otherInp), as_is = FALSE, numpad_esc; int ret = key;