1 /* SCCS Id: @(#)nhdefkey.c 3.4 $Date: 2003/12/11 09:49:08 $ */
2 /* Copyright (c) NetHack PC Development Team 2003 */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 /*
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.
10 *
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.
16 *
17 */
18
19 static char where_to_get_source[] = "http://www.nethack.org/";
20 static char author[] = "The NetHack Development Team";
21
22 #include "hack.h"
23 #include "wintty.h"
24 #include "win32api.h"
25
26 extern HANDLE hConIn;
27 extern INPUT_RECORD ir;
28 char dllname[512];
29 char *shortdllname;
30
31 int FDECL(__declspec(dllexport) __stdcall
32 ProcessKeystroke, (HANDLE hConIn, INPUT_RECORD *ir,
33 boolean *valid, BOOLEAN_P numberpad, int portdebug));
34
DllMain(HINSTANCE hInstance,DWORD fdwReason,PVOID pvReserved)35 int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
36 {
37 char dlltmpname[512];
38 char *tmp = dlltmpname, *tmp2;
39 *(tmp + GetModuleFileName(hInstance, tmp, 511)) = '\0';
40 (void)strcpy(dllname, tmp);
41 tmp2 = strrchr(dllname, '\\');
42 if (tmp2) {
43 tmp2++;
44 shortdllname = tmp2;
45 }
46 return TRUE;
47 }
48
49 /*
50 * Keyboard translation tables.
51 * (Adopted from the MSDOS port)
52 */
53
54 #define KEYPADLO 0x47
55 #define KEYPADHI 0x53
56
57 #define PADKEYS (KEYPADHI - KEYPADLO + 1)
58 #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI)
59
60 /*
61 * Keypad keys are translated to the normal values below.
62 * Shifted keypad keys are translated to the
63 * shift values below.
64 */
65
66 static const struct pad {
67 uchar normal, shift, cntrl;
68 } keypad[PADKEYS] = {
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 */
96 };
97
98 #define inmap(x,vk) (((x) > 'A' && (x) < 'Z') || (vk) == 0xBF || (x) == '2')
99
100 static BYTE KeyState[256];
101
102 int __declspec(dllexport) __stdcall
103 ProcessKeystroke(hConIn,ir, valid, numberpad, portdebug)
104 HANDLE hConIn;
105 INPUT_RECORD *ir;
106 boolean *valid;
107 boolean numberpad;
108 int portdebug;
109 {
110 int metaflags = 0, k = 0;
111 int keycode, vk;
112 unsigned char ch, pre_ch, mk = 0;
113 unsigned short int scan;
114 unsigned long shiftstate;
115 int altseq = 0;
116 const struct pad *kpad;
117
118 shiftstate = 0L;
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)) ?
126 0x81 : 0;
127 KeyState[VK_CAPITAL] = (shiftstate & CAPSLOCK_ON) ? 0x81 : 0;
128
129 if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) {
130 if (ch || inmap(keycode,vk)) altseq = 1;
131 else altseq = -1; /* invalid altseq */
132 }
133 if (ch || (iskeypad(scan)) || (altseq > 0))
134 *valid = TRUE;
135 /* if (!valid) return 0; */
136 /*
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.
140 *
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
145 *
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.
149 */
150 if (iskeypad(scan)) {
151 kpad = numberpad ? numpad : keypad;
152 if (shiftstate & SHIFT_PRESSED) {
153 ch = kpad[scan - KEYPADLO].shift;
154 }
155 else if (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
156 ch = kpad[scan - KEYPADLO].cntrl;
157 }
158 else {
159 ch = kpad[scan - KEYPADLO].normal;
160 }
161 }
162 else if (altseq > 0) { /* ALT sequence */
163 if (vk == 0xBF) ch = M('?');
164 else ch = M(tolower(keycode));
165 }
166 /* Attempt to work better with international keyboards. */
167 else {
168 WORD chr[2];
169 k = ToAscii(vk, scan, KeyState, chr, 0);
170 if (k <= 2)
171 switch(k) {
172 case 2: /* two characters */
173 ch = (unsigned char)chr[1];
174 *valid = TRUE;
175 break;
176 case 1: /* one character */
177 ch = (unsigned char)chr[0];
178 *valid = TRUE;
179 break;
180 case 0: /* no translation */
181 default: /* negative */
182 *valid = FALSE;
183 }
184 }
185 if (ch == '\r') ch = '\n';
186 #ifdef PORT_DEBUG
187 if (portdebug) {
188 char buf[BUFSZ];
189 Sprintf(buf,
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);
193 }
194 #endif
195 return ch;
196 }
197
198
199 int __declspec(dllexport) __stdcall
200 NHkbhit(hConIn, ir)
201 HANDLE hConIn;
202 INPUT_RECORD *ir;
203 {
204 int done = 0; /* true = "stop searching" */
205 int retval; /* true = "we had a match" */
206 DWORD count;
207 unsigned short int scan;
208 unsigned char ch;
209 unsigned long shiftstate;
210 int altseq = 0, keycode, vk;
211 done = 0;
212 retval = 0;
213 while (!done)
214 {
215 count = 0;
216 PeekConsoleInput(hConIn,ir,1,&count);
217 if (count > 0) {
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 */
227 }
228 if (ch || iskeypad(scan) || altseq) {
229 done = 1; /* Stop looking */
230 retval = 1; /* Found what we sought */
231 } else {
232 /* Strange Key event; let's purge it to avoid trouble */
233 ReadConsoleInput(hConIn,ir,1,&count);
234 }
235
236 }
237 else if ((ir->EventType == MOUSE_EVENT &&
238 (ir->Event.MouseEvent.dwButtonState & MOUSEMASK))) {
239 done = 1;
240 retval = 1;
241 }
242
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 */
247 retval = 0;
248 }
249 }
250 return retval;
251 }
252
253 int __declspec(dllexport) __stdcall
254 CheckInput(hConIn, ir, count, numpad, mode, mod, cc)
255 HANDLE hConIn;
256 INPUT_RECORD *ir;
257 DWORD *count;
258 boolean numpad;
259 int mode;
260 int *mod;
261 coord *cc;
262 {
263 int ch;
264 boolean valid = 0, done = 0;
265 while (!done) {
266 ReadConsoleInput(hConIn,ir,1,count);
267 if (mode == 0) {
268 if ((ir->EventType == KEY_EVENT) && ir->Event.KeyEvent.bKeyDown) {
269 ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0);
270 done = valid;
271 }
272 } else {
273 if (count > 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;
282
283 if (ir->Event.MouseEvent.dwButtonState & LEFTBUTTON)
284 *mod = CLICK_1;
285 else if (ir->Event.MouseEvent.dwButtonState & RIGHTBUTTON)
286 *mod = CLICK_2;
287 #if 0 /* middle button */
288 else if (ir->Event.MouseEvent.dwButtonState & MIDBUTTON)
289 *mod = CLICK_3;
290 #endif
291 return 0;
292 }
293 }
294 } else
295 done = 1;
296 }
297 }
298 return mode ? 0 : ch;
299 }
300
301 int __declspec(dllexport) __stdcall
302 SourceWhere(buf)
303 char **buf;
304 {
305 if (!buf) return 0;
306 *buf = where_to_get_source;
307 return 1;
308 }
309
310 int __declspec(dllexport) __stdcall
311 SourceAuthor(buf)
312 char **buf;
313 {
314 if (!buf) return 0;
315 *buf = author;
316 return 1;
317 }
318
319 int __declspec(dllexport) __stdcall
320 KeyHandlerName(buf, full)
321 char **buf;
322 int full;
323 {
324 if (!buf) return 0;
325 if (full) *buf = dllname;
326 else *buf = shortdllname;
327 return 1;
328 }
329
330