]> granicus.if.org Git - nethack/commitdiff
win32tty keystroke handling
authornethack.allison <nethack.allison>
Sun, 9 Mar 2003 15:44:50 +0000 (15:44 +0000)
committernethack.allison <nethack.allison>
Sun, 9 Mar 2003 15:44:50 +0000 (15:44 +0000)
- Move the code for keystroke handling into its own source file.
- Compile and link it as a dynamic link library.
- Dynamically load the keystroke handler at runtime
- Add support for specifying a different handler in defaults.nh
  so that internationalization issues can be dealt with without
  rebuilding nethack, just supply alternative handlers in HACKDIR.

The following exported functions need to be present in
the keystroke handler .dll:
ProcessKeystroke - returns an ascii value to NetHack
NHkbhit  - allows peeking to see if a key/mouse press is waiting
SourceWhere - returns location for souce code for a keystroke handler
SourceAuthor  - returns author information for a keystroke handler
KeyHandlerName  - returns the full or short name of the keystroke handling dll.

Files
include/flag.h
include/ntconf.h
src/cmd.c
src/options.c
sys/winnt/Makefile.msc
sys/winnt/nhdefkey.c [new file with mode: 0644]
sys/winnt/nttty.c

diff --git a/Files b/Files
index f72faddf18d591438aa17ba522f7aed0a05ea9a4..6e014e6601412e7e4f6ebf76e16245811e44b465 100644 (file)
--- a/Files
+++ b/Files
@@ -190,8 +190,9 @@ winmain.c
 sys/winnt:
 (files for Windows 9x, NT and Windows2000 version)
 Install.nt      Makefile.bcc    Makefile.gcc    Makefile.msc    console.rc
-defaults.nh     mapimail.c      nethack.def     nhico.uu        nhsetup.bat
-ntsound.c       nttty.c         porthelp        win32api.h      winnt.c
+defaults.nh     mapimail.c      nethack.def     nhdefkey.c      nhico.uu
+nhsetup.bat     ntsound.c       nttty.c         porthelp        win32api.h
+winnt.c
 
 util:
 (files for all versions)
index 3c78743c8dc251791a75d2b50892441a608c350b..5d49b27db4d40fadad672ec50e56f08fe785775f 100644 (file)
@@ -262,6 +262,10 @@ struct instance_flags {
 
        boolean  cmdassist;     /* provide detailed assistance for some commands */
        boolean  obsolete;      /* obsolete options can point at this, it isn't used */
+#ifdef WIN32CON
+#define MAX_ALTKEYHANDLER 25
+       char     altkeyhandler[MAX_ALTKEYHANDLER];
+#endif
 };
 
 /*
index 003bc55ea36661e18301e02e278f147f99ed7d49..2761128017a530b961e254aebcfe17cb3ac528d0 100644 (file)
@@ -133,6 +133,7 @@ extern void NDECL(win32_abort);
 extern void FDECL(nttty_preference_update, (const char *));
 extern void NDECL(toggle_mouse_support);
 extern void FDECL(map_subkeyvalue, (char *));
+extern void NDECL(load_keyboard_handler);
 #endif
 
 #include <fcntl.h>
@@ -184,5 +185,11 @@ int  _RTLENTRY _EXPFUNC read  (int __handle, void _FAR *__buf, unsigned __len);
 #endif
 
 extern int FDECL(set_win32_option, (const char *, const char *));
+#ifdef WIN32CON
+#define LEFTBUTTON  FROM_LEFT_1ST_BUTTON_PRESSED
+#define RIGHTBUTTON RIGHTMOST_BUTTON_PRESSED
+#define MIDBUTTON   FROM_LEFT_2ND_BUTTON_PRESSED
+#define MOUSEMASK (LEFTBUTTON | RIGHTBUTTON | MIDBUTTON)
+#endif /* WIN32CON */
 
 #endif /* NTCONF_H */
index f04d5a8bb959a89aa73aadc6f8e000bd3844b0ae..e04e3a9d976e49d2d6b29583e9baf7d76ae5e5df 100644 (file)
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -2401,6 +2401,7 @@ dotravel()
 #ifdef PORT_DEBUG
 # ifdef WIN32CON
 extern void NDECL(win32con_debug_keystrokes);
+extern void NDECL(win32con_author_info);
 # endif
 
 int
@@ -2417,6 +2418,7 @@ wiz_port_debug()
        } menu_selections[] = {
 #ifdef WIN32CON
                {"test win32 keystrokes", win32con_debug_keystrokes},
+               {"show keystroke handler information", win32con_handler_info},
 #endif
                {(char *)0, (void NDECL((*)))0}         /* array terminator */
        };
