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