Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Win32 keyboard fix technical notes

20 views
Skip to first unread message

Ray Chason

unread,
May 11, 2003, 12:55:59 PM5/11/03
to
These are technical notes on the keyboard fix. Those who don't know how
to program will probably want to skip this post.

The problem
===========

The console-mode Nethack wants both keyboard and mouse input. The
problem is that the Windows API provides no easy way to get mouse input
and also keyboard input properly translated according to the user's
chosen keyboard layout.

The ReadConsoleInput function returns a stream of keyboard and mouse
events. Nethack is interested in those events that represent a key
pressed, or a click on a mouse button. The keyboard events from
ReadConsoleInput are not translated according to the keyboard layout,
and do not take into account the shift, control, or alt keys.

The PeekConsoleInput function works similarly to ReadConsoleInput,
except that it does not remove an event from the queue and it returns
instead of blocking when the queue is empty.

A program can also use ReadConsole to get a properly translated stream
of characters. Unfortunately, ReadConsole does not return mouse events,
does not distinguish the keypad from the main keyboard, does not return
keys shifted with Alt, and does not even return the ESC key when
pressed.

We want both the functionality of ReadConsole and the functionality of
ReadConsoleInput. But Microsoft didn't seem to think of that.


The solution, in the original code
==================================

The original 3.4.1 distribution tries to get proper keyboard translation
by passing keyboard events to the ToAscii function. This works, to some
extent -- it takes the shift key into account, and it processes dead
keys properly. But it doesn't take non-US keyboards into account. It
appears that ToAscii is meant for windowed applications, and does not
have enough information to do its job properly in a console application.


The Finnish keyboard patch
==========================

This patch adds the "subkeyvalue" option to the defaults.nh file. The
user can then add OPTIONS=sukeyvalue:171/92, for instance, to replace
the 171 character with 92, which is \. This works, once properly
configured, but places too much burden on the user. It also bars the
use of the substituted characters in naming objects or monsters.


The solution presented here
===========================

The best way I could find to combine the functionality of ReadConsole
with that of ReadConsoleInput is simple in concept. First, call
PeekConsoleInput to get the first event. If it represents a key press,
call ReadConsole to retrieve the key. Otherwise, pop it off the queue
with ReadConsoleInput and, if it's a mouse click, return it as such.

But the Devil, as they say, is in the details. The problem is in
recognizing an event that ReadConsole will return as a key. We don't
want to call ReadConsole unless we know that it will immediately return:
if it blocks, the mouse and the Alt sequences will cease to function
until it returns.

Separating process_keystroke into two functions, one for commands and a
new one, process_keystroke2, for answering prompts, makes the job a lot
easier. process_keystroke2 doesn't have to worry about mouse events or
Alt sequences, and so the consequences are minor if ReadConsole blocks.
process_keystroke, OTOH, never needs to return a non-ASCII character
that was read from ReadConsole; it returns bytes with the high bit set
only in response to an Alt sequence.

So in process_keystroke, before calling ReadConsole, a bogus key event
is pushed on the queue. This event causes ReadConsole to return, even
if there was no other character available. Because the bogus key has
the eighth bit set, it is filtered out. This is not done in
process_keystroke2, because that would render dead keys unusable.

A separate process_keystroke2 can also process the numeric keypad in a
way that makes sense for prompts: just return the corresponding symbol,
and pay no mind to number_pad or the num lock key.

The recognition of Alt sequences is modified, to support the use of
characters generated with the AltGr key. A keystroke is an Alt sequence
if an Alt key is seen that can't be an AltGr (since an AltGr sequence
could be a character, and in some layouts it could even be an ASCII
character). This recognition is different on NT-based and 95-based
Windows:

* On NT-based Windows, AltGr signals as right Alt and left Ctrl
together. So an Alt sequence is recognized if either Alt key is
pressed and if right Alt and left Ctrl are not both present. This
is true even if the keyboard in use does not have an AltGr key, and
uses right Alt for AltGr.

* On 95-based Windows, with a keyboard that lacks the AltGr key, the
right Alt key is used instead. But it still signals as right Alt,
without left Ctrl. There is no way for the application to know
whether right Alt is Alt or AltGr, and so it is always assumed
to be AltGr. This means that Alt sequences must be formed with
left Alt.

So the patch processes keystrokes as follows:

* If the scan and virtual key codes are both 0, it's the bogus key,
and we ignore it.

* Keys on the numeric keypad are processed for commands as in the
unpatched Nethack, and for prompts by returning the ASCII
character, even if the num lock is off.

* Alt sequences are processed for commands as in the unpatched
Nethack, and ignored for prompts.

* Control codes are returned as received, because ReadConsole will
not return the ESC key.

* Other key-down events are passed to ReadConsole. The use of
ReadConsole is different for commands than for prompts:

o For commands, the bogus key is pushed onto the queue before
ReadConsole is called. On return, non-ASCII characters are
filtered, so they are not mistaken for Alt sequences; this also
filters the bogus key.

o For prompts, the bogus key is not used, because that would
interfere with dead keys. Eight bit characters may be returned,
and are coded in the configured code page.


Possible improvements
=====================

Some possible improvements remain:

* Integrate the existing Finnish keyboard patch, for use with non-
QWERTY layouts such as the German QWERTZ keyboard or Dvorak.

* Fix the keyboard glitches in the graphical version. Namely, dead
keys don't work, and input comes in as ISO-8859-1 but is displayed
as code page 437 if IBMgraphics is set on startup.

* Transform incoming text to ISO-8859-1, for full compatibility with
the graphical version.

* After pushing the bogus key and calling ReadConsole, check to see
if we got the bogus key; if so, and an Alt is pressed, process the
event as an Alt sequence.


--
--------------===============<[ Ray Chason ]>===============--------------
PGP public key at http://www.smart.net/~rchason/pubkey.asc
Delendae sunt RIAA, MPAA et Windoze

0 new messages