index 8df297995af1e02442a2bcf01d2c95b37d1aa0e6..bec56a70fbd1c984f3f5776aae01b8eb3c5f82f5 100644 (file)
@@ -208,6 +208,7 @@ static struct Comp_Opt
                                                8, DISP_IN_GAME },
        { "align_message", "message window alignment", 20, DISP_IN_GAME },      /*WC*/
        { "align_status", "status window alignment", 20, DISP_IN_GAME },        /*WC*/
+       { "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME },
        { "boulder",  "the symbol to use for displaying boulders",
                                                1, SET_IN_GAME },
        { "catname",  "the name of your (first) cat (e.g., catname:Tabby)",
@@ -1471,6 +1472,19 @@ goodfruit:
                return;
        }
 
+       /* altkeyhandler:string */
+       fullname = "altkeyhandler";
+       if (match_optname(opts, fullname, 4, TRUE)) {
+               if (negated) bad_negation(fullname, FALSE);
+               else if ((op = string_for_opt(opts, negated))) {
+#ifdef WIN32CON
+                   (void)strncpy(iflags.altkeyhandler, op, MAX_ALTKEYHANDLER - 5);
+                   load_keyboard_handler();
+#endif
+               }
+               return;
+       }
+
        /* WINCAP
         * align_status:[left|top|right|bottom] */
        fullname = "align_status";
index 8a61a33a0aad76d5450215fdbf73fe1b2b65fa4e..c8b92bf81611dd1ec4e0f503f09291346ffcb600 100644 (file)
@@ -23,8 +23,6 @@
 #
 #       If you have any questions read the sys/winnt/Install.nt file included 
 #       with the distribution.
-#       --
-#       Michael Allison
 #==============================================================================
 # Do not delete the following 3 lines.
 #
@@ -574,7 +572,7 @@ $(NHRES): $(NTSYS)\console.rc $(NTSYS)\NetHack.ico
 #  DO NOT INDENT THE << below!
 #
 
-$(GAMEFILE) : $(ALLOBJ) $(NHRES)
+$(GAMEFILE) : $(ALLOBJ) $(NHRES) $(GAMEDIR)\nhdefkey.dll
        @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
        @echo Linking....
        $(link) $(LFLAGS) user32.lib winmm.lib -out:$@ @<<$(GAME).lnk
@@ -584,6 +582,21 @@ $(GAMEFILE) : $(ALLOBJ) $(NHRES)
        @if exist $(O)install.tag del $(O)install.tag
        @if exist $(GAMEDIR)\$(GAME).bak del $(GAMEDIR)\$(GAME).bak
 
+$(O)nhdefkey.def:
+       @echo EXPORTS >$@
+       @echo    ProcessKeystroke >>$@
+       @echo    NHkbhit >>$@
+       @echo    SourceWhere >>$@
+       @echo    SourceAuthor >>$@
+       @echo    KeyHandlerName >>$@
+
+$(GAMEDIR)\nhdefkey.dll : $(O)$(@B).o $(O)$(@B).def
+       @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
+       @echo Linking $@
+       $(link) -debug:full -debugtype:cv /RELEASE /NOLOGO /DLL user32.lib \
+               /PDB:"$(@B).PDB" /MAP:"$(@B).map" /DEF:$(O)$(@B).def \
+               -out:$@ $(O)$(@B).o
+
 #
 #  Secondary Targets.
 #
@@ -1094,20 +1107,22 @@ $(DAT)\dungeon: $(O)utility.tag  $(DAT)\dungeon.def
 #
 
 $(O)nttty.o:   $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(NTSYS)\nttty.c
-       @@$(CC) $(CFLAGS) -I$(WSHR) -Fo$@  $(NTSYS)\nttty.c
+       @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@  $(NTSYS)\nttty.c
+$(O)nhkeys.o:   $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(NTSYS)\nhkeys.c
+       @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@  $(NTSYS)\nhkeys.c
 $(O)winnt.o: $(HACK_H) $(INCL)\win32api.h $(NTSYS)\winnt.c
-       @@$(CC) $(CFLAGS) -Fo$@  $(NTSYS)\winnt.c
+       @$(CC) $(CFLAGS) -Fo$@  $(NTSYS)\winnt.c
 $(O)ntsound.o: $(HACK_H) $(NTSYS)\ntsound.c
-       @@$(CC) $(CFLAGS)  -Fo$@ $(NTSYS)\ntsound.c
+       @$(CC) $(CFLAGS)  -Fo$@ $(NTSYS)\ntsound.c
 $(O)mapimail.o: $(HACK_H) $(INCL)\nhlan.h $(NTSYS)\mapimail.c
-       @@$(CC) $(CFLAGS) -DMAPI_VERBOSE  -Fo$@ $(NTSYS)\mapimail.c
+       @$(CC) $(CFLAGS) -DMAPI_VERBOSE  -Fo$@ $(NTSYS)\mapimail.c
 
 # 
 # util dependencies
 #
 
 $(O)panic.o:  $(U)panic.c $(CONFIG_H)
-       @@$(CC) $(CFLAGS) -Fo$@ $(U)panic.c
+       @$(CC) $(CFLAGS) -Fo$@ $(U)panic.c
 
 #
 # The rest are stolen from sys/unix/Makefile.src, 
diff --git a/sys/winnt/nhdefkey.c b/sys/winnt/nhdefkey.c
new file mode 100644 (file)
index 0000000..eeeeb0f
--- /dev/null
@@ -0,0 +1,272 @@
+/*     SCCS Id: @(#)nhdefkey.c 3.4     $Date$   */
+/* Copyright (c) NetHack PC Development Team 2003                      */
+/* NetHack may be freely redistributed.  See license for details.      */
+
+/*
+ * This is the default NetHack keystroke processing.
+ * It can be built as a run-time loadable dll (nhdefkey.dll).
+ * Alternative keystroke handlers can be built using the
+ * entry points in this file as a template.
+ *
+ * Use the defaults.nh "altkeyhandler" option to set a
+ * different dll name (without the ".DLL" extension) to
+ * get different processing. Ensure that the dll referenced
+ * in defaults.nh exists in the same directory as NetHack in
+ * order for it to load successfully.
+ *
+ */
+
+static char where_to_get_source[] = "http://www.nethack.org/";
+static char author[] = "The NetHack Development Team";
+
+#include "hack.h"
+#include "wintty.h"
+#include "win32api.h"
+
+extern HANDLE hConIn;
+extern INPUT_RECORD ir;
+char dllname[512];
+char *shortdllname;
+
+int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
+{
+       char dlltmpname[512];
+       char *tmp = dlltmpname, *tmp2;
+       *(tmp + GetModuleFileName(hInstance, tmp, 511)) = '\0';
+       (void)strcpy(dllname, tmp);
+       tmp2 = strrchr(dllname, '\\');
+       if (tmp2) {
+               tmp2++;
+               shortdllname = tmp2;
+       }
+       return TRUE;
+}
+
+/*
+ *  Keyboard translation tables.
+ *  (Adopted from the MSDOS port)
+ */
+
+#define KEYPADLO       0x47
+#define KEYPADHI       0x53
+
+#define PADKEYS        (KEYPADHI - KEYPADLO + 1)
+#define iskeypad(x)    (KEYPADLO <= (x) && (x) <= KEYPADHI)
+
+/*
+ * Keypad keys are translated to the normal values below.
+ * Shifted keypad keys are translated to the
+ *    shift values below.
+ */
+
+static const struct pad {
+       uchar normal, shift, cntrl;
+} keypad[PADKEYS] = {
+                       {'y', 'Y', C('y')},             /* 7 */
+                       {'k', 'K', C('k')},             /* 8 */
+                       {'u', 'U', C('u')},             /* 9 */
+                       {'m', C('p'), C('p')},          /* - */
+                       {'h', 'H', C('h')},             /* 4 */
+                       {'g', 'G', 'g'},                /* 5 */
+                       {'l', 'L', C('l')},             /* 6 */
+                       {'+', 'P', C('p')},             /* + */
+                       {'b', 'B', C('b')},             /* 1 */
+                       {'j', 'J', C('j')},             /* 2 */
+                       {'n', 'N', C('n')},             /* 3 */
+                       {'i', 'I', C('i')},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+}, numpad[PADKEYS] = {
+                       {'7', M('7'), '7'},             /* 7 */
+                       {'8', M('8'), '8'},             /* 8 */
+                       {'9', M('9'), '9'},             /* 9 */
+                       {'m', C('p'), C('p')},          /* - */
+                       {'4', M('4'), '4'},             /* 4 */
+                       {'g', 'G', 'g'},                /* 5 */
+                       {'6', M('6'), '6'},             /* 6 */
+                       {'+', 'P', C('p')},             /* + */
+                       {'1', M('1'), '1'},             /* 1 */
+                       {'2', M('2'), '2'},             /* 2 */
+                       {'3', M('3'), '3'},             /* 3 */
+                       {'i', 'I', C('i')},             /* Ins */
+                       {'.', ':', ':'}                 /* Del */
+};
+
+#define inmap(x,vk)    (((x) > 'A' && (x) < 'Z') || (vk) == 0xBF || (x) == '2')
+
+static BYTE KeyState[256];
+
+int __declspec(dllexport) __stdcall
+ProcessKeystroke(ir, valid, numberpad, portdebug)
+INPUT_RECORD *ir;
+boolean *valid;
+boolean numberpad;
+int portdebug;
+{
+       int metaflags = 0, k = 0;
+       int keycode, vk;
+       unsigned char ch, pre_ch, mk = 0;
+       unsigned short int scan;
+       unsigned long shiftstate;
+       int altseq = 0;
+       const struct pad *kpad;
+
+       shiftstate = 0L;
+       ch = pre_ch = ir->Event.KeyEvent.uChar.AsciiChar;
+       scan  = ir->Event.KeyEvent.wVirtualScanCode;
+       vk    = ir->Event.KeyEvent.wVirtualKeyCode;
+       keycode = MapVirtualKey(vk, 2);
+       shiftstate = ir->Event.KeyEvent.dwControlKeyState;
+       KeyState[VK_SHIFT]   = (shiftstate & SHIFT_PRESSED) ? 0x81 : 0;
+       KeyState[VK_CONTROL] = (shiftstate & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) ?
+                               0x81 : 0;
+       KeyState[VK_CAPITAL] = (shiftstate & CAPSLOCK_ON) ? 0x81 : 0;
+
+       if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) {
+               if (ch || inmap(keycode,vk)) altseq = 1;
+               else altseq = -1;       /* invalid altseq */
+       }
+       if (ch || (iskeypad(scan)) || (altseq > 0))
+               *valid = TRUE;
+       /* if (!valid) return 0; */
+       /*
+        * shiftstate can be checked to see if various special
+         * keys were pressed at the same time as the key.
+         * Currently we are using the ALT & SHIFT & CONTROLS.
+         *
+         *           RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED,
+         *           RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED,
+         *           SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON,
+         *           CAPSLOCK_ON, ENHANCED_KEY
+         *
+         * are all valid bit masks to use on shiftstate.
+         * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the
+         *      left control key was pressed with the keystroke.
+         */
+        if (iskeypad(scan)) {
+            kpad = numberpad ? numpad : keypad;
+            if (shiftstate & SHIFT_PRESSED) {
+                ch = kpad[scan - KEYPADLO].shift;
+            }
+            else if (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
+                ch = kpad[scan - KEYPADLO].cntrl;
+            }
+            else {
+                ch = kpad[scan - KEYPADLO].normal;
+            }
+        }
+        else if (altseq > 0) { /* ALT sequence */
+               if (vk == 0xBF) ch = M('?');
+               else ch = M(tolower(keycode));
+        }
+       /* Attempt to work better with international keyboards. */
+       else {
+               WORD chr[2];
+               k = ToAscii(vk, scan, KeyState, chr, 0);
+               if (k <= 2)
+                   switch(k) {
+                       case 2:  /* two characters */
+                               ch = (unsigned char)chr[1];
+                               *valid = TRUE;
+                               break;
+                       case 1:  /* one character */
+                               ch = (unsigned char)chr[0];
+                               *valid = TRUE;
+                               break;
+                       case 0:  /* no translation */
+                       default: /* negative */
+                               *valid = FALSE;
+                   }
+       }
+       if (ch == '\r') ch = '\n';
+#ifdef PORT_DEBUG
+       if (portdebug) {
+               char buf[BUFSZ];
+               Sprintf(buf,
+       "PORTDEBUG (%s): ch=%u, sc=%u, vk=%d, pre=%d, sh=0x%X, ta=%d (ESC to end)",
+                       shortdllname, ch, scan, vk, pre_ch, shiftstate, k);
+               fprintf(stdout, "\n%s", buf);
+       }
+#endif
+       return ch;
+}
+
+int __declspec(dllexport) __stdcall
+NHkbhit(hConIn, ir)
+HANDLE hConIn;
+INPUT_RECORD *ir;
+{
+       int done = 0;   /* true =  "stop searching"        */
+       int retval;     /* true =  "we had a match"        */
+       DWORD count;
+       unsigned short int scan;
+       unsigned char ch;
+       unsigned long shiftstate;
+       int altseq = 0, keycode, vk;
+       done = 0;
+       retval = 0;
+       while (!done)
+       {
+           count = 0;
+           PeekConsoleInput(hConIn,ir,1,&count);
+           if (count > 0) {
+               if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) {
+                       ch    = ir->Event.KeyEvent.uChar.AsciiChar;
+                       scan  = ir->Event.KeyEvent.wVirtualScanCode;
+                       shiftstate = ir->Event.KeyEvent.dwControlKeyState;
+                       vk = ir->Event.KeyEvent.wVirtualKeyCode;
+                       keycode = MapVirtualKey(vk, 2);
+                       if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) {
+                               if  (ch || inmap(keycode,vk)) altseq = 1;
+                               else altseq = -1;       /* invalid altseq */
+                       }
+                       if (ch || iskeypad(scan) || altseq) {
+                               done = 1;           /* Stop looking         */
+                               retval = 1;         /* Found what we sought */
+                       }
+               }
+               else if ((ir->EventType == MOUSE_EVENT &&
+                 (ir->Event.MouseEvent.dwButtonState & MOUSEMASK))) {
+                       done = 1;
+                       retval = 1;
+               }
+
+               else /* Discard it, it's an insignificant event */
+                       ReadConsoleInput(hConIn,ir,1,&count);
+               } else  /* There are no events in console event queue */ {
+               done = 1;         /* Stop looking               */
+               retval = 0;
+           }
+       }
+       return retval;
+}
+
+
+int __declspec(dllexport) __stdcall
+SourceWhere(buf)
+char **buf;
+{
+       if (!buf) return 0;
+       *buf = where_to_get_source;
+       return 1;
+}
+
+int __declspec(dllexport) __stdcall
+SourceAuthor(buf)
+char **buf;
+{
+       if (!buf) return 0;
+       *buf = author;
+       return 1;
+}
+
+int __declspec(dllexport) __stdcall
+KeyHandlerName(buf, full)
+char **buf;
+int full;
+{
+       if (!buf) return 0;
+       if (full) *buf = dllname;
+       else *buf = shortdllname;
+       return 1;
+}
+
index 9420de205d868c4c5da6fd4aaad79e879ff67a80..8d878e3a71bb108b79b131430d6c22855d4e7a76 100644 (file)
@@ -15,7 +15,6 @@
 #include <sys\types.h>
 #include <sys\stat.h>
 #include "win32api.h"
