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