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