-#include <wincon.h>
 
 void FDECL(cmov, (int, int));
 void FDECL(nocmov, (int, int));
@@ -53,6 +52,39 @@ INPUT_RECORD ir;
 int GUILaunched;
 static BOOL FDECL(CtrlHandler, (DWORD));
 
+/* dynamic keystroke handling .DLL support */
+typedef int (__stdcall * PROCESS_KEYSTROKE)(
+    INPUT_RECORD *,
+    boolean *,
+    BOOLEAN_P,
+    int
+);
+
+typedef int (__stdcall * NHKBHIT)(
+    HANDLE,
+    INPUT_RECORD *
+);
+
+typedef int (__stdcall * SOURCEWHERE)(
+    char **
+);
+
+typedef int (__stdcall * SOURCEAUTHOR)(
+    char **
+);
+
+typedef int (__stdcall * KEYHANDLERNAME)(
+    char **,
+    int
+);
+
+HANDLE hLibrary;
+PROCESS_KEYSTROKE pProcessKeystroke;
+NHKBHIT pNHkbhit;
+SOURCEWHERE pSourceWhere;
+SOURCEAUTHOR pSourceAuthor;
+KEYHANDLERNAME pKeyHandlerName;
+
 #ifndef CLR_MAX
 #define CLR_MAX 16
 #endif
