DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/ints/bios_keyboard.cpp
00001 /*
00002  *  Copyright (C) 2002-2019  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
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, 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 &0x02) {  /*extend key. e.g key above arrows or arrows*/
00485             if(scancode == 0x52) flags2 |=0x80; /* press insert */         
00486             if(flags1 &0x08) {
00487                 add_key(scan_to_scanascii[scancode].normal+0x5000);
00488             } else if (flags1 &0x04) {
00489                 add_key((scan_to_scanascii[scancode].control&0xff00)|0xe0);
00490             } else if( ((flags1 &0x3) != 0) || ((flags1 &0x20) != 0) ) { //Due to |0xe0 results are identical. 
00491                 add_key((scan_to_scanascii[scancode].shift&0xff00)|0xe0);
00492             } else add_key((scan_to_scanascii[scancode].normal&0xff00)|0xe0);
00493             break;
00494         }
00495         if(flags1 &0x08) {
00496             Bit8u token = mem_readb(BIOS_KEYBOARD_TOKEN);
00497             token = token*10 + (Bit8u)(scan_to_scanascii[scancode].alt&0xff);
00498             mem_writeb(BIOS_KEYBOARD_TOKEN,token);
00499         } else if (flags1 &0x04) {
00500             add_key(scan_to_scanascii[scancode].control);
00501         } else if( ((flags1 &0x3) != 0) ^ ((flags1 &0x20) != 0) ) { //Xor shift and numlock (both means off)
00502             add_key(scan_to_scanascii[scancode].shift);
00503         } else add_key(scan_to_scanascii[scancode].normal);
00504         break;
00505 
00506     default: /* Normal Key */
00507     normal_key:
00508         Bit16u asciiscan;
00509         /* Now Handle the releasing of keys and see if they match up for a code */
00510         /* Handle the actual scancode */
00511         if (scancode & 0x80) goto irq1_end;
00512         if (scancode > MAX_SCAN_CODE) goto irq1_end;
00513         if (flags1 & 0x08) {                    /* Alt is being pressed */
00514             asciiscan=scan_to_scanascii[scancode].alt;
00515 #if 0 /* old unicode support disabled*/
00516         } else if (ascii) {
00517             asciiscan=(scancode << 8) | ascii;
00518 #endif
00519         } else if (flags1 & 0x04) {                 /* Ctrl is being pressed */
00520             asciiscan=scan_to_scanascii[scancode].control;
00521         } else if (flags1 & 0x03) {                 /* Either shift is being pressed */
00522             asciiscan=scan_to_scanascii[scancode].shift;
00523         } else {
00524             asciiscan=scan_to_scanascii[scancode].normal;
00525         }
00526         /* cancel shift is letter and capslock active */
00527         if(flags1&64) {
00528             if(flags1&3) {
00529                 /*cancel shift */  
00530                 if(((asciiscan&0x00ff) >0x40) && ((asciiscan&0x00ff) <0x5b)) 
00531                     asciiscan=scan_to_scanascii[scancode].normal; 
00532             } else {
00533                 /* add shift */
00534                 if(((asciiscan&0x00ff) >0x60) && ((asciiscan&0x00ff) <0x7b)) 
00535                     asciiscan=scan_to_scanascii[scancode].shift; 
00536             }
00537         }
00538         if (flags3 &0x02) {
00539             /* extended key (numblock), return and slash need special handling */
00540             if (scancode==0x1c) {   /* return */
00541                 if (flags1 &0x08) asciiscan=0xa600;
00542                 else asciiscan=(asciiscan&0xff)|0xe000;
00543             } else if (scancode==0x35) {    /* slash */
00544                 if (flags1 &0x08) asciiscan=0xa400;
00545                 else if (flags1 &0x04) asciiscan=0x9500;
00546                 else asciiscan=0xe02f;
00547             }
00548         }
00549         add_key(asciiscan);
00550         break;
00551     }
00552 irq1_end:
00553     if(scancode !=0xe0) flags3 &=~0x02;                                 //Reset 0xE0 Flag
00554     mem_writeb(BIOS_KEYBOARD_FLAGS1,flags1);
00555     if ((scancode&0x80)==0) flags2&=0xf7;
00556     mem_writeb(BIOS_KEYBOARD_FLAGS2,flags2);
00557     mem_writeb(BIOS_KEYBOARD_FLAGS3,flags3);
00558     mem_writeb(BIOS_KEYBOARD_LEDS,leds);
00559 
00560     /* update LEDs on keyboard */
00561     if (leds_orig != leds) KEYBOARD_SetLEDs(leds);
00562 
00563     /* update insert cursor */
00564     extern bool dos_program_running;
00565     if (!dos_program_running)
00566     {
00567         const auto flg = mem_readb(BIOS_KEYBOARD_FLAGS1);
00568         const auto ins = static_cast<bool>(flg & BIOS_KEYBOARD_FLAGS1_INSERT_ACTIVE);
00569         const auto ssl = static_cast<Bit8u>(ins ? CURSOR_SCAN_LINE_INSERT : CURSOR_SCAN_LINE_NORMAL);
00570         if (CurMode->type == M_TEXT)
00571             INT10_SetCursorShape(ssl, CURSOR_SCAN_LINE_END);
00572     }
00573                                         
00574 /*  IO_Write(0x20,0x20); moved out of handler to be virtualizable */
00575 #if 0
00576 /* Signal the keyboard for next code */
00577 /* In dosbox port 60 reads do this as well */
00578     Bit8u old61=IO_Read(0x61);
00579     IO_Write(0x61,old61 | 128);
00580     IO_Write(0x64,0xae);
00581 #endif
00582     return CBRET_NONE;
00583 }
00584 
00585 unsigned char AT_read_60(void);
00586 extern bool pc98_force_ibm_layout;
00587 
00588 /* BIOS INT 18h output vs keys:
00589  *
00590  *              Unshifted   Shifted     CTRL    Caps    Kana    Kana+Shift
00591  *              -----------------------------------------------------------
00592  * ESC          0x001B      0x001B      0x001B  0x001B  0x001B  0x001B
00593  * STOP         --          --          --      --      --      --
00594  * F1..F10      <--------------- scan code in upper, zero in lower ------->
00595  * INS/DEL      <--------------- scan code in upper, zero in lower ------->
00596  * ROLL UP/DOWN <--------------- scan code in upper, zero in lower ------->
00597  * COPY         --          --          --      --      --      --
00598  * HOME CLR     0x3E00      0xAE00      --      --      --      --
00599  * HELP         <--------------- scan code in upper, zero in lower ------->
00600  * ARROW KEYS   <--------------- scan code in upper, zero in lower ------->
00601  * XFER         0x3500      0xA500      0xB500  0x3500  0x3500  0xA500
00602  * NFER         0x5100      0xA100      0xB100  0x5100  0x5100  0xA100
00603  * GRPH         --          --          --      --      --      --
00604  * TAB          0x0F09      0x0F09      0x0F09  0x0F09  0x0F09  0x0F09
00605  * - / 口       --          0x335F      0x331F  --      0x33DB  0x33DB      Kana+CTRL = 0x331F
00606  */
00607 static Bitu IRQ1_Handler_PC98(void) {
00608     unsigned char sc_8251,status;
00609     unsigned int patience = 32;
00610     Bit16u scan_add;
00611     bool pressed;
00612 
00613     status = IO_ReadB(0x43); /* 8251 status */
00614     while (status & 2/*RxRDY*/) {
00615         sc_8251 = IO_ReadB(0x41); /* 8251 data */
00616 
00617         pressed = !(sc_8251 & 0x80);
00618         sc_8251 &= 0x7F;
00619 
00620         /* Testing on real hardware shows INT 18h AH=0 returns raw scancode in upper half, ASCII in lower half.
00621          * Just like INT 16h on IBM PC hardware */
00622         scan_add = sc_8251 << 8U;
00623 
00624         /* NOTES:
00625          *  - The bitmap also tracks CAPS, and KANA state. It does NOT track NUM state.
00626          *    The bit corresponding to the key code will show a bit set if in that state.
00627          *  - The STS byte returned by INT 18h AH=02h seems to match the 14th byte of the bitmap... so far.
00628          *
00629          *  STS layout (based on real hardware):
00630          *
00631          *    bit[7] = ?
00632          *    bit[6] = ?
00633          *    bit[5] = ?
00634          *    bit[4] = CTRL is down
00635          *    bit[3] = GRPH is down
00636          *    bit[2] = KANA engaged
00637          *    bit[1] = CAPS engaged
00638          *    bit[0] = SHIFT is down
00639          */
00640         Bit8u modflags = mem_readb(0x52A + 0xE);
00641 
00642         bool caps_capitals = (modflags & 1) ^ ((modflags >> 1) & 1); /* CAPS XOR SHIFT */
00643 
00644         /* According to Neko Project II, the BIOS maintains a "pressed key" bitmap at 0x50:0x2A.
00645          * Without this bitmap many PC-98 games are unplayable. */
00646         /* ALSO note that byte 0xE of this array is the "shift" state byte. */
00647         {
00648             unsigned int o = 0x52Au + ((unsigned int)sc_8251 >> 3u);
00649             unsigned char c = mem_readb(o);
00650             unsigned char b = 1u << (sc_8251 & 7u);
00651 
00652             if (pressed)
00653                 c |= b;
00654             else
00655                 c &= ~b;
00656 
00657             mem_writeb(o,c);
00658 
00659             /* mirror CTRL+GRAPH+KANA+CAPS+SHIFT at 0x53A which is returned by INT 18h AH=2 */
00660             if (o == 0x538) mem_writeb(0x53A,c);
00661         }
00662 
00663         /* NOTES:
00664          *  - SHIFT/CTRL scan code changes (no scan code emitted if GRPH is held down for these keys)
00665          *
00666          *    CTRL apparently takes precedence over SHIFT.
00667          *
00668          *      Key       Unshifted      Shifted        CTRL
00669          *      --------------------------------------------
00670          *      F1        0x62           0x82           0x92
00671          *      F2        0x63           0x83           0x93
00672          *      F3        0x64           0x84           0x94
00673          *      F4        0x65           0x85           0x95
00674          *      F5        0x66           0x86           0x96
00675          *      F6        0x67           0x87           0x97
00676          *      F7        0x68           0x88           0x98
00677          *      F8        0x69           0x89           0x99
00678          *      F9        0x6A           0x8A           0x9A
00679          *      F10       0x6B           0x8B           0x9B
00680          *      HOME/CLR  0x3E           0xAE           <none>
00681          *      XFER      0x35           0xA5           0xB5
00682          *      NFER      0x51           0xA1           0xB1
00683          *      VF1       0x52           0xC2           0xD2
00684          *      VF2       0x53           0xC3           0xD3
00685          *      VF3       0x54           0xC4           0xD4
00686          *      VF4       0x55           0xC5           0xD5
00687          *      VF5       0x56           0xC6           0xD6
00688          */
00689 
00690         /* FIXME: I'm fully aware of obvious problems with this code so far:
00691          *        - This is coded around my American keyboard layout
00692          *        - No support for CAPS or KANA modes.
00693          *
00694          *        As this code develops refinements will occur.
00695          *
00696          *        - Scan codes will be mapped to unshifted/shifted/kana modes
00697          *          as laid out on Japanese keyboards.
00698          *        - This will use a lookup table with special cases such as
00699          *          modifier keys. */
00700         //                  Keyboard layout and processing, copied from an actual PC-98 keyboard
00701         //
00702         //                  KEY         UNSHIFT SHIFT   CTRL    KANA
00703         //                  ----------------------------------------
00704         switch (sc_8251) {
00705             case 0x00: //   ESC         ESC     ???     ???     ???
00706                 if (pressed) {
00707                     add_key(scan_add + 27);
00708                 }
00709                 break;
00710             case 0x01: //   1           1       !       ???     ヌ
00711                 if (pressed) {
00712                     if (modflags & 1) /* either shift */
00713                         add_key(scan_add + '!');
00714                     else
00715                         add_key(scan_add + '1');
00716                 }
00717                 break;
00718             case 0x02:  //  2           2       "       ???     フ
00719                 if (pressed) {
00720                     if (modflags & 1) { /* shift */
00721                         if(!pc98_force_ibm_layout)
00722                             add_key(scan_add + '\"');
00723                         else
00724                             add_key(scan_add + '@');
00725                     }
00726                     else {
00727                         add_key(scan_add + '2');
00728                     }
00729                 }
00730                 break;
00731             case 0x03:  //  3           3       #       ???     ア
00732                 if (pressed) {
00733                     if (modflags & 1) /* shift */
00734                         add_key(scan_add + '#');
00735                     else
00736                         add_key(scan_add + '3');
00737                 }
00738                 break;
00739             case 0x04:  //  4           4       $       ???     ウ
00740                 if (pressed) {
00741                     if (modflags & 1) /* shift */
00742                         add_key(scan_add + '$');
00743                     else
00744                         add_key(scan_add + '4');
00745                 }
00746                 break;
00747             case 0x05:  //  5           5       %       ???     エ
00748                 if (pressed) {
00749                     if (modflags & 1) /* shift */
00750                         add_key(scan_add + '%');
00751                     else
00752                         add_key(scan_add + '5');
00753                 }
00754                 break;
00755             case 0x06:  //  6           6       &       ???     オ
00756                 if (pressed) {
00757                     if (modflags & 1) { /* shift */
00758                         if(!pc98_force_ibm_layout)
00759                             add_key(scan_add + '&');
00760                         else
00761                             add_key(scan_add + '^');
00762                     }
00763                     else {
00764                         add_key(scan_add + '6');
00765                     }
00766                 }
00767                 break;
00768             case 0x07:  //  7           7       '       ???     ヤ
00769                 if (pressed) {
00770                     if (modflags & 1) { /* shift */
00771                         if(!pc98_force_ibm_layout)
00772                             add_key(scan_add + '\'');
00773                         else
00774                             add_key(scan_add + '&');
00775                     }
00776                     else {
00777                         add_key(scan_add + '7');
00778                     }
00779                 }
00780                 break;
00781             case 0x08:  //  8           8       (       ???     ユ
00782                 if (pressed) {
00783                     if (modflags & 1) { /* shift */
00784                         if(!pc98_force_ibm_layout)
00785                             add_key(scan_add + '(');
00786                         else
00787                             add_key(scan_add + '*');
00788                     }
00789                     else {
00790                         add_key(scan_add + '8');
00791                     }
00792                 }
00793                 break;
00794             case 0x09:  //  9           9       )       ???     ヨ
00795                 if (pressed) {
00796                     if (modflags & 1) { /* shift */
00797                         if(!pc98_force_ibm_layout)
00798                             add_key(scan_add + ')');
00799                         else
00800                             add_key(scan_add + '(');
00801                     }
00802                     else {
00803                         add_key(scan_add + '9');
00804                     }
00805                 }
00806                 break;
00807             case 0x0A:  //  0           0       ---     ???     ワ
00808                 if (pressed) {
00809                     if (modflags & 1) { /* shift */
00810                         if(!pc98_force_ibm_layout)
00811                             { /* nothing */ }
00812                         else
00813                             add_key(scan_add + ')');
00814                     }
00815                     else {
00816                         add_key(scan_add + '0');
00817                     }
00818                 }
00819                 break;
00820             case 0x0B:  //  -           -       =       ???     ホ
00821                 if (pressed) {
00822                     if (modflags & 1) { /* shift */
00823                         if(!pc98_force_ibm_layout)
00824                             add_key(scan_add + '=');
00825                         else
00826                             add_key(scan_add + '_');
00827                     }
00828                     else {
00829                         add_key(scan_add + '-');
00830                     }
00831                 }
00832                 break;
00833             case 0x0C:  //  ^           ^       `       ???     ヘ
00834                 if (pressed) {
00835                     if(!pc98_force_ibm_layout) {
00836                         if (modflags & 1) /* shift */
00837                             add_key(scan_add + '`');
00838                         else
00839                             add_key(scan_add + '^');
00840                     } else {
00841                         if (modflags & 1) /* shift */
00842                             add_key(scan_add + '+');
00843                         else
00844                             add_key(scan_add + '=');                    
00845                     }
00846                 }
00847                 break;
00848             case 0x0D:  //  ¥           ¥       |       ???     ???
00849                 if (pressed) {
00850                     if (modflags & 1) /* shift */
00851                         add_key(scan_add + '|');
00852                     else
00853                         add_key(scan_add + '\\'); /* In Shift-JIS, backslash becomes the Yen symbol */
00854                 }
00855                 break;
00856             case 0x0E: // backspace
00857                 if (pressed) {
00858                     add_key(scan_add + 8);
00859                 }
00860                 break;
00861             case 0x0F: // tab
00862                 if (pressed) {
00863                     add_key(scan_add + 9);
00864                 }
00865                 break;
00866             case 0x10: // q
00867                 if (pressed) {
00868                     if (caps_capitals) /* shift */
00869                         add_key(scan_add + 'Q');
00870                     else
00871                         add_key(scan_add + 'q');
00872                 }
00873                 break;
00874             case 0x11: // w
00875                 if (pressed) {
00876                     if (caps_capitals) /* shift */
00877                         add_key(scan_add + 'W');
00878                     else
00879                         add_key(scan_add + 'w');
00880                 }
00881                 break;
00882             case 0x12: // e
00883                 if (pressed) {
00884                     if (caps_capitals) /* shift */
00885                         add_key(scan_add + 'E');
00886                     else
00887                         add_key(scan_add + 'e');
00888                 }
00889                 break;
00890             case 0x13: // r
00891                 if (pressed) {
00892                     if (caps_capitals) /* shift */
00893                         add_key(scan_add + 'R');
00894                     else
00895                         add_key(scan_add + 'r');
00896                 }
00897                 break;
00898             case 0x14: // t
00899                 if (pressed) {
00900                     if (caps_capitals) /* shift */
00901                         add_key(scan_add + 'T');
00902                     else
00903                         add_key(scan_add + 't');
00904                 }
00905                 break;
00906             case 0x15: // y
00907                 if (pressed) {
00908                     if (caps_capitals) /* shift */
00909                         add_key(scan_add + 'Y');
00910                     else
00911                         add_key(scan_add + 'y');
00912                 }
00913                 break;
00914             case 0x16: // u
00915                 if (pressed) {
00916                     if (caps_capitals) /* shift */
00917                         add_key(scan_add + 'U');
00918                     else
00919                         add_key(scan_add + 'u');
00920                 }
00921                 break;
00922             case 0x17: // i
00923                 if (pressed) {
00924                     if (caps_capitals) /* shift */
00925                         add_key(scan_add + 'I');
00926                     else
00927                         add_key(scan_add + 'i');
00928                 }
00929                 break;
00930             case 0x18: // o
00931                 if (pressed) {
00932                     if (caps_capitals) /* shift */
00933                         add_key(scan_add + 'O');
00934                     else
00935                         add_key(scan_add + 'o');
00936                 }
00937                 break;
00938             case 0x19: // p
00939                 if (pressed) {
00940                     if (caps_capitals) /* shift */
00941                         add_key(scan_add + 'P');
00942                     else
00943                         add_key(scan_add + 'p');
00944                 }
00945                 break;
00946             case 0x1A: // @             @       ~       --      ゙
00947                 if (pressed) {
00948                     if (modflags & 1) { /* shift */
00949                         add_key(scan_add + '~');
00950                     }
00951                     else {
00952                         if(!pc98_force_ibm_layout)
00953                             add_key(scan_add + '@');
00954                         else
00955                             add_key(scan_add + '`');
00956                     }
00957                 }
00958                 break;
00959             case 0x1B: // [             [       {       --      ゚       「
00960                 if (pressed) {
00961                     if (modflags & 1) /* shift */
00962                         add_key(scan_add + '{');
00963                     else
00964                         add_key(scan_add + '[');
00965                 }
00966                 break;
00967             case 0x1C: // Enter
00968                 if (pressed) {
00969                     add_key(scan_add + 13);
00970                 }
00971                 break;
00972             case 0x1D: // A
00973                 if (pressed) {
00974                     if (caps_capitals) /* shift */
00975                         add_key(scan_add + 'A');
00976                     else
00977                         add_key(scan_add + 'a');
00978                 }
00979                 break;
00980             case 0x1E: // S
00981                 if (pressed) {
00982                     if (caps_capitals) /* shift */
00983                         add_key(scan_add + 'S');
00984                     else
00985                         add_key(scan_add + 's');
00986                 }
00987                 break;
00988             case 0x1F: // D
00989                 if (pressed) {
00990                     if (caps_capitals) /* shift */
00991                         add_key(scan_add + 'D');
00992                     else
00993                         add_key(scan_add + 'd');
00994                 }
00995                 break;
00996             case 0x20: // F
00997                 if (pressed) {
00998                     if (caps_capitals) /* shift */
00999                         add_key(scan_add + 'F');
01000                     else
01001                         add_key(scan_add + 'f');
01002                 }
01003                 break;
01004             case 0x21: // G
01005                 if (pressed) {
01006                     if (caps_capitals) /* shift */
01007                         add_key(scan_add + 'G');
01008                     else
01009                         add_key(scan_add + 'g');
01010                 }
01011                 break;
01012             case 0x22: // H
01013                 if (pressed) {
01014                     if (caps_capitals) /* shift */
01015                         add_key(scan_add + 'H');
01016                     else
01017                         add_key(scan_add + 'h');
01018                 }
01019                 break;
01020             case 0x23: // J
01021                 if (pressed) {
01022                     if (caps_capitals) /* shift */
01023                         add_key(scan_add + 'J');
01024                     else
01025                         add_key(scan_add + 'j');
01026                 }
01027                 break;
01028             case 0x24: // K
01029                 if (pressed) {
01030                     if (caps_capitals) /* shift */
01031                         add_key(scan_add + 'K');
01032                     else
01033                         add_key(scan_add + 'k');
01034                 }
01035                 break;
01036             case 0x25: // L
01037                 if (pressed) {
01038                     if (caps_capitals) /* shift */
01039                         add_key(scan_add + 'L');
01040                     else
01041                         add_key(scan_add + 'l');
01042                 }
01043                 break;
01044             case 0x26: //   ;           ;       +       ---     レ
01045                 if (pressed) {
01046                     if (modflags & 1) { /* shift */
01047                         if(!pc98_force_ibm_layout)
01048                             add_key(scan_add + '+');
01049                         else
01050                             add_key(scan_add + ':');
01051                     }
01052                     else {
01053                         add_key(scan_add + ';');
01054                     }
01055                 }
01056                 break;
01057             case 0x27: //   :           :       *       ---     ケ
01058                 if (pressed) {
01059                     if(!pc98_force_ibm_layout) {
01060                         if (modflags & 1) /* shift */
01061                             add_key(scan_add + '*');
01062                         else
01063                             add_key(scan_add + ':');
01064                     } else {
01065                         if (modflags & 1) /* shift */
01066                             add_key(scan_add + '\"');
01067                         else
01068                             add_key(scan_add + '\'');
01069                     }
01070                 }
01071                 break;
01072             case 0x28: //   ]           ]       }       ---     ム      」
01073                 if (pressed) {
01074                     if (modflags & 1) /* shift */
01075                         add_key(scan_add + '}');
01076                     else
01077                         add_key(scan_add + ']');
01078                 }
01079                 break;
01080             case 0x29: // Z
01081                 if (pressed) {
01082                     if (caps_capitals) /* shift */
01083                         add_key(scan_add + 'Z');
01084                     else
01085                         add_key(scan_add + 'z');
01086                 }
01087                 break;
01088             case 0x2A: // X
01089                 if (pressed) {
01090                     if (caps_capitals) /* shift */
01091                         add_key(scan_add + 'X');
01092                     else
01093                         add_key(scan_add + 'x');
01094                 }
01095                 break;
01096             case 0x2B: // C
01097                 if (pressed) {
01098                     if (caps_capitals) /* shift */
01099                         add_key(scan_add + 'C');
01100                     else
01101                         add_key(scan_add + 'c');
01102                 }
01103                 break;
01104             case 0x2C: // V
01105                 if (pressed) {
01106                     if (caps_capitals) /* shift */
01107                         add_key(scan_add + 'V');
01108                     else
01109                         add_key(scan_add + 'v');
01110                 }
01111                 break;
01112             case 0x2D: // B
01113                 if (pressed) {
01114                     if (caps_capitals) /* shift */
01115                         add_key(scan_add + 'B');
01116                     else
01117                         add_key(scan_add + 'b');
01118                 }
01119                 break;
01120             case 0x2E: // N
01121                 if (pressed) {
01122                     if (caps_capitals) /* shift */
01123                         add_key(scan_add + 'N');
01124                     else
01125                         add_key(scan_add + 'n');
01126                 }
01127                 break;
01128             case 0x2F: // M
01129                 if (pressed) {
01130                     if (caps_capitals) /* shift */
01131                         add_key(scan_add + 'M');
01132                     else
01133                         add_key(scan_add + 'm');
01134                 }
01135                 break;
01136             case 0x30: //   ,           ,       <       ---     ネ      、
01137                 if (pressed) {
01138                     if (modflags & 1) /* shift */
01139                         add_key(scan_add + '<');
01140                     else
01141                         add_key(scan_add + ',');
01142                 }
01143                 break;
01144             case 0x31: //   .           .       >       ---     ル      。
01145                 if (pressed) {
01146                     if (modflags & 1) /* shift */
01147                         add_key(scan_add + '>');
01148                     else
01149                         add_key(scan_add + '.');
01150                 }
01151                 break;
01152             case 0x32: //   /           /       ?       ---     メ      ・
01153                 if (pressed) {
01154                     if (modflags & 1) /* shift */
01155                         add_key(scan_add + '?');
01156                     else
01157                         add_key(scan_add + '/');
01158                 }
01159                 break;
01160             case 0x33: //  _ / Ro
01161                 if (pressed) {
01162                     if (modflags & 1) /* shift */
01163                         add_key(scan_add + '_');
01164                     else
01165                         { /*nothing*/ }
01166                 }
01167                 break;
01168             case 0x34: // <space>
01169                 if (pressed) {
01170                     add_key(scan_add + ' ');
01171                 }
01172                 break;
01173 
01174             case 0x40: // keypad minus
01175                 if (pressed) {//TODO: Shift state?
01176                     add_key(scan_add + '-');
01177                 }
01178                 break;
01179             case 0x41: // keypad divide
01180                 if (pressed) {//TODO: Shift state?
01181                     add_key(scan_add + '/');
01182                 }
01183                 break;
01184             case 0x42: // keypad 7
01185                 if (pressed) {//TODO: Shift state?
01186                     add_key(scan_add + '7');
01187                 }
01188                 break;
01189             case 0x43: // keypad 8
01190                 if (pressed) {//TODO: Shift state?
01191                     add_key(scan_add + '8');
01192                 }
01193                 break;
01194             case 0x44: // keypad 9
01195                 if (pressed) {//TODO: Shift state?
01196                     add_key(scan_add + '9');
01197                 }
01198                 break;
01199             case 0x45: // keypad multiply
01200                 if (pressed) {//TODO: Shift state?
01201                     add_key(scan_add + '*');
01202                 }
01203                 break;
01204             case 0x46: // keypad 4
01205                 if (pressed) {//TODO: Shift state?
01206                     add_key(scan_add + '4');
01207                 }
01208                 break;
01209             case 0x47: // keypad 5
01210                 if (pressed) {//TODO: Shift state?
01211                     add_key(scan_add + '5');
01212                 }
01213                 break;
01214             case 0x48: // keypad 6
01215                 if (pressed) {//TODO: Shift state?
01216                     add_key(scan_add + '6');
01217                 }
01218                 break;
01219             case 0x49: // keypad +
01220                 if (pressed) {//TODO: Shift state?
01221                     add_key(scan_add + '+');
01222                 }
01223                 break;
01224             case 0x4A: // keypad 1
01225                 if (pressed) {//TODO: Shift state?
01226                     add_key(scan_add + '1');
01227                 }
01228                 break;
01229             case 0x4B: // keypad 2
01230                 if (pressed) {//TODO: Shift state?
01231                     add_key(scan_add + '2');
01232                 }
01233                 break;
01234             case 0x4C: // keypad 3
01235                 if (pressed) {//TODO: Shift state?
01236                     add_key(scan_add + '3');
01237                 }
01238                 break;
01239             case 0x4D: // keypad =
01240                 if (pressed) {//TODO: Shift state?
01241                     add_key(scan_add + '=');
01242                 }
01243                 break;
01244             case 0x4E: // keypad 0
01245                 if (pressed) {//TODO: Shift state?
01246                     add_key(scan_add + '0');
01247                 }
01248                 break;
01249             case 0x4F: // keypad ,
01250                 if (pressed) {//TODO: Shift state?
01251                     add_key(scan_add + ',');
01252                 }
01253                 break;
01254             case 0x50: // keypad .
01255                 if (pressed) {//TODO: Shift state?
01256                     add_key(scan_add + '.');
01257                 }
01258                 break;
01259 
01260             case 0x52: // VF1           vf・1    ???     ???     ???     ???
01261             case 0x53: // VF2           vf・2    ???     ???     ???     ???
01262             case 0x54: // VF3           vf・3    ???     ???     ???     ???
01263             case 0x55: // VF4           vf・4    ???     ???     ???     ???
01264             case 0x56: // VF5           vf・5    ???     ???     ???     ???
01265                 if (pressed) {
01266                     if (modflags & 0x10) /* CTRL */
01267                         add_key(scan_add + 0x8000); /* 0xD2-0xD6 */
01268                     else if (modflags & 1) /* SHIFT */
01269                         add_key(scan_add + 0x7000); /* 0xC2-0xC6 */
01270                     else
01271                         add_key(scan_add + 0x0000); /* 0x52-0x56 */
01272                 }
01273                 break;
01274 
01275             case 0x60: // STOP
01276                 // does not pass it on
01277                 break;
01278 
01279             case 0x62: // F1            f・1     ???     ???     ???     ???
01280             case 0x63: // F2            f・2     ???     ???     ???     ???
01281             case 0x64: // F3            f・3     ???     ???     ???     ???
01282             case 0x65: // F4            f・4     ???     ???     ???     ???
01283             case 0x66: // F5            f・5     ???     ???     ???     ???
01284             case 0x67: // F6            f・6     ???     ???     ???     ???
01285             case 0x68: // F7            f・7     ???     ???     ???     ???
01286             case 0x69: // F8            f・8     ???     ???     ???     ???
01287             case 0x6A: // F9            f・9     ???     ???     ???     ???
01288             case 0x6B: // F10           f・10    ???     ???     ???     ???
01289                 if (pressed) {
01290                     if (modflags & 0x10) /* CTRL */
01291                         add_key(scan_add + 0x3000); /* 0x92-0x9B */
01292                     else if (modflags & 1) /* SHIFT */
01293                         add_key(scan_add + 0x2000); /* 0x82-0x8B */
01294                     else
01295                         add_key(scan_add + 0x0000); /* 0x62-0x6B */
01296                 }
01297                 break;
01298 
01299             case 0x70: // left/right shift. do nothing
01300                 break;
01301 
01302             case 0x71: // caps. do nothing
01303                 break;
01304 
01305             case 0x72: // kana. do nothing
01306                 break;
01307 
01308             case 0x73: // graph. do nothing
01309                 break;
01310 
01311             case 0x74: // left/right ctrl. do nothing
01312                 break;
01313 
01314             default:
01315                 if (pressed) {
01316                     add_key(scan_add + 0x00); /* zero low byte */
01317                 }
01318                 break;
01319         }
01320 
01321         if (--patience == 0) break; /* in case of stuck 8251 */
01322         status = IO_ReadB(0x43); /* 8251 status */
01323     }
01324 
01325     return CBRET_NONE;
01326 }
01327 
01328 static Bitu PCjr_NMI_Keyboard_Handler(void) {
01329 #if 0
01330     Bitu DEBUG_EnableDebugger(void);
01331     DEBUG_EnableDebugger();
01332 #endif
01333     if (IO_ReadB(0x64) & 1) /* while data is available */
01334         reg_eip++; /* skip over EIP to IRQ1 call through */
01335 
01336     return CBRET_NONE;
01337 }
01338 
01339 static Bitu IRQ1_CtrlBreakAfterInt1B(void) {
01340     BIOS_AddKeyToBuffer(0x0000);
01341     return CBRET_NONE;
01342 }
01343 
01344 
01345 /* check whether key combination is enhanced or not,
01346    translate key if necessary */
01347 static bool IsEnhancedKey(Bit16u &key) {
01348     if (IS_PC98_ARCH)
01349         return false;
01350 
01351     /* test for special keys (return and slash on numblock) */
01352     if ((key>>8)==0xe0) {
01353         if (((key&0xff)==0x0a) || ((key&0xff)==0x0d)) {
01354             /* key is return on the numblock */
01355             key=(key&0xff)|0x1c00;
01356         } else {
01357             /* key is slash on the numblock */
01358             key=(key&0xff)|0x3500;
01359         }
01360         /* both keys are not considered enhanced keys */
01361         return false;
01362     } else if (((key>>8)>0x84) || (((key&0xff)==0xf0) && (key>>8))) {
01363         /* key is enhanced key (either scancode part>0x84 or
01364            specially-marked keyboard combination, low part==0xf0) */
01365         return true;
01366     }
01367     /* convert key if necessary (extended keys) */
01368     if ((key>>8) && ((key&0xff)==0xe0))  {
01369         key&=0xff00;
01370     }
01371     return false;
01372 }
01373 
01374 bool int16_unmask_irq1_on_read = true;
01375 bool int16_ah_01_cf_undoc = true;
01376 
01377 Bitu INT16_Handler(void) {
01378     Bit16u temp=0;
01379     switch (reg_ah) {
01380     case 0x00: /* GET KEYSTROKE */
01381         if (int16_unmask_irq1_on_read)
01382             PIC_SetIRQMask(1,false); /* unmask keyboard */
01383 
01384         if ((get_key(temp)) && (!IsEnhancedKey(temp))) {
01385             /* normal key found, return translated key in ax */
01386             reg_ax=temp;
01387         } else {
01388             /* enter small idle loop to allow for irqs to happen */
01389             reg_ip+=1;
01390         }
01391         break;
01392     case 0x10: /* GET KEYSTROKE (enhanced keyboards only) */
01393         if (int16_unmask_irq1_on_read)
01394             PIC_SetIRQMask(1,false); /* unmask keyboard */
01395 
01396         if (get_key(temp)) {
01397             if (!IS_PC98_ARCH && ((temp&0xff)==0xf0) && (temp>>8)) {
01398                 /* special enhanced key, clear low part before returning key */
01399                 temp&=0xff00;
01400             }
01401             reg_ax=temp;
01402         } else {
01403             /* enter small idle loop to allow for irqs to happen */
01404             reg_ip+=1;
01405         }
01406         break;
01407     case 0x01: /* CHECK FOR KEYSTROKE */
01408         // enable interrupt-flag after IRET of this int16
01409         CALLBACK_SIF(true);
01410         if (int16_unmask_irq1_on_read)
01411             PIC_SetIRQMask(1,false); /* unmask keyboard */
01412 
01413         for (;;) {
01414             if (check_key(temp)) {
01415                 if (!IsEnhancedKey(temp)) {
01416                     /* normal key, return translated key in ax */
01417                     CALLBACK_SZF(false);
01418                     if (int16_ah_01_cf_undoc) CALLBACK_SCF(true);
01419                     reg_ax=temp;
01420                     break;
01421                 } else {
01422                     /* remove enhanced key from buffer and ignore it */
01423                     get_key(temp);
01424                 }
01425             } else {
01426                 /* no key available */
01427                 CALLBACK_SZF(true);
01428                 if (int16_ah_01_cf_undoc) CALLBACK_SCF(false);
01429                 break;
01430             }
01431 //          CALLBACK_Idle();
01432         }
01433         break;
01434     case 0x11: /* CHECK FOR KEYSTROKE (enhanced keyboards only) */
01435         // enable interrupt-flag after IRET of this int16
01436         CALLBACK_SIF(true);
01437         if (int16_unmask_irq1_on_read)
01438             PIC_SetIRQMask(1,false); /* unmask keyboard */
01439 
01440         if (!check_key(temp)) {
01441             CALLBACK_SZF(true);
01442         } else {
01443             CALLBACK_SZF(false);
01444             if (!IS_PC98_ARCH && ((temp&0xff)==0xf0) && (temp>>8)) {
01445                 /* special enhanced key, clear low part before returning key */
01446                 temp&=0xff00;
01447             }
01448             reg_ax=temp;
01449         }
01450         break;
01451     case 0x02:  /* GET SHIFT FLAGS */
01452         reg_al=mem_readb(BIOS_KEYBOARD_FLAGS1);
01453         break;
01454     case 0x03:  /* SET TYPEMATIC RATE AND DELAY */
01455         if (reg_al == 0x00) { // set default delay and rate
01456             IO_Write(0x60,0xf3);
01457             IO_Write(0x60,0x20); // 500 msec delay, 30 cps
01458         } else if (reg_al == 0x05) { // set repeat rate and delay
01459             IO_Write(0x60,0xf3);
01460             IO_Write(0x60,(reg_bh&3)<<5|(reg_bl&0x1f));
01461         } else {
01462             LOG(LOG_BIOS,LOG_ERROR)("INT16:Unhandled Typematic Rate Call %2X BX=%X",reg_al,reg_bx);
01463         }
01464         break;
01465     case 0x05:  /* STORE KEYSTROKE IN KEYBOARD BUFFER */
01466         if (BIOS_AddKeyToBuffer(reg_cx)) reg_al=0;
01467         else reg_al=1;
01468         break;
01469     case 0x12: /* GET EXTENDED SHIFT STATES */
01470         reg_al = mem_readb(BIOS_KEYBOARD_FLAGS1);
01471         reg_ah = (mem_readb(BIOS_KEYBOARD_FLAGS2)&0x73)   |
01472                  ((mem_readb(BIOS_KEYBOARD_FLAGS2)&4)<<5) | // SysReq pressed, bit 7
01473                  (mem_readb(BIOS_KEYBOARD_FLAGS3)&0x0c);    // Right Ctrl/Alt pressed, bits 2,3
01474         break;
01475     case 0x55:
01476         /* Weird call used by some dos apps */
01477         LOG(LOG_BIOS,LOG_NORMAL)("INT16:55:Word TSR compatible call");
01478         break;
01479     default:
01480         LOG(LOG_BIOS,LOG_ERROR)("INT16:Unhandled call %02X",reg_ah);
01481         break;
01482 
01483     }
01484 
01485     return CBRET_NONE;
01486 }
01487 
01488 /* The INT16h handler manipulates reg_ip and expects it to work
01489  * based on the layout of the callback. So to allow calling
01490  * directly we have to save/restore CS:IP and run the DOS
01491  * machine. */
01492 Bitu INT16_Handler_Wrap(void) {
01493     Bitu proc;
01494 
01495     proc = CALLBACK_RealPointer(call_int16);
01496     CALLBACK_RunRealFarInt(proc >> 16/*seg*/,proc & 0xFFFFU/*off*/);
01497     return 0;
01498 }
01499 
01500 //Keyboard initialisation. src/gui/sdlmain.cpp
01501 extern bool startup_state_numlock;
01502 extern bool startup_state_capslock;
01503 extern bool startup_state_scrlock;
01504 
01505 static void InitBiosSegment(void) {
01506     if (IS_PC98_ARCH) {
01507         mem_writew(0x524/*tail*/,0x502);
01508         mem_writew(0x526/*tail*/,0x502);
01509     }
01510     else { /* IBM PC */
01511         /* Setup the variables for keyboard in the bios data segment */
01512         mem_writew(BIOS_KEYBOARD_BUFFER_START,0x1e);
01513         mem_writew(BIOS_KEYBOARD_BUFFER_END,0x3e);
01514         mem_writew(BIOS_KEYBOARD_BUFFER_HEAD,0x1e);
01515         mem_writew(BIOS_KEYBOARD_BUFFER_TAIL,0x1e);
01516         Bit8u flag1 = 0;
01517         Bit8u leds = 16; /* Ack received */
01518 
01519 #if 0 /*SDL_VERSION_ATLEAST(1, 2, 14)*/
01520         //Nothing, mapper handles all.
01521 #else
01522         if (startup_state_capslock) { flag1|=BIOS_KEYBOARD_FLAGS1_CAPS_LOCK_ACTIVE; leds|=BIOS_KEYBOARD_LEDS_CAPS_LOCK;}
01523         if (startup_state_numlock)  { flag1|=BIOS_KEYBOARD_FLAGS1_NUMLOCK_ACTIVE; leds|=BIOS_KEYBOARD_LEDS_NUM_LOCK;}
01524         if (startup_state_scrlock)  { flag1|=BIOS_KEYBOARD_FLAGS1_SCROLL_LOCK_ACTIVE; leds|=BIOS_KEYBOARD_LEDS_SCROLL_LOCK;}
01525 #endif
01526 
01527         mem_writeb(BIOS_KEYBOARD_FLAGS1,flag1);
01528         mem_writeb(BIOS_KEYBOARD_FLAGS2,0);
01529         mem_writeb(BIOS_KEYBOARD_FLAGS3,16); /* Enhanced keyboard installed */  
01530         mem_writeb(BIOS_KEYBOARD_TOKEN,0);
01531         mem_writeb(BIOS_KEYBOARD_LEDS,leds);
01532     }
01533 }
01534 
01535 void CALLBACK_DeAllocate(Bitu in);
01536 
01537 void BIOS_UnsetupKeyboard(void) {
01538     if (call_int16 != 0) {
01539         CALLBACK_DeAllocate(call_int16);
01540         RealSetVec(0x16,0);
01541         call_int16 = 0;
01542     }
01543     if (call_irq1 != 0) {
01544         CALLBACK_DeAllocate(call_irq1);
01545         call_irq1 = 0;
01546     }
01547     if (call_irq_pcjr_nmi != 0) {
01548         CALLBACK_DeAllocate(call_irq_pcjr_nmi);
01549         call_irq_pcjr_nmi = 0;
01550     }
01551     if (call_irq6 != 0) {
01552         CALLBACK_DeAllocate(call_irq6);
01553         call_irq6 = 0;
01554     }
01555     if (irq1_ret_ctrlbreak_callback != 0) {
01556         CALLBACK_DeAllocate(irq1_ret_ctrlbreak_callback);
01557         irq1_ret_ctrlbreak_callback = 0;
01558     }
01559 }
01560 
01561 void BIOS_SetupKeyboard(void) {
01562     /* Init the variables */
01563     InitBiosSegment();
01564 
01565     if (IS_PC98_ARCH) {
01566         /* HACK */
01567         /* Allocate/setup a callback for int 0x16 and for standard IRQ 1 handler */
01568         call_int16=CALLBACK_Allocate(); 
01569         CALLBACK_Setup(call_int16,&INT16_Handler,CB_INT16,"Keyboard");
01570         /* DO NOT set up an INT 16h vector. This exists only for the DOS CONIO emulation. */
01571     }
01572     else {
01573         /* Allocate/setup a callback for int 0x16 and for standard IRQ 1 handler */
01574         call_int16=CALLBACK_Allocate(); 
01575         CALLBACK_Setup(call_int16,&INT16_Handler,CB_INT16,"Keyboard");
01576         RealSetVec(0x16,CALLBACK_RealPointer(call_int16));
01577     }
01578 
01579     call_irq1=CALLBACK_Allocate();
01580     if (machine == MCH_PCJR) { /* PCjr keyboard interrupt connected to NMI */
01581         call_irq_pcjr_nmi=CALLBACK_Allocate();
01582 
01583         CALLBACK_Setup(call_irq_pcjr_nmi,&PCjr_NMI_Keyboard_Handler,CB_IRET,"PCjr NMI Keyboard");
01584 
01585         Bit32u a = CALLBACK_RealPointer(call_irq_pcjr_nmi);
01586 
01587         RealSetVec(0x02/*NMI*/,a);
01588 
01589         /* TODO: PCjr calls INT 48h to convert PCjr scan codes to IBM PC/XT compatible */
01590 
01591         a = ((a >> 16) << 4) + (a & 0xFFFF);
01592         /* a+0 = callback instruction (4 bytes)
01593          * a+4 = iret (1 bytes) */
01594         phys_writeb(a+5,0x50);          /* push ax */
01595         phys_writew(a+6,0x60E4);        /* in al,60h */
01596         phys_writew(a+8,0x09CD);        /* int 9h */
01597         phys_writeb(a+10,0x58);         /* pop ax */
01598         phys_writew(a+11,0x00EB + ((256-13)<<8));    /* jmp a+0 */
01599     }
01600 
01601     if (IS_PC98_ARCH) {
01602         CALLBACK_Setup(call_irq1,&IRQ1_Handler_PC98,CB_IRET_EOI_PIC1,Real2Phys(BIOS_DEFAULT_IRQ1_LOCATION),"IRQ 1 Keyboard PC-98");
01603         RealSetVec(0x09/*IRQ 1*/,BIOS_DEFAULT_IRQ1_LOCATION);
01604     }
01605     else {
01606         CALLBACK_Setup(call_irq1,&IRQ1_Handler,CB_IRQ1,Real2Phys(BIOS_DEFAULT_IRQ1_LOCATION),"IRQ 1 Keyboard");
01607         RealSetVec(0x09/*IRQ 1*/,BIOS_DEFAULT_IRQ1_LOCATION);
01608         // pseudocode for CB_IRQ1:
01609         //  push ax
01610         //  in al, 0x60
01611         //  mov ah, 0x4f
01612         //  stc
01613         //  int 15
01614         //  jc skip
01615         //  callback IRQ1_Handler
01616         //  label skip:
01617         //  cli
01618         //  mov al, 0x20
01619         //  out 0x20, al
01620         //  pop ax
01621         //  iret
01622         //  cli
01623         //  mov al, 0x20
01624         //  out 0x20, al
01625         //  push bp
01626         //  int 0x05
01627         //  pop bp
01628         //  pop ax
01629         //  iret
01630     }
01631 
01632     irq1_ret_ctrlbreak_callback=CALLBACK_Allocate();
01633     CALLBACK_Setup(irq1_ret_ctrlbreak_callback,&IRQ1_CtrlBreakAfterInt1B,CB_IRQ1_BREAK,"IRQ 1 Ctrl-Break callback");
01634     // pseudocode for CB_IRQ1_BREAK:
01635     //  int 1b
01636     //  cli
01637     //  callback IRQ1_CtrlBreakAfterInt1B
01638     //  mov al, 0x20
01639     //  out 0x20, al
01640     //  pop ax
01641     //  iret
01642 
01643     if (machine==MCH_PCJR) {
01644         call_irq6=CALLBACK_Allocate();
01645         CALLBACK_Setup(call_irq6,NULL,CB_IRQ6_PCJR,"PCJr kb irq");
01646         RealSetVec(0x0e,CALLBACK_RealPointer(call_irq6));
01647         // pseudocode for CB_IRQ6_PCJR:
01648         //  push ax
01649         //  in al, 0x60
01650         //  cmp al, 0xe0
01651         //  je skip
01652         //  push ds
01653         //  push 0x40
01654         //  pop ds
01655         //  int 0x09
01656         //  pop ds
01657         //  label skip:
01658         //  cli
01659         //  mov al, 0x20
01660         //  out 0x20, al
01661         //  pop ax
01662         //  iret
01663     }
01664 }
01665