DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/ints/bios_keyboard.cpp
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