From: PatR Date: Fri, 25 Dec 2020 21:57:05 +0000 (-0800) Subject: fix github issue #426 - binding special commands X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0ec355bdb4340cf8e055b3be61ce0577a2064ce9;p=nethack fix github issue #426 - binding special commands Binding 'repeat' (DOAGAIN, or redo) to a different key than ^A didn't work as intended because the code that used it was checking for DOAGAIN (a key value from config.h) instead of g.Cmd.spkeys[NHKF_DOAGAIN] (the key currently bound to repeat). Contrary to the github issue, re-bound prefix keys worked ok for me if followed by a direction. However, they behaved strangely if followed by anything else. If the keystroke was stolen from some other command and that command hadn't been bound to another key, following the prefix with a non-direction could end up executing the command that used to own the key. For example, BIND=d:nopickup to use 'd' to move without auto-pickup would work if you used d but if you used d if would execute the drop command. The NHKF_REQMENU prefix could be bound to some key other than 'm' but it only worked as intended if the new key was a movement prefix. This also makes DOAGAIN be unconditional. If it is deleted or commented out in config.h, the default binding will be '\000' so unusable (freeing up ^A for something), but still be available to be bound to some key (perhaps even ^A). This also includes an unrelated change to mdlib.c. The comments added to config.h will force a full rebuild. Changing mdlib.c now rather than separately will avoid forcing that twice. Fixes #426 --- diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 6a52bd5fc..f538e48a5 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -1,4 +1,4 @@ -NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.401 $ $NHDT-Date: 1608846067 2020/12/24 21:41:07 $ +NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.402 $ $NHDT-Date: 1608933417 2020/12/25 21:56:57 $ General Fixes and Modified Features ----------------------------------- @@ -345,6 +345,15 @@ best possible armor class reduced from -127 to -99; worst from +127 to +99; charged or enchanted individual items also capped at +/- 99 (affects wizard mode wishing, negligible effect on normal play) fix several inconsistencies for objects at hole locations +make repeat (^A) work when bound to some other keystroke +if a prefix key was bound to some character which ordinarily ran a regular + command and that command wasn't bound to another key, typing the + prefix followed by a non-movement key behaved strangely: instead + of reporting "invalid direction" it would run the other command + (actually depended upon relative order of prefix's new and old key) +reqmenu (the request-a-menu prefix supported by a handful of non-movement + commands) could be bound to some key other than 'm' but it only + worked if the new key was also a movement prefix Fixes to 3.7.0-x Problems that Were Exposed Via git Repository @@ -692,6 +701,8 @@ add 'sortdiscoveries' option to control output of '\' and '`' commands include an indication of monsters' health during farlook feedback (including /M and autodescribe); also include it in death reason when killed by a monster: "killed by {an uninjured newt,a heavily injured mumak}" +make DOAGAIN (^A) become unconditional; commenting it out in config.h makes + it be bound to NUL, a no-op, but allows BIND=k:repeat to set it to k Platform- and/or Interface-Specific New Features diff --git a/include/config.h b/include/config.h index a94b38267..1d762d99e 100644 --- a/include/config.h +++ b/include/config.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 config.h $NHDT-Date: 1596498529 2020/08/03 23:48:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.143 $ */ +/* NetHack 3.7 config.h $NHDT-Date: 1608933417 2020/12/25 21:56:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.146 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2016. */ /* NetHack may be freely redistributed. See license for details. */ @@ -482,7 +482,12 @@ typedef unsigned char uchar; #endif #endif -#define DOAGAIN '\001' /* ^A, the "redo" key used in cmd.c and getline.c */ +/* The "repeat" key used in cmd.c as NHKF_DOAGAIN; if commented out or the + * value is changed from C('A') to 0, it won't be bound to any keystroke + * unless you use the run-time configuration file's BIND directive for it. + * [Note: C() macro isn't defined yet but it will be before DOAGAIN is used.] + */ +#define DOAGAIN C('A') /* repeat previous command; default is ^A, '\001' */ /* CONFIG_ERROR_SECURE: If user makes NETHACKOPTIONS point to a file ... * TRUE: Show the first error, nothing else. diff --git a/src/cmd.c b/src/cmd.c index 2192f499c..e40b4eab6 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 cmd.c $NHDT-Date: 1608233885 2020/12/17 19:38:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.437 $ */ +/* NetHack 3.7 cmd.c $NHDT-Date: 1608933418 2020/12/25 21:56:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.440 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2875,6 +2875,10 @@ wiz_migrate_mons() } #endif +#ifndef DOAGAIN /* might have gotten undefined in config.h */ +#define DOAGAIN '\0' /* undefined => 0, '\0' => no key to activate redo */ +#endif + static struct { int nhkf; uchar key; @@ -3364,7 +3368,9 @@ register char *cmd; g.context.move = FALSE; return; } - if (*cmd == DOAGAIN && !g.in_doagain && g.saveq[0]) { + /* DOAGAIN might be '\0'; if so, don't execute it even if *cmd is too */ + if ((*cmd && *cmd == g.Cmd.spkeys[NHKF_DOAGAIN]) + && !g.in_doagain && g.saveq[0]) { g.in_doagain = TRUE; g.stail = 0; rhack((char *) 0); /* read and execute command */ @@ -3475,9 +3481,9 @@ register char *cmd; break; } - /* some special prefix handling */ - /* overload 'm' prefix to mean "request a menu" */ - if (prefix_seen && cmd[0] == g.Cmd.spkeys[NHKF_REQMENU]) { + /* after movement--if reqmenu duplicates a prefix, movement takes + precedence; "request a menu" (default 'm') */ + if (cmd[0] == g.Cmd.spkeys[NHKF_REQMENU]) { /* (for func_tab cast, see below) */ const struct ext_func_tab *ft = g.Cmd.commands[cmd[1] & 0xff]; int NDECL((*func)) = ft ? ((struct ext_func_tab *) ft)->ef_funct : 0; @@ -3485,6 +3491,9 @@ register char *cmd; if (func && accept_menu_prefix(func)) { iflags.menu_requested = TRUE; ++cmd; + prefix_seen = FALSE; + } else { + prefix_seen = TRUE; } } @@ -3518,10 +3527,14 @@ register char *cmd; g.context.mv = TRUE; domove(); return; - } else if (prefix_seen && cmd[1] == g.Cmd.spkeys[NHKF_ESC]) { - /* */ - /* don't report "unknown command" for change of heart... */ - bad_command = FALSE; + } else if (prefix_seen) { + if (cmd[1] == g.Cmd.spkeys[NHKF_ESC]) { + /* */ + /* don't report "unknown command" for change of heart... */ + bad_command = FALSE; + } else { /* prefix followed by non-movement command */ + bad_command = TRUE; /* skip cmdlist[] loop */ + } } else if (*cmd == ' ' && !flags.rest_on_space) { bad_command = TRUE; /* skip cmdlist[] loop */ @@ -3641,7 +3654,8 @@ static boolean prefix_cmd(c) char c; { - return (c == g.Cmd.spkeys[NHKF_RUSH] + return (c == g.Cmd.spkeys[NHKF_REQMENU] + || c == g.Cmd.spkeys[NHKF_RUSH] || c == g.Cmd.spkeys[NHKF_RUN] || c == g.Cmd.spkeys[NHKF_NOPICKUP] || c == g.Cmd.spkeys[NHKF_RUN_NOPICKUP] @@ -4448,7 +4462,7 @@ parse() if (foo == g.Cmd.spkeys[NHKF_ESC]) { /* esc cancels count (TH) */ clear_nhwindow(WIN_MESSAGE); g.multi = g.last_multi = 0; - } else if (foo == g.Cmd.spkeys[NHKF_DOAGAIN] || g.in_doagain) { + } else if ((foo && foo == g.Cmd.spkeys[NHKF_DOAGAIN]) || g.in_doagain) { g.multi = g.last_multi; } else { g.last_multi = g.multi; diff --git a/src/mdlib.c b/src/mdlib.c index bbd85225b..c1595450f 100644 --- a/src/mdlib.c +++ b/src/mdlib.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mdlib.c $NHDT-Date: 1596567095 2020/08/04 18:51:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 mdlib.c $NHDT-Date: 1608933420 2020/12/25 21:57:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.17 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */ /* Copyright (c) M. Stephenson, 1990, 1991. */ @@ -478,6 +478,13 @@ static const char *build_opts[] = { #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__)) "external program as a message handler", #endif +#if defined(HANGUPHANDLING) && !defined(NO_SIGNAL) +#ifdef SAFERHANGUP + "deferred handling of hangup signal", +#else + "immediate handling of hangup signal", +#endif +#endif #ifdef INSURANCE "insurance files for recovering from crashes", #endif @@ -709,9 +716,9 @@ build_options() continue; #endif #endif /* !MAKEDEFS_C && FOR_RUNTIME */ - opt_out_words(strcat(strcpy(buf, build_opts[i]), - (i < SIZE(build_opts) - 1) ? "," : "."), - &length); + Strcat(strcpy(buf, build_opts[i]), + (i < SIZE(build_opts) - 1) ? "," : "."); + opt_out_words(buf, &length); } opttext[idxopttext] = strdup(optbuf); if (idxopttext < (MAXOPT - 1)) diff --git a/win/Qt/qt_main.cpp b/win/Qt/qt_main.cpp index 18759e0d8..cb2eade3d 100644 --- a/win/Qt/qt_main.cpp +++ b/win/Qt/qt_main.cpp @@ -814,7 +814,8 @@ NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : QSignalMapper* sm = new QSignalMapper(this); connect(sm, SIGNAL(mapped(const QString&)), this, SLOT(doKeys(const QString&))); - // 'donull' is a placeholder here; AddToolButton() will fix it up + // 'donull' is a placeholder here; AddToolButton() will fix it up; + // button will be omitted if DOAGAIN is bound to '\0' AddToolButton(toolbar, sm, "Again", donull, QPixmap(again_xpm)); // this used to be called "Get" which is confusing to experienced players AddToolButton(toolbar, sm, "Pick up", dopickup, QPixmap(pickup_xpm)); @@ -888,20 +889,29 @@ NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : } } +// add a toolbar button to invoke command 'name' via function '(*func)()' void NetHackQtMainWindow::AddToolButton(QToolBar *toolbar, QSignalMapper *sm, const char *name, int NDECL((*func)), QPixmap xpm) { - QToolButton *tb = new SmallToolButton(xpm, QString(name), "Action", - sm, SLOT(map()), toolbar); - char actchar[32]; + char actchar[2]; + uchar key; + // the ^A command is just a keystroke, not a full blown command function - if (!strcmp(name, "Again")) - (void) strkitten(actchar, ::g.Cmd.spkeys[NHKF_DOAGAIN]); - else - Sprintf(actchar, "%c", cmd_from_func(func)); - sm->setMapping(tb, actchar); - toolbar->addWidget(tb); + if (!strcmp(name, "Again")) { + key = ::g.Cmd.spkeys[NHKF_DOAGAIN]; + } else + key = (uchar) cmd_from_func(func); + + // if key is valid, add a button for it; otherwise omit the command + // (won't work as intended if a different command is bound to same key) + if (key) { + QToolButton *tb = new SmallToolButton(xpm, QString(name), "Action", + sm, SLOT(map()), toolbar); + actchar[0] = '\0'; + sm->setMapping(tb, strkitten(actchar, (char) key)); + toolbar->addWidget(tb); + } } void NetHackQtMainWindow::zoomMap()