Support user's terminal settings for erase char and for kill char.
Erase char is typically <delete> or <backspace>, both of which are
already explicitly handled so probably no effect there. Kill char
(generally ^U these days) will be honored unless it is a printable
character (don't know whether there are any troglodytes out there
who still use '@' for that...). The current handling for ESC works
the same if there is any input to kill, but yields 'cancelled' when
there isn't.
That's for message window getline(), which operates char-by-char.
The popup getline() uses a curses routine to get an entire string
and already honors kill char but treats ESC as input of ^[.
The position bars shown by curses when the map is clipped weren't
being drawn as intended (integer arithmetic). Changing parentheses
was enough to get it working, but it didn't handle the edge case
where non-zero got rounded to 0 (so when map was panned down, the
uppermost character of the vertical position bar still showed '*',
falsely indicating that top of map was currently within view.
Followup to 1c03d0970115c776d1c4791fea3c33f70b0b5378; that had been
too easy. When map was clipped and panned to the side, the highlight
for hero's spot was shown next to the '@' instead of on it.
Using ':' to have search string matching toggle items chosen for
selection would show selection highlighting on the current page for
items matched off-page.
I noticed the wrapping issue while testing out the 'bad fruit' fix,
then the other things while fixing it.
1) inventory entries too wide for narrow persistent inventory window
wrapped without any control; normally can't be seen except for the
last entry when the list is short enough to leave at least one line
available; it looked fairly reasonable with window borders Off, but
when On the last char of the first line and first char of second
line were clobbered by the border box;
2) when there were too many entries to fit within the height, those
after the last one which fit were appended to it for borders Off
(or written on bottom line and then overwritten by the border box
for borders On); noticed because the selector letter is highlighted
with inverse video, even when written at an unexpected place;
3) suppress the inverse video hightlighting of inventory letters since
they can't be selected from that 'menu';
4) for borders Off, the top line was left blank as if a border was
going to be drawn there;
5) since the entries are truncated due to the narrow window (on a
modest sized display), strip off leading "a", "an", or "the" prefix
for inventory entries (written to curses perm_invent window only);
lets a couple more characters of more interesting stuff be seen.
Most of the entries for '?' looked awful because curses was using
((terminal_width / 2) - 2) for the window width ('- 2' was to make
for for a border around the popup window, regardless of what the
'windowborder' option was set to). Splitting text that has been
manually formatted for 80 columns "worked" but looked bad when not
required.
Some of the help files are using 79 characters on a few lines,
producing wrapped text when displayed. Those would look better if
limited them to 78 or if curses can be modified to suppress the
window border when the entire display is being covered by a popup.
tty ignores map column #0 (0-based index), like the core, and draws
the map in screen columns 1 (1-based index) through 79, leaving screen
column 80 blank. curses was drawing all 80 map columns and since #0
was always unused, screen column 1 was blank and the map was shown in
2 through 80. Change curses to work like tty.
This was too easy; there may be problems lurking. One known issue: it
should be made smarter about when clipping/panning is necessary since
it thinks that a full 80 columns are needed but 79 suffice.
EDIT_GETLIN is more complicated on curses than on tty due to way that
long lines are handled....
Using ESC to get rid of the default response removed it from the
answer buffer but didn't erase back to the end of actual prompt,
making it look as if it was still there. Fixing that for a one-line
prompt+answer was needed and would have been easy but it also needs to
be prepared to go back to prior lines. Both the prompt and the answer
could conceivably span lines although in practice it will usually just
be one line or else prompt+answer combined spanning to a second line.
This hasn't been exhaustively tested been seems to be working correctly.
Fixes#197Fixes#195
Add a call to nonl() to tell curses not to convert carriage return (^M)
to newline. Line input accepts both ^J and ^M as end of line/end of
input, but the core's command processing treats ^M as "unknown command"
(by default; someone could use the BIND option to assign some command
to that character). The end result is that accidentally pressing the
<return> or <enter> key (or Ctrl+M key combination) won't make the hero
run towards the bottom of the screen as if the user had typed ^J. The
curses docs also claim that it allows more optimization during screen
updating by making ^J work as plain linefeed rather than ^M^J newline.
The tty interface can achieve this (the 'do not convert ^M to ^J part',
not the 'more optimization' part) by issuing the command 'stty -icrnl'
(on Unix or sufficiently Unix-like system) prior to running nethack,
but that has no effect when using the curses interface (at least with
ncurses on OSX where I've tested it).
A better fix would be to look up the current terminal settings at
program startup and only call nonl() if -crnl was in effect so that
curses and tty would behave the same in this regard, but curses is
supposed to let us avoid those sorts of messy details....
Fixes#193
Under curses interface, make characters which are both entry selectors
and menu commands function as a selector. Needed to support using ':'
to look inside a container when applying/looting it via menu, instead
of performing a menu search operation. (There was another case like
this but I can't remember what the circumstances are. The fix is
general enough to cover it, whatever it is.)
For menus which don't have ':' as a choice, make sure search prompt
doesn't offer garbage default input when built with EDIT_GETLIN.
Bug? If player has 'popup_dialog' option On, EDIT_GETLIN is ignored.
Plain curses I/O doesn't seem to offer a way to implement it.
After going back and forth between prompts causing message lines
to be overwritten and to be skipped, this yoyo might have finally
run out of string. Fingers crossed....
Fix a 'FIXME': don't follow a message with two spaces in anticipation
of combining with the next one, precede the next one with two spaces
when they're being combined. Keeps nethack's message window <mx,my>
coordinates in sync with curses' internal coordinates.
Back in February, my e991dd1b0c added
ESC (when there's no input) as an early return for curses' getline,
but it neglected to clean up some allocated memory.
Fix a problem introduced by f218e3f15e
and/or a19e64e470. Sometimes the line
after a prompt would be empty and the next message get shown on the
line after that. a19e64e470 was intended to fix the opposite problem
so probably overshot the mark....
Sometimes curses tears down and recreates all its windows (when the
display is resized, for instance) and after doing that it repopulates
the message window with data saved for use by ^P. But it was showing
the oldest messages available rather than the most recent ones.
There is still room for improvement. That process combines short
messages but the refresh is based on the available number of lines;
combining messages can result in lines at the bottom of the message
window being left blank. This could be fixed by reverse-scrolling the
window and inserting more messages at the top, or by combining short
messages in history data instead of at refresh time. The second seems
easier but won't handle changing the message window's width sensibly,
and neither method handles wrapped, long lines well. A More>> prompt
(possibly more than one) is issued if the refresh shows too many lines
(either because long messages already took multiple lines or because
the window has become narrower and ones which used to fit now need to
be wrapped).
Some prompts were being overwritten by the message that followed.
And clear_nhwindow(WIN_MESSAGE) gets called for just about every
keystroke so try to reduce the overhead I unwittingly added. The
"scroll up one line earlier than the next message" mentioned in
the prior commit is much more obvious that I realized and prompt
erasure might need to be redone.
Autodescribe feedback and multi-digit count prompts are always shown
on the last line of the message window and are suppressed from message
history (both ^P and DUMPLOG). When the message window is using all
available lines, the last one was being overwritten (until the count
or the feedback was completed or dismissed, then last line returned).
Adopt the suggestion that it be scrolled up a line instead of being
overwritten. [I haven't been able to reproduce the reported problem
where shorter overlaid text left some of longer underlying text visible
but that should now become moot.]
Bonus fix: while testing, I noticed that if your screen only has room
for a one-line message window and you used ESC to cancel 'pick a spot
with cursor' prompting before moving the cursor, the prompt was left
intact on the message line. tty erases it in that situation, but the
clear_nhwindow(WIN_MESSAGE) was a no-op for curses because it usually
doesn't erase old messages. This changes the curses behavior when the
core asks it to erase the message window: now it forces one blank line
of fake autodesribe feedback (causing the prompt or other most recent
message to scroll off top), then removes that fake feedback (leaving
a blank message line). For multi-line message window, the old messages
scroll up by one line sooner than they would when waiting for the next
real message but are otherwise unaffected.
The curses interface would assign menu selector characters a-z, A-Z,
and then 0-9, but trying to type 0-9 would start a count rather than
select an entry, and if the display was tall enough for more than 62
entries, the ones after '9' were ASCII punctuation characters.
Limit the number of entries per page to 52 + number_of_'$'_entries
(which should be 0 or 1) so that it won't run out of normal letters.
The perm_invent window, if enabled, ought to allow more than that
because it isn't used to make selections and might have an arbtirary
number of '#' overflow entries. But I'll leave that for somebody
else to tackle.
Tested by temporarily setting the limit to 26 instead of 52 since
I'm not able to display anything tall enough to exercise the latter.
DEC C in one of its non-ANSI modes didn't like
fieldorder = test ? &array1 : &array2;
It first complained that '&' applied to an array has no effect (which
was typically true in pre-ANSI environments) and once those '&'s are
ignored, the attempted assignment didn't match the variable's type.
That code was actually more complicated that it needed to be; slightly
simpler code works as intended.
The curses interface wouldn't build with HILITE_STATUS disabled. I
started adapting it to handle genl_status_update() but that was taking
too much effort with each niggling detail leading to another. This
goes the opposite direction: forcing the old STATUS_VIA_WINDOWPORT
behavior without having that #define available. That dragged along a
bunch of unexpected changes too.
I've noticed many instances of the game pausing and not being sure why,
then pressing <space> and having it resume. The curses interface had
a tendency to put its equivalent of the --More-- prompt, >>, somewhere
where that wasn't visible, either off the right hand edge (possibly) or
underneath the window borders if those were enabled. Especially the
very last one it issues prior to exit. (An extra one compared to tty
behavior.)
This ended up being a pretty substantial overhaul of message window
handling. I wouldn't be surprised if it has off-by-one errors which
happen to be paired up and cancel each other out. ">>" is still drawn
in orange if guicolor is on, now in inverse video when that is off.
If it happens to be drawn at the same screen location in consecutive
instances, the first ">" will toggle between blink and not blink so
that there'll be no doubt as to whether the keypress registered when
dismissing it (moot if the text preceding it is different but there's
no attempt to be smart enough to check that, just screen placement).
Make the same fix to curses that was done for tty in 3.6.1: don't
let MSGTYPE entries be matched against prompt strings. Like tty,
curses was using ordinary pline() to issue prompts; something like
MSGTYPE=hide"yn"
could wreak havoc. Switch to custompline(OVERRIDE_MSGTYPE,...).
This changes the recently added msg_window:f for curses to start
viewing the old messages on the last page rather than the first. For
msg_window:Reversed (the default for curses) and for either direction
when all of the message history happens to fit on one page, there's
no change. But for multiple pages, the FIFO feedback now pads the top
of the first page with blank lines so that the last page is full, and
it starts out showing that last page first. So if you only want to go
back few or several messages, they will be in view immediately.
Old layout:
|first message (oldest) | |1st message of last page |
|2nd message of 1st page | | ... |
| ... | |final (most recent) mesg |
| ... | | (blank filler) |
|last message of 1st page | | (blank filler) |
| (1 of 2) => | | <= (2 of 2) |
and ^P started with first page visible and needed normal menu handling,
<space> or '>' or '|', to go forward to view the most recent messages.
New layout:
|1st message of last page | | (blank filler) |
|2nd message of last page | | (blank filler) |
| ... | |first message (oldest) |
| ... | | ... |
|final (most recent) | |last message of 1st page |
| <= (2 of 2) | | (1 of 2) => |
and ^P starts on last page (two of two in this example) but can go
back with '<' and '^'.
So if the total size takes one and third pages (which isn't uncommon
for the default number of kept messages), you'll see 3/4 of the most
recent messages on the initial screen, then you can page backward if
you want to see the other 1/4.
The page indicator is deliberately drawn a bit differently just to
draw attention to the fact you're starting on the last page. I'm not
sure whether that is actually worthwhile but it was trivial to do.
The curses interface was using 'moves' as if it meant "moves" rather
than "turns". Typing ESC at >> (curses' terser version of --More--)
prompt would suppress messages for the rest of the current turn rather
than just the rest of the current move. So if the hero got an extra
move due to being Fast, there would be no feedback during that move.
window.doc states that the colormasks argument to status_update() is
only relevant for BL_CONDITION, but curses was relying on it to be
passed for BL_FLUSH as well. Yesterday's changes stopped the latter
and broke highlighting of status conditions. Other interfaces appear
to honor the description in window.doc.