DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #include "dosbox.h" 00021 #include "callback.h" 00022 #include "mem.h" 00023 #include "bios.h" 00024 #include "keyboard.h" 00025 #include "regs.h" 00026 #include "inout.h" 00027 #include "dos_inc.h" 00028 #include "SDL.h" 00029 #include "int10.h" 00030 00031 #if defined(_MSC_VER) 00032 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */ 00033 #endif 00034 00035 /* SDL by default treats numlock and scrolllock different from all other keys. 00036 * In recent versions this can disabled by a environment variable which we set in sdlmain.cpp 00037 * Define the following if this is the case */ 00038 #if SDL_VERSION_ATLEAST(1, 2, 14) 00039 #define CAN_USE_LOCK 1 00040 /* For lower versions of SDL we also use a slight hack to get the startup states of numclock and capslock right. 00041 * The proper way is in the mapper, but the repeating key is an unwanted side effect for lower versions of SDL */ 00042 #endif 00043 00044 static Bitu call_int16 = 0,call_irq1 = 0,irq1_ret_ctrlbreak_callback = 0,call_irq6 = 0,call_irq_pcjr_nmi = 0; 00045 00046 /* Nice table from BOCHS i should feel bad for ripping this */ 00047 #define none 0 00048 static struct { 00049 Bit16u normal; 00050 Bit16u shift; 00051 Bit16u control; 00052 Bit16u alt; 00053 } scan_to_scanascii[MAX_SCAN_CODE + 1] = { 00054 { none, none, none, none }, 00055 { 0x011b, 0x011b, 0x011b, 0x01f0 }, /* escape */ 00056 { 0x0231, 0x0221, none, 0x7800 }, /* 1! */ 00057 { 0x0332, 0x0340, 0x0300, 0x7900 }, /* 2@ */ 00058 { 0x0433, 0x0423, none, 0x7a00 }, /* 3# */ 00059 { 0x0534, 0x0524, none, 0x7b00 }, /* 4$ */ 00060 { 0x0635, 0x0625, none, 0x7c00 }, /* 5% */ 00061 { 0x0736, 0x075e, 0x071e, 0x7d00 }, /* 6^ */ 00062 { 0x0837, 0x0826, none, 0x7e00 }, /* 7& */ 00063 { 0x0938, 0x092a, none, 0x7f00 }, /* 8* */ 00064 { 0x0a39, 0x0a28, none, 0x8000 }, /* 9( */ 00065 { 0x0b30, 0x0b29, none, 0x8100 }, /* 0) */ 00066 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200 }, /* -_ */ 00067 { 0x0d3d, 0x0d2b, none, 0x8300 }, /* =+ */ 00068 { 0x0e08, 0x0e08, 0x0e7f, 0x0ef0 }, /* backspace */ 00069 { 0x0f09, 0x0f00, 0x9400, none }, /* tab */ 00070 { 0x1071, 0x1051, 0x1011, 0x1000 }, /* Q */ 00071 { 0x1177, 0x1157, 0x1117, 0x1100 }, /* W */ 00072 { 0x1265, 0x1245, 0x1205, 0x1200 }, /* E */ 00073 { 0x1372, 0x1352, 0x1312, 0x1300 }, /* R */ 00074 { 0x1474, 0x1454, 0x1414, 0x1400 }, /* T */ 00075 { 0x1579, 0x1559, 0x1519, 0x1500 }, /* Y */ 00076 { 0x1675, 0x1655, 0x1615, 0x1600 }, /* U */ 00077 { 0x1769, 0x1749, 0x1709, 0x1700 }, /* I */ 00078 { 0x186f, 0x184f, 0x180f, 0x1800 }, /* O */ 00079 { 0x1970, 0x1950, 0x1910, 0x1900 }, /* P */ 00080 { 0x1a5b, 0x1a7b, 0x1a1b, 0x1af0 }, /* [{ */ 00081 { 0x1b5d, 0x1b7d, 0x1b1d, 0x1bf0 }, /* ]} */ 00082 { 0x1c0d, 0x1c0d, 0x1c0a, none }, /* Enter */ 00083 { none, none, none, none }, /* L Ctrl */ 00084 { 0x1e61, 0x1e41, 0x1e01, 0x1e00 }, /* A */ 00085 { 0x1f73, 0x1f53, 0x1f13, 0x1f00 }, /* S */ 00086 { 0x2064, 0x2044, 0x2004, 0x2000 }, /* D */ 00087 { 0x2166, 0x2146, 0x2106, 0x2100 }, /* F */ 00088 { 0x2267, 0x2247, 0x2207, 0x2200 }, /* G */ 00089 { 0x2368, 0x2348, 0x2308, 0x2300 }, /* H */ 00090 { 0x246a, 0x244a, 0x240a, 0x2400 }, /* J */ 00091 { 0x256b, 0x254b, 0x250b, 0x2500 }, /* K */ 00092 { 0x266c, 0x264c, 0x260c, 0x2600 }, /* L */ 00093 { 0x273b, 0x273a, none, 0x27f0 }, /* ;: */ 00094 { 0x2827, 0x2822, none, 0x28f0 }, /* '" */ 00095 { 0x2960, 0x297e, none, 0x29f0 }, /* `~ */ 00096 { none, none, none, none }, /* L shift */ 00097 { 0x2b5c, 0x2b7c, 0x2b1c, 0x2bf0 }, /* |\ */ 00098 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00 }, /* Z */ 00099 { 0x2d78, 0x2d58, 0x2d18, 0x2d00 }, /* X */ 00100 { 0x2e63, 0x2e43, 0x2e03, 0x2e00 }, /* C */ 00101 { 0x2f76, 0x2f56, 0x2f16, 0x2f00 }, /* V */ 00102 { 0x3062, 0x3042, 0x3002, 0x3000 }, /* B */ 00103 { 0x316e, 0x314e, 0x310e, 0x3100 }, /* N */ 00104 { 0x326d, 0x324d, 0x320d, 0x3200 }, /* M */ 00105 { 0x332c, 0x333c, none, 0x33f0 }, /* ,< */ 00106 { 0x342e, 0x343e, none, 0x34f0 }, /* .> */ 00107 { 0x352f, 0x353f, none, 0x35f0 }, /* /? */ 00108 { none, none, none, none }, /* R Shift */ 00109 { 0x372a, 0x372a, 0x9600, 0x37f0 }, /* * */ 00110 { none, none, none, none }, /* L Alt */ 00111 { 0x3920, 0x3920, 0x3920, 0x3920 }, /* space */ 00112 { none, none, none, none }, /* caps lock */ 00113 { 0x3b00, 0x5400, 0x5e00, 0x6800 }, /* F1 */ 00114 { 0x3c00, 0x5500, 0x5f00, 0x6900 }, /* F2 */ 00115 { 0x3d00, 0x5600, 0x6000, 0x6a00 }, /* F3 */ 00116 { 0x3e00, 0x5700, 0x6100, 0x6b00 }, /* F4 */ 00117 { 0x3f00, 0x5800, 0x6200, 0x6c00 }, /* F5 */ 00118 { 0x4000, 0x5900, 0x6300, 0x6d00 }, /* F6 */ 00119 { 0x4100, 0x5a00, 0x6400, 0x6e00 }, /* F7 */ 00120 { 0x4200, 0x5b00, 0x6500, 0x6f00 }, /* F8 */ 00121 { 0x4300, 0x5c00, 0x6600, 0x7000 }, /* F9 */ 00122 { 0x4400, 0x5d00, 0x6700, 0x7100 }, /* F10 */ 00123 { none, none, none, none }, /* Num Lock */ 00124 { none, none, none, none }, /* Scroll Lock */ 00125 { 0x4700, 0x4737, 0x7700, 0x0007 }, /* 7 Home */ 00126 { 0x4800, 0x4838, 0x8d00, 0x0008 }, /* 8 UP */ 00127 { 0x4900, 0x4939, 0x8400, 0x0009 }, /* 9 PgUp */ 00128 { 0x4a2d, 0x4a2d, 0x8e00, 0x4af0 }, /* - */ 00129 { 0x4b00, 0x4b34, 0x7300, 0x0004 }, /* 4 Left */ 00130 { 0x4cf0, 0x4c35, 0x8f00, 0x0005 }, /* 5 */ 00131 { 0x4d00, 0x4d36, 0x7400, 0x0006 }, /* 6 Right */ 00132 { 0x4e2b, 0x4e2b, 0x9000, 0x4ef0 }, /* + */ 00133 { 0x4f00, 0x4f31, 0x7500, 0x0001 }, /* 1 End */ 00134 { 0x5000, 0x5032, 0x9100, 0x0002 }, /* 2 Down */ 00135 { 0x5100, 0x5133, 0x7600, 0x0003 }, /* 3 PgDn */ 00136 { 0x5200, 0x5230, 0x9200, 0x0000 }, /* 0 Ins */ 00137 { 0x5300, 0x532e, 0x9300, none }, /* Del */ 00138 { none, none, none, none }, 00139 { none, none, none, none }, 00140 { 0x565c, 0x567c, none, none }, /* (102-key) */ 00141 { 0x8500, 0x8700, 0x8900, 0x8b00 }, /* F11 */ 00142 { 0x8600, 0x8800, 0x8a00, 0x8c00 } /* F12 */ 00143 }; 00144 00145 bool BIOS_AddKeyToBuffer(Bit16u code) { 00146 if (!IS_PC98_ARCH) { 00147 if (mem_readb(BIOS_KEYBOARD_FLAGS2)&8) return true; 00148 } 00149 00150 Bit16u start,end,head,tail,ttail; 00151 if (IS_PC98_ARCH) { 00152 start=0x502; 00153 end=0x522; 00154 } 00155 else if (machine==MCH_PCJR) { 00156 /* should be done for cga and others as well, to be tested */ 00157 start=0x1e; 00158 end=0x3e; 00159 } else { 00160 start=mem_readw(BIOS_KEYBOARD_BUFFER_START); 00161 end =mem_readw(BIOS_KEYBOARD_BUFFER_END); 00162 } 00163 00164 if (IS_PC98_ARCH) { 00165 head =mem_readw(0x524/*head*/); 00166 tail =mem_readw(0x526/*tail*/); 00167 } 00168 else { 00169 head =mem_readw(BIOS_KEYBOARD_BUFFER_HEAD); 00170 tail =mem_readw(BIOS_KEYBOARD_BUFFER_TAIL); 00171 } 00172 00173 ttail=tail+2; 00174 if (ttail>=end) { 00175 ttail=start; 00176 } 00177 /* Check for buffer Full */ 00178 //TODO Maybe beeeeeeep or something although that should happend when internal buffer is full 00179 if (ttail==head) return false; 00180 00181 if (IS_PC98_ARCH) { 00182 real_writew(0x0,tail,code); 00183 mem_writew(0x526/*tail*/,ttail); 00184 00185 /* PC-98 BIOSes also manage a key counter, which is required for 00186 * some games and even the PC-98 version of MS-DOS to detect keyboard input */ 00187 unsigned char b = real_readw(0,0x528); 00188 real_writew(0,0x528,b+1); 00189 } 00190 else { 00191 real_writew(0x40,tail,code); 00192 mem_writew(BIOS_KEYBOARD_BUFFER_TAIL,ttail); 00193 } 00194 00195 return true; 00196 } 00197 00198 static void add_key(Bit16u code) { 00199 if (code!=0 || IS_PC98_ARCH) BIOS_AddKeyToBuffer(code); 00200 } 00201 00202 static bool get_key(Bit16u &code) { 00203 Bit16u start,end,head,tail,thead; 00204 if (IS_PC98_ARCH) { 00205 start=0x502; 00206 end=0x522; 00207 } 00208 else if (machine==MCH_PCJR) { 00209 /* should be done for cga and others as well, to be tested */ 00210 start=0x1e; 00211 end=0x3e; 00212 } else { 00213 start=mem_readw(BIOS_KEYBOARD_BUFFER_START); 00214 end =mem_readw(BIOS_KEYBOARD_BUFFER_END); 00215 } 00216 00217 if (IS_PC98_ARCH) { 00218 head =mem_readw(0x524/*head*/); 00219 tail =mem_readw(0x526/*tail*/); 00220 } 00221 else { 00222 head =mem_readw(BIOS_KEYBOARD_BUFFER_HEAD); 00223 tail =mem_readw(BIOS_KEYBOARD_BUFFER_TAIL); 00224 } 00225 00226 /* PC-98 BIOSes also manage a key counter, which is required for 00227 * some games and even the PC-98 version of MS-DOS to detect keyboard input */ 00228 unsigned char b = real_readw(0,0x528); 00229 if (b != 0) real_writew(0,0x528,b-1); 00230 00231 if (head==tail) return false; 00232 thead=head+2; 00233 if (thead>=end) thead=start; 00234 00235 if (IS_PC98_ARCH) { 00236 mem_writew(0x524/*head*/,thead); 00237 code = real_readw(0x0,head); 00238 } 00239 else { 00240 mem_writew(BIOS_KEYBOARD_BUFFER_HEAD,thead); 00241 code = real_readw(0x40,head); 00242 } 00243 00244 return true; 00245 } 00246 00247 bool INT16_get_key(Bit16u &code) { 00248 return get_key(code); 00249 } 00250 00251 static bool check_key(Bit16u &code) { 00252 Bit16u head,tail; 00253 00254 if (IS_PC98_ARCH) { 00255 head =mem_readw(0x524/*head*/); 00256 tail =mem_readw(0x526/*tail*/); 00257 } 00258 else { 00259 head =mem_readw(BIOS_KEYBOARD_BUFFER_HEAD); 00260 tail =mem_readw(BIOS_KEYBOARD_BUFFER_TAIL); 00261 } 00262 00263 if (head==tail) return false; 00264 00265 if (IS_PC98_ARCH) 00266 code = real_readw(0x0,head); 00267 else 00268 code = real_readw(0x40,head); 00269 00270 return true; 00271 } 00272 00273 bool INT16_peek_key(Bit16u &code) { 00274 return check_key(code); 00275 } 00276 00277 static void empty_keyboard_buffer() { 00278 mem_writew(BIOS_KEYBOARD_BUFFER_TAIL, mem_readw(BIOS_KEYBOARD_BUFFER_HEAD)); 00279 } 00280 00281 /* Flag Byte 1 00282 bit 7 =1 INSert active 00283 bit 6 =1 Caps Lock active 00284 bit 5 =1 Num Lock active 00285 bit 4 =1 Scroll Lock active 00286 bit 3 =1 either Alt pressed 00287 bit 2 =1 either Ctrl pressed 00288 bit 1 =1 Left Shift pressed 00289 bit 0 =1 Right Shift pressed 00290 */ 00291 /* Flag Byte 2 00292 bit 7 =1 INSert pressed 00293 bit 6 =1 Caps Lock pressed 00294 bit 5 =1 Num Lock pressed 00295 bit 4 =1 Scroll Lock pressed 00296 bit 3 =1 Pause state active 00297 bit 2 =1 Sys Req pressed 00298 bit 1 =1 Left Alt pressed 00299 bit 0 =1 Left Ctrl pressed 00300 */ 00301 /* 00302 Keyboard status byte 3 00303 bit 7 =1 read-ID in progress 00304 bit 6 =1 last code read was first of two ID codes 00305 bit 5 =1 force Num Lock if read-ID and enhanced keyboard 00306 bit 4 =1 enhanced keyboard installed 00307 bit 3 =1 Right Alt pressed 00308 bit 2 =1 Right Ctrl pressed 00309 bit 1 =1 last code read was E0h 00310 bit 0 =1 last code read was E1h 00311 */ 00312 00313 00314 void KEYBOARD_SetLEDs(Bit8u bits); 00315 00316 /* the scancode is in reg_al */ 00317 static Bitu IRQ1_Handler(void) { 00318 /* handling of the locks key is difficult as sdl only gives 00319 * states for numlock capslock. 00320 */ 00321 Bitu scancode=reg_al; 00322 Bit8u flags1,flags2,flags3,leds,leds_orig; 00323 flags1=mem_readb(BIOS_KEYBOARD_FLAGS1); 00324 flags2=mem_readb(BIOS_KEYBOARD_FLAGS2); 00325 flags3=mem_readb(BIOS_KEYBOARD_FLAGS3); 00326 leds =mem_readb(BIOS_KEYBOARD_LEDS); 00327 leds_orig = leds; 00328 #ifdef CAN_USE_LOCK 00329 /* No hack anymore! */ 00330 #else 00331 flags2&=~(0x40+0x20);//remove numlock/capslock pressed (hack for sdl only reporting states) 00332 #endif 00333 if (DOS_LayoutKey(scancode,flags1,flags2,flags3)) return CBRET_NONE; 00334 //LOG_MSG("key input %d %d %d %d",scancode,flags1,flags2,flags3); 00335 switch (scancode) { 00336 /* First the hard ones */ 00337 case 0xfa: /* ack. Do nothing for now */ 00338 break; 00339 case 0xe1: /* Extended key special. Only pause uses this */ 00340 flags3 |=0x01; 00341 break; 00342 case 0xe0: /* Extended key */ 00343 flags3 |=0x02; 00344 break; 00345 case 0x1d: /* Ctrl Pressed */ 00346 if (!(flags3 &0x01)) { 00347 flags1 |=0x04; 00348 if (flags3 &0x02) flags3 |=0x04; 00349 else flags2 |=0x01; 00350 } /* else it's part of the pause scancodes */ 00351 break; 00352 case 0x9d: /* Ctrl Released */ 00353 if (!(flags3 &0x01)) { 00354 if (flags3 &0x02) flags3 &=~0x04; 00355 else flags2 &=~0x01; 00356 if( !( (flags3 &0x04) || (flags2 &0x01) ) ) flags1 &=~0x04; 00357 } 00358 break; 00359 case 0x2a: /* Left Shift Pressed */ 00360 flags1 |=0x02; 00361 break; 00362 case 0xaa: /* Left Shift Released */ 00363 flags1 &=~0x02; 00364 break; 00365 case 0x36: /* Right Shift Pressed */ 00366 flags1 |=0x01; 00367 break; 00368 case 0xb6: /* Right Shift Released */ 00369 flags1 &=~0x01; 00370 break; 00371 case 0x37: /* Keypad * or PrtSc Pressed */ 00372 if (!(flags3 & 0x02)) goto normal_key; 00373 reg_ip += 7; // call int 5 00374 break; 00375 case 0xb7: /* Keypad * or PrtSc Released */ 00376 if (!(flags3 & 0x02)) goto normal_key; 00377 break; 00378 case 0x38: /* Alt Pressed */ 00379 flags1 |=0x08; 00380 if (flags3 &0x02) flags3 |=0x08; 00381 else flags2 |=0x02; 00382 break; 00383 case 0xb8: /* Alt Released */ 00384 if (flags3 &0x02) flags3 &= ~0x08; 00385 else flags2 &= ~0x02; 00386 if( !( (flags3 &0x08) || (flags2 &0x02) ) ) { /* Both alt released */ 00387 flags1 &= ~0x08; 00388 Bit16u token =mem_readb(BIOS_KEYBOARD_TOKEN); 00389 if(token != 0){ 00390 add_key(token); 00391 mem_writeb(BIOS_KEYBOARD_TOKEN,0); 00392 } 00393 } 00394 break; 00395 00396 #ifdef CAN_USE_LOCK 00397 case 0x3a:flags2 |=0x40;break;//CAPSLOCK 00398 case 0xba:flags1 ^=0x40;flags2 &=~0x40;leds ^=0x04;break; 00399 #else 00400 case 0x3a:flags2 |=0x40;flags1 |=0x40;leds |=0x04;break; //SDL gives only the state instead of the toggle /* Caps Lock */ 00401 case 0xba:flags1 &=~0x40;leds &=~0x04;break; 00402 #endif 00403 case 0x45: 00404 /* if it has E1 prefix or is Ctrl-NumLock on non-enhanced keyboard => Pause */ 00405 if ((flags3 &0x01) || (!(flags3&0x10) && (flags1&0x04))) { 00406 /* last scancode of pause received; first remove 0xe1-prefix */ 00407 flags3 &=~0x01; 00408 mem_writeb(BIOS_KEYBOARD_FLAGS3,flags3); 00409 if ((flags2&8)==0) { 00410 /* normal pause key, enter loop */ 00411 mem_writeb(BIOS_KEYBOARD_FLAGS2,flags2|8); 00412 IO_Write(0x20,0x20); 00413 while (mem_readb(BIOS_KEYBOARD_FLAGS2)&8) CALLBACK_Idle(); // pause loop 00414 reg_ip+=5; // skip out 20,20 00415 return CBRET_NONE; 00416 } 00417 } else { 00418 /* Num Lock */ 00419 #ifdef CAN_USE_LOCK 00420 flags2 |=0x20; 00421 #else 00422 flags2 |=0x20; 00423 flags1 |=0x20; 00424 leds |=0x02; 00425 #endif 00426 } 00427 break; 00428 case 0xc5: 00429 if ((flags3 &0x01) || (!(flags3&0x10) && (flags1&0x04))) { 00430 /* pause released */ 00431 flags3 &=~0x01; 00432 } else { 00433 #ifdef CAN_USE_LOCK 00434 flags1^=0x20; 00435 leds^=0x02; 00436 flags2&=~0x20; 00437 #else 00438 /* Num Lock released */ 00439 flags1 &=~0x20; 00440 leds &=~0x02; 00441 #endif 00442 } 00443 break; 00444 case 0x46: /* Scroll Lock or Ctrl-Break */ 00445 /* if it has E0 prefix, or is Ctrl-NumLock on non-enhanced keyboard => Break */ 00446 if((flags3&0x02) || (!(flags3&0x10) && (flags1&0x04))) { /* Ctrl-Break? */ 00447 /* remove 0xe0-prefix */ 00448 flags3 &=~0x02; 00449 mem_writeb(BIOS_KEYBOARD_FLAGS3,flags3); 00450 mem_writeb(BIOS_CTRL_BREAK_FLAG,0x80); 00451 empty_keyboard_buffer(); 00452 BIOS_AddKeyToBuffer(0); 00453 SegSet16(cs, RealSeg(CALLBACK_RealPointer(irq1_ret_ctrlbreak_callback))); 00454 reg_ip = RealOff(CALLBACK_RealPointer(irq1_ret_ctrlbreak_callback)); 00455 return CBRET_NONE; 00456 } else { /* Scroll Lock. */ 00457 flags2 |=0x10; /* Scroll Lock SDL Seems to do this one fine (so break and make codes) */ 00458 } 00459 break; 00460 case 0xc6: 00461 if((flags3&0x02) || (!(flags3&0x10) && (flags1&0x04))) { /* Ctrl-Break released? */ 00462 /* nothing to do */ 00463 } else { 00464 flags1 ^=0x10;flags2 &=~0x10;leds ^=0x01;break; /* Scroll Lock released */ 00465 } 00466 case 0xd2: /* NUMPAD insert, ironically, regular one is handled by 0x52 */ 00467 if (flags3 & BIOS_KEYBOARD_FLAGS3_HIDDEN_E0 || !(flags1 & BIOS_KEYBOARD_FLAGS1_NUMLOCK_ACTIVE)) 00468 { 00469 flags1 ^= BIOS_KEYBOARD_FLAGS1_INSERT_ACTIVE; 00470 flags2 &= BIOS_KEYBOARD_FLAGS2_INSERT_PRESSED; 00471 } 00472 break; 00473 case 0x47: /* Numpad */ 00474 case 0x48: 00475 case 0x49: 00476 case 0x4b: 00477 case 0x4c: 00478 case 0x4d: 00479 case 0x4f: 00480 case 0x50: 00481 case 0x51: 00482 case 0x52: 00483 case 0x53: /* del . Not entirely correct, but works fine */ 00484 if (!(flags3 & 0x01) && !(flags1 & 0x03) && (flags1 & 0x0c) == 0x0c && ((!(flags3 & 0x10) && (flags3 & 0x0c) == 0x0c) || ((flags3 & 0x10) && (flags2 & 0x03) == 0x03))) { /* Ctrl-Alt-Del? */ 00485 throw int(3); 00486 break; 00487 } 00488 if(flags3 &0x02) { /*extend key. e.g key above arrows or arrows*/ 00489 if(scancode == 0x52) flags2 |=0x80; /* press insert */ 00490 if(flags1 &0x08) { 00491 add_key(scan_to_scanascii[scancode].normal+0x5000); 00492 } else if (flags1 &0x04) { 00493 add_key((scan_to_scanascii[scancode].control&0xff00)|0xe0); 00494 } else if( ((flags1 &0x3) != 0) || ((flags1 &0x20) != 0) ) { //Due to |0xe0 results are identical. 00495 add_key((scan_to_scanascii[scancode].shift&0xff00)|0xe0); 00496 } else add_key((scan_to_scanascii[scancode].normal&0xff00)|0xe0); 00497 break; 00498 } 00499 if(flags1 &0x08) { 00500 Bit8u token = mem_readb(BIOS_KEYBOARD_TOKEN); 00501 token = token*10 + (Bit8u)(scan_to_scanascii[scancode].alt&0xff); 00502 mem_writeb(BIOS_KEYBOARD_TOKEN,token); 00503 } else if (flags1 &0x04) { 00504 add_key(scan_to_scanascii[scancode].control); 00505 } else if( ((flags1 &0x3) != 0) ^ ((flags1 &0x20) != 0) ) { //Xor shift and numlock (both means off) 00506 add_key(scan_to_scanascii[scancode].shift); 00507 } else add_key(scan_to_scanascii[scancode].normal); 00508 break; 00509 00510 default: /* Normal Key */ 00511 normal_key: 00512 Bit16u asciiscan; 00513 /* Now Handle the releasing of keys and see if they match up for a code */ 00514 /* Handle the actual scancode */ 00515 if (scancode & 0x80) goto irq1_end; 00516 if (scancode > MAX_SCAN_CODE) goto irq1_end; 00517 if (flags1 & 0x08) { /* Alt is being pressed */ 00518 asciiscan=scan_to_scanascii[scancode].alt; 00519 #if 0 /* old unicode support disabled*/ 00520 } else if (ascii) { 00521 asciiscan=(scancode << 8) | ascii; 00522 #endif 00523 } else if (flags1 & 0x04) { /* Ctrl is being pressed */ 00524 asciiscan=scan_to_scanascii[scancode].control; 00525 } else if (flags1 & 0x03) { /* Either shift is being pressed */ 00526 asciiscan=scan_to_scanascii[scancode].shift; 00527 } else { 00528 asciiscan=scan_to_scanascii[scancode].normal; 00529 } 00530 /* cancel shift is letter and capslock active */ 00531 if(flags1&64) { 00532 if(flags1&3) { 00533 /*cancel shift */ 00534 if(((asciiscan&0x00ff) >0x40) && ((asciiscan&0x00ff) <0x5b)) 00535 asciiscan=scan_to_scanascii[scancode].normal; 00536 } else { 00537 /* add shift */ 00538 if(((asciiscan&0x00ff) >0x60) && ((asciiscan&0x00ff) <0x7b)) 00539 asciiscan=scan_to_scanascii[scancode].shift; 00540 } 00541 } 00542 if (flags3 &0x02) { 00543 /* extended key (numblock), return and slash need special handling */ 00544 if (scancode==0x1c) { /* return */ 00545 if (flags1 &0x08) asciiscan=0xa600; 00546 else asciiscan=(asciiscan&0xff)|0xe000; 00547 } else if (scancode==0x35) { /* slash */ 00548 if (flags1 &0x08) asciiscan=0xa400; 00549 else if (flags1 &0x04) asciiscan=0x9500; 00550 else asciiscan=0xe02f; 00551 } 00552 } 00553 add_key(asciiscan); 00554 break; 00555 } 00556 irq1_end: 00557 if(scancode !=0xe0) flags3 &=~0x02; //Reset 0xE0 Flag 00558 mem_writeb(BIOS_KEYBOARD_FLAGS1,flags1); 00559 if ((scancode&0x80)==0) flags2&=0xf7; 00560 mem_writeb(BIOS_KEYBOARD_FLAGS2,flags2); 00561 mem_writeb(BIOS_KEYBOARD_FLAGS3,flags3); 00562 mem_writeb(BIOS_KEYBOARD_LEDS,leds); 00563 00564 /* update LEDs on keyboard */ 00565 if (leds_orig != leds) KEYBOARD_SetLEDs(leds); 00566 00567 /* update insert cursor */ 00568 extern bool dos_program_running; 00569 if (!dos_program_running) 00570 { 00571 const auto flg = mem_readb(BIOS_KEYBOARD_FLAGS1); 00572 const auto ins = static_cast<bool>(flg & BIOS_KEYBOARD_FLAGS1_INSERT_ACTIVE); 00573 const auto ssl = static_cast<Bit8u>(ins ? CURSOR_SCAN_LINE_INSERT : CURSOR_SCAN_LINE_NORMAL); 00574 if (CurMode->type == M_TEXT) 00575 INT10_SetCursorShape(ssl, CURSOR_SCAN_LINE_END); 00576 } 00577 00578 /* IO_Write(0x20,0x20); moved out of handler to be virtualizable */ 00579 #if 0 00580 /* Signal the keyboard for next code */ 00581 /* In dosbox port 60 reads do this as well */ 00582 Bit8u old61=IO_Read(0x61); 00583 IO_Write(0x61,old61 | 128); 00584 IO_Write(0x64,0xae); 00585 #endif 00586 return CBRET_NONE; 00587 } 00588 00589 unsigned char AT_read_60(void); 00590 extern bool pc98_force_ibm_layout; 00591 00592 /* BIOS INT 18h output vs keys: 00593 * 00594 * Unshifted Shifted CTRL Caps Kana Kana+Shift 00595 * ----------------------------------------------------------- 00596 * ESC 0x001B 0x001B 0x001B 0x001B 0x001B 0x001B 00597 * STOP -- -- -- -- -- -- 00598 * F1..F10 <--------------- scan code in upper, zero in lower -------> 00599 * INS/DEL <--------------- scan code in upper, zero in lower -------> 00600 * ROLL UP/DOWN <--------------- scan code in upper, zero in lower -------> 00601 * COPY -- -- -- -- -- -- 00602 * HOME CLR 0x3E00 0xAE00 -- -- -- -- 00603 * HELP <--------------- scan code in upper, zero in lower -------> 00604 * ARROW KEYS <--------------- scan code in upper, zero in lower -------> 00605 * XFER 0x3500 0xA500 0xB500 0x3500 0x3500 0xA500 00606 * NFER 0x5100 0xA100 0xB100 0x5100 0x5100 0xA100 00607 * GRPH -- -- -- -- -- -- 00608 * TAB 0x0F09 0x0F09 0x0F09 0x0F09 0x0F09 0x0F09 00609 * - / 口 -- 0x335F 0x331F -- 0x33DB 0x33DB Kana+CTRL = 0x331F 00610 */ 00611 static Bitu IRQ1_Handler_PC98(void) { 00612 unsigned char status; 00613 unsigned int patience = 32; 00614 00615 status = IO_ReadB(0x43); /* 8251 status */ 00616 while (status & 2/*RxRDY*/) { 00617 unsigned char sc_8251 = IO_ReadB(0x41); /* 8251 data */ 00618 00619 bool pressed = !(sc_8251 & 0x80); 00620 sc_8251 &= 0x7F; 00621 00622 /* Testing on real hardware shows INT 18h AH=0 returns raw scancode in upper half, ASCII in lower half. 00623 * Just like INT 16h on IBM PC hardware */ 00624 Bit16u scan_add = sc_8251 << 8U; 00625 00626 /* NOTES: 00627 * - The bitmap also tracks CAPS, and KANA state. It does NOT track NUM state. 00628 * The bit corresponding to the key code will show a bit set if in that state. 00629 * - The STS byte returned by INT 18h AH=02h seems to match the 14th byte of the bitmap... so far. 00630 * 00631 * STS layout (based on real hardware): 00632 * 00633 * bit[7] = ? 00634 * bit[6] = ? 00635 * bit[5] = ? 00636 * bit[4] = CTRL is down 00637 * bit[3] = GRPH is down 00638 * bit[2] = KANA engaged 00639 * bit[1] = CAPS engaged 00640 * bit[0] = SHIFT is down 00641 */ 00642 Bit8u modflags = mem_readb(0x52A + 0xE); 00643 00644 bool caps_capitals = (modflags & 1) ^ ((modflags >> 1) & 1); /* CAPS XOR SHIFT */ 00645 00646 /* According to Neko Project II, the BIOS maintains a "pressed key" bitmap at 0x50:0x2A. 00647 * Without this bitmap many PC-98 games are unplayable. */ 00648 /* ALSO note that byte 0xE of this array is the "shift" state byte. */ 00649 { 00650 unsigned int o = 0x52Au + ((unsigned int)sc_8251 >> 3u); 00651 unsigned char c = mem_readb(o); 00652 unsigned char b = 1u << (sc_8251 & 7u); 00653 00654 if (pressed) 00655 c |= b; 00656 else 00657 c &= ~b; 00658 00659 mem_writeb(o,c); 00660 00661 /* mirror CTRL+GRAPH+KANA+CAPS+SHIFT at 0x53A which is returned by INT 18h AH=2 */ 00662 if (o == 0x538) mem_writeb(0x53A,c); 00663 } 00664 00665 /* NOTES: 00666 * - SHIFT/CTRL scan code changes (no scan code emitted if GRPH is held down for these keys) 00667 * 00668 * CTRL apparently takes precedence over SHIFT. 00669 * 00670 * Key Unshifted Shifted CTRL 00671 * -------------------------------------------- 00672 * F1 0x62 0x82 0x92 00673 * F2 0x63 0x83 0x93 00674 * F3 0x64 0x84 0x94 00675 * F4 0x65 0x85 0x95 00676 * F5 0x66 0x86 0x96 00677 * F6 0x67 0x87 0x97 00678 * F7 0x68 0x88 0x98 00679 * F8 0x69 0x89 0x99 00680 * F9 0x6A 0x8A 0x9A 00681 * F10 0x6B 0x8B 0x9B 00682 * HOME/CLR 0x3E 0xAE <none> 00683 * XFER 0x35 0xA5 0xB5 00684 * NFER 0x51 0xA1 0xB1 00685 * VF1 0x52 0xC2 0xD2 00686 * VF2 0x53 0xC3 0xD3 00687 * VF3 0x54 0xC4 0xD4 00688 * VF4 0x55 0xC5 0xD5 00689 * VF5 0x56 0xC6 0xD6 00690 */ 00691 00692 /* FIXME: I'm fully aware of obvious problems with this code so far: 00693 * - This is coded around my American keyboard layout 00694 * - No support for CAPS or KANA modes. 00695 * 00696 * As this code develops refinements will occur. 00697 * 00698 * - Scan codes will be mapped to unshifted/shifted/kana modes 00699 * as laid out on Japanese keyboards. 00700 * - This will use a lookup table with special cases such as 00701 * modifier keys. */ 00702 // Keyboard layout and processing, copied from an actual PC-98 keyboard 00703 // 00704 // KEY UNSHIFT SHIFT CTRL KANA 00705 // ---------------------------------------- 00706 switch (sc_8251) { 00707 case 0x00: // ESC ESC ??? ??? ??? 00708 if (pressed) { 00709 add_key(scan_add + 27); 00710 } 00711 break; 00712 case 0x01: // 1 1 ! ??? ヌ 00713 if (pressed) { 00714 if (modflags & 1) /* either shift */ 00715 add_key(scan_add + '!'); 00716 else 00717 add_key(scan_add + '1'); 00718 } 00719 break; 00720 case 0x02: // 2 2 " ??? フ 00721 if (pressed) { 00722 if (modflags & 1) { /* shift */ 00723 if(!pc98_force_ibm_layout) 00724 add_key(scan_add + '\"'); 00725 else 00726 add_key(scan_add + '@'); 00727 } 00728 else { 00729 add_key(scan_add + '2'); 00730 } 00731 } 00732 break; 00733 case 0x03: // 3 3 # ??? ア 00734 if (pressed) { 00735 if (modflags & 1) /* shift */ 00736 add_key(scan_add + '#'); 00737 else 00738 add_key(scan_add + '3'); 00739 } 00740 break; 00741 case 0x04: // 4 4 $ ??? ウ 00742 if (pressed) { 00743 if (modflags & 1) /* shift */ 00744 add_key(scan_add + '$'); 00745 else 00746 add_key(scan_add + '4'); 00747 } 00748 break; 00749 case 0x05: // 5 5 % ??? エ 00750 if (pressed) { 00751 if (modflags & 1) /* shift */ 00752 add_key(scan_add + '%'); 00753 else 00754 add_key(scan_add + '5'); 00755 } 00756 break; 00757 case 0x06: // 6 6 & ??? オ 00758 if (pressed) { 00759 if (modflags & 1) { /* shift */ 00760 if(!pc98_force_ibm_layout) 00761 add_key(scan_add + '&'); 00762 else 00763 add_key(scan_add + '^'); 00764 } 00765 else { 00766 add_key(scan_add + '6'); 00767 } 00768 } 00769 break; 00770 case 0x07: // 7 7 ' ??? ヤ 00771 if (pressed) { 00772 if (modflags & 1) { /* shift */ 00773 if(!pc98_force_ibm_layout) 00774 add_key(scan_add + '\''); 00775 else 00776 add_key(scan_add + '&'); 00777 } 00778 else { 00779 add_key(scan_add + '7'); 00780 } 00781 } 00782 break; 00783 case 0x08: // 8 8 ( ??? ユ 00784 if (pressed) { 00785 if (modflags & 1) { /* shift */ 00786 if(!pc98_force_ibm_layout) 00787 add_key(scan_add + '('); 00788 else 00789 add_key(scan_add + '*'); 00790 } 00791 else { 00792 add_key(scan_add + '8'); 00793 } 00794 } 00795 break; 00796 case 0x09: // 9 9 ) ??? ヨ 00797 if (pressed) { 00798 if (modflags & 1) { /* shift */ 00799 if(!pc98_force_ibm_layout) 00800 add_key(scan_add + ')'); 00801 else 00802 add_key(scan_add + '('); 00803 } 00804 else { 00805 add_key(scan_add + '9'); 00806 } 00807 } 00808 break; 00809 case 0x0A: // 0 0 --- ??? ワ 00810 if (pressed) { 00811 if (modflags & 1) { /* shift */ 00812 if(!pc98_force_ibm_layout) 00813 { /* nothing */ } 00814 else 00815 add_key(scan_add + ')'); 00816 } 00817 else { 00818 add_key(scan_add + '0'); 00819 } 00820 } 00821 break; 00822 case 0x0B: // - - = ??? ホ 00823 if (pressed) { 00824 if (modflags & 1) { /* shift */ 00825 if(!pc98_force_ibm_layout) 00826 add_key(scan_add + '='); 00827 else 00828 add_key(scan_add + '_'); 00829 } 00830 else { 00831 add_key(scan_add + '-'); 00832 } 00833 } 00834 break; 00835 case 0x0C: // ^ ^ ` ??? ヘ 00836 if (pressed) { 00837 if(!pc98_force_ibm_layout) { 00838 if (modflags & 1) /* shift */ 00839 add_key(scan_add + '`'); 00840 else 00841 add_key(scan_add + '^'); 00842 } else { 00843 if (modflags & 1) /* shift */ 00844 add_key(scan_add + '+'); 00845 else 00846 add_key(scan_add + '='); 00847 } 00848 } 00849 break; 00850 case 0x0D: // ¥ ¥ | ??? ??? 00851 if (pressed) { 00852 if (modflags & 1) /* shift */ 00853 add_key(scan_add + '|'); 00854 else 00855 add_key(scan_add + '\\'); /* In Shift-JIS, backslash becomes the Yen symbol */ 00856 } 00857 break; 00858 case 0x0E: // backspace 00859 if (pressed) { 00860 add_key(scan_add + 8); 00861 } 00862 break; 00863 case 0x0F: // tab 00864 if (pressed) { 00865 add_key(scan_add + 9); 00866 } 00867 break; 00868 case 0x10: // q 00869 if (pressed) { 00870 if (caps_capitals) /* shift */ 00871 add_key(scan_add + 'Q'); 00872 else 00873 add_key(scan_add + 'q'); 00874 } 00875 break; 00876 case 0x11: // w 00877 if (pressed) { 00878 if (caps_capitals) /* shift */ 00879 add_key(scan_add + 'W'); 00880 else 00881 add_key(scan_add + 'w'); 00882 } 00883 break; 00884 case 0x12: // e 00885 if (pressed) { 00886 if (caps_capitals) /* shift */ 00887 add_key(scan_add + 'E'); 00888 else 00889 add_key(scan_add + 'e'); 00890 } 00891 break; 00892 case 0x13: // r 00893 if (pressed) { 00894 if (caps_capitals) /* shift */ 00895 add_key(scan_add + 'R'); 00896 else 00897 add_key(scan_add + 'r'); 00898 } 00899 break; 00900 case 0x14: // t 00901 if (pressed) { 00902 if (caps_capitals) /* shift */ 00903 add_key(scan_add + 'T'); 00904 else 00905 add_key(scan_add + 't'); 00906 } 00907 break; 00908 case 0x15: // y 00909 if (pressed) { 00910 if (caps_capitals) /* shift */ 00911 add_key(scan_add + 'Y'); 00912 else 00913 add_key(scan_add + 'y'); 00914 } 00915 break; 00916 case 0x16: // u 00917 if (pressed) { 00918 if (caps_capitals) /* shift */ 00919 add_key(scan_add + 'U'); 00920 else 00921 add_key(scan_add + 'u'); 00922 } 00923 break; 00924 case 0x17: // i 00925 if (pressed) { 00926 if (caps_capitals) /* shift */ 00927 add_key(scan_add + 'I'); 00928 else 00929 add_key(scan_add + 'i'); 00930 } 00931 break; 00932 case 0x18: // o 00933 if (pressed) { 00934 if (caps_capitals) /* shift */ 00935 add_key(scan_add + 'O'); 00936 else 00937 add_key(scan_add + 'o'); 00938 } 00939 break; 00940 case 0x19: // p 00941 if (pressed) { 00942 if (caps_capitals) /* shift */ 00943 add_key(scan_add + 'P'); 00944 else 00945 add_key(scan_add + 'p'); 00946 } 00947 break; 00948 case 0x1A: // @ @ ~ -- ゙ 00949 if (pressed) { 00950 if (modflags & 1) { /* shift */ 00951 add_key(scan_add + '~'); 00952 } 00953 else { 00954 if(!pc98_force_ibm_layout) 00955 add_key(scan_add + '@'); 00956 else 00957 add_key(scan_add + '`'); 00958 } 00959 } 00960 break; 00961 case 0x1B: // [ [ { -- ゚ 「 00962 if (pressed) { 00963 if (modflags & 1) /* shift */ 00964 add_key(scan_add + '{'); 00965 else 00966 add_key(scan_add + '['); 00967 } 00968 break; 00969 case 0x1C: // Enter 00970 if (pressed) { 00971 add_key(scan_add + 13); 00972 } 00973 break; 00974 case 0x1D: // A 00975 if (pressed) { 00976 if (caps_capitals) /* shift */ 00977 add_key(scan_add + 'A'); 00978 else 00979 add_key(scan_add + 'a'); 00980 } 00981 break; 00982 case 0x1E: // S 00983 if (pressed) { 00984 if (caps_capitals) /* shift */ 00985 add_key(scan_add + 'S'); 00986 else 00987 add_key(scan_add + 's'); 00988 } 00989 break; 00990 case 0x1F: // D 00991 if (pressed) { 00992 if (caps_capitals) /* shift */ 00993 add_key(scan_add + 'D'); 00994 else 00995 add_key(scan_add + 'd'); 00996 } 00997 break; 00998 case 0x20: // F 00999 if (pressed) { 01000 if (caps_capitals) /* shift */ 01001 add_key(scan_add + 'F'); 01002 else 01003 add_key(scan_add + 'f'); 01004 } 01005 break; 01006 case 0x21: // G 01007 if (pressed) { 01008 if (caps_capitals) /* shift */ 01009 add_key(scan_add + 'G'); 01010 else 01011 add_key(scan_add + 'g'); 01012 } 01013 break; 01014 case 0x22: // H 01015 if (pressed) { 01016 if (caps_capitals) /* shift */ 01017 add_key(scan_add + 'H'); 01018 else 01019 add_key(scan_add + 'h'); 01020 } 01021 break; 01022 case 0x23: // J 01023 if (pressed) { 01024 if (caps_capitals) /* shift */ 01025 add_key(scan_add + 'J'); 01026 else 01027 add_key(scan_add + 'j'); 01028 } 01029 break; 01030 case 0x24: // K 01031 if (pressed) { 01032 if (caps_capitals) /* shift */ 01033 add_key(scan_add + 'K'); 01034 else 01035 add_key(scan_add + 'k'); 01036 } 01037 break; 01038 case 0x25: // L 01039 if (pressed) { 01040 if (caps_capitals) /* shift */ 01041 add_key(scan_add + 'L'); 01042 else 01043 add_key(scan_add + 'l'); 01044 } 01045 break; 01046 case 0x26: // ; ; + --- レ 01047 if (pressed) { 01048 if (modflags & 1) { /* shift */ 01049 if(!pc98_force_ibm_layout) 01050 add_key(scan_add + '+'); 01051 else 01052 add_key(scan_add + ':'); 01053 } 01054 else { 01055 add_key(scan_add + ';'); 01056 } 01057 } 01058 break; 01059 case 0x27: // : : * --- ケ 01060 if (pressed) { 01061 if(!pc98_force_ibm_layout) { 01062 if (modflags & 1) /* shift */ 01063 add_key(scan_add + '*'); 01064 else 01065 add_key(scan_add + ':'); 01066 } else { 01067 if (modflags & 1) /* shift */ 01068 add_key(scan_add + '\"'); 01069 else 01070 add_key(scan_add + '\''); 01071 } 01072 } 01073 break; 01074 case 0x28: // ] ] } --- ム 」 01075 if (pressed) { 01076 if (modflags & 1) /* shift */ 01077 add_key(scan_add + '}'); 01078 else 01079 add_key(scan_add + ']'); 01080 } 01081 break; 01082 case 0x29: // Z 01083 if (pressed) { 01084 if (caps_capitals) /* shift */ 01085 add_key(scan_add + 'Z'); 01086 else 01087 add_key(scan_add + 'z'); 01088 } 01089 break; 01090 case 0x2A: // X 01091 if (pressed) { 01092 if (caps_capitals) /* shift */ 01093 add_key(scan_add + 'X'); 01094 else 01095 add_key(scan_add + 'x'); 01096 } 01097 break; 01098 case 0x2B: // C 01099 if (pressed) { 01100 if (caps_capitals) /* shift */ 01101 add_key(scan_add + 'C'); 01102 else 01103 add_key(scan_add + 'c'); 01104 } 01105 break; 01106 case 0x2C: // V 01107 if (pressed) { 01108 if (caps_capitals) /* shift */ 01109 add_key(scan_add + 'V'); 01110 else 01111 add_key(scan_add + 'v'); 01112 } 01113 break; 01114 case 0x2D: // B 01115 if (pressed) { 01116 if (caps_capitals) /* shift */ 01117 add_key(scan_add + 'B'); 01118 else 01119 add_key(scan_add + 'b'); 01120 } 01121 break; 01122 case 0x2E: // N 01123 if (pressed) { 01124 if (caps_capitals) /* shift */ 01125 add_key(scan_add + 'N'); 01126 else 01127 add_key(scan_add + 'n'); 01128 } 01129 break; 01130 case 0x2F: // M 01131 if (pressed) { 01132 if (caps_capitals) /* shift */ 01133 add_key(scan_add + 'M'); 01134 else 01135 add_key(scan_add + 'm'); 01136 } 01137 break; 01138 case 0x30: // , , < --- ネ 、 01139 if (pressed) { 01140 if (modflags & 1) /* shift */ 01141 add_key(scan_add + '<'); 01142 else 01143 add_key(scan_add + ','); 01144 } 01145 break; 01146 case 0x31: // . . > --- ル 。 01147 if (pressed) { 01148 if (modflags & 1) /* shift */ 01149 add_key(scan_add + '>'); 01150 else 01151 add_key(scan_add + '.'); 01152 } 01153 break; 01154 case 0x32: // / / ? --- メ ・ 01155 if (pressed) { 01156 if (modflags & 1) /* shift */ 01157 add_key(scan_add + '?'); 01158 else 01159 add_key(scan_add + '/'); 01160 } 01161 break; 01162 case 0x33: // _ / Ro 01163 if (pressed) { 01164 if (modflags & 1) /* shift */ 01165 add_key(scan_add + '_'); 01166 else 01167 { /*nothing*/ } 01168 } 01169 break; 01170 case 0x34: // <space> 01171 if (pressed) { 01172 add_key(scan_add + ' '); 01173 } 01174 break; 01175 01176 case 0x40: // keypad minus 01177 if (pressed) {//TODO: Shift state? 01178 add_key(scan_add + '-'); 01179 } 01180 break; 01181 case 0x41: // keypad divide 01182 if (pressed) {//TODO: Shift state? 01183 add_key(scan_add + '/'); 01184 } 01185 break; 01186 case 0x42: // keypad 7 01187 if (pressed) {//TODO: Shift state? 01188 add_key(scan_add + '7'); 01189 } 01190 break; 01191 case 0x43: // keypad 8 01192 if (pressed) {//TODO: Shift state? 01193 add_key(scan_add + '8'); 01194 } 01195 break; 01196 case 0x44: // keypad 9 01197 if (pressed) {//TODO: Shift state? 01198 add_key(scan_add + '9'); 01199 } 01200 break; 01201 case 0x45: // keypad multiply 01202 if (pressed) {//TODO: Shift state? 01203 add_key(scan_add + '*'); 01204 } 01205 break; 01206 case 0x46: // keypad 4 01207 if (pressed) {//TODO: Shift state? 01208 add_key(scan_add + '4'); 01209 } 01210 break; 01211 case 0x47: // keypad 5 01212 if (pressed) {//TODO: Shift state? 01213 add_key(scan_add + '5'); 01214 } 01215 break; 01216 case 0x48: // keypad 6 01217 if (pressed) {//TODO: Shift state? 01218 add_key(scan_add + '6'); 01219 } 01220 break; 01221 case 0x49: // keypad + 01222 if (pressed) {//TODO: Shift state? 01223 add_key(scan_add + '+'); 01224 } 01225 break; 01226 case 0x4A: // keypad 1 01227 if (pressed) {//TODO: Shift state? 01228 add_key(scan_add + '1'); 01229 } 01230 break; 01231 case 0x4B: // keypad 2 01232 if (pressed) {//TODO: Shift state? 01233 add_key(scan_add + '2'); 01234 } 01235 break; 01236 case 0x4C: // keypad 3 01237 if (pressed) {//TODO: Shift state? 01238 add_key(scan_add + '3'); 01239 } 01240 break; 01241 case 0x4D: // keypad = 01242 if (pressed) {//TODO: Shift state? 01243 add_key(scan_add + '='); 01244 } 01245 break; 01246 case 0x4E: // keypad 0 01247 if (pressed) {//TODO: Shift state? 01248 add_key(scan_add + '0'); 01249 } 01250 break; 01251 case 0x4F: // keypad , 01252 if (pressed) {//TODO: Shift state? 01253 add_key(scan_add + ','); 01254 } 01255 break; 01256 case 0x50: // keypad . 01257 if (pressed) {//TODO: Shift state? 01258 add_key(scan_add + '.'); 01259 } 01260 break; 01261 01262 case 0x52: // VF1 vf・1 ??? ??? ??? ??? 01263 case 0x53: // VF2 vf・2 ??? ??? ??? ??? 01264 case 0x54: // VF3 vf・3 ??? ??? ??? ??? 01265 case 0x55: // VF4 vf・4 ??? ??? ??? ??? 01266 case 0x56: // VF5 vf・5 ??? ??? ??? ??? 01267 if (pressed) { 01268 if (modflags & 0x10) /* CTRL */ 01269 add_key(scan_add + 0x8000); /* 0xD2-0xD6 */ 01270 else if (modflags & 1) /* SHIFT */ 01271 add_key(scan_add + 0x7000); /* 0xC2-0xC6 */ 01272 else 01273 add_key(scan_add + 0x0000); /* 0x52-0x56 */ 01274 } 01275 break; 01276 01277 case 0x60: // STOP 01278 // does not pass it on 01279 break; 01280 01281 case 0x62: // F1 f・1 ??? ??? ??? ??? 01282 case 0x63: // F2 f・2 ??? ??? ??? ??? 01283 case 0x64: // F3 f・3 ??? ??? ??? ??? 01284 case 0x65: // F4 f・4 ??? ??? ??? ??? 01285 case 0x66: // F5 f・5 ??? ??? ??? ??? 01286 case 0x67: // F6 f・6 ??? ??? ??? ??? 01287 case 0x68: // F7 f・7 ??? ??? ??? ??? 01288 case 0x69: // F8 f・8 ??? ??? ??? ??? 01289 case 0x6A: // F9 f・9 ??? ??? ??? ??? 01290 case 0x6B: // F10 f・10 ??? ??? ??? ??? 01291 if (pressed) { 01292 if (modflags & 0x10) /* CTRL */ 01293 add_key(scan_add + 0x3000); /* 0x92-0x9B */ 01294 else if (modflags & 1) /* SHIFT */ 01295 add_key(scan_add + 0x2000); /* 0x82-0x8B */ 01296 else 01297 add_key(scan_add + 0x0000); /* 0x62-0x6B */ 01298 } 01299 break; 01300 01301 case 0x70: // left/right shift. do nothing 01302 break; 01303 01304 case 0x71: // caps. do nothing 01305 break; 01306 01307 case 0x72: // kana. do nothing 01308 break; 01309 01310 case 0x73: // graph. do nothing 01311 break; 01312 01313 case 0x74: // left/right ctrl. do nothing 01314 break; 01315 01316 default: 01317 if (pressed) { 01318 add_key(scan_add + 0x00); /* zero low byte */ 01319 } 01320 break; 01321 } 01322 01323 if (--patience == 0) break; /* in case of stuck 8251 */ 01324 status = IO_ReadB(0x43); /* 8251 status */ 01325 } 01326 01327 return CBRET_NONE; 01328 } 01329 01330 static Bitu PCjr_NMI_Keyboard_Handler(void) { 01331 #if 0 01332 Bitu DEBUG_EnableDebugger(void); 01333 DEBUG_EnableDebugger(); 01334 #endif 01335 if (IO_ReadB(0x64) & 1) /* while data is available */ 01336 reg_eip++; /* skip over EIP to IRQ1 call through */ 01337 01338 return CBRET_NONE; 01339 } 01340 01341 static Bitu IRQ1_CtrlBreakAfterInt1B(void) { 01342 BIOS_AddKeyToBuffer(0x0000); 01343 return CBRET_NONE; 01344 } 01345 01346 01347 /* check whether key combination is enhanced or not, 01348 translate key if necessary */ 01349 static bool IsEnhancedKey(Bit16u &key) { 01350 if (IS_PC98_ARCH) 01351 return false; 01352 01353 /* test for special keys (return and slash on numblock) */ 01354 if ((key>>8)==0xe0) { 01355 if (((key&0xff)==0x0a) || ((key&0xff)==0x0d)) { 01356 /* key is return on the numblock */ 01357 key=(key&0xff)|0x1c00; 01358 } else { 01359 /* key is slash on the numblock */ 01360 key=(key&0xff)|0x3500; 01361 } 01362 /* both keys are not considered enhanced keys */ 01363 return false; 01364 } else if (((key>>8)>0x84) || (((key&0xff)==0xf0) && (key>>8))) { 01365 /* key is enhanced key (either scancode part>0x84 or 01366 specially-marked keyboard combination, low part==0xf0) */ 01367 return true; 01368 } 01369 /* convert key if necessary (extended keys) */ 01370 if ((key>>8) && ((key&0xff)==0xe0)) { 01371 key&=0xff00; 01372 } 01373 return false; 01374 } 01375 01376 bool int16_unmask_irq1_on_read = true; 01377 bool int16_ah_01_cf_undoc = true; 01378 01379 Bitu INT16_Handler(void) { 01380 Bit16u temp=0; 01381 switch (reg_ah) { 01382 case 0x00: /* GET KEYSTROKE */ 01383 if (int16_unmask_irq1_on_read) 01384 PIC_SetIRQMask(1,false); /* unmask keyboard */ 01385 01386 if ((get_key(temp)) && (!IsEnhancedKey(temp))) { 01387 /* normal key found, return translated key in ax */ 01388 reg_ax=temp; 01389 } else { 01390 /* enter small idle loop to allow for irqs to happen */ 01391 reg_ip+=1; 01392 } 01393 break; 01394 case 0x10: /* GET KEYSTROKE (enhanced keyboards only) */ 01395 if (int16_unmask_irq1_on_read) 01396 PIC_SetIRQMask(1,false); /* unmask keyboard */ 01397 01398 if (get_key(temp)) { 01399 if (!IS_PC98_ARCH && ((temp&0xff)==0xf0) && (temp>>8)) { 01400 /* special enhanced key, clear low part before returning key */ 01401 temp&=0xff00; 01402 } 01403 reg_ax=temp; 01404 } else { 01405 /* enter small idle loop to allow for irqs to happen */ 01406 reg_ip+=1; 01407 } 01408 break; 01409 case 0x01: /* CHECK FOR KEYSTROKE */ 01410 // enable interrupt-flag after IRET of this int16 01411 CALLBACK_SIF(true); 01412 if (int16_unmask_irq1_on_read) 01413 PIC_SetIRQMask(1,false); /* unmask keyboard */ 01414 01415 for (;;) { 01416 if (check_key(temp)) { 01417 if (!IsEnhancedKey(temp)) { 01418 /* normal key, return translated key in ax */ 01419 CALLBACK_SZF(false); 01420 if (int16_ah_01_cf_undoc) CALLBACK_SCF(true); 01421 reg_ax=temp; 01422 break; 01423 } else { 01424 /* remove enhanced key from buffer and ignore it */ 01425 get_key(temp); 01426 } 01427 } else { 01428 /* no key available */ 01429 CALLBACK_SZF(true); 01430 if (int16_ah_01_cf_undoc) CALLBACK_SCF(false); 01431 break; 01432 } 01433 // CALLBACK_Idle(); 01434 } 01435 break; 01436 case 0x11: /* CHECK FOR KEYSTROKE (enhanced keyboards only) */ 01437 // enable interrupt-flag after IRET of this int16 01438 CALLBACK_SIF(true); 01439 if (int16_unmask_irq1_on_read) 01440 PIC_SetIRQMask(1,false); /* unmask keyboard */ 01441 01442 if (!check_key(temp)) { 01443 CALLBACK_SZF(true); 01444 } else { 01445 CALLBACK_SZF(false); 01446 if (!IS_PC98_ARCH && ((temp&0xff)==0xf0) && (temp>>8)) { 01447 /* special enhanced key, clear low part before returning key */ 01448 temp&=0xff00; 01449 } 01450 reg_ax=temp; 01451 } 01452 break; 01453 case 0x02: /* GET SHIFT FLAGS */ 01454 reg_al=mem_readb(BIOS_KEYBOARD_FLAGS1); 01455 break; 01456 case 0x03: /* SET TYPEMATIC RATE AND DELAY */ 01457 if (reg_al == 0x00) { // set default delay and rate 01458 IO_Write(0x60,0xf3); 01459 IO_Write(0x60,0x20); // 500 msec delay, 30 cps 01460 } else if (reg_al == 0x05) { // set repeat rate and delay 01461 IO_Write(0x60,0xf3); 01462 IO_Write(0x60,(reg_bh&3)<<5|(reg_bl&0x1f)); 01463 } else { 01464 LOG(LOG_BIOS,LOG_ERROR)("INT16:Unhandled Typematic Rate Call %2X BX=%X",reg_al,reg_bx); 01465 } 01466 break; 01467 case 0x05: /* STORE KEYSTROKE IN KEYBOARD BUFFER */ 01468 if (BIOS_AddKeyToBuffer(reg_cx)) reg_al=0; 01469 else reg_al=1; 01470 break; 01471 case 0x12: /* GET EXTENDED SHIFT STATES */ 01472 reg_al = mem_readb(BIOS_KEYBOARD_FLAGS1); 01473 reg_ah = (mem_readb(BIOS_KEYBOARD_FLAGS2)&0x73) | 01474 ((mem_readb(BIOS_KEYBOARD_FLAGS2)&4)<<5) | // SysReq pressed, bit 7 01475 (mem_readb(BIOS_KEYBOARD_FLAGS3)&0x0c); // Right Ctrl/Alt pressed, bits 2,3 01476 break; 01477 case 0x55: 01478 /* Weird call used by some dos apps */ 01479 LOG(LOG_BIOS,LOG_NORMAL)("INT16:55:Word TSR compatible call"); 01480 break; 01481 default: 01482 LOG(LOG_BIOS,LOG_ERROR)("INT16:Unhandled call %02X",reg_ah); 01483 break; 01484 01485 } 01486 01487 return CBRET_NONE; 01488 } 01489 01490 /* The INT16h handler manipulates reg_ip and expects it to work 01491 * based on the layout of the callback. So to allow calling 01492 * directly we have to save/restore CS:IP and run the DOS 01493 * machine. */ 01494 Bitu INT16_Handler_Wrap(void) { 01495 Bitu proc; 01496 01497 proc = CALLBACK_RealPointer(call_int16); 01498 CALLBACK_RunRealFarInt(proc >> 16/*seg*/,proc & 0xFFFFU/*off*/); 01499 return 0; 01500 } 01501 01502 //Keyboard initialisation. src/gui/sdlmain.cpp 01503 extern bool startup_state_numlock; 01504 extern bool startup_state_capslock; 01505 extern bool startup_state_scrlock; 01506 01507 static void InitBiosSegment(void) { 01508 if (IS_PC98_ARCH) { 01509 mem_writew(0x524/*tail*/,0x502); 01510 mem_writew(0x526/*tail*/,0x502); 01511 } 01512 else { /* IBM PC */ 01513 /* Setup the variables for keyboard in the bios data segment */ 01514 mem_writew(BIOS_KEYBOARD_BUFFER_START,0x1e); 01515 mem_writew(BIOS_KEYBOARD_BUFFER_END,0x3e); 01516 mem_writew(BIOS_KEYBOARD_BUFFER_HEAD,0x1e); 01517 mem_writew(BIOS_KEYBOARD_BUFFER_TAIL,0x1e); 01518 Bit8u flag1 = 0; 01519 Bit8u leds = 16; /* Ack received */ 01520 01521 #if 0 /*SDL_VERSION_ATLEAST(1, 2, 14)*/ 01522 //Nothing, mapper handles all. 01523 #else 01524 if (startup_state_capslock) { flag1|=BIOS_KEYBOARD_FLAGS1_CAPS_LOCK_ACTIVE; leds|=BIOS_KEYBOARD_LEDS_CAPS_LOCK;} 01525 if (startup_state_numlock) { flag1|=BIOS_KEYBOARD_FLAGS1_NUMLOCK_ACTIVE; leds|=BIOS_KEYBOARD_LEDS_NUM_LOCK;} 01526 if (startup_state_scrlock) { flag1|=BIOS_KEYBOARD_FLAGS1_SCROLL_LOCK_ACTIVE; leds|=BIOS_KEYBOARD_LEDS_SCROLL_LOCK;} 01527 #endif 01528 01529 mem_writeb(BIOS_KEYBOARD_FLAGS1,flag1); 01530 mem_writeb(BIOS_KEYBOARD_FLAGS2,0); 01531 mem_writeb(BIOS_KEYBOARD_FLAGS3,16); /* Enhanced keyboard installed */ 01532 mem_writeb(BIOS_KEYBOARD_TOKEN,0); 01533 mem_writeb(BIOS_KEYBOARD_LEDS,leds); 01534 } 01535 } 01536 01537 void CALLBACK_DeAllocate(Bitu in); 01538 01539 void BIOS_UnsetupKeyboard(void) { 01540 if (call_int16 != 0) { 01541 CALLBACK_DeAllocate(call_int16); 01542 RealSetVec(0x16,0); 01543 call_int16 = 0; 01544 } 01545 if (call_irq1 != 0) { 01546 CALLBACK_DeAllocate(call_irq1); 01547 call_irq1 = 0; 01548 } 01549 if (call_irq_pcjr_nmi != 0) { 01550 CALLBACK_DeAllocate(call_irq_pcjr_nmi); 01551 call_irq_pcjr_nmi = 0; 01552 } 01553 if (call_irq6 != 0) { 01554 CALLBACK_DeAllocate(call_irq6); 01555 call_irq6 = 0; 01556 } 01557 if (irq1_ret_ctrlbreak_callback != 0) { 01558 CALLBACK_DeAllocate(irq1_ret_ctrlbreak_callback); 01559 irq1_ret_ctrlbreak_callback = 0; 01560 } 01561 } 01562 01563 void BIOS_SetupKeyboard(void) { 01564 /* Init the variables */ 01565 InitBiosSegment(); 01566 01567 if (IS_PC98_ARCH) { 01568 /* HACK */ 01569 /* Allocate/setup a callback for int 0x16 and for standard IRQ 1 handler */ 01570 call_int16=CALLBACK_Allocate(); 01571 CALLBACK_Setup(call_int16,&INT16_Handler,CB_INT16,"Keyboard"); 01572 /* DO NOT set up an INT 16h vector. This exists only for the DOS CONIO emulation. */ 01573 } 01574 else { 01575 /* Allocate/setup a callback for int 0x16 and for standard IRQ 1 handler */ 01576 call_int16=CALLBACK_Allocate(); 01577 CALLBACK_Setup(call_int16,&INT16_Handler,CB_INT16,"Keyboard"); 01578 RealSetVec(0x16,CALLBACK_RealPointer(call_int16)); 01579 } 01580 01581 call_irq1=CALLBACK_Allocate(); 01582 if (machine == MCH_PCJR) { /* PCjr keyboard interrupt connected to NMI */ 01583 call_irq_pcjr_nmi=CALLBACK_Allocate(); 01584 01585 CALLBACK_Setup(call_irq_pcjr_nmi,&PCjr_NMI_Keyboard_Handler,CB_IRET,"PCjr NMI Keyboard"); 01586 01587 Bit32u a = CALLBACK_RealPointer(call_irq_pcjr_nmi); 01588 01589 RealSetVec(0x02/*NMI*/,a); 01590 01591 /* TODO: PCjr calls INT 48h to convert PCjr scan codes to IBM PC/XT compatible */ 01592 01593 a = ((a >> 16) << 4) + (a & 0xFFFF); 01594 /* a+0 = callback instruction (4 bytes) 01595 * a+4 = iret (1 bytes) */ 01596 phys_writeb(a+5,0x50); /* push ax */ 01597 phys_writew(a+6,0x60E4); /* in al,60h */ 01598 phys_writew(a+8,0x09CD); /* int 9h */ 01599 phys_writeb(a+10,0x58); /* pop ax */ 01600 phys_writew(a+11,0x00EB + ((256-13)<<8)); /* jmp a+0 */ 01601 } 01602 01603 if (IS_PC98_ARCH) { 01604 CALLBACK_Setup(call_irq1,&IRQ1_Handler_PC98,CB_IRET_EOI_PIC1,Real2Phys(BIOS_DEFAULT_IRQ1_LOCATION),"IRQ 1 Keyboard PC-98"); 01605 RealSetVec(0x09/*IRQ 1*/,BIOS_DEFAULT_IRQ1_LOCATION); 01606 } 01607 else { 01608 CALLBACK_Setup(call_irq1,&IRQ1_Handler,CB_IRQ1,Real2Phys(BIOS_DEFAULT_IRQ1_LOCATION),"IRQ 1 Keyboard"); 01609 RealSetVec(0x09/*IRQ 1*/,BIOS_DEFAULT_IRQ1_LOCATION); 01610 // pseudocode for CB_IRQ1: 01611 // push ax 01612 // in al, 0x60 01613 // mov ah, 0x4f 01614 // stc 01615 // int 15 01616 // jc skip 01617 // callback IRQ1_Handler 01618 // label skip: 01619 // cli 01620 // mov al, 0x20 01621 // out 0x20, al 01622 // pop ax 01623 // iret 01624 // cli 01625 // mov al, 0x20 01626 // out 0x20, al 01627 // push bp 01628 // int 0x05 01629 // pop bp 01630 // pop ax 01631 // iret 01632 } 01633 01634 irq1_ret_ctrlbreak_callback=CALLBACK_Allocate(); 01635 CALLBACK_Setup(irq1_ret_ctrlbreak_callback,&IRQ1_CtrlBreakAfterInt1B,CB_IRQ1_BREAK,"IRQ 1 Ctrl-Break callback"); 01636 // pseudocode for CB_IRQ1_BREAK: 01637 // int 1b 01638 // cli 01639 // callback IRQ1_CtrlBreakAfterInt1B 01640 // mov al, 0x20 01641 // out 0x20, al 01642 // pop ax 01643 // iret 01644 01645 if (machine==MCH_PCJR) { 01646 call_irq6=CALLBACK_Allocate(); 01647 CALLBACK_Setup(call_irq6,NULL,CB_IRQ6_PCJR,"PCJr kb irq"); 01648 RealSetVec(0x0e,CALLBACK_RealPointer(call_irq6)); 01649 // pseudocode for CB_IRQ6_PCJR: 01650 // push ax 01651 // in al, 0x60 01652 // cmp al, 0xe0 01653 // je skip 01654 // push ds 01655 // push 0x40 01656 // pop ds 01657 // int 0x09 01658 // pop ds 01659 // label skip: 01660 // cli 01661 // mov al, 0x20 01662 // out 0x20, al 01663 // pop ax 01664 // iret 01665 } 01666 } 01667