19180dd6c31281cd6aa6177e4b9ce03a3aa6646e
[btb/d2x.git] / arch / win32 / key.c
1 /* $Id: key.c,v 1.2 2004-05-20 22:53:53 btb Exp $ */
2 #define WIN32_LEAN_AND_MEAN
3 #include <windows.h>
4 #include <stdio.h>
5 #include <dinput.h>
6 //#include "inferno.h"
7 #include "fix.h"
8 #include "timer.h"
9 #include "key.h"
10
11 extern void PumpMessages(void);
12
13 // These are to kludge up a bit my slightly broken GCC directx port.
14 #ifndef E_FAIL
15 #define E_FAIL (HRESULT)0x80004005L
16 #endif
17 #ifndef SUCCEEDED
18 #define SUCCEEDED(a) ((HRESULT)(a) >= 0)
19 #endif
20 #ifndef S_OK
21 #define S_OK 0
22 #define S_FALSE 1
23 #endif
24
25 extern void PumpMessages(void);
26
27 volatile int keyd_time_when_last_pressed;
28 volatile unsigned char  keyd_last_pressed;
29 volatile unsigned char  keyd_last_released;
30 volatile unsigned char  keyd_pressed [256];
31 unsigned char           keyd_repeat;
32 unsigned char WMKey_Handler_Ready=0;
33
34
35 fix g_rgtimeDown [256];
36 fix g_rgtimeElapsed [256];
37 ULONG g_rgcDowns [256];
38 ULONG g_rgcUps [256];
39
40 char ascii_table[256];
41 char shifted_ascii_table[256];
42
43 LPDIRECTINPUT g_lpdi;
44 LPDIRECTINPUTDEVICE g_lpdidKeybd;
45 extern HWND g_hWnd;
46
47 typedef int KEYCODE;
48
49 #define KEY_BUFFER_SIZE 16
50
51 ULONG g_rgbKeyQueue [KEY_BUFFER_SIZE];
52 fix g_rgtimeQueue [KEY_BUFFER_SIZE];
53 ULONG g_rgbPressedQueue [KEY_BUFFER_SIZE];
54
55 ULONG iQueueStart = 0;
56 ULONG iQueueEnd = 0;
57
58 KEYCODE ShiftKeyCode (KEYCODE kcKey)
59 {
60        KEYCODE kcShifted;
61
62        if (keyd_pressed [kcKey])
63        {
64                kcShifted = kcKey;
65
66                // the key is down
67                if (keyd_pressed [KEY_LSHIFT] || keyd_pressed [KEY_RSHIFT])
68                {
69                        kcShifted |= KEY_SHIFTED;
70                }
71                if (keyd_pressed [KEY_LCTRL] || keyd_pressed [KEY_RCTRL])
72                {
73                        kcShifted |= KEY_CTRLED;
74                }
75                if (keyd_pressed [KEY_LALT] || keyd_pressed [KEY_RALT])
76                {
77                        kcShifted |= KEY_ALTED;
78                }
79        }
80        else
81        {
82                // the key is UP!
83                kcShifted = 0;
84        }
85        return kcShifted;
86 }
87
88 BOOL SpaceInBuffer ()
89 {
90         if (iQueueStart == 0)
91         {
92                 return iQueueEnd != KEY_BUFFER_SIZE - 1;
93         }
94         else
95         {
96                 return iQueueEnd != iQueueStart - 1;
97         }
98 }
99
100 void FlushQueue (void)
101 {
102         iQueueStart = iQueueEnd = 0;
103 }
104
105 void PushKey (ULONG kcKey, fix timeDown)
106 {
107         if (SpaceInBuffer ())
108         {
109                 g_rgbKeyQueue [iQueueEnd] = ShiftKeyCode(kcKey);
110                 g_rgtimeQueue [iQueueEnd] = timeDown;
111
112                 if (iQueueEnd ++ == KEY_BUFFER_SIZE)
113                 {
114                         iQueueEnd = 0;
115                 }
116         }
117 }
118
119 BOOL PopKey (KEYCODE *piKey, fix *ptimeDown)
120 {
121         if (iQueueEnd != iQueueStart)
122         {
123                 // there are items in the queue
124
125                 if (piKey != NULL)
126                 {
127                         *piKey = g_rgbKeyQueue [iQueueStart];
128                 }
129                 if (ptimeDown != NULL)
130                 {
131                         *ptimeDown = g_rgbPressedQueue [iQueueStart];
132                 }
133
134                 if (iQueueStart ++ == KEY_BUFFER_SIZE)
135                 {
136                         iQueueStart = 0;
137                 }
138
139                 return TRUE;
140         }
141         else
142         {
143                 return FALSE;
144         }
145 }
146
147 static BOOL EnsureInit (void)
148 {
149         if (g_lpdidKeybd == NULL)
150         {
151                 key_init ();
152         }
153
154         return g_lpdidKeybd != NULL;
155 }
156
157 void key_close(void);
158
159 void key_init()
160 {
161         HRESULT hr;
162         // my kingdom, my kingdom for C++...
163         if (SUCCEEDED (hr = DirectInputCreate (GetModuleHandle (NULL), DIRECTINPUT_VERSION, &g_lpdi, NULL)))
164         {
165                if (SUCCEEDED (hr = IDirectInput_CreateDevice (g_lpdi, (void *)&GUID_SysKeyboard, &g_lpdidKeybd, NULL)))
166                 {
167                         DIPROPDWORD dipdw;
168
169                         dipdw.diph.dwSize = sizeof (DIPROPDWORD);
170                         dipdw.diph.dwHeaderSize = sizeof (DIPROPHEADER);
171                         dipdw.diph.dwObj = 0;
172                         dipdw.diph.dwHow = DIPH_DEVICE;
173                         dipdw.dwData = 40;
174
175                         if (SUCCEEDED (hr = IDirectInputDevice_SetDataFormat (g_lpdidKeybd, &c_dfDIKeyboard)) &&
176                                                                 SUCCEEDED (hr = IDirectInputDevice_SetCooperativeLevel (g_lpdidKeybd, g_hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND)) &&
177                                 SUCCEEDED (hr = IDirectInputDevice_SetProperty (g_lpdidKeybd, DIPROP_BUFFERSIZE, &dipdw.diph)) &&
178                                 SUCCEEDED (hr = IDirectInputDevice_Acquire (g_lpdidKeybd)))
179                         {
180                                 // fine
181                                 WMKey_Handler_Ready = 1;
182
183                                 // Clear the keyboard array
184                                 key_flush();
185
186                                 atexit(key_close);
187                         }
188                         else
189                         {
190                                 IDirectInputDevice_Release (g_lpdidKeybd);
191                                 g_lpdidKeybd = NULL;
192                         }
193                 }
194         }
195 }
196
197 void key_close(void)
198 {
199         WMKey_Handler_Ready = 0;
200         if (g_lpdidKeybd != NULL)
201         {
202                 IDirectInputDevice_Unacquire (g_lpdidKeybd);
203                 IDirectInputDevice_Release (g_lpdidKeybd);
204                 g_lpdidKeybd = NULL;
205         }
206         if (g_lpdi != NULL)
207         {
208                 IDirectInput_Release (g_lpdi);
209                 g_lpdi = NULL;
210         }
211 }
212
213 HRESULT ReadKey (DIDEVICEOBJECTDATA *pdidod)
214 {
215         ULONG cElements = 1;
216         HRESULT hr;
217         if (g_lpdidKeybd == NULL)
218                 return E_FAIL;
219         hr = IDirectInputDevice_Acquire (g_lpdidKeybd);
220         if (SUCCEEDED (hr))
221         {
222                 hr = IDirectInputDevice_GetDeviceData (
223                         g_lpdidKeybd,
224                         sizeof (*pdidod),
225                         pdidod,
226                         (int *) &cElements,
227                         0);
228                 if (SUCCEEDED (hr) && cElements != 1)
229                         hr = E_FAIL;
230         }
231
232         return hr;
233 }
234
235 void UpdateState (DIDEVICEOBJECTDATA *pdidod)
236 {
237         KEYCODE kcKey = pdidod->dwOfs;
238
239         fix timeNow = timer_get_fixed_seconds ();
240
241         if (pdidod->dwData & 0x80)
242         {
243                 keyd_pressed [kcKey] = 1;
244                 keyd_last_pressed = kcKey;
245                 g_rgtimeDown [kcKey] = keyd_time_when_last_pressed = timeNow;
246                 g_rgcDowns [kcKey] ++;
247                 PushKey (kcKey, keyd_time_when_last_pressed);
248         }
249         else
250         {
251                 keyd_pressed [kcKey] = 0;
252                 keyd_last_released = kcKey;
253                 g_rgcUps [kcKey] ++;
254                 g_rgtimeElapsed [kcKey] = timeNow - g_rgtimeDown [kcKey];
255         }
256 }
257
258 void keyboard_handler()
259 {
260 //        static int peekmsgcount = 0;
261         DIDEVICEOBJECTDATA didod;
262         while (SUCCEEDED (ReadKey (&didod)))
263         {
264                 UpdateState (&didod);
265                 
266                 //added 02/20/99 by adb to prevent message overflow
267                 //(this should probably go somewhere else...)
268 //              if (++peekmsgcount == 64) // 64 = wild guess...
269 //              {
270 //                      peekmsgcount = 0;
271 //              }
272                 //end additions
273         }
274         PumpMessages();
275 }
276
277
278
279 void key_flush()
280 {
281         if (EnsureInit ())
282         {
283                 ULONG cElements = INFINITE;
284                 ULONG kcKey;
285 //                HRESULT hr =
286                                IDirectInputDevice_GetDeviceData (
287                         g_lpdidKeybd,
288                         sizeof (DIDEVICEOBJECTDATA),
289                         NULL,
290                         (int *) &cElements,
291                         0);
292
293                 for (kcKey = 0; kcKey < 256; kcKey ++)
294                 {
295                         g_rgtimeElapsed [kcKey] = 0;
296                         g_rgcDowns [kcKey] = 0;
297                         g_rgcUps [kcKey] = 0;
298                         keyd_pressed [kcKey] = 0;
299                 }
300
301                 FlushQueue ();
302         }
303 }
304
305 int key_getch()
306 {
307         KEYCODE kcKey;
308                 keyboard_handler();
309         while (!PopKey (&kcKey, NULL))
310         {
311                 keyboard_handler ();
312         }
313
314         return kcKey;
315 }
316
317 KEYCODE key_inkey_time(fix * pTime)
318 {
319         KEYCODE kcKey = 0;
320
321         keyboard_handler ();
322
323         PopKey (&kcKey, pTime);
324
325         return kcKey;
326 }
327
328 KEYCODE key_inkey ()
329 {
330         return key_inkey_time (NULL);
331 }
332
333 KEYCODE key_peekkey ()
334 {
335                 keyboard_handler();
336         return 0;
337 }
338
339 int key_checkch()
340 {
341   return 1; // FIXME
342
343
344 unsigned char key_to_ascii(KEYCODE kcKey )
345 {
346         BOOL bShifted = kcKey & KEY_SHIFTED;
347         unsigned char ch;
348
349         kcKey &= ~KEY_SHIFTED;
350
351         if (kcKey <= 127)
352         {
353                 if (bShifted)
354                 {
355                         ch = shifted_ascii_table [kcKey & 0xff];
356                 }
357                 else
358                 {
359                         ch = ascii_table [kcKey & 0xff];
360                 }
361         }
362         else
363         {
364                 ch = 255;
365         }
366
367         return ch;
368 }
369
370 // Returns the number of seconds this key has been down since last call.
371 fix key_down_time(KEYCODE kcKey)
372 {
373         ULONG timeElapsed;
374                 keyboard_handler();
375         if ((kcKey<0) || (kcKey>127)) return 0;
376
377         if (keyd_pressed [kcKey])
378         {
379                 fix timeNow = timer_get_fixed_seconds ();
380                 timeElapsed = timeNow - g_rgtimeDown [kcKey];
381                 g_rgtimeDown [kcKey] = timeNow;
382         }
383         else
384         {
385                 timeElapsed = g_rgtimeElapsed [kcKey];
386                 g_rgtimeElapsed [kcKey] = 0;
387         }
388
389         return timeElapsed;;
390 }
391
392
393 unsigned int key_down_count(KEYCODE kcKey)
394 {
395         int n;
396                 keyboard_handler();
397         if ((kcKey < 0) || (kcKey > 127))
398         {
399                 n = 0;
400         }
401         else
402         {
403                 n = g_rgcDowns [kcKey];
404                 g_rgcDowns [kcKey] = 0;
405         }
406
407         return n;
408 }
409
410 unsigned int key_up_count(KEYCODE kcKey)
411 {
412         int n;
413
414                 keyboard_handler();
415         if ((kcKey < 0) || (kcKey > 127))
416         {
417                 n = 0;
418         }
419         else
420         {
421                 n = g_rgcUps [kcKey];
422                 g_rgcUps [kcKey] = 0;
423         }
424
425         return n;
426 }
427
428
429 #define ___ ((char) 255)
430 char ascii_table[256] =
431 {
432 ___, ___, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', ___, ___,
433 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', ___, ___, 'a', 's',
434 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'', '`', ___,'\\', 'z', 'x', 'c', 'v',
435 'b', 'n', 'm', ',', '.', '/', ___, '*', ___, ' ', ___, ___, ___, ___, ___, ___,
436 ___, ___, ___, ___, ___, ___, ___, '7', '8', '9', '-', '4', '5', '6', '+', '1',
437 '2', '3', '0', '.', ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___,
438 ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___,
439 ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___,
440 };
441
442 char shifted_ascii_table[256] =
443 {
444 ___, ___, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', ___, ___,
445 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', ___, ___, 'A', 'S',
446 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':','\"', '~', ___, '|', 'Z', 'X', 'C', 'V',
447 'B', 'N', 'M', '<', '>', '?', ___, '*', ___, ' ', ___, ___, ___, ___, ___, ___,
448 ___, ___, ___, ___, ___, ___, ___, '&', '*', '(', '_', '$', '%', '^', '=', '!',
449 '@', '#', ')', '>', ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___,
450 ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___,
451 ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___,
452 };
453 #undef ___
454
455 char * key_text[256] = {
456 "","ESC","1","2","3","4","5","6","7","8","9","0","-",
457 "=","BSPC","TAB","Q","W","E","R","T","Y","U","I","O",
458 "P","[","]","\83","LCTRL","A","S","D","F",
459 "G","H","J","K","L",";","'","`",
460 "LSHFT","\\","Z","X","C","V","B","N","M",",",
461 ".","/","RSHFT","PAD*","LALT","SPC",
462 "CPSLK","F1","F2","F3","F4","F5","F6","F7","F8","F9",
463 "F10","NMLCK","SCLK","PAD7","PAD8","PAD9","PAD-",
464 "PAD4","PAD5","PAD6","PAD+","PAD1","PAD2","PAD3","PAD0",
465 "PAD.","","","","F11","F12","","","","","","","","","",
466 "","","","","","","","","","","","","","","","","","","","",
467 "","","","","","","","","","","","","","","","","","","","",
468 "","","","","","","","","","","","","","","","","","",
469 "PAD\83","RCTRL","","","","","","","","","","","","","",
470 "","","","","","","","","","","PAD/","","","RALT","",
471 "","","","","","","","","","","","","","HOME","\82","PGUP",
472 "","\81","","\7f","","END","\80","PGDN","INS",
473 "DEL","","","","","","","","","","","","","","","","","",
474 "","","","","","","","","","","","","","","","","","","","",
475 "","","","","","","" };
476 #if 0 // what was this? -- adb
477 "","","","HOME","UP","PGUP","","LEFT","","RGHT","","END","DOWN","PGDN","INS","DEL",
478 "","\81","","\7f","","","?","","",
479 "","","","","","","","","","","","","","","","","","",
480 "","","","","","","","","","","","","","","","","","","","",
481 "","","","","","","" };
482 #endif