1 /* SCCS Id: @(#)nhdefkey.c 3.4 $Date: 2003/11/01 23:57:00 $ */
2 /* Copyright (c) NetHack PC Development Team 2003 */
3 /* NetHack may be freely redistributed. See license for details. */
6 * This is the default NetHack keystroke processing.
7 * It can be built as a run-time loadable dll (nhdefkey.dll).
8 * Alternative keystroke handlers can be built using the
9 * entry points in this file as a template.
11 * Use the defaults.nh "altkeyhandler" option to set a
12 * different dll name (without the ".DLL" extension) to
13 * get different processing. Ensure that the dll referenced
14 * in defaults.nh exists in the same directory as NetHack in
15 * order for it to load successfully.
19 static char where_to_get_source[] = "http://www.nethack.org/";
20 static char author[] = "The NetHack Development Team";
27 extern INPUT_RECORD ir;
31 int FDECL(__declspec(dllexport) __stdcall
32 ProcessKeystroke, (HANDLE hConIn, INPUT_RECORD *ir,
33 boolean *valid, BOOLEAN_P numberpad, int portdebug));
35 int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
38 char *tmp = dlltmpname, *tmp2;
39 *(tmp + GetModuleFileName(hInstance, tmp, 511)) = '\0';
40 (void)strcpy(dllname, tmp);
41 tmp2 = strrchr(dllname, '\\');
50 * Keyboard translation tables.
51 * (Adopted from the MSDOS port)
57 #define PADKEYS (KEYPADHI - KEYPADLO + 1)
58 #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI)
61 * Keypad keys are translated to the normal values below.
62 * Shifted keypad keys are translated to the
66 static const struct pad {
67 uchar normal, shift, cntrl;
69 {'y', 'Y', C('y')}, /* 7 */
70 {'k', 'K', C('k')}, /* 8 */
71 {'u', 'U', C('u')}, /* 9 */
72 {'m', C('p'), C('p')}, /* - */
73 {'h', 'H', C('h')}, /* 4 */
74 {'g', 'G', 'g'}, /* 5 */
75 {'l', 'L', C('l')}, /* 6 */
76 {'+', 'P', C('p')}, /* + */
77 {'b', 'B', C('b')}, /* 1 */
78 {'j', 'J', C('j')}, /* 2 */
79 {'n', 'N', C('n')}, /* 3 */
80 {'i', 'I', C('i')}, /* Ins */
81 {'.', ':', ':'} /* Del */
82 }, numpad[PADKEYS] = {
83 {'7', M('7'), '7'}, /* 7 */
84 {'8', M('8'), '8'}, /* 8 */
85 {'9', M('9'), '9'}, /* 9 */
86 {'m', C('p'), C('p')}, /* - */
87 {'4', M('4'), '4'}, /* 4 */
88 {'5', M('5'), '5'}, /* 5 */
89 {'6', M('6'), '6'}, /* 6 */
90 {'+', 'P', C('p')}, /* + */
91 {'1', M('1'), '1'}, /* 1 */
92 {'2', M('2'), '2'}, /* 2 */
93 {'3', M('3'), '3'}, /* 3 */
94 {'0', M('0'), '0'}, /* Ins */
95 {'.', ':', ':'} /* Del */
98 #define inmap(x,vk) (((x) > 'A' && (x) < 'Z') || (vk) == 0xBF || (x) == '2')
100 static BYTE KeyState[256];
102 int __declspec(dllexport) __stdcall
103 ProcessKeystroke(hConIn,ir, valid, numberpad, portdebug)
110 int metaflags = 0, k = 0;
112 unsigned char ch, pre_ch, mk = 0;
113 unsigned short int scan;
114 unsigned long shiftstate;
116 const struct pad *kpad;
119 ch = pre_ch = ir->Event.KeyEvent.uChar.AsciiChar;
120 scan = ir->Event.KeyEvent.wVirtualScanCode;
121 vk = ir->Event.KeyEvent.wVirtualKeyCode;
122 keycode = MapVirtualKey(vk, 2);
123 shiftstate = ir->Event.KeyEvent.dwControlKeyState;
124 KeyState[VK_SHIFT] = (shiftstate & SHIFT_PRESSED) ? 0x81 : 0;
125 KeyState[VK_CONTROL] = (shiftstate & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) ?
127 KeyState[VK_CAPITAL] = (shiftstate & CAPSLOCK_ON) ? 0x81 : 0;
129 if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) {
130 if (ch || inmap(keycode,vk)) altseq = 1;
131 else altseq = -1; /* invalid altseq */
133 if (ch || (iskeypad(scan)) || (altseq > 0))
135 /* if (!valid) return 0; */
137 * shiftstate can be checked to see if various special
138 * keys were pressed at the same time as the key.
139 * Currently we are using the ALT & SHIFT & CONTROLS.
141 * RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED,
142 * RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED,
143 * SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON,
144 * CAPSLOCK_ON, ENHANCED_KEY
146 * are all valid bit masks to use on shiftstate.
147 * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the
148 * left control key was pressed with the keystroke.
150 if (iskeypad(scan)) {
151 kpad = numberpad ? numpad : keypad;
152 if (shiftstate & SHIFT_PRESSED) {
153 ch = kpad[scan - KEYPADLO].shift;
155 else if (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
156 ch = kpad[scan - KEYPADLO].cntrl;
159 ch = kpad[scan - KEYPADLO].normal;
162 else if (altseq > 0) { /* ALT sequence */
163 if (vk == 0xBF) ch = M('?');
164 else ch = M(tolower(keycode));
166 /* Attempt to work better with international keyboards. */
169 k = ToAscii(vk, scan, KeyState, chr, 0);
172 case 2: /* two characters */
173 ch = (unsigned char)chr[1];
176 case 1: /* one character */
177 ch = (unsigned char)chr[0];
180 case 0: /* no translation */
181 default: /* negative */
185 if (ch == '\r') ch = '\n';
190 "PORTDEBUG (%s): ch=%u, sc=%u, vk=%d, pre=%d, sh=0x%X, ta=%d (ESC to end)",
191 shortdllname, ch, scan, vk, pre_ch, shiftstate, k);
192 fprintf(stdout, "\n%s", buf);
199 int __declspec(dllexport) __stdcall
204 int done = 0; /* true = "stop searching" */
205 int retval; /* true = "we had a match" */
207 unsigned short int scan;
209 unsigned long shiftstate;
210 int altseq = 0, keycode, vk;
216 PeekConsoleInput(hConIn,ir,1,&count);
218 if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) {
219 ch = ir->Event.KeyEvent.uChar.AsciiChar;
220 scan = ir->Event.KeyEvent.wVirtualScanCode;
221 shiftstate = ir->Event.KeyEvent.dwControlKeyState;
222 vk = ir->Event.KeyEvent.wVirtualKeyCode;
223 keycode = MapVirtualKey(vk, 2);
224 if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) {
225 if (ch || inmap(keycode,vk)) altseq = 1;
226 else altseq = -1; /* invalid altseq */
228 if (ch || iskeypad(scan) || altseq) {
229 done = 1; /* Stop looking */
230 retval = 1; /* Found what we sought */
232 /* Strange Key event; let's purge it to avoid trouble */
233 ReadConsoleInput(hConIn,ir,1,&count);
237 else if ((ir->EventType == MOUSE_EVENT &&
238 (ir->Event.MouseEvent.dwButtonState & MOUSEMASK))) {
243 else /* Discard it, it's an insignificant event */
244 ReadConsoleInput(hConIn,ir,1,&count);
245 } else /* There are no events in console event queue */ {
246 done = 1; /* Stop looking */
253 int __declspec(dllexport) __stdcall
254 CheckInput(hConIn, ir, count, numpad, mode, mod, cc)
264 boolean valid = 0, done = 0;
266 ReadConsoleInput(hConIn,ir,1,count);
268 if ((ir->EventType == KEY_EVENT) && ir->Event.KeyEvent.bKeyDown) {
269 ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0);
274 if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) {
275 ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0);
276 if (valid) return ch;
277 } else if (ir->EventType == MOUSE_EVENT) {
278 if ((ir->Event.MouseEvent.dwEventFlags == 0) &&
279 (ir->Event.MouseEvent.dwButtonState & MOUSEMASK)) {
280 cc->x = ir->Event.MouseEvent.dwMousePosition.X + 1;
281 cc->y = ir->Event.MouseEvent.dwMousePosition.Y - 1;
283 if (ir->Event.MouseEvent.dwButtonState & LEFTBUTTON)
285 else if (ir->Event.MouseEvent.dwButtonState & RIGHTBUTTON)
287 #if 0 /* middle button */
288 else if (ir->Event.MouseEvent.dwButtonState & MIDBUTTON)
298 return mode ? 0 : ch;
301 int __declspec(dllexport) __stdcall
306 *buf = where_to_get_source;
310 int __declspec(dllexport) __stdcall
319 int __declspec(dllexport) __stdcall
320 KeyHandlerName(buf, full)
325 if (full) *buf = dllname;
326 else *buf = shortdllname;