How it works
NetHack wants both keyboard and mouse input, but the Win32 console APIs provide no easy way of getting mouse input and also translating keystrokes according to the user's locale. The ReadConsole API retrieves keystrokes and translates them properly, but discards mouse events. The ReadConsoleInput API retrieves key and mouse events but does not translate the keys.
NetHack 3.4.1 attempted to solve this problem by reading all input with ReadConsoleInput and passing it to the ToAscii API. The default keyboard handler, nhdefkey.dll, still works this way. This approach, however, only seems to work with USA keyboards. With others, it ends up using the USA layout, and the user is likely to find this confusing.
Nhraykey.dll takes a different approach. First, it notes that commands have different needs from prompts:
- When NetHack is waiting for a command, such as (d)rop or one of the hjklyubn keys, it wants any of three kinds of input: an ASCII character, a character with the eighth bit set to indicate an Alt sequence, or a mouse event. We do not want to send a non-ASCII character except in response to an Alt sequence, else the game might give surprising behavior, even accidentally invoking the #quit command.
- When NetHack has prompted for text, the mouse is unimportant, and we don't want Alt sequences; but we do want any character that the user can type, ASCII or not.
So it separates these two functions, which had previously been one, and solves the problem according to the needs of each mode. For a command, it first uses PeekConsoleInput to determine what type of input is available. For a key event, it goes to ReadConsole to retrieve the key properly translated. For a mouse event, it goes to ReadConsoleInput to fetch the event.
The idea is never to call ReadConsole when a mouse event is important, unless we can be sure that it will not block; if that happened, the mouse would cease to function until it returned. ReadConsole is prevented from blocking by pushing a bogus key event on the queue; if there's nothing else for ReadConsole to fetch, it will fetch the bogus key. The bogus key is constructed so that it does not match any real key event, and can be filtered out.
For prompts, ReadConsole is used directly, because mouse events are not needed.
There is one point at which the unmodified nhraykey.dll needs to filter the bogus key, but fails to do so. This can result in ReadConsole being called and blocking because there is no real key for it to read. A patch is available to fix this bug in 3.4.3, and it is fixed in 3.6.1.
Description of the patch.
Fix for bug W343-4.