OSDN Git Service

upgrade to 3.6.1
[jnethack/source.git] / sys / winnt / nhdefkey.c
1 /* NetHack 3.6  nhdefkey.c      $NHDT-Date: 1432512793 2015/05/25 00:13:13 $  $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ */
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 extern struct sinfo program_state;
29
30 char dllname[512];
31 char *shortdllname;
32
33 int FDECL(__declspec(dllexport) __stdcall ProcessKeystroke,
34           (HANDLE hConIn, INPUT_RECORD *ir, boolean *valid,
35            BOOLEAN_P numberpad, int portdebug));
36
37 int WINAPI
38 DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
39 {
40     char dlltmpname[512];
41     char *tmp = dlltmpname, *tmp2;
42     *(tmp + GetModuleFileName(hInstance, tmp, 511)) = '\0';
43     (void) strcpy(dllname, tmp);
44     tmp2 = strrchr(dllname, '\\');
45     if (tmp2) {
46         tmp2++;
47         shortdllname = tmp2;
48     }
49     return TRUE;
50 }
51
52 /*
53  *  Keyboard translation tables.
54  *  (Adopted from the MSDOS port)
55  */
56
57 #define KEYPADLO 0x47
58 #define KEYPADHI 0x53
59
60 #define PADKEYS (KEYPADHI - KEYPADLO + 1)
61 #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI)
62
63 /*
64  * Keypad keys are translated to the normal values below.
65  * Shifted keypad keys are translated to the
66  *    shift values below.
67  */
68
69 static const struct pad {
70     uchar normal, shift, cntrl;
71 } keypad[PADKEYS] =
72     {
73       { 'y', 'Y', C('y') },    /* 7 */
74       { 'k', 'K', C('k') },    /* 8 */
75       { 'u', 'U', C('u') },    /* 9 */
76       { 'm', C('p'), C('p') }, /* - */
77       { 'h', 'H', C('h') },    /* 4 */
78       { 'g', 'G', 'g' },       /* 5 */
79       { 'l', 'L', C('l') },    /* 6 */
80       { '+', 'P', C('p') },    /* + */
81       { 'b', 'B', C('b') },    /* 1 */
82       { 'j', 'J', C('j') },    /* 2 */
83       { 'n', 'N', C('n') },    /* 3 */
84       { 'i', 'I', C('i') },    /* Ins */
85       { '.', ':', ':' }        /* Del */
86     },
87   numpad[PADKEYS] = {
88       { '7', M('7'), '7' },    /* 7 */
89       { '8', M('8'), '8' },    /* 8 */
90       { '9', M('9'), '9' },    /* 9 */
91       { 'm', C('p'), C('p') }, /* - */
92       { '4', M('4'), '4' },    /* 4 */
93       { '5', M('5'), '5' },    /* 5 */
94       { '6', M('6'), '6' },    /* 6 */
95       { '+', 'P', C('p') },    /* + */
96       { '1', M('1'), '1' },    /* 1 */
97       { '2', M('2'), '2' },    /* 2 */
98       { '3', M('3'), '3' },    /* 3 */
99       { '0', M('0'), '0' },    /* Ins */
100       { '.', ':', ':' }        /* Del */
101   };
102
103 #define inmap(x, vk) (((x) > 'A' && (x) < 'Z') || (vk) == 0xBF || (x) == '2')
104
105 static BYTE KeyState[256];
106
107 int __declspec(dllexport) __stdcall ProcessKeystroke(hConIn, ir, valid,
108                                                      numberpad, portdebug)
109 HANDLE hConIn;
110 INPUT_RECORD *ir;
111 boolean *valid;
112 boolean numberpad;
113 int portdebug;
114 {
115     int metaflags = 0, k = 0;
116     int keycode, vk;
117     unsigned char ch, pre_ch, mk = 0;
118     unsigned short int scan;
119     unsigned long shiftstate;
120     int altseq = 0;
121     const struct pad *kpad;
122
123     shiftstate = 0L;
124     ch = pre_ch = ir->Event.KeyEvent.uChar.AsciiChar;
125     scan = ir->Event.KeyEvent.wVirtualScanCode;
126     vk = ir->Event.KeyEvent.wVirtualKeyCode;
127     keycode = MapVirtualKey(vk, 2);
128     shiftstate = ir->Event.KeyEvent.dwControlKeyState;
129     KeyState[VK_SHIFT] = (shiftstate & SHIFT_PRESSED) ? 0x81 : 0;
130     KeyState[VK_CONTROL] =
131         (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) ? 0x81 : 0;
132     KeyState[VK_CAPITAL] = (shiftstate & CAPSLOCK_ON) ? 0x81 : 0;
133
134     if (shiftstate & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
135         if (ch || inmap(keycode, vk))
136             altseq = 1;
137         else
138             altseq = -1; /* invalid altseq */
139     }
140     if (ch || (iskeypad(scan)) || (altseq > 0))
141         *valid = TRUE;
142     /* if (!valid) return 0; */
143     /*
144      * shiftstate can be checked to see if various special
145      * keys were pressed at the same time as the key.
146      * Currently we are using the ALT & SHIFT & CONTROLS.
147      *
148      *           RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED,
149      *           RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED,
150      *           SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON,
151      *           CAPSLOCK_ON, ENHANCED_KEY
152      *
153      * are all valid bit masks to use on shiftstate.
154      * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the
155      *      left control key was pressed with the keystroke.
156      */
157     if (iskeypad(scan)) {
158         kpad = numberpad ? numpad : keypad;
159         if (shiftstate & SHIFT_PRESSED) {
160             ch = kpad[scan - KEYPADLO].shift;
161         } else if (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
162             ch = kpad[scan - KEYPADLO].cntrl;
163         } else {
164             ch = kpad[scan - KEYPADLO].normal;
165         }
166     } else if (altseq > 0) { /* ALT sequence */
167         if (vk == 0xBF)
168             ch = M('?');
169         else
170             ch = M(tolower((uchar) keycode));
171     }
172 #if 0 /*JP*/
173     /* Attempt to work better with international keyboards. */
174     else {
175         WORD chr[2];
176         k = ToAscii(vk, scan, KeyState, chr, 0);
177         if (k <= 2)
178             switch (k) {
179             case 2: /* two characters */
180                 ch = (unsigned char) chr[1];
181                 *valid = TRUE;
182                 break;
183             case 1: /* one character */
184                 ch = (unsigned char) chr[0];
185                 *valid = TRUE;
186                 break;
187             case 0:  /* no translation */
188             default: /* negative */
189                 *valid = FALSE;
190             }
191     }
192 #else
193         if(ch != 0){
194                 *valid = TRUE;
195         }
196 #endif
197     if (ch == '\r')
198         ch = '\n';
199 #ifdef PORT_DEBUG
200     if (portdebug) {
201         char buf[BUFSZ];
202         Sprintf(buf, "PORTDEBUG (%s): ch=%u, sc=%u, vk=%d, pre=%d, sh=0x%X, "
203                      "ta=%d (ESC to end)",
204                 shortdllname, ch, scan, vk, pre_ch, shiftstate, k);
205         fprintf(stdout, "\n%s", buf);
206     }
207 #endif
208     return ch;
209 }
210
211 int __declspec(dllexport) __stdcall NHkbhit(hConIn, ir)
212 HANDLE hConIn;
213 INPUT_RECORD *ir;
214 {
215     int done = 0; /* true =  "stop searching"        */
216     int retval;   /* true =  "we had a match"        */
217     DWORD count;
218     unsigned short int scan;
219     unsigned char ch;
220     unsigned long shiftstate;
221     int altseq = 0, keycode, vk;
222     done = 0;
223     retval = 0;
224     while (!done) {
225         count = 0;
226         PeekConsoleInput(hConIn, ir, 1, &count);
227         if (count > 0) {
228             if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) {
229                 ch = ir->Event.KeyEvent.uChar.AsciiChar;
230                 scan = ir->Event.KeyEvent.wVirtualScanCode;
231                 shiftstate = ir->Event.KeyEvent.dwControlKeyState;
232                 vk = ir->Event.KeyEvent.wVirtualKeyCode;
233                 keycode = MapVirtualKey(vk, 2);
234                 if (shiftstate & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
235                     if (ch || inmap(keycode, vk))
236                         altseq = 1;
237                     else
238                         altseq = -1; /* invalid altseq */
239                 }
240                 if (ch || iskeypad(scan) || altseq) {
241                     done = 1;   /* Stop looking         */
242                     retval = 1; /* Found what we sought */
243                 } else {
244                     /* Strange Key event; let's purge it to avoid trouble */
245                     ReadConsoleInput(hConIn, ir, 1, &count);
246                 }
247
248             } else if ((ir->EventType == MOUSE_EVENT
249                         && (ir->Event.MouseEvent.dwButtonState
250                             & MOUSEMASK))) {
251                 done = 1;
252                 retval = 1;
253             }
254
255             else /* Discard it, it's an insignificant event */
256                 ReadConsoleInput(hConIn, ir, 1, &count);
257         } else /* There are no events in console event queue */ {
258             done = 1; /* Stop looking               */
259             retval = 0;
260         }
261     }
262     return retval;
263 }
264
265 #if 1 /*JP*/
266 static INPUT_RECORD irbuf[2];
267 static int irbufnext = 0;
268 #endif
269
270 int __declspec(dllexport) __stdcall CheckInput(hConIn, ir, count, numpad,
271                                                mode, mod, cc)
272 HANDLE hConIn;
273 INPUT_RECORD *ir;
274 DWORD *count;
275 boolean numpad;
276 int mode;
277 int *mod;
278 coord *cc;
279 {
280 #if defined(SAFERHANGUP)
281     DWORD dwWait;
282 #endif
283     int ch;
284     boolean valid = 0, done = 0;
285     while (!done) {
286 #if defined(SAFERHANGUP)
287         dwWait = WaitForSingleObjectEx(hConIn,   // event object to wait for
288                                        INFINITE, // waits indefinitely
289                                        TRUE);    // alertable wait enabled
290         if (dwWait == WAIT_FAILED)
291             return '\033';
292 #endif
293 #if 0 /*JP*/
294         ReadConsoleInput(hConIn, ir, 1, count);
295 #else
296         /*JP
297           Windows8\88È\8d~\82Å\82Í\93ú\96{\8cê\82ð\93ü\97Í\82·\82é\82Æ2\83o\83C\83g\82Ü\82Æ\82ß\82Ä\95Ô\82Á\82Ä\82­\82é\82Ì\82Å
298           2\83o\83C\83g\96Ú\82ð\83L\83\83\83b\83V\83\85\82µ\82Ä1\83o\83C\83g\82¸\82Â\95Ô\82·\81B
299         */
300         if (irbufnext == 1) {
301             memcpy(ir, &irbuf[1], sizeof(INPUT_RECORD));
302             irbufnext = 0;
303         } else {
304             ReadConsoleInput(hConIn, irbuf, 2, count);
305             memcpy(ir, &irbuf[0], sizeof(INPUT_RECORD));
306             if (*count == 2) {
307                 irbufnext = 1;
308             }
309         }
310 #endif
311         if (mode == 0) {
312             if ((ir->EventType == KEY_EVENT) && ir->Event.KeyEvent.bKeyDown) {
313                 ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0);
314                 done = valid;
315             }
316         } else {
317             if (count > 0) {
318                 if (ir->EventType == KEY_EVENT
319                     && ir->Event.KeyEvent.bKeyDown) {
320                     ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0);
321                     if (valid)
322                         return ch;
323                 } else if (ir->EventType == MOUSE_EVENT) {
324                     if ((ir->Event.MouseEvent.dwEventFlags == 0)
325                         && (ir->Event.MouseEvent.dwButtonState & MOUSEMASK)) {
326                         cc->x = ir->Event.MouseEvent.dwMousePosition.X + 1;
327                         cc->y = ir->Event.MouseEvent.dwMousePosition.Y - 1;
328
329                         if (ir->Event.MouseEvent.dwButtonState & LEFTBUTTON)
330                             *mod = CLICK_1;
331                         else if (ir->Event.MouseEvent.dwButtonState
332                                  & RIGHTBUTTON)
333                             *mod = CLICK_2;
334 #if 0 /* middle button */
335                                     else if (ir->Event.MouseEvent.dwButtonState & MIDBUTTON)
336                                         *mod = CLICK_3;
337 #endif
338                         return 0;
339                     }
340                 }
341             } else
342                 done = 1;
343         }
344     }
345     return mode ? 0 : ch;
346 }
347
348 int __declspec(dllexport) __stdcall SourceWhere(buf)
349 char **buf;
350 {
351     if (!buf)
352         return 0;
353     *buf = where_to_get_source;
354     return 1;
355 }
356
357 int __declspec(dllexport) __stdcall SourceAuthor(buf)
358 char **buf;
359 {
360     if (!buf)
361         return 0;
362     *buf = author;
363     return 1;
364 }
365
366 int __declspec(dllexport) __stdcall KeyHandlerName(buf, full)
367 char **buf;
368 int full;
369 {
370     if (!buf)
371         return 0;
372     if (full)
373         *buf = dllname;
374     else
375         *buf = shortdllname;
376     return 1;
377 }