@@ -80,11 +112,6 @@ static char currenthilite = 0;
 static char currentbackground = 0;
 static boolean colorchange = TRUE;
 
-#define LEFTBUTTON  FROM_LEFT_1ST_BUTTON_PRESSED
-#define RIGHTBUTTON RIGHTMOST_BUTTON_PRESSED
-#define MIDBUTTON   FROM_LEFT_2ND_BUTTON_PRESSED
-#define MOUSEMASK (LEFTBUTTON | RIGHTBUTTON | MIDBUTTON)
-
 /*
  * Called after returning from ! or ^Z
  */
@@ -199,11 +226,11 @@ nttty_open()
         HANDLE hStdOut;
         DWORD cmode;
         long mask;
-        
+
+       load_keyboard_handler();
        /* Initialize the function pointer that points to
          * the kbhit() equivalent, in this TTY case nttty_kbhit()
          */
-
        nt_kbhit = nttty_kbhit;
 
         /* The following 6 lines of code were suggested by 
@@ -252,6 +279,26 @@ nttty_open()
        get_scr_size();
 }
 
+int process_keystroke(ir, valid, numberpad, portdebug)
+INPUT_RECORD *ir;
+boolean *valid;
+boolean numberpad;
+int portdebug;
+{
+       int ch = pProcessKeystroke(ir, valid, numberpad, portdebug);
+       /* check for override */
+       if (ch && ch < MAX_OVERRIDES && key_overrides[ch])
+               ch = key_overrides[ch];
+       return ch;
+}
+
+int
+nttty_kbhit()
+{
+       return pNHkbhit(hConIn, &ir);
+}
+
+
 void
 get_scr_size()
 {
@@ -273,162 +320,6 @@ get_scr_size()
        }
 }
 
