2 * PC/HW routine collection v1.3 for DOS/DJGPP
4 * Copyright (C) 2002 - Daniel Borca
5 * Email : dborca@yahoo.com
6 * Web : http://www.geocities.com/dborca
11 #include <sys/exceptn.h>
12 #include <sys/farptr.h>
19 #define KEY_BUFFER_SIZE 64
21 #define KB_MODIFIERS (KB_SHIFT_FLAG | KB_CTRL_FLAG | KB_ALT_FLAG | KB_LWIN_FLAG | KB_RWIN_FLAG | KB_MENU_FLAG)
22 #define KB_LED_FLAGS (KB_SCROLOCK_FLAG | KB_NUMLOCK_FLAG | KB_CAPSLOCK_FLAG)
24 static int keyboard_installed
;
26 static volatile struct {
27 volatile int start
, end
;
28 volatile int key
[KEY_BUFFER_SIZE
];
31 static volatile int key_enhanced
, key_pause_loop
, key_shifts
;
32 static int leds_ok
= TRUE
;
33 static int in_a_terrupt
= FALSE
;
34 static volatile char pc_key
[KEY_MAX
];
37 /* convert Allegro format scancodes into key_shifts flag bits */
38 static unsigned short modifier_table
[KEY_MAX
- KEY_MODIFIERS
] = {
39 KB_SHIFT_FLAG
, KB_SHIFT_FLAG
, KB_CTRL_FLAG
,
40 KB_CTRL_FLAG
, KB_ALT_FLAG
, KB_ALT_FLAG
,
41 KB_LWIN_FLAG
, KB_RWIN_FLAG
, KB_MENU_FLAG
,
42 KB_SCROLOCK_FLAG
, KB_NUMLOCK_FLAG
, KB_CAPSLOCK_FLAG
46 /* lookup table for converting hardware scancodes into Allegro format */
47 static unsigned char hw_to_mycode
[128] = {
48 /* 0x00 */ 0, KEY_ESC
, KEY_1
, KEY_2
,
49 /* 0x04 */ KEY_3
, KEY_4
, KEY_5
, KEY_6
,
50 /* 0x08 */ KEY_7
, KEY_8
, KEY_9
, KEY_0
,
51 /* 0x0C */ KEY_MINUS
, KEY_EQUALS
, KEY_BACKSPACE
, KEY_TAB
,
52 /* 0x10 */ KEY_Q
, KEY_W
, KEY_E
, KEY_R
,
53 /* 0x14 */ KEY_T
, KEY_Y
, KEY_U
, KEY_I
,
54 /* 0x18 */ KEY_O
, KEY_P
, KEY_OPENBRACE
, KEY_CLOSEBRACE
,
55 /* 0x1C */ KEY_ENTER
, KEY_LCONTROL
, KEY_A
, KEY_S
,
56 /* 0x20 */ KEY_D
, KEY_F
, KEY_G
, KEY_H
,
57 /* 0x24 */ KEY_J
, KEY_K
, KEY_L
, KEY_COLON
,
58 /* 0x28 */ KEY_QUOTE
, KEY_TILDE
, KEY_LSHIFT
, KEY_BACKSLASH
,
59 /* 0x2C */ KEY_Z
, KEY_X
, KEY_C
, KEY_V
,
60 /* 0x30 */ KEY_B
, KEY_N
, KEY_M
, KEY_COMMA
,
61 /* 0x34 */ KEY_STOP
, KEY_SLASH
, KEY_RSHIFT
, KEY_ASTERISK
,
62 /* 0x38 */ KEY_ALT
, KEY_SPACE
, KEY_CAPSLOCK
, KEY_F1
,
63 /* 0x3C */ KEY_F2
, KEY_F3
, KEY_F4
, KEY_F5
,
64 /* 0x40 */ KEY_F6
, KEY_F7
, KEY_F8
, KEY_F9
,
65 /* 0x44 */ KEY_F10
, KEY_NUMLOCK
, KEY_SCRLOCK
, KEY_7_PAD
,
66 /* 0x48 */ KEY_8_PAD
, KEY_9_PAD
, KEY_MINUS_PAD
, KEY_4_PAD
,
67 /* 0x4C */ KEY_5_PAD
, KEY_6_PAD
, KEY_PLUS_PAD
, KEY_1_PAD
,
68 /* 0x50 */ KEY_2_PAD
, KEY_3_PAD
, KEY_0_PAD
, KEY_DEL_PAD
,
69 /* 0x54 */ KEY_PRTSCR
, 0, KEY_BACKSLASH2
, KEY_F11
,
70 /* 0x58 */ KEY_F12
, 0, 0, KEY_LWIN
,
71 /* 0x5C */ KEY_RWIN
, KEY_MENU
, 0, 0,
72 /* 0x60 */ 0, 0, 0, 0,
73 /* 0x64 */ 0, 0, 0, 0,
74 /* 0x68 */ 0, 0, 0, 0,
75 /* 0x6C */ 0, 0, 0, 0,
76 /* 0x70 */ KEY_KANA
, 0, 0, KEY_ABNT_C1
,
77 /* 0x74 */ 0, 0, 0, 0,
78 /* 0x78 */ 0, KEY_CONVERT
, 0, KEY_NOCONVERT
,
79 /* 0x7C */ 0, KEY_YEN
, 0, 0
83 /* lookup table for converting extended hardware codes into Allegro format */
84 static unsigned char hw_to_mycode_ex
[128] = {
85 /* 0x00 */ 0, KEY_ESC
, KEY_1
, KEY_2
,
86 /* 0x04 */ KEY_3
, KEY_4
, KEY_5
, KEY_6
,
87 /* 0x08 */ KEY_7
, KEY_8
, KEY_9
, KEY_0
,
88 /* 0x0C */ KEY_MINUS
, KEY_EQUALS
, KEY_BACKSPACE
, KEY_TAB
,
89 /* 0x10 */ KEY_CIRCUMFLEX
, KEY_AT
, KEY_COLON2
, KEY_R
,
90 /* 0x14 */ KEY_KANJI
, KEY_Y
, KEY_U
, KEY_I
,
91 /* 0x18 */ KEY_O
, KEY_P
, KEY_OPENBRACE
, KEY_CLOSEBRACE
,
92 /* 0x1C */ KEY_ENTER_PAD
, KEY_RCONTROL
, KEY_A
, KEY_S
,
93 /* 0x20 */ KEY_D
, KEY_F
, KEY_G
, KEY_H
,
94 /* 0x24 */ KEY_J
, KEY_K
, KEY_L
, KEY_COLON
,
95 /* 0x28 */ KEY_QUOTE
, KEY_TILDE
, 0, KEY_BACKSLASH
,
96 /* 0x2C */ KEY_Z
, KEY_X
, KEY_C
, KEY_V
,
97 /* 0x30 */ KEY_B
, KEY_N
, KEY_M
, KEY_COMMA
,
98 /* 0x34 */ KEY_STOP
, KEY_SLASH_PAD
, 0, KEY_PRTSCR
,
99 /* 0x38 */ KEY_ALTGR
, KEY_SPACE
, KEY_CAPSLOCK
, KEY_F1
,
100 /* 0x3C */ KEY_F2
, KEY_F3
, KEY_F4
, KEY_F5
,
101 /* 0x40 */ KEY_F6
, KEY_F7
, KEY_F8
, KEY_F9
,
102 /* 0x44 */ KEY_F10
, KEY_NUMLOCK
, KEY_PAUSE
, KEY_HOME
,
103 /* 0x48 */ KEY_UP
, KEY_PGUP
, KEY_MINUS_PAD
, KEY_LEFT
,
104 /* 0x4C */ KEY_5_PAD
, KEY_RIGHT
, KEY_PLUS_PAD
, KEY_END
,
105 /* 0x50 */ KEY_DOWN
, KEY_PGDN
, KEY_INSERT
, KEY_DEL
,
106 /* 0x54 */ KEY_PRTSCR
, 0, KEY_BACKSLASH2
, KEY_F11
,
107 /* 0x58 */ KEY_F12
, 0, 0, KEY_LWIN
,
108 /* 0x5C */ KEY_RWIN
, KEY_MENU
, 0, 0,
109 /* 0x60 */ 0, 0, 0, 0,
110 /* 0x64 */ 0, 0, 0, 0,
111 /* 0x68 */ 0, 0, 0, 0,
112 /* 0x6C */ 0, 0, 0, 0,
113 /* 0x70 */ 0, 0, 0, 0,
114 /* 0x74 */ 0, 0, 0, 0,
115 /* 0x78 */ 0, 0, 0, 0,
116 /* 0x7C */ 0, 0, 0, 0
120 /* default mapping table for the US keyboard layout */
121 static unsigned short standard_key_ascii_table
[KEY_MAX
] = {
123 /* alphabet */ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
124 /* numbers */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
125 /* numpad */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
126 /* func keys */ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
127 /* misc chars */ 27, '`', '-', '=', 8, 9, '[', ']', 13, ';', '\'', '\\', '\\', ',', '.', '/', ' ',
128 /* controls */ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
129 /* numpad */ '/', '*', '-', '+', '.', 13,
130 /* modifiers */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
134 /* capslock mapping table for the US keyboard layout */
135 static unsigned short standard_key_capslock_table
[KEY_MAX
] = {
137 /* alphabet */ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
138 /* numbers */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
139 /* numpad */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
140 /* func keys */ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
141 /* misc chars */ 27, '`', '-', '=', 8, 9, '[', ']', 13, ';', '\'', '\\', '\\', ',', '.', '/', ' ',
142 /* controls */ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
143 /* numpad */ '/', '*', '-', '+', '.', 13,
144 /* modifiers */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
148 /* shifted mapping table for the US keyboard layout */
149 static unsigned short standard_key_shift_table
[KEY_MAX
] = {
151 /* alphabet */ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
152 /* numbers */ ')', '!', '@', '#', '$', '%', '^', '&', '*', '(',
153 /* numpad */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
154 /* func keys */ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
155 /* misc chars */ 27, '~', '_', '+', 8, 9, '{', '}', 13, ':', '"', '|', '|', '<', '>', '?', ' ',
156 /* controls */ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
157 /* numpad */ '/', '*', '-', '+', '.', 13,
158 /* modifiers */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
162 /* ctrl+key mapping table for the US keyboard layout */
163 static unsigned short standard_key_control_table
[KEY_MAX
] = {
165 /* alphabet */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
166 /* numbers */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
167 /* numpad */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
168 /* func keys */ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
169 /* misc chars */ 27, 2, 2, 2, 127, 127, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2,
170 /* controls */ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
171 /* numpad */ 2, 2, 2, 2, 2, 10,
172 /* modifiers */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
176 /* convert numeric pad scancodes into arrow codes */
177 static unsigned char numlock_table
[10] = {
178 KEY_INSERT
, KEY_END
, KEY_DOWN
, KEY_PGDN
, KEY_LEFT
,
179 KEY_5_PAD
, KEY_RIGHT
, KEY_HOME
, KEY_UP
, KEY_PGUP
183 /* kb_wait_for_write_ready:
184 * Wait for the keyboard controller to set the ready-for-write bit.
187 kb_wait_for_write_ready (void)
191 while ((timeout
> 0) && (inportb(0x64) & 2)) timeout
--;
193 return (timeout
> 0);
197 /* kb_wait_for_read_ready:
198 * Wait for the keyboard controller to set the ready-for-read bit.
201 kb_wait_for_read_ready (void)
205 while ((timeout
> 0) && (!(inportb(0x64) & 1))) timeout
--;
207 return (timeout
> 0);
212 * Sends a byte to the keyboard controller. Returns 1 if all OK.
215 kb_send_data (unsigned char data
)
221 if (!kb_wait_for_write_ready())
224 outportb(0x60, data
);
227 while (--timeout
> 0) {
228 if (!kb_wait_for_read_ready())
231 temp
= inportb(0x60);
239 } while ((resends
-- > 0) && (timeout
> 0));
246 update_leds (int leds
)
252 if (!kb_send_data(0xED)) {
255 } else if (!kb_send_data((leds
>> 8) & 7)) {
263 } ENDOFUNC(update_leds
)
267 inject_key (int scancode
)
269 unsigned short *table
;
271 if ((scancode
>= KEY_0_PAD
) && (scancode
<= KEY_9_PAD
)) {
272 if (((key_shifts
& KB_NUMLOCK_FLAG
) != 0) == ((key_shifts
& KB_SHIFT_FLAG
) != 0)) {
273 scancode
= numlock_table
[scancode
- KEY_0_PAD
];
275 table
= standard_key_ascii_table
;
276 } else if (key_shifts
& KB_CTRL_FLAG
) {
277 table
= standard_key_control_table
;
278 } else if (key_shifts
& KB_SHIFT_FLAG
) {
279 if (key_shifts
& KB_CAPSLOCK_FLAG
) {
280 if (standard_key_ascii_table
[scancode
] == standard_key_capslock_table
[scancode
]) {
281 table
= standard_key_shift_table
;
283 table
= standard_key_ascii_table
;
286 table
= standard_key_shift_table
;
288 } else if (key_shifts
& KB_CAPSLOCK_FLAG
) {
289 table
= standard_key_capslock_table
;
291 table
= standard_key_ascii_table
;
294 key_buffer
.key
[key_buffer
.end
++] = (scancode
<< 16) | table
[scancode
];
296 if (key_buffer
.end
>= KEY_BUFFER_SIZE
)
298 if (key_buffer
.end
== key_buffer
.start
) {
300 if (key_buffer
.start
>= KEY_BUFFER_SIZE
)
301 key_buffer
.start
= 0;
303 } ENDOFUNC(inject_key
)
307 handle_code (int scancode
, int keycode
)
311 if (keycode
== 0) { /* pause */
312 inject_key(scancode
);
313 pc_key
[KEY_PAUSE
] ^= TRUE
;
314 } else if (scancode
) {
317 if (scancode
>= KEY_MODIFIERS
) {
318 flag
= modifier_table
[scancode
- KEY_MODIFIERS
];
322 if ((char)keycode
< 0) { /* release */
323 pc_key
[scancode
] = FALSE
;
324 if (flag
& KB_MODIFIERS
) {
327 } else { /* keypress */
328 pc_key
[scancode
] = TRUE
;
329 if (flag
& KB_MODIFIERS
) {
332 if (flag
& KB_LED_FLAGS
) {
334 update_leds(key_shifts
);
336 if (scancode
< KEY_MODIFIERS
) {
337 inject_key(scancode
);
343 } ENDOFUNC(handle_code
)
349 unsigned char temp
, scancode
;
351 temp
= inportb(0x60);
354 if (key_pause_loop
) {
355 if (!--key_pause_loop
) handle_code(KEY_PAUSE
, 0);
366 key_enhanced
= FALSE
;
367 scancode
= hw_to_mycode_ex
[temp
& 0x7f];
369 scancode
= hw_to_mycode
[temp
& 0x7f];
371 handle_code(scancode
, temp
);
375 if (((temp
==0x4F)||(temp
==0x53))&&(key_shifts
&KB_CTRL_FLAG
)&&(key_shifts
&KB_ALT_FLAG
)) {
377 * only SIGINT (but not Ctrl-Break)
378 * calls the destructors and will safely clean up
382 call ___djgpp_hw_exception \n\
383 ":::"%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
403 return (key_buffer
.start
!=key_buffer
.end
);
410 if (keyboard_installed
) {
413 while (key_buffer
.start
== key_buffer
.end
) {
418 key
= key_buffer
.key
[key_buffer
.start
++];
419 if (key_buffer
.start
>= KEY_BUFFER_SIZE
)
420 key_buffer
.start
= 0;
431 pc_keydown (int code
)
445 pc_remove_keyb (void)
447 if (keyboard_installed
) {
450 keyboard_installed
= FALSE
;
451 pc_clexit(pc_remove_keyb
);
454 _farsetsel(__djgpp_dos_sel
);
455 _farnspokew(0x41c, _farnspeekw(0x41a));
457 s1
= _farnspeekb(0x417) & 0x80;
458 s2
= _farnspeekb(0x418) & 0xFC;
459 s3
= _farnspeekb(0x496) & 0xF3;
461 if (pc_key
[KEY_RSHIFT
]) { s1
|= 1; }
462 if (pc_key
[KEY_LSHIFT
]) { s1
|= 2; }
463 if (pc_key
[KEY_LCONTROL
]) { s2
|= 1; s1
|= 4; }
464 if (pc_key
[KEY_ALT
]) { s1
|= 8; s2
|= 2; }
465 if (pc_key
[KEY_RCONTROL
]) { s1
|= 4; s3
|= 4; }
466 if (pc_key
[KEY_ALTGR
]) { s1
|= 8; s3
|= 8; }
468 if (key_shifts
& KB_SCROLOCK_FLAG
) s1
|= 16;
469 if (key_shifts
& KB_NUMLOCK_FLAG
) s1
|= 32;
470 if (key_shifts
& KB_CAPSLOCK_FLAG
) s1
|= 64;
472 _farnspokeb(0x417, s1
);
473 _farnspokeb(0x418, s2
);
474 _farnspokeb(0x496, s3
);
475 update_leds(key_shifts
);
478 pc_remove_irq(KEYB_IRQ
);
484 pc_install_keyb (void)
486 if (keyboard_installed
|| pc_install_irq(KEYB_IRQ
, keyboard
)) {
491 LOCKDATA(key_buffer
);
492 LOCKDATA(key_enhanced
);
493 LOCKDATA(key_pause_loop
);
494 LOCKDATA(key_shifts
);
496 LOCKDATA(in_a_terrupt
);
498 LOCKDATA(modifier_table
);
499 LOCKDATA(hw_to_mycode
);
500 LOCKDATA(hw_to_mycode_ex
);
501 LOCKDATA(standard_key_ascii_table
);
502 LOCKDATA(standard_key_capslock_table
);
503 LOCKDATA(standard_key_shift_table
);
504 LOCKDATA(standard_key_control_table
);
505 LOCKDATA(numlock_table
);
506 LOCKFUNC(update_leds
);
507 LOCKFUNC(inject_key
);
508 LOCKFUNC(handle_code
);
512 _farsetsel(__djgpp_dos_sel
);
513 _farnspokew(0x41c, _farnspeekw(0x41a));
516 s1
= _farnspeekb(0x417);
517 s2
= _farnspeekb(0x418);
518 s3
= _farnspeekb(0x496);
520 if (s1
& 1) { key_shifts
|= KB_SHIFT_FLAG
; pc_key
[KEY_RSHIFT
] = TRUE
; }
521 if (s1
& 2) { key_shifts
|= KB_SHIFT_FLAG
; pc_key
[KEY_LSHIFT
] = TRUE
; }
522 if (s2
& 1) { key_shifts
|= KB_CTRL_FLAG
; pc_key
[KEY_LCONTROL
] = TRUE
; }
523 if (s2
& 2) { key_shifts
|= KB_ALT_FLAG
; pc_key
[KEY_ALT
] = TRUE
; }
524 if (s3
& 4) { key_shifts
|= KB_CTRL_FLAG
; pc_key
[KEY_RCONTROL
] = TRUE
; }
525 if (s3
& 8) { key_shifts
|= KB_ALT_FLAG
; pc_key
[KEY_ALTGR
] = TRUE
; }
527 if (s1
& 16) key_shifts
|= KB_SCROLOCK_FLAG
;
528 if (s1
& 32) key_shifts
|= KB_NUMLOCK_FLAG
;
529 if (s1
& 64) key_shifts
|= KB_CAPSLOCK_FLAG
;
530 update_leds(key_shifts
);
532 key_enhanced
= key_pause_loop
= 0;
533 key_buffer
.start
= key_buffer
.end
= 0;
536 pc_atexit(pc_remove_keyb
);
537 keyboard_installed
= TRUE
;