diff --git a/Files b/Files index f72faddf1..6e014e660 100644 --- 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) diff --git a/include/flag.h b/include/flag.h index 3c78743c8..5d49b27db 100644 --- a/include/flag.h +++ b/include/flag.h @@ -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 }; /* diff --git a/include/ntconf.h b/include/ntconf.h index 003bc55ea..276112801 100644 --- a/include/ntconf.h +++ b/include/ntconf.h @@ -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 @@ -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 */ diff --git a/src/cmd.c b/src/cmd.c index f04d5a8bb..e04e3a9d9 100644 --- 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 */ }; diff --git a/src/options.c b/src/options.c index 8df297995..bec56a70f 100644 --- a/src/options.c +++ b/src/options.c @@ -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"; diff --git a/sys/winnt/Makefile.msc b/sys/winnt/Makefile.msc index 8a61a33a0..c8b92bf81 100644 --- a/sys/winnt/Makefile.msc +++ b/sys/winnt/Makefile.msc @@ -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 index 000000000..eeeeb0f30 --- /dev/null +++ b/sys/winnt/nhdefkey.c @@ -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; +} + diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 9420de205..8d878e3a7 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -15,7 +15,6 @@ #include #include #include "win32api.h" -#include 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 */