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<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
This commit is contained in:
PatR
2020-12-25 13:57:05 -08:00
parent 1a2afd21d4
commit 0ec355bdb4
5 changed files with 75 additions and 28 deletions
+12 -1
View 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 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 charged or enchanted individual items also capped at +/- 99 (affects
wizard mode wishing, negligible effect on normal play) wizard mode wishing, negligible effect on normal play)
fix several inconsistencies for objects at hole locations 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 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 include an indication of monsters' health during farlook feedback (including
/M and autodescribe); also include it in death reason when killed by /M and autodescribe); also include it in death reason when killed by
a monster: "killed by {an uninjured newt,a heavily injured mumak}" 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 Platform- and/or Interface-Specific New Features
+7 -2
View 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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2016. */ /*-Copyright (c) Robert Patrick Rankin, 2016. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -482,7 +482,12 @@ typedef unsigned char uchar;
#endif #endif
#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 ... /* CONFIG_ERROR_SECURE: If user makes NETHACKOPTIONS point to a file ...
* TRUE: Show the first error, nothing else. * TRUE: Show the first error, nothing else.
+25 -11
View File
@@ -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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2013. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -2875,6 +2875,10 @@ wiz_migrate_mons()
} }
#endif #endif
#ifndef DOAGAIN /* might have gotten undefined in config.h */
#define DOAGAIN '\0' /* undefined => 0, '\0' => no key to activate redo */
#endif
static struct { static struct {
int nhkf; int nhkf;
uchar key; uchar key;
@@ -3364,7 +3368,9 @@ register char *cmd;
g.context.move = FALSE; g.context.move = FALSE;
return; 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.in_doagain = TRUE;
g.stail = 0; g.stail = 0;
rhack((char *) 0); /* read and execute command */ rhack((char *) 0); /* read and execute command */
@@ -3475,9 +3481,9 @@ register char *cmd;
break; break;
} }
/* some special prefix handling */ /* after movement--if reqmenu duplicates a prefix, movement takes
/* overload 'm' prefix to mean "request a menu" */ precedence; "request a menu" (default 'm') */
if (prefix_seen && cmd[0] == g.Cmd.spkeys[NHKF_REQMENU]) { if (cmd[0] == g.Cmd.spkeys[NHKF_REQMENU]) {
/* (for func_tab cast, see below) */ /* (for func_tab cast, see below) */
const struct ext_func_tab *ft = g.Cmd.commands[cmd[1] & 0xff]; const struct ext_func_tab *ft = g.Cmd.commands[cmd[1] & 0xff];
int NDECL((*func)) = ft ? ((struct ext_func_tab *) ft)->ef_funct : 0; 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)) { if (func && accept_menu_prefix(func)) {
iflags.menu_requested = TRUE; iflags.menu_requested = TRUE;
++cmd; ++cmd;
prefix_seen = FALSE;
} else {
prefix_seen = TRUE;
} }
} }
@@ -3518,10 +3527,14 @@ register char *cmd;
g.context.mv = TRUE; g.context.mv = TRUE;
domove(); domove();
return; return;
} else if (prefix_seen && cmd[1] == g.Cmd.spkeys[NHKF_ESC]) { } else if (prefix_seen) {
/* <prefix><escape> */ if (cmd[1] == g.Cmd.spkeys[NHKF_ESC]) {
/* don't report "unknown command" for change of heart... */ /* <prefix><escape> */
bad_command = FALSE; /* 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) { } else if (*cmd == ' ' && !flags.rest_on_space) {
bad_command = TRUE; /* skip cmdlist[] loop */ bad_command = TRUE; /* skip cmdlist[] loop */
@@ -3641,7 +3654,8 @@ static boolean
prefix_cmd(c) prefix_cmd(c)
char 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_RUN]
|| c == g.Cmd.spkeys[NHKF_NOPICKUP] || c == g.Cmd.spkeys[NHKF_NOPICKUP]
|| c == g.Cmd.spkeys[NHKF_RUN_NOPICKUP] || c == g.Cmd.spkeys[NHKF_RUN_NOPICKUP]
@@ -4448,7 +4462,7 @@ parse()
if (foo == g.Cmd.spkeys[NHKF_ESC]) { /* esc cancels count (TH) */ if (foo == g.Cmd.spkeys[NHKF_ESC]) { /* esc cancels count (TH) */
clear_nhwindow(WIN_MESSAGE); clear_nhwindow(WIN_MESSAGE);
g.multi = g.last_multi = 0; 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; g.multi = g.last_multi;
} else { } else {
g.last_multi = g.multi; g.last_multi = g.multi;
+11 -4
View 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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */ /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */
/* Copyright (c) M. Stephenson, 1990, 1991. */ /* Copyright (c) M. Stephenson, 1990, 1991. */
@@ -478,6 +478,13 @@ static const char *build_opts[] = {
#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__)) #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
"external program as a message handler", "external program as a message handler",
#endif #endif
#if defined(HANGUPHANDLING) && !defined(NO_SIGNAL)
#ifdef SAFERHANGUP
"deferred handling of hangup signal",
#else
"immediate handling of hangup signal",
#endif
#endif
#ifdef INSURANCE #ifdef INSURANCE
"insurance files for recovering from crashes", "insurance files for recovering from crashes",
#endif #endif
@@ -709,9 +716,9 @@ build_options()
continue; continue;
#endif #endif
#endif /* !MAKEDEFS_C && FOR_RUNTIME */ #endif /* !MAKEDEFS_C && FOR_RUNTIME */
opt_out_words(strcat(strcpy(buf, build_opts[i]), Strcat(strcpy(buf, build_opts[i]),
(i < SIZE(build_opts) - 1) ? "," : "."), (i < SIZE(build_opts) - 1) ? "," : ".");
&length); opt_out_words(buf, &length);
} }
opttext[idxopttext] = strdup(optbuf); opttext[idxopttext] = strdup(optbuf);
if (idxopttext < (MAXOPT - 1)) if (idxopttext < (MAXOPT - 1))
+20 -10
View File
@@ -814,7 +814,8 @@ NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) :
QSignalMapper* sm = new QSignalMapper(this); QSignalMapper* sm = new QSignalMapper(this);
connect(sm, SIGNAL(mapped(const QString&)), connect(sm, SIGNAL(mapped(const QString&)),
this, SLOT(doKeys(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)); AddToolButton(toolbar, sm, "Again", donull, QPixmap(again_xpm));
// this used to be called "Get" which is confusing to experienced players // this used to be called "Get" which is confusing to experienced players
AddToolButton(toolbar, sm, "Pick up", dopickup, QPixmap(pickup_xpm)); 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, void NetHackQtMainWindow::AddToolButton(QToolBar *toolbar, QSignalMapper *sm,
const char *name, int NDECL((*func)), const char *name, int NDECL((*func)),
QPixmap xpm) QPixmap xpm)
{ {
QToolButton *tb = new SmallToolButton(xpm, QString(name), "Action", char actchar[2];
sm, SLOT(map()), toolbar); uchar key;
char actchar[32];
// the ^A command is just a keystroke, not a full blown command function // the ^A command is just a keystroke, not a full blown command function
if (!strcmp(name, "Again")) if (!strcmp(name, "Again")) {
(void) strkitten(actchar, ::g.Cmd.spkeys[NHKF_DOAGAIN]); key = ::g.Cmd.spkeys[NHKF_DOAGAIN];
else } else
Sprintf(actchar, "%c", cmd_from_func(func)); key = (uchar) cmd_from_func(func);
sm->setMapping(tb, actchar);
toolbar->addWidget(tb); // 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() void NetHackQtMainWindow::zoomMap()