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