1 /*
2 * Copyright (C) 2002-2010 The DOSBox Team
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 /* $Id: bios_keyboard.cpp,v 1.36 2009-06-11 16:05:17 c2woody Exp $ */
20
21 #include "dosbox.h"
22 #include "callback.h"
23 #include "mem.h"
24 #include "bios.h"
25 #include "keyboard.h"
26 #include "regs.h"
27 #include "inout.h"
28 #include "dos_inc.h"
29 #include "SDL.h"
30
31 /* SDL by default treats numlock and scrolllock different from all other keys.
32 * In recent versions this can disabled by a environment variable which we set in sdlmain.cpp
33 * Define the following if this is the case */
34 #if SDL_VERSION_ATLEAST(1, 2, 14)
35 #define CAN_USE_LOCK 1
36 /* For lower versions of SDL we also use a slight hack to get the startup states of numclock and capslock right.
37 * The proper way is in the mapper, but the repeating key is an unwanted side effect for lower versions of SDL */
38 #endif
39
40 static Bitu call_int16,call_irq1,call_irq6;
41
42 /* Nice table from BOCHS i should feel bad for ripping this */
43 #define none 0
44 static struct {
45 Bit16u normal;
46 Bit16u shift;
47 Bit16u control;
48 Bit16u alt;
49 } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
50 { none, none, none, none },
51 { 0x011b, 0x011b, 0x011b, 0x01f0 }, /* escape */
52 { 0x0231, 0x0221, none, 0x7800 }, /* 1! */
53 { 0x0332, 0x0340, 0x0300, 0x7900 }, /* 2@ */
54 { 0x0433, 0x0423, none, 0x7a00 }, /* 3# */
55 { 0x0534, 0x0524, none, 0x7b00 }, /* 4$ */
56 { 0x0635, 0x0625, none, 0x7c00 }, /* 5% */
57 { 0x0736, 0x075e, 0x071e, 0x7d00 }, /* 6^ */
58 { 0x0837, 0x0826, none, 0x7e00 }, /* 7& */
59 { 0x0938, 0x092a, none, 0x7f00 }, /* 8* */
60 { 0x0a39, 0x0a28, none, 0x8000 }, /* 9( */
61 { 0x0b30, 0x0b29, none, 0x8100 }, /* 0) */
62 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200 }, /* -_ */
63 { 0x0d3d, 0x0d2b, none, 0x8300 }, /* =+ */
64 { 0x0e08, 0x0e08, 0x0e7f, 0x0ef0 }, /* backspace */
65 { 0x0f09, 0x0f00, 0x9400, none }, /* tab */
66 { 0x1071, 0x1051, 0x1011, 0x1000 }, /* Q */
67 { 0x1177, 0x1157, 0x1117, 0x1100 }, /* W */
68 { 0x1265, 0x1245, 0x1205, 0x1200 }, /* E */
69 { 0x1372, 0x1352, 0x1312, 0x1300 }, /* R */
70 { 0x1474, 0x1454, 0x1414, 0x1400 }, /* T */
71 { 0x1579, 0x1559, 0x1519, 0x1500 }, /* Y */
72 { 0x1675, 0x1655, 0x1615, 0x1600 }, /* U */
73 { 0x1769, 0x1749, 0x1709, 0x1700 }, /* I */
74 { 0x186f, 0x184f, 0x180f, 0x1800 }, /* O */
75 { 0x1970, 0x1950, 0x1910, 0x1900 }, /* P */
76 { 0x1a5b, 0x1a7b, 0x1a1b, 0x1af0 }, /* [{ */
77 { 0x1b5d, 0x1b7d, 0x1b1d, 0x1bf0 }, /* ]} */
78 { 0x1c0d, 0x1c0d, 0x1c0a, none }, /* Enter */
79 { none, none, none, none }, /* L Ctrl */
80 { 0x1e61, 0x1e41, 0x1e01, 0x1e00 }, /* A */
81 { 0x1f73, 0x1f53, 0x1f13, 0x1f00 }, /* S */
82 { 0x2064, 0x2044, 0x2004, 0x2000 }, /* D */
83 { 0x2166, 0x2146, 0x2106, 0x2100 }, /* F */
84 { 0x2267, 0x2247, 0x2207, 0x2200 }, /* G */
85 { 0x2368, 0x2348, 0x2308, 0x2300 }, /* H */
86 { 0x246a, 0x244a, 0x240a, 0x2400 }, /* J */
87 { 0x256b, 0x254b, 0x250b, 0x2500 }, /* K */
88 { 0x266c, 0x264c, 0x260c, 0x2600 }, /* L */
89 { 0x273b, 0x273a, none, 0x27f0 }, /* ;: */
90 { 0x2827, 0x2822, none, 0x28f0 }, /* '" */
91 { 0x2960, 0x297e, none, 0x29f0 }, /* `~ */
92 { none, none, none, none }, /* L shift */
93 { 0x2b5c, 0x2b7c, 0x2b1c, 0x2bf0 }, /* |\ */
94 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00 }, /* Z */
95 { 0x2d78, 0x2d58, 0x2d18, 0x2d00 }, /* X */
96 { 0x2e63, 0x2e43, 0x2e03, 0x2e00 }, /* C */
97 { 0x2f76, 0x2f56, 0x2f16, 0x2f00 }, /* V */
98 { 0x3062, 0x3042, 0x3002, 0x3000 }, /* B */
99 { 0x316e, 0x314e, 0x310e, 0x3100 }, /* N */
100 { 0x326d, 0x324d, 0x320d, 0x3200 }, /* M */
101 { 0x332c, 0x333c, none, 0x33f0 }, /* ,< */
102 { 0x342e, 0x343e, none, 0x34f0 }, /* .> */
103 { 0x352f, 0x353f, none, 0x35f0 }, /* /? */
104 { none, none, none, none }, /* R Shift */
105 { 0x372a, 0x372a, 0x9600, 0x37f0 }, /* * */
106 { none, none, none, none }, /* L Alt */
107 { 0x3920, 0x3920, 0x3920, 0x3920 }, /* space */
108 { none, none, none, none }, /* caps lock */
109 { 0x3b00, 0x5400, 0x5e00, 0x6800 }, /* F1 */
110 { 0x3c00, 0x5500, 0x5f00, 0x6900 }, /* F2 */
111 { 0x3d00, 0x5600, 0x6000, 0x6a00 }, /* F3 */
112 { 0x3e00, 0x5700, 0x6100, 0x6b00 }, /* F4 */
113 { 0x3f00, 0x5800, 0x6200, 0x6c00 }, /* F5 */
114 { 0x4000, 0x5900, 0x6300, 0x6d00 }, /* F6 */
115 { 0x4100, 0x5a00, 0x6400, 0x6e00 }, /* F7 */
116 { 0x4200, 0x5b00, 0x6500, 0x6f00 }, /* F8 */
117 { 0x4300, 0x5c00, 0x6600, 0x7000 }, /* F9 */
118 { 0x4400, 0x5d00, 0x6700, 0x7100 }, /* F10 */
119 { none, none, none, none }, /* Num Lock */
120 { none, none, none, none }, /* Scroll Lock */
121 { 0x4700, 0x4737, 0x7700, 0x0007 }, /* 7 Home */
122 { 0x4800, 0x4838, 0x8d00, 0x0008 }, /* 8 UP */
123 { 0x4900, 0x4939, 0x8400, 0x0009 }, /* 9 PgUp */
124 { 0x4a2d, 0x4a2d, 0x8e00, 0x4af0 }, /* - */
125 { 0x4b00, 0x4b34, 0x7300, 0x0004 }, /* 4 Left */
126 { 0x4cf0, 0x4c35, 0x8f00, 0x0005 }, /* 5 */
127 { 0x4d00, 0x4d36, 0x7400, 0x0006 }, /* 6 Right */
128 { 0x4e2b, 0x4e2b, 0x9000, 0x4ef0 }, /* + */
129 { 0x4f00, 0x4f31, 0x7500, 0x0001 }, /* 1 End */
130 { 0x5000, 0x5032, 0x9100, 0x0002 }, /* 2 Down */
131 { 0x5100, 0x5133, 0x7600, 0x0003 }, /* 3 PgDn */
132 { 0x5200, 0x5230, 0x9200, 0x0000 }, /* 0 Ins */
133 { 0x5300, 0x532e, 0x9300, none }, /* Del */
134 { none, none, none, none },
135 { none, none, none, none },
136 { 0x565c, 0x567c, none, none }, /* (102-key) */
137 { 0x8500, 0x8700, 0x8900, 0x8b00 }, /* F11 */
138 { 0x8600, 0x8800, 0x8a00, 0x8c00 } /* F12 */
139 };
140
BIOS_AddKeyToBuffer(Bit16u code)141 bool BIOS_AddKeyToBuffer(Bit16u code) {
142 if (mem_readb(BIOS_KEYBOARD_FLAGS2)&8) return true;
143 Bit16u start,end,head,tail,ttail;
144 if (machine==MCH_PCJR) {
145 /* should be done for cga and others as well, to be tested */
146 start=0x1e;
147 end=0x3e;
148 } else {
149 start=mem_readw(BIOS_KEYBOARD_BUFFER_START);
150 end =mem_readw(BIOS_KEYBOARD_BUFFER_END);
151 }
152 head =mem_readw(BIOS_KEYBOARD_BUFFER_HEAD);
153 tail =mem_readw(BIOS_KEYBOARD_BUFFER_TAIL);
154 ttail=tail+2;
155 if (ttail>=end) {
156 ttail=start;
157 }
158 /* Check for buffer Full */
159 //TODO Maybe beeeeeeep or something although that should happend when internal buffer is full
160 if (ttail==head) return false;
161 real_writew(0x40,tail,code);
162 mem_writew(BIOS_KEYBOARD_BUFFER_TAIL,ttail);
163 return true;
164 }
165
add_key(Bit16u code)166 static void add_key(Bit16u code) {
167 if (code!=0) BIOS_AddKeyToBuffer(code);
168 }
169
get_key(Bit16u & code)170 static bool get_key(Bit16u &code) {
171 Bit16u start,end,head,tail,thead;
172 if (machine==MCH_PCJR) {
173 /* should be done for cga and others as well, to be tested */
174 start=0x1e;
175 end=0x3e;
176 } else {
177 start=mem_readw(BIOS_KEYBOARD_BUFFER_START);
178 end =mem_readw(BIOS_KEYBOARD_BUFFER_END);
179 }
180 head =mem_readw(BIOS_KEYBOARD_BUFFER_HEAD);
181 tail =mem_readw(BIOS_KEYBOARD_BUFFER_TAIL);
182
183 if (head==tail) return false;
184 thead=head+2;
185 if (thead>=end) thead=start;
186 mem_writew(BIOS_KEYBOARD_BUFFER_HEAD,thead);
187 code = real_readw(0x40,head);
188 return true;
189 }
190
check_key(Bit16u & code)191 static bool check_key(Bit16u &code) {
192 Bit16u head,tail;
193 head =mem_readw(BIOS_KEYBOARD_BUFFER_HEAD);
194 tail =mem_readw(BIOS_KEYBOARD_BUFFER_TAIL);
195 if (head==tail) return false;
196 code = real_readw(0x40,head);
197 return true;
198 }
199
200 /* Flag Byte 1
201 bit 7 =1 INSert active
202 bit 6 =1 Caps Lock active
203 bit 5 =1 Num Lock active
204 bit 4 =1 Scroll Lock active
205 bit 3 =1 either Alt pressed
206 bit 2 =1 either Ctrl pressed
207 bit 1 =1 Left Shift pressed
208 bit 0 =1 Right Shift pressed
209 */
210 /* Flag Byte 2
211 bit 7 =1 INSert pressed
212 bit 6 =1 Caps Lock pressed
213 bit 5 =1 Num Lock pressed
214 bit 4 =1 Scroll Lock pressed
215 bit 3 =1 Pause state active
216 bit 2 =1 Sys Req pressed
217 bit 1 =1 Left Alt pressed
218 bit 0 =1 Left Ctrl pressed
219 */
220 /*
221 Keyboard status byte 3
222 bit 7 =1 read-ID in progress
223 bit 6 =1 last code read was first of two ID codes
224 bit 5 =1 force Num Lock if read-ID and enhanced keyboard
225 bit 4 =1 enhanced keyboard installed
226 bit 3 =1 Right Alt pressed
227 bit 2 =1 Right Ctrl pressed
228 bit 1 =1 last code read was E0h
229 bit 0 =1 last code read was E1h
230 */
231
232
233 /* the scancode is in reg_al */
IRQ1_Handler(void)234 static Bitu IRQ1_Handler(void) {
235 /* handling of the locks key is difficult as sdl only gives
236 * states for numlock capslock.
237 */
238 Bitu scancode=reg_al; /* Read the code */
239
240 Bit8u flags1,flags2,flags3,leds;
241 flags1=mem_readb(BIOS_KEYBOARD_FLAGS1);
242 flags2=mem_readb(BIOS_KEYBOARD_FLAGS2);
243 flags3=mem_readb(BIOS_KEYBOARD_FLAGS3);
244 leds =mem_readb(BIOS_KEYBOARD_LEDS);
245 #ifdef CAN_USE_LOCK
246 /* No hack anymore! */
247 #else
248 flags2&=~(0x40+0x20);//remove numlock/capslock pressed (hack for sdl only reporting states)
249 #endif
250 if (DOS_LayoutKey(scancode,flags1,flags2,flags3)) return CBRET_NONE;
251 //LOG_MSG("key input %d %d %d %d",scancode,flags1,flags2,flags3);
252 switch (scancode) {
253 /* First the hard ones */
254 case 0xfa: /* ack. Do nothing for now */
255 break;
256 case 0xe1: /* Extended key special. Only pause uses this */
257 flags3 |=0x01;
258 break;
259 case 0xe0: /* Extended key */
260 flags3 |=0x02;
261 break;
262 case 0x1d: /* Ctrl Pressed */
263 if (!(flags3 &0x01)) {
264 flags1 |=0x04;
265 if (flags3 &0x02) flags3 |=0x04;
266 else flags2 |=0x01;
267 } /* else it's part of the pause scancodes */
268 break;
269 case 0x9d: /* Ctrl Released */
270 if (!(flags3 &0x01)) {
271 if (flags3 &0x02) flags3 &=~0x04;
272 else flags2 &=~0x01;
273 if( !( (flags3 &0x04) || (flags2 &0x01) ) ) flags1 &=~0x04;
274 }
275 break;
276 case 0x2a: /* Left Shift Pressed */
277 flags1 |=0x02;
278 break;
279 case 0xaa: /* Left Shift Released */
280 flags1 &=~0x02;
281 break;
282 case 0x36: /* Right Shift Pressed */
283 flags1 |=0x01;
284 break;
285 case 0xb6: /* Right Shift Released */
286 flags1 &=~0x01;
287 break;
288 case 0x38: /* Alt Pressed */
289 flags1 |=0x08;
290 if (flags3 &0x02) flags3 |=0x08;
291 else flags2 |=0x02;
292 break;
293 case 0xb8: /* Alt Released */
294 if (flags3 &0x02) flags3 &= ~0x08;
295 else flags2 &= ~0x02;
296 if( !( (flags3 &0x08) || (flags2 &0x02) ) ) { /* Both alt released */
297 flags1 &= ~0x08;
298 Bit16u token =mem_readb(BIOS_KEYBOARD_TOKEN);
299 if(token != 0){
300 add_key(token);
301 mem_writeb(BIOS_KEYBOARD_TOKEN,0);
302 }
303 }
304 break;
305
306 #ifdef CAN_USE_LOCK
307 case 0x3a:flags2 |=0x40;break;//CAPSLOCK
308 case 0xba:flags1 ^=0x40;flags2 &=~0x40;leds ^=0x04;break;
309 #else
310 case 0x3a:flags2 |=0x40;flags1 |=0x40;leds |=0x04;break; //SDL gives only the state instead of the toggle /* Caps Lock */
311 case 0xba:flags1 &=~0x40;leds &=~0x04;break;
312 #endif
313 case 0x45:
314 if (flags3 &0x01) {
315 /* last scancode of pause received; first remove 0xe1-prefix */
316 flags3 &=~0x01;
317 mem_writeb(BIOS_KEYBOARD_FLAGS3,flags3);
318 if (flags2&1) {
319 /* ctrl-pause (break), special handling needed:
320 add zero to the keyboard buffer, call int 0x1b which
321 sets ctrl-c flag which calls int 0x23 in certain dos
322 input/output functions; not handled */
323 } else if ((flags2&8)==0) {
324 /* normal pause key, enter loop */
325 mem_writeb(BIOS_KEYBOARD_FLAGS2,flags2|8);
326 IO_Write(0x20,0x20);
327 while (mem_readb(BIOS_KEYBOARD_FLAGS2)&8) CALLBACK_Idle(); // pause loop
328 reg_ip+=5; // skip out 20,20
329 return CBRET_NONE;
330 }
331 } else {
332 /* Num Lock */
333 #ifdef CAN_USE_LOCK
334 flags2 |=0x20;
335 #else
336 flags2 |=0x20;
337 flags1 |=0x20;
338 leds |=0x02;
339 #endif
340 }
341 break;
342 case 0xc5:
343 if (flags3 &0x01) {
344 /* pause released */
345 flags3 &=~0x01;
346 } else {
347 #ifdef CAN_USE_LOCK
348 flags1^=0x20;
349 leds^=0x02;
350 flags2&=~0x20;
351 #else
352 /* Num Lock released */
353 flags1 &=~0x20;
354 leds &=~0x02;
355 #endif
356 }
357 break;
358 case 0x46:flags2 |=0x10;break; /* Scroll Lock SDL Seems to do this one fine (so break and make codes) */
359 case 0xc6:flags1 ^=0x10;flags2 &=~0x10;leds ^=0x01;break;
360 // case 0x52:flags2|=128;break;//See numpad /* Insert */
361 case 0xd2:
362 if(flags3&0x02) { /* Maybe honour the insert on keypad as well */
363 flags1^=0x80;
364 flags2&=~0x80;
365 break;
366 } else {
367 goto irq1_end;/*Normal release*/
368 }
369 case 0x47: /* Numpad */
370 case 0x48:
371 case 0x49:
372 case 0x4b:
373 case 0x4c:
374 case 0x4d:
375 case 0x4f:
376 case 0x50:
377 case 0x51:
378 case 0x52:
379 case 0x53: /* del . Not entirely correct, but works fine */
380 if(flags3 &0x02) { /*extend key. e.g key above arrows or arrows*/
381 if(scancode == 0x52) flags2 |=0x80; /* press insert */
382 if(flags1 &0x08) {
383 add_key(scan_to_scanascii[scancode].normal+0x5000);
384 } else if (flags1 &0x04) {
385 add_key((scan_to_scanascii[scancode].control&0xff00)|0xe0);
386 } else if( ((flags1 &0x3) != 0) || ((flags1 &0x20) != 0) ) {
387 add_key((scan_to_scanascii[scancode].shift&0xff00)|0xe0);
388 } else add_key((scan_to_scanascii[scancode].normal&0xff00)|0xe0);
389 break;
390 }
391 if(flags1 &0x08) {
392 Bit8u token = mem_readb(BIOS_KEYBOARD_TOKEN);
393 token = token*10 + (Bit8u)(scan_to_scanascii[scancode].alt&0xff);
394 mem_writeb(BIOS_KEYBOARD_TOKEN,token);
395 } else if (flags1 &0x04) {
396 add_key(scan_to_scanascii[scancode].control);
397 } else if( ((flags1 &0x3) != 0) || ((flags1 &0x20) != 0) ) {
398 add_key(scan_to_scanascii[scancode].shift);
399 } else add_key(scan_to_scanascii[scancode].normal);
400 break;
401
402 default: /* Normal Key */
403 Bit16u asciiscan;
404 /* Now Handle the releasing of keys and see if they match up for a code */
405 /* Handle the actual scancode */
406 if (scancode & 0x80) goto irq1_end;
407 if (scancode > MAX_SCAN_CODE) goto irq1_end;
408 if (flags1 & 0x08) { /* Alt is being pressed */
409 asciiscan=scan_to_scanascii[scancode].alt;
410 #if 0 /* old unicode support disabled*/
411 } else if (ascii) {
412 asciiscan=(scancode << 8) | ascii;
413 #endif
414 } else if (flags1 & 0x04) { /* Ctrl is being pressed */
415 asciiscan=scan_to_scanascii[scancode].control;
416 } else if (flags1 & 0x03) { /* Either shift is being pressed */
417 asciiscan=scan_to_scanascii[scancode].shift;
418 } else {
419 asciiscan=scan_to_scanascii[scancode].normal;
420 }
421 /* cancel shift is letter and capslock active */
422 if(flags1&64) {
423 if(flags1&3) {
424 /*cancel shift */
425 if(((asciiscan&0x00ff) >0x40) && ((asciiscan&0x00ff) <0x5b))
426 asciiscan=scan_to_scanascii[scancode].normal;
427 } else {
428 /* add shift */
429 if(((asciiscan&0x00ff) >0x60) && ((asciiscan&0x00ff) <0x7b))
430 asciiscan=scan_to_scanascii[scancode].shift;
431 }
432 }
433 if (flags3 &0x02) {
434 /* extended key (numblock), return and slash need special handling */
435 if (scancode==0x1c) { /* return */
436 if (flags1 &0x08) asciiscan=0xa600;
437 else asciiscan=(asciiscan&0xff)|0xe000;
438 } else if (scancode==0x35) { /* slash */
439 if (flags1 &0x08) asciiscan=0xa400;
440 else if (flags1 &0x04) asciiscan=0x9500;
441 else asciiscan=0xe02f;
442 }
443 }
444 add_key(asciiscan);
445 break;
446 };
447 irq1_end:
448 if(scancode !=0xe0) flags3 &=~0x02; //Reset 0xE0 Flag
449 mem_writeb(BIOS_KEYBOARD_FLAGS1,flags1);
450 if ((scancode&0x80)==0) flags2&=0xf7;
451 mem_writeb(BIOS_KEYBOARD_FLAGS2,flags2);
452 mem_writeb(BIOS_KEYBOARD_FLAGS3,flags3);
453 mem_writeb(BIOS_KEYBOARD_LEDS,leds);
454 /* IO_Write(0x20,0x20); moved out of handler to be virtualizable */
455 #if 0
456 /* Signal the keyboard for next code */
457 /* In dosbox port 60 reads do this as well */
458 Bit8u old61=IO_Read(0x61);
459 IO_Write(0x61,old61 | 128);
460 IO_Write(0x64,0xae);
461 #endif
462 return CBRET_NONE;
463 }
464
465
466 /* check whether key combination is enhanced or not,
467 translate key if necessary */
IsEnhancedKey(Bit16u & key)468 static bool IsEnhancedKey(Bit16u &key) {
469 /* test for special keys (return and slash on numblock) */
470 if ((key>>8)==0xe0) {
471 if (((key&0xff)==0x0a) || ((key&0xff)==0x0d)) {
472 /* key is return on the numblock */
473 key=(key&0xff)|0x1c00;
474 } else {
475 /* key is slash on the numblock */
476 key=(key&0xff)|0x3500;
477 }
478 /* both keys are not considered enhanced keys */
479 return false;
480 } else if (((key>>8)>0x84) || (((key&0xff)==0xf0) && (key>>8))) {
481 /* key is enhanced key (either scancode part>0x84 or
482 specially-marked keyboard combination, low part==0xf0) */
483 return true;
484 }
485 /* convert key if necessary (extended keys) */
486 if ((key>>8) && ((key&0xff)==0xe0)) {
487 key&=0xff00;
488 }
489 return false;
490 }
491
INT16_Handler(void)492 static Bitu INT16_Handler(void) {
493 Bit16u temp=0;
494 switch (reg_ah) {
495 case 0x00: /* GET KEYSTROKE */
496 if ((get_key(temp)) && (!IsEnhancedKey(temp))) {
497 /* normal key found, return translated key in ax */
498 reg_ax=temp;
499 } else {
500 /* enter small idle loop to allow for irqs to happen */
501 reg_ip+=1;
502 }
503 break;
504 case 0x10: /* GET KEYSTROKE (enhanced keyboards only) */
505 if (get_key(temp)) {
506 if (((temp&0xff)==0xf0) && (temp>>8)) {
507 /* special enhanced key, clear low part before returning key */
508 temp&=0xff00;
509 }
510 reg_ax=temp;
511 } else {
512 /* enter small idle loop to allow for irqs to happen */
513 reg_ip+=1;
514 }
515 break;
516 case 0x01: /* CHECK FOR KEYSTROKE */
517 // enable interrupt-flag after IRET of this int16
518 mem_writew(SegPhys(ss)+reg_sp+4,(mem_readw(SegPhys(ss)+reg_sp+4) | FLAG_IF));
519 for (;;) {
520 if (check_key(temp)) {
521 if (!IsEnhancedKey(temp)) {
522 /* normal key, return translated key in ax */
523 CALLBACK_SZF(false);
524 reg_ax=temp;
525 break;
526 } else {
527 /* remove enhanced key from buffer and ignore it */
528 get_key(temp);
529 }
530 } else {
531 /* no key available */
532 CALLBACK_SZF(true);
533 break;
534 }
535 // CALLBACK_Idle();
536 }
537 break;
538 case 0x11: /* CHECK FOR KEYSTROKE (enhanced keyboards only) */
539 if (!check_key(temp)) {
540 CALLBACK_SZF(true);
541 } else {
542 CALLBACK_SZF(false);
543 if (((temp&0xff)==0xf0) && (temp>>8)) {
544 /* special enhanced key, clear low part before returning key */
545 temp&=0xff00;
546 }
547 reg_ax=temp;
548 }
549 break;
550 case 0x02: /* GET SHIFT FlAGS */
551 reg_al=mem_readb(BIOS_KEYBOARD_FLAGS1);
552 break;
553 case 0x03: /* SET TYPEMATIC RATE AND DELAY */
554 if (reg_al == 0x00) { // set default delay and rate
555 IO_Write(0x60,0xf3);
556 IO_Write(0x60,0x20); // 500 msec delay, 30 cps
557 } else if (reg_al == 0x05) { // set repeat rate and delay
558 IO_Write(0x60,0xf3);
559 IO_Write(0x60,(reg_bh&3)<<5|(reg_bl&0x1f));
560 } else {
561 LOG(LOG_BIOS,LOG_ERROR)("INT16:Unhandled Typematic Rate Call %2X BX=%X",reg_al,reg_bx);
562 }
563 break;
564 case 0x05: /* STORE KEYSTROKE IN KEYBOARD BUFFER */
565 if (BIOS_AddKeyToBuffer(reg_cx)) reg_al=0;
566 else reg_al=1;
567 break;
568 case 0x12: /* GET EXTENDED SHIFT STATES */
569 reg_al=mem_readb(BIOS_KEYBOARD_FLAGS1);
570 reg_ah=mem_readb(BIOS_KEYBOARD_FLAGS2);
571 break;
572 case 0x55:
573 /* Weird call used by some dos apps */
574 LOG(LOG_BIOS,LOG_NORMAL)("INT16:55:Word TSR compatible call");
575 break;
576 default:
577 LOG(LOG_BIOS,LOG_ERROR)("INT16:Unhandled call %02X",reg_ah);
578 break;
579
580 };
581
582 return CBRET_NONE;
583 }
584
585 //Keyboard initialisation. src/gui/sdlmain.cpp
586 extern bool startup_state_numlock;
587 extern bool startup_state_capslock;
588
InitBiosSegment(void)589 static void InitBiosSegment(void) {
590 /* Setup the variables for keyboard in the bios data segment */
591 mem_writew(BIOS_KEYBOARD_BUFFER_START,0x1e);
592 mem_writew(BIOS_KEYBOARD_BUFFER_END,0x3e);
593 mem_writew(BIOS_KEYBOARD_BUFFER_HEAD,0x1e);
594 mem_writew(BIOS_KEYBOARD_BUFFER_TAIL,0x1e);
595 Bit8u flag1 = 0;
596 Bit8u leds = 16; /* Ack recieved */
597
598 #if SDL_VERSION_ATLEAST(1, 2, 14)
599 //Nothing, mapper handles all.
600 #else
601 if (startup_state_capslock) { flag1|=0x40; leds|=0x04;}
602 if (startup_state_numlock) { flag1|=0x20; leds|=0x02;}
603 #endif
604
605 mem_writeb(BIOS_KEYBOARD_FLAGS1,flag1);
606 mem_writeb(BIOS_KEYBOARD_FLAGS2,0);
607 mem_writeb(BIOS_KEYBOARD_FLAGS3,16); /* Enhanced keyboard installed */
608 mem_writeb(BIOS_KEYBOARD_TOKEN,0);
609 mem_writeb(BIOS_KEYBOARD_LEDS,leds);
610 }
611
BIOS_SetupKeyboard(void)612 void BIOS_SetupKeyboard(void) {
613 /* Init the variables */
614 InitBiosSegment();
615
616 /* Allocate/setup a callback for int 0x16 and for standard IRQ 1 handler */
617 call_int16=CALLBACK_Allocate();
618 CALLBACK_Setup(call_int16,&INT16_Handler,CB_INT16,"Keyboard");
619 RealSetVec(0x16,CALLBACK_RealPointer(call_int16));
620
621 call_irq1=CALLBACK_Allocate();
622 CALLBACK_Setup(call_irq1,&IRQ1_Handler,CB_IRQ1,Real2Phys(BIOS_DEFAULT_IRQ1_LOCATION),"IRQ 1 Keyboard");
623 RealSetVec(0x09,BIOS_DEFAULT_IRQ1_LOCATION);
624 // pseudocode for CB_IRQ1:
625 // push ax
626 // in al, 0x60
627 // mov ah, 0x4f
628 // stc
629 // int 15
630 // jc skip
631 // callback IRQ1_Handler
632 // label skip:
633 // cli
634 // mov al, 0x20
635 // out 0x20, al
636 // pop ax
637 // iret
638
639 if (machine==MCH_PCJR) {
640 call_irq6=CALLBACK_Allocate();
641 CALLBACK_Setup(call_irq6,NULL,CB_IRQ6_PCJR,"PCJr kb irq");
642 RealSetVec(0x0e,CALLBACK_RealPointer(call_irq6));
643 // pseudocode for CB_IRQ6_PCJR:
644 // push ax
645 // in al, 0x60
646 // cmp al, 0xe0
647 // je skip
648 // int 0x09
649 // label skip:
650 // cli
651 // mov al, 0x20
652 // out 0x20, al
653 // pop ax
654 // iret
655 }
656 }
657
658