-
-/*
- *  Keyboard translation tables.
- *  (Adopted from the MSDOS port)
- */
-
-#define KEYPADLO       0x47
-#define KEYPADHI       0x53
-
-#define PADKEYS        (KEYPADHI - KEYPADLO + 1)
-#define iskeypad(x)    (KEYPADLO <= (x) && (x) <= KEYPADHI)
-
-/*
- * Keypad keys are translated to the normal values below.
- * Shifted keypad keys are translated to the
- *    shift values below.
- */
-
-static const struct pad {
-       uchar normal, shift, cntrl;
-} keypad[PADKEYS] = {
-                       {'y', 'Y', C('y')},             /* 7 */
-                       {'k', 'K', C('k')},             /* 8 */
-                       {'u', 'U', C('u')},             /* 9 */
-                       {'m', C('p'), C('p')},          /* - */
-                       {'h', 'H', C('h')},             /* 4 */
-                       {'g', 'G', 'g'},                /* 5 */
-                       {'l', 'L', C('l')},             /* 6 */
-                       {'+', 'P', C('p')},             /* + */
-                       {'b', 'B', C('b')},             /* 1 */
-                       {'j', 'J', C('j')},             /* 2 */
-                       {'n', 'N', C('n')},             /* 3 */
-                       {'i', 'I', C('i')},             /* Ins */
-                       {'.', ':', ':'}                 /* Del */
-}, numpad[PADKEYS] = {
-                       {'7', M('7'), '7'},             /* 7 */
-                       {'8', M('8'), '8'},             /* 8 */
-                       {'9', M('9'), '9'},             /* 9 */
-                       {'m', C('p'), C('p')},          /* - */
-                       {'4', M('4'), '4'},             /* 4 */
-                       {'g', 'G', 'g'},                /* 5 */
-                       {'6', M('6'), '6'},             /* 6 */
-                       {'+', 'P', C('p')},             /* + */
-                       {'1', M('1'), '1'},             /* 1 */
-                       {'2', M('2'), '2'},             /* 2 */
-                       {'3', M('3'), '3'},             /* 3 */
-                       {'i', 'I', C('i')},             /* Ins */
-                       {'.', ':', ':'}                 /* Del */
-};
-
-#define inmap(x,vk)    (((x) > 'A' && (x) < 'Z') || (vk) == 0xBF || (x) == '2')
-
-static BYTE KeyState[256];
-int FDECL(process_keystroke, (INPUT_RECORD *ir, boolean *valid, int portdebug));
-
-int process_keystroke(ir, valid, portdebug)
-INPUT_RECORD *ir;
-boolean *valid;
-int portdebug;
-{
-       int metaflags = 0, k = 0;
-       int keycode, vk;
-       unsigned char ch, pre_ch, mk = 0;
-       unsigned short int scan;
-       unsigned long shiftstate;
-       int altseq = 0;
-       const struct pad *kpad;
-
-       shiftstate = 0L;
-       ch = pre_ch = ir->Event.KeyEvent.uChar.AsciiChar;
-       scan  = ir->Event.KeyEvent.wVirtualScanCode;
-       vk    = ir->Event.KeyEvent.wVirtualKeyCode;
-       keycode = MapVirtualKey(vk, 2);
-       shiftstate = ir->Event.KeyEvent.dwControlKeyState;
-       KeyState[VK_SHIFT]   = (shiftstate & SHIFT_PRESSED) ? 0x81 : 0;
-       KeyState[VK_CONTROL] = (shiftstate & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) ?
-                               0x81 : 0;
-       KeyState[VK_CAPITAL] = (shiftstate & CAPSLOCK_ON) ? 0x81 : 0;
-
-       if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) {
-               if (ch || inmap(keycode,vk)) altseq = 1;
-               else altseq = -1;       /* invalid altseq */
-       }
-       if (ch || (iskeypad(scan)) || (altseq > 0))
-               *valid = TRUE;
-       /* if (!valid) return 0; */
-       /*
-        * shiftstate can be checked to see if various special
-         * keys were pressed at the same time as the key.
-         * Currently we are using the ALT & SHIFT & CONTROLS.
-         *
-         *           RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED,
-         *           RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED,
-         *           SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON,
-         *           CAPSLOCK_ON, ENHANCED_KEY
-         *
-         * are all valid bit masks to use on shiftstate.
-         * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the
-         *      left control key was pressed with the keystroke.
-         */
-        if (iskeypad(scan)) {
-            kpad = iflags.num_pad ? numpad : keypad;
-            if (shiftstate & SHIFT_PRESSED) {
-                ch = kpad[scan - KEYPADLO].shift;
-            }
-            else if (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
-                ch = kpad[scan - KEYPADLO].cntrl;
-            }
-            else {
-                ch = kpad[scan - KEYPADLO].normal;
-            }
-        }
-        else if (altseq > 0) { /* ALT sequence */
-               if (vk == 0xBF) ch = M('?');
-               else ch = M(tolower(keycode));
-        }
-       /* Attempt to work better with international keyboards. */
-       else {
-               WORD chr[2];
-               k = ToAscii(vk, scan, KeyState, chr, 0);
-               if (k <= 2)
-                   switch(k) {
-                       case 2:  /* two characters */
-                               ch = (unsigned char)chr[1];
-                               *valid = TRUE;
-                               break;
-                       case 1:  /* one character */
-                               ch = (unsigned char)chr[0];
-                               *valid = TRUE;
-                               break;
-                       case 0:  /* no translation */
-                       default: /* negative */
-                               *valid = FALSE;
-                   }
-       }
-       /* check for override */
-       if (ch && ch < MAX_OVERRIDES && key_overrides[ch]) {
-               mk = ch;
-               ch = key_overrides[ch];
-               *valid = TRUE;
-       }
-
-       if (ch == '\r') ch = '\n';
-#ifdef PORT_DEBUG
-       if (portdebug) {
-               char buf[BUFSZ];
-               Sprintf(buf,
-       "PORTDEBUG: ch=%u, sc=%u, vk=%d, pre=%d, sh=0x%X, ta=%d, mk=%d (ESC to end)\n",
-                       ch, scan, vk, pre_ch, shiftstate, k, mk);
-               xputs(buf);
-       }
-#endif
-       return ch;
-}
-
 int
 tgetch()
 {
@@ -439,7 +330,7 @@ tgetch()
        while (!valid) {
           ReadConsoleInput(hConIn,&ir,1,&count);
           if ((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown)
-               ch = process_keystroke(&ir, &valid, 0);
+               ch = process_keystroke(&ir, &valid, iflags.num_pad, 0);
        }
        return ch;
 }
@@ -458,7 +349,7 @@ int *x, *y, *mod;
            ReadConsoleInput(hConIn,&ir,1,&count);
            if (count > 0) {
                if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown) {
-                       keystroke = process_keystroke(&ir, &valid, 0);
+                       keystroke = process_keystroke(&ir, &valid, iflags.num_pad, 0);
                        if (valid) return keystroke;
                } else if (ir.EventType == MOUSE_EVENT) {
                        if ((ir.Event.MouseEvent.dwEventFlags == 0) &&
@@ -492,54 +383,6 @@ int *x, *y, *mod;
        return 0;
 }
 
-int
-nttty_kbhit()
-{
-       int done = 0;   /* true =  "stop searching"        */
-       int retval;     /* true =  "we had a match"        */
-       DWORD count;
-       unsigned short int scan;
-       unsigned char ch;
-       unsigned long shiftstate;
-       int altseq = 0, keycode, vk;
-       done = 0;
-       retval = 0;
-       while (!done)
-       {
-           count = 0;
-           PeekConsoleInput(hConIn,&ir,1,&count);
-           if (count > 0) {
-               if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown) {
-                       ch    = ir.Event.KeyEvent.uChar.AsciiChar;
-                       scan  = ir.Event.KeyEvent.wVirtualScanCode;
-                       shiftstate = ir.Event.KeyEvent.dwControlKeyState;
-                       vk = ir.Event.KeyEvent.wVirtualKeyCode;
-                       keycode = MapVirtualKey(vk, 2);
-                       if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) {
-                               if  (ch || inmap(keycode,vk)) altseq = 1;
-                               else altseq = -1;       /* invalid altseq */
-                       }
-                       if (ch || iskeypad(scan) || altseq) {
-                               done = 1;           /* Stop looking         */
-                               retval = 1;         /* Found what we sought */
-                       }
-               }
-               else if ((ir.EventType == MOUSE_EVENT &&
-                 (ir.Event.MouseEvent.dwButtonState & MOUSEMASK))) {
-                       done = 1;
-                       retval = 1;
-               }
-
-               else /* Discard it, it's an insignificant event */
-                       ReadConsoleInput(hConIn,&ir,1,&count);
-               } else  /* There are no events in console event queue */ {
-               done = 1;         /* Stop looking               */
-               retval = 0;
-           }
-       }
-       return retval;
-}
-
 void
 nocmov(x, y)
 int x,y;
@@ -945,6 +788,34 @@ win32con_debug_keystrokes()
        }
        (void)doredraw();
 }
+void
+win32con_handler_info()
+{
+       char *buf;
+       int ci;
+       if (!pSourceAuthor && !pSourceWhere)
+           pline("Keyboard handler source info and author unavailable.");
+       else {
+               if (pKeyHandlerName && pKeyHandlerName(&buf, 1)) {
+                       xputs("\n");
+                       xputs("Keystroke handler loaded: \n    ");
+                       xputs(buf);
+               }
+               if (pSourceAuthor && pSourceAuthor(&buf)) {
+                       xputs("\n");
+                       xputs("Keystroke handler Author: \n    ");
+                       xputs(buf);
+               }
+               if (pSourceWhere && pSourceWhere(&buf)) {
+                       xputs("\n");
+                       xputs("Keystroke handler source code available at:\n    ");
+                       xputs(buf);
+               }
+               xputs("\nPress any key to resume.");
+               ci=nhgetch();
+               (void)doredraw();
+       }
+}
 #endif
 
 void
@@ -977,4 +848,64 @@ register char *op;
        key_overrides[idx] = val;
 }
 
+void
+load_keyboard_handler()
+{
+       char suffx[] = ".dll";  
+#define MAX_DLLNAME 25
+       char kh[MAX_ALTKEYHANDLER];
+       if (iflags.altkeyhandler[0]) {
+               if (hLibrary) { /* already one loaded apparently */
+                       FreeLibrary(hLibrary);
+                       hLibrary = (HANDLE)0;
+               }
+               (void) strncpy(kh, iflags.altkeyhandler,
+                               (MAX_ALTKEYHANDLER - sizeof suffx) - 1);
+               kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0';
+               Strcat(kh, suffx);
+               hLibrary = LoadLibrary(kh);
+               if (hLibrary) {
+                  pProcessKeystroke =
+                  (PROCESS_KEYSTROKE) GetProcAddress (hLibrary, TEXT ("ProcessKeystroke"));
+                  pNHkbhit =
+                  (NHKBHIT) GetProcAddress (hLibrary, TEXT ("NHkbhit"));
+                  pSourceWhere =
+                  (SOURCEWHERE) GetProcAddress (hLibrary, TEXT ("SourceWhere"));
+                  pSourceAuthor =
+                  (SOURCEAUTHOR) GetProcAddress (hLibrary, TEXT ("SourceAuthor"));
+                  pKeyHandlerName =
+                  (KEYHANDLERNAME) GetProcAddress (hLibrary, TEXT ("KeyHandlerName"));
+               }
+       }
+       if (!pProcessKeystroke || !pNHkbhit) {
+               if (hLibrary) {
+                       FreeLibrary(hLibrary);
+                       hLibrary = (HANDLE)0;
+               }
+               hLibrary = LoadLibrary("nhdefkey.dll");
+               if (hLibrary) {
+                  pProcessKeystroke =
+                  (PROCESS_KEYSTROKE) GetProcAddress (hLibrary, TEXT ("ProcessKeystroke"));
+                  pNHkbhit =
+                  (NHKBHIT) GetProcAddress (hLibrary, TEXT ("NHkbhit"));
+                  pSourceWhere =
+                  (SOURCEWHERE) GetProcAddress (hLibrary, TEXT ("SourceWhere"));
+                  pSourceAuthor =
+                  (SOURCEAUTHOR) GetProcAddress (hLibrary, TEXT ("SourceAuthor"));
+                  pKeyHandlerName =
+                  (KEYHANDLERNAME) GetProcAddress (hLibrary, TEXT ("KeyHandlerName"));
+               }
+       }
+       if (!pProcessKeystroke || !pNHkbhit) {
+               if (!hLibrary)
+                       raw_printf("\nNetHack was unable to load keystroke handler.\n");
+               else {
+                       FreeLibrary(hLibrary);
+                       hLibrary = (HANDLE)0;
+                       raw_printf("\nNetHack keystroke handler is invalid.\n");
+               }
+               exit(EXIT_FAILURE);
+       }
+}
+
 #endif /* WIN32CON */