]> granicus.if.org Git - nethack/commitdiff
fix github issue #426 - binding special commands
authorPatR <rankin@nethack.org>
Fri, 25 Dec 2020 21:57:05 +0000 (13:57 -0800)
committerPatR <rankin@nethack.org>
Fri, 25 Dec 2020 21:57:05 +0000 (13:57 -0800)
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<direction> but if you used d<something-else> 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

doc/fixes37.0
include/config.h
src/cmd.c
src/mdlib.c
win/Qt/qt_main.cpp

index 6a52bd5fcdc3c5e1e17d48fe338a820728b0faaf..f538e48a5932145ab511265b73dfc61c9b25fa1c 100644 (file)
@@ -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
index a94b382678c7dfc9b2b6831d2aae97b17b08a6fb..1d762d99e11eb95186f257c7be6dd0bedd76f6a6 100644 (file)
@@ -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.
index 2192f499c5b2ed83acf632cdeb0f6c5b78dc0c9f..e40b4eab6a4761b4009b2bb8a9456f1be2009a60 100644 (file)
--- 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]) {
-        /* <prefix><escape> */
-        /* don't report "unknown command" for change of heart... */
-        bad_command = FALSE;
+    } else if (prefix_seen) {
+        if (cmd[1] == g.Cmd.spkeys[NHKF_ESC]) {
+            /* <prefix><escape> */
+            /* 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;
index bbd85225b6e321546801692807e93167d10f61d3..c1595450fd54703e2cdecd14b3cf39dbead33c2a 100644 (file)
@@ -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))
index 18759e0d83607093e30a01c24b41ae920bef2ea6..cb2eade3d1aa22ea19101225089183181bd6df2a 100644 (file)
@@ -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()