DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/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 "keyboard.h"
00022 #include "support.h"
00023 #include "setup.h"
00024 #include "inout.h"
00025 #include "mouse.h"
00026 #include "pic.h"
00027 #include "mem.h"
00028 #include "cpu.h"
00029 #include "mixer.h"
00030 #include "timer.h"
00031 #include <math.h>
00032 #include "8255.h"
00033 
00034 #if defined(_MSC_VER)
00035 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */
00036 #endif
00037 
00038 #define KEYBUFSIZE 32*3
00039 #define RESETDELAY 400
00040 #define KEYDELAY 0.300f         //Considering 20-30 khz serial clock and 11 bits/char
00041 
00042 #define AUX 0x100
00043 
00044 void AUX_Reset();
00045 void KEYBOARD_Reset();
00046 static void KEYBOARD_SetPort60(Bit16u val);
00047 void KEYBOARD_AddBuffer(Bit16u data);
00048 static void KEYBOARD_Add8042Response(Bit8u data);
00049 void KEYBOARD_SetLEDs(Bit8u bits);
00050 
00051 static unsigned int aux_warning = 0;
00052 
00053 enum AuxCommands {
00054     ACMD_NONE,
00055     ACMD_SET_RATE,
00056     ACMD_SET_RESOLUTION
00057 };
00058 
00059 enum KeyCommands {
00060     CMD_NONE,
00061     CMD_SETLEDS,
00062     CMD_SETTYPERATE,
00063     CMD_SETOUTPORT,
00064     CMD_SETCOMMAND,
00065     CMD_WRITEOUTPUT,
00066     CMD_WRITEAUXOUT,
00067     CMD_SETSCANSET,
00068     CMD_WRITEAUX
00069 };
00070 
00071 enum MouseMode {
00072     MM_REMOTE=0,
00073     MM_WRAP,
00074     MM_STREAM
00075 };
00076 
00077 enum MouseType {
00078     MOUSE_NONE=0,
00079     MOUSE_2BUTTON,
00080     MOUSE_3BUTTON,
00081     MOUSE_INTELLIMOUSE,
00082     MOUSE_INTELLIMOUSE45
00083 };
00084 
00085 struct ps2mouse {
00086     MouseType   type;           /* what kind of mouse we are emulating */
00087     MouseMode   mode;           /* current mode */
00088     MouseMode   reset_mode;     /* mode to change to on reset */
00089     Bit8u       samplerate;     /* current sample rate */
00090     Bit8u       resolution;     /* current resolution */
00091     Bit8u       last_srate[3];      /* last 3 "set sample rate" values */
00092     float       acx,acy;        /* accumulator */
00093     bool        reporting;      /* reporting */
00094     bool        scale21;        /* 2:1 scaling */
00095     bool        intellimouse_mode;  /* intellimouse scroll wheel */
00096     bool        intellimouse_btn45; /* 4th & 5th buttons */
00097     bool        int33_taken;        /* for compatability with existing DOSBox code: allow INT 33H emulation to "take over" and disable us */
00098     bool        l,m,r;          /* mouse button states */
00099 };
00100 
00101 static struct {
00102     Bit8u buf8042[8];       /* for 8042 responses, taking priority over keyboard responses */
00103     Bitu buf8042_len;
00104     Bitu buf8042_pos;
00105     int pending_key;
00106 
00107     Bit16u buffer[KEYBUFSIZE];
00108     Bitu used;
00109     Bitu pos;
00110 
00111     struct {
00112         KBD_KEYS key;
00113         Bitu wait;
00114         Bitu pause,rate;
00115     } repeat;
00116     struct ps2mouse ps2mouse;
00117     KeyCommands command;
00118     AuxCommands aux_command;
00119     Bitu led_state;
00120     Bit8u p60data;
00121     Bit8u scanset;
00122     bool enable_aux;
00123     bool reset;
00124     bool active;
00125     bool scanning;
00126     bool auxactive;
00127     bool scheduled;
00128     bool p60changed;
00129     bool auxchanged;
00130     bool pending_key_state;
00131     /* command byte related */
00132     bool cb_override_inhibit;
00133     bool cb_irq12;          /* PS/2 mouse */
00134     bool cb_irq1;
00135     bool cb_xlat;
00136     bool cb_sys;
00137     bool leftctrl_pressed;
00138     bool rightctrl_pressed;
00139 } keyb;
00140 
00141 uint8_t Mouse_GetButtonState(void);
00142 
00143 uint32_t Keyb_ig_status() {
00144     uint8_t mousebtn = Mouse_GetButtonState() & 7;
00145 
00146     return  ((uint32_t)keyb.led_state     << (uint32_t)0 ) |
00147         ((uint32_t)keyb.scanset       << (uint32_t)8 ) |
00148         ((uint32_t)keyb.reset         << (uint32_t)10) |
00149         ((uint32_t)keyb.active        << (uint32_t)11) |
00150         ((uint32_t)keyb.scanning      << (uint32_t)12) |
00151         ((uint32_t)keyb.auxactive     << (uint32_t)13) |
00152         ((uint32_t)keyb.scheduled     << (uint32_t)14) |
00153         ((uint32_t)keyb.p60changed    << (uint32_t)15) |
00154         ((uint32_t)keyb.auxchanged    << (uint32_t)16) |
00155         ((uint32_t)keyb.cb_xlat       << (uint32_t)17) |
00156         ((uint32_t)keyb.ps2mouse.l    << (uint32_t)18) |
00157         ((uint32_t)keyb.ps2mouse.m    << (uint32_t)19) |
00158         ((uint32_t)keyb.ps2mouse.r    << (uint32_t)20) |
00159         ((uint32_t)keyb.ps2mouse.reporting << (uint32_t)21) |
00160         ((uint32_t)(keyb.ps2mouse.mode == MM_STREAM ? 1 : 0) << (uint32_t)22) |
00161         ((uint32_t)mousebtn           << (uint32_t)23);
00162 }
00163 
00164 bool MouseTypeNone() {
00165     return (keyb.ps2mouse.type == MOUSE_NONE);
00166 }
00167 
00168 /* NTS: INT33H emulation is coded to call this ONLY if it hasn't taken over the role of mouse input */
00169 void KEYBOARD_AUX_Event(float x,float y,Bitu buttons,int scrollwheel) {
00170     if (IS_PC98_ARCH) {
00171         LOG_MSG("WARNING: KEYBOARD_AUX_Event called in PC-98 emulation mode. This is a bug.");
00172         return;
00173     }
00174 
00175     keyb.ps2mouse.acx += x;
00176     keyb.ps2mouse.acy += y;
00177     keyb.ps2mouse.l = (buttons & 1)>0;
00178     keyb.ps2mouse.r = (buttons & 2)>0;
00179     keyb.ps2mouse.m = (buttons & 4)>0;
00180 
00181     /* "Valid ranges are -8 to 7"
00182      * http://www.computer-engineering.org/ps2mouse/ */
00183     if (scrollwheel < -8)
00184         scrollwheel = -8;
00185     else if (scrollwheel > 7)
00186         scrollwheel = 7;
00187 
00188     if (keyb.ps2mouse.reporting && keyb.ps2mouse.mode == MM_STREAM) {
00189         if ((keyb.used+4) < KEYBUFSIZE) {
00190             int x,y;
00191 
00192             x = (int)(keyb.ps2mouse.acx * (1 << keyb.ps2mouse.resolution));
00193             x /= 16; /* FIXME: Or else the cursor is WAY too sensitive in Windows 3.1 */
00194             if (x < -256) x = -256;
00195             else if (x > 255) x = 255;
00196 
00197             y = -((int)(keyb.ps2mouse.acy * (1 << keyb.ps2mouse.resolution)));
00198             y /= 16; /* FIXME: Or else the cursor is WAY too sensitive in Windows 3.1 */
00199             if (y < -256) y = -256;
00200             else if (y > 255) y = 255;
00201 
00202             KEYBOARD_AddBuffer(AUX|
00203                 ((y == -256 || y == 255) ? 0x80 : 0x00) |   /* Y overflow */
00204                 ((x == -256 || x == 255) ? 0x40 : 0x00) |   /* X overflow */
00205                 (y & 0x100 ? 0x20 : 0x00) |         /* Y sign bit */
00206                 (x & 0x100 ? 0x10 : 0x00) |         /* X sign bit */
00207                 0x08 |                      /* always 1? */
00208                 (keyb.ps2mouse.m ? 4 : 0) |         /* M */
00209                 (keyb.ps2mouse.r ? 2 : 0) |         /* R */
00210                 (keyb.ps2mouse.l ? 1 : 0));         /* L */
00211             KEYBOARD_AddBuffer(AUX|(x&0xFF));
00212             KEYBOARD_AddBuffer(AUX|(y&0xFF));
00213             if (keyb.ps2mouse.intellimouse_btn45) {
00214                 KEYBOARD_AddBuffer(AUX|(scrollwheel&0xFF)); /* TODO: 4th & 5th buttons */
00215             }
00216             else if (keyb.ps2mouse.intellimouse_mode) {
00217                 KEYBOARD_AddBuffer(AUX|(scrollwheel&0xFF));
00218             }
00219         }
00220 
00221         keyb.ps2mouse.acx = 0;
00222         keyb.ps2mouse.acy = 0;
00223     }
00224 }
00225 
00226 int KEYBOARD_AUX_Active() {
00227     /* NTS: We want to allow software to read by polling, which doesn't
00228      *      require interrupts to be enabled. Whether or not IRQ12 is
00229      *      unmasked is irrelevent */
00230     return keyb.auxactive && !keyb.ps2mouse.int33_taken;
00231 }
00232 
00233 static void KEYBOARD_SetPort60(Bit16u val) {
00234     keyb.auxchanged=(val&AUX)>0;
00235     keyb.p60changed=true;
00236     keyb.p60data=(Bit8u)val;
00237     if (keyb.auxchanged) {
00238         if (keyb.cb_irq12) {
00239             PIC_ActivateIRQ(12);
00240         }
00241     }
00242     else {
00243         if (keyb.cb_irq1) {
00244             if (machine == MCH_PCJR) CPU_Raise_NMI(); /* NTS: PCjr apparently hooked the keyboard to NMI */
00245             else PIC_ActivateIRQ(1);
00246         }
00247     }
00248 }
00249 
00250 static void KEYBOARD_ResetDelay(Bitu val) {
00251     (void)val;//UNUSED
00252     keyb.reset=false;
00253     KEYBOARD_SetLEDs(0);
00254     KEYBOARD_Add8042Response(0x00); /* BAT */
00255 }
00256 
00257 static void KEYBOARD_TransferBuffer(Bitu val) {
00258     (void)val;//UNUSED
00259     /* 8042 responses take priority over the keyboard */
00260     if (keyb.enable_aux && keyb.buf8042_len != 0) {
00261         KEYBOARD_SetPort60(keyb.buf8042[keyb.buf8042_pos]);
00262         if (++keyb.buf8042_pos >= keyb.buf8042_len)
00263             keyb.buf8042_len = keyb.buf8042_pos = 0;
00264         return;
00265     }
00266 
00267     keyb.scheduled=false;
00268     if (!keyb.used) {
00269         LOG(LOG_KEYBOARD,LOG_NORMAL)("Transfer started with empty buffer");
00270         return;
00271     }
00272     KEYBOARD_SetPort60(keyb.buffer[keyb.pos]);
00273     if (++keyb.pos>=KEYBUFSIZE) keyb.pos-=KEYBUFSIZE;
00274     keyb.used--;
00275 }
00276 
00277 void KEYBOARD_ClrBuffer(void) {
00278     keyb.buf8042_len=0;
00279     keyb.buf8042_pos=0;
00280     keyb.used=0;
00281     keyb.pos=0;
00282     PIC_RemoveEvents(KEYBOARD_TransferBuffer);
00283     keyb.scheduled=false;
00284 }
00285 
00286 size_t KEYBOARD_BufferSpaceAvail()   // emendelson from dbDOS
00287 {
00288     return (KEYBUFSIZE - keyb.used);
00289 }                                   // end emendelson from dbDOS
00290 
00291 static void KEYBOARD_Add8042Response(Bit8u data) {
00292     if(!keyb.enable_aux) return;
00293     if (keyb.buf8042_pos >= keyb.buf8042_len)
00294         keyb.buf8042_pos = keyb.buf8042_len = 0;
00295     else if (keyb.buf8042_len == 0)
00296         keyb.buf8042_pos = 0;
00297 
00298     if (keyb.buf8042_pos >= sizeof(keyb.buf8042)) {
00299         LOG(LOG_KEYBOARD,LOG_NORMAL)("8042 Buffer full, dropping code");
00300         KEYBOARD_ClrBuffer(); return;
00301     }
00302 
00303     keyb.buf8042[keyb.buf8042_len++] = data;
00304     PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY);
00305 }
00306 
00307 void KEYBOARD_AddBuffer(Bit16u data) {
00308     if (keyb.used>=KEYBUFSIZE) {
00309         LOG(LOG_KEYBOARD,LOG_NORMAL)("Buffer full, dropping code");
00310         KEYBOARD_ClrBuffer(); return;
00311     }
00312     Bitu start=keyb.pos+keyb.used;
00313     if (start>=KEYBUFSIZE) start-=KEYBUFSIZE;
00314     keyb.buffer[start]=data;
00315     keyb.used++;
00316     /* Start up an event to start the first IRQ */
00317     if (!keyb.scheduled && !keyb.p60changed) {
00318         keyb.scheduled=true;
00319         PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY);
00320     }
00321 }
00322 
00323 Bitu Keyboard_Guest_LED_State() {
00324     return keyb.led_state;
00325 }
00326 
00327 void UpdateKeyboardLEDState(Bitu led_state/* in the same bitfield arrangement as using command 0xED on PS/2 keyboards */);
00328 
00329 void KEYBOARD_SetLEDs(Bit8u bits) {
00330     /* Some OSes we have control of the LEDs if keyboard+mouse capture */
00331     keyb.led_state = bits;
00332     UpdateKeyboardLEDState(bits);
00333 
00334     /* TODO: Maybe someday you could have DOSBox show the LEDs */
00335 
00336     /* log for debug info */
00337     LOG(LOG_KEYBOARD,LOG_DEBUG)("Keyboard LEDs: SCR=%u NUM=%u CAPS=%u",bits&1,(bits>>1)&1,(bits>>2)&1);
00338 }
00339 
00340 static Bitu read_p60(Bitu port,Bitu iolen) {
00341     (void)port;//UNUSED
00342     (void)iolen;//UNUSED
00343     keyb.p60changed=false;
00344     keyb.auxchanged=false;
00345     if (!keyb.scheduled && keyb.used) {
00346         keyb.scheduled=true;
00347         PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY);
00348     }
00349     return keyb.p60data;
00350 }
00351 
00352 unsigned char KEYBOARD_AUX_GetType() {
00353     /* and then the ID */
00354     if (keyb.ps2mouse.intellimouse_btn45)
00355         return 0x04;
00356     else if (keyb.ps2mouse.intellimouse_mode)
00357         return 0x03;
00358     else
00359         return 0x00;
00360 }
00361 
00362 unsigned char KEYBOARD_AUX_DevStatus() {
00363     return  (keyb.ps2mouse.mode == MM_REMOTE ? 0x40 : 0x00)|
00364         (keyb.ps2mouse.reporting << 5)|
00365         (keyb.ps2mouse.scale21 << 4)|
00366         (keyb.ps2mouse.m << 2)|
00367         (keyb.ps2mouse.r << 1)|
00368         (keyb.ps2mouse.l << 0);
00369 }
00370 
00371 unsigned char KEYBOARD_AUX_Resolution() {
00372     return keyb.ps2mouse.resolution;
00373 }
00374 
00375 unsigned char KEYBOARD_AUX_SampleRate() {
00376     return keyb.ps2mouse.samplerate;
00377 }
00378 
00379 void KEYBOARD_AUX_Write(Bitu val) {
00380     if (keyb.ps2mouse.type == MOUSE_NONE)
00381         return;
00382 
00383     if (keyb.ps2mouse.mode == MM_WRAP) {
00384         if (val != 0xFF && val != 0xEC) {
00385             KEYBOARD_AddBuffer(AUX|val);
00386             return;
00387         }
00388     }
00389 
00390     switch (keyb.aux_command) {
00391         case ACMD_NONE:
00392             switch (val) {
00393                 case 0xff:  /* reset */
00394                     LOG(LOG_KEYBOARD,LOG_NORMAL)("AUX reset");
00395                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00396                     KEYBOARD_AddBuffer(AUX|0xaa);   /* reset */
00397                     KEYBOARD_AddBuffer(AUX|0x00);   /* i am mouse */
00398                     Mouse_AutoLock(false);
00399                     AUX_Reset();
00400                     break;
00401                 case 0xf6:  /* set defaults */
00402                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00403                     AUX_Reset();
00404                     break;
00405                 case 0xf5:  /* disable data reporting */
00406                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00407                     keyb.ps2mouse.reporting = false;
00408                     break;
00409                 case 0xf4:  /* enable data reporting */
00410                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00411                     keyb.ps2mouse.reporting = true;
00412                     Mouse_AutoLock(true);
00413                     break;
00414                 case 0xf3:  /* set sample rate */
00415                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00416                     keyb.aux_command = ACMD_SET_RATE;
00417                     break;
00418                 case 0xf2:  /* get device ID */
00419                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00420 
00421                     /* and then the ID */
00422                     if (keyb.ps2mouse.intellimouse_btn45)
00423                         KEYBOARD_AddBuffer(AUX|0x04);
00424                     else if (keyb.ps2mouse.intellimouse_mode)
00425                         KEYBOARD_AddBuffer(AUX|0x03);
00426                     else
00427                         KEYBOARD_AddBuffer(AUX|0x00);
00428                     break;
00429                 case 0xf0:  /* set remote mode */
00430                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00431                     keyb.ps2mouse.mode = MM_REMOTE;
00432                     break;
00433                 case 0xee:  /* set wrap mode */
00434                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00435                     keyb.ps2mouse.mode = MM_WRAP;
00436                     break;
00437                 case 0xec:  /* reset wrap mode */
00438                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00439                     keyb.ps2mouse.mode = MM_REMOTE;
00440                     break;
00441                 case 0xeb:  /* read data */
00442                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00443                     KEYBOARD_AUX_Event(0,0,
00444                         ((unsigned int)keyb.ps2mouse.m << 2u) |
00445                         ((unsigned int)keyb.ps2mouse.r << 1u) |
00446                         ((unsigned int)keyb.ps2mouse.l << 0u),
00447                         0);
00448                     break;
00449                 case 0xea:  /* set stream mode */
00450                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00451                     keyb.ps2mouse.mode = MM_STREAM;
00452                     break;
00453                 case 0xe9:  /* status request */
00454                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00455                     KEYBOARD_AddBuffer(AUX|KEYBOARD_AUX_DevStatus());
00456                     KEYBOARD_AddBuffer(AUX|keyb.ps2mouse.resolution);
00457                     KEYBOARD_AddBuffer(AUX|keyb.ps2mouse.samplerate);
00458                     break;
00459                 case 0xe8:  /* set resolution */
00460                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00461                     keyb.aux_command = ACMD_SET_RESOLUTION;
00462                     break;
00463                 case 0xe7:  /* set scaling 2:1 */
00464                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00465                     keyb.ps2mouse.scale21 = true;
00466                     LOG(LOG_KEYBOARD,LOG_NORMAL)("PS/2 mouse scaling 2:1");
00467                     break;
00468                 case 0xe6:  /* set scaling 1:1 */
00469                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00470                     keyb.ps2mouse.scale21 = false;
00471                     LOG(LOG_KEYBOARD,LOG_NORMAL)("PS/2 mouse scaling 1:1");
00472                     break;
00473             }
00474             break;
00475         case ACMD_SET_RATE:
00476             KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00477             memmove(keyb.ps2mouse.last_srate,keyb.ps2mouse.last_srate+1,2);
00478             keyb.ps2mouse.last_srate[2] = val;
00479             keyb.ps2mouse.samplerate = val;
00480             keyb.aux_command = ACMD_NONE;
00481             LOG(LOG_KEYBOARD,LOG_NORMAL)("PS/2 mouse sample rate set to %u",(int)val);
00482             if (keyb.ps2mouse.type >= MOUSE_INTELLIMOUSE) {
00483                 if (keyb.ps2mouse.last_srate[0] == 200 && keyb.ps2mouse.last_srate[2] == 80) {
00484                     if (keyb.ps2mouse.last_srate[1] == 100) {
00485                         if (!keyb.ps2mouse.intellimouse_mode) {
00486                             LOG(LOG_KEYBOARD,LOG_NORMAL)("Intellimouse mode enabled");
00487                             keyb.ps2mouse.intellimouse_mode=true;
00488                         }
00489                     }
00490                     else if (keyb.ps2mouse.last_srate[1] == 200 && keyb.ps2mouse.type >= MOUSE_INTELLIMOUSE45) {
00491                         if (!keyb.ps2mouse.intellimouse_btn45) {
00492                             LOG(LOG_KEYBOARD,LOG_NORMAL)("Intellimouse 4/5-button mode enabled");
00493                             keyb.ps2mouse.intellimouse_btn45=true;
00494                         }
00495                     }
00496                 }
00497             }
00498             break;
00499         case ACMD_SET_RESOLUTION:
00500             keyb.aux_command = ACMD_NONE;
00501             KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00502             keyb.ps2mouse.resolution = val & 3;
00503             LOG(LOG_KEYBOARD,LOG_NORMAL)("PS/2 mouse resolution set to %u",(int)(1 << (val&3)));
00504             break;
00505     };
00506 }
00507 
00508 #include "control.h"
00509 
00510 bool allow_keyb_reset = true;
00511 
00512 void On_Software_CPU_Reset();
00513 void restart_program(std::vector<std::string> & parameters);
00514 
00515 static void write_p60(Bitu port,Bitu val,Bitu iolen) {
00516     (void)port;//UNUSED
00517     (void)iolen;//UNUSED
00518     switch (keyb.command) {
00519     case CMD_NONE:  /* None */
00520         if (keyb.reset)
00521             return;
00522 
00523         /* No active command this would normally get sent to the keyboard then */
00524         KEYBOARD_ClrBuffer();
00525         switch (val) {
00526         case 0xed:  /* Set Leds */
00527             keyb.command=CMD_SETLEDS;
00528             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00529             break;
00530         case 0xee:  /* Echo */
00531             KEYBOARD_AddBuffer(0xee);   /* JC: The correct response is 0xEE, not 0xFA */
00532             break;
00533         case 0xf0:  /* set scancode set */
00534             keyb.command=CMD_SETSCANSET;
00535             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00536             break;
00537         case 0xf2:  /* Identify keyboard */
00538             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00539             KEYBOARD_AddBuffer(0xab);   /* ID */
00540             KEYBOARD_AddBuffer(0x83);
00541             break;
00542         case 0xf3: /* Typematic rate programming */
00543             keyb.command=CMD_SETTYPERATE;
00544             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00545             break;
00546         case 0xf4:  /* Enable keyboard,clear buffer, start scanning */
00547             LOG(LOG_KEYBOARD,LOG_NORMAL)("Clear buffer, enable scanning");
00548             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00549             keyb.scanning=true;
00550             break;
00551         case 0xf5:   /* Reset keyboard and disable scanning */
00552             LOG(LOG_KEYBOARD,LOG_NORMAL)("Reset, disable scanning");            
00553             keyb.scanning=false;
00554             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00555             break;
00556         case 0xf6:  /* Reset keyboard and enable scanning */
00557             LOG(LOG_KEYBOARD,LOG_NORMAL)("Reset, enable scanning");
00558             keyb.scanning=true;     /* JC: Original DOSBox code was wrong, this command enables scanning */
00559             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00560             break;
00561         case 0xff:      /* keyboard resets take a long time (about 250ms), most keyboards flash the LEDs during reset */
00562             KEYBOARD_Reset();
00563             KEYBOARD_Add8042Response(0xFA); /* ACK */
00564             KEYBOARD_Add8042Response(0xAA); /* SELF TEST OK (TODO: Need delay!) */
00565             keyb.reset=true;
00566             KEYBOARD_SetLEDs(7); /* most keyboard I test with tend to flash the LEDs during reset */
00567             PIC_AddEvent(KEYBOARD_ResetDelay,RESETDELAY);
00568             break;
00569         default:
00570             /* Just always acknowledge strange commands */
00571             LOG(LOG_KEYBOARD,LOG_ERROR)("60:Unhandled command %X",(int)val);
00572             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00573         }
00574         return;
00575     case CMD_SETSCANSET:
00576         keyb.command=CMD_NONE;
00577         KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00578         if (val == 0) { /* just asking */
00579             if (keyb.cb_xlat) {
00580                 switch (keyb.scanset) {
00581                     case 1: KEYBOARD_AddBuffer(0x43); break;
00582                     case 2: KEYBOARD_AddBuffer(0x41); break;
00583                     case 3: KEYBOARD_AddBuffer(0x3F); break;
00584                 }
00585             }
00586             else {
00587                 KEYBOARD_AddBuffer(keyb.scanset);
00588             }
00589         }
00590         else {
00591             if (val > 3) val = 3;
00592             keyb.scanset = val;
00593         }
00594         break;
00595     case CMD_WRITEAUX:
00596         keyb.command=CMD_NONE;
00597         KEYBOARD_AUX_Write(val);
00598         break;
00599     case CMD_WRITEOUTPUT:
00600         keyb.command=CMD_NONE;
00601         KEYBOARD_ClrBuffer();
00602         KEYBOARD_AddBuffer(val);    /* and now you return the byte as if it were typed in */
00603         break;
00604     case CMD_WRITEAUXOUT:
00605         KEYBOARD_AddBuffer(AUX|val); /* stuff into AUX output */
00606         break;
00607     case CMD_SETOUTPORT:
00608         if (!(val & 1)) {
00609             if (allow_keyb_reset) {
00610                 LOG_MSG("Restart by keyboard controller requested\n");
00611                 On_Software_CPU_Reset();
00612             }
00613             else {
00614                 LOG_MSG("WARNING: Keyboard output port written with bit 1 clear. Is the guest OS or application attempting to reset the system?\n");
00615             }
00616         }
00617         MEM_A20_Enable((val & 2)>0);
00618         keyb.command = CMD_NONE;
00619         break;
00620     case CMD_SETTYPERATE: 
00621         if (keyb.reset)
00622             return;
00623 
00624         {
00625             static const unsigned int delay[] = { 250, 500, 750, 1000 };
00626             static const unsigned int repeat[] =
00627             { 33,37,42,46,50,54,58,63,67,75,83,92,100,
00628               109,118,125,133,149,167,182,200,217,233,
00629               250,270,303,333,370,400,435,476,500 };
00630             keyb.repeat.pause = delay[(val >> 5) & 3];
00631             keyb.repeat.rate = repeat[val & 0x1f];
00632             keyb.command = CMD_NONE;
00633             KEYBOARD_ClrBuffer();
00634             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00635         }
00636         break;
00637     case CMD_SETLEDS:
00638         if (keyb.reset)
00639             return;
00640 
00641         keyb.command=CMD_NONE;
00642         KEYBOARD_ClrBuffer();
00643         KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00644         KEYBOARD_SetLEDs(val&7);
00645         break;
00646     case CMD_SETCOMMAND: /* 8042 command, not keyboard */
00647         /* TODO: If biosps2=true and aux=false, disallow the guest OS from changing AUX port parameters including IRQ */
00648         keyb.command=CMD_NONE;
00649         keyb.cb_xlat = (val >> 6) & 1;
00650         keyb.auxactive = !((val >> 5) & 1);
00651         keyb.active = !((val >> 4) & 1);
00652         keyb.cb_sys = (val >> 2) & 1;
00653         keyb.cb_irq12 = (val >> 1) & 1;
00654         keyb.cb_irq1 = (val >> 0) & 1;
00655         if (keyb.used && !keyb.scheduled && !keyb.p60changed && keyb.active) {
00656             keyb.scheduled=true;
00657             PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY);
00658         }
00659         break;
00660     }
00661 }
00662 
00663 static Bit8u port_61_data = 0;
00664 
00665 static Bitu read_p61(Bitu, Bitu) {
00666     unsigned char dbg;
00667     dbg = ((port_61_data & 0xF) |
00668         ((TIMER_GetOutput2() || (port_61_data&1) == 0)? 0x20:0) | // NTS: Timer 2 doesn't cycle if Port 61 gate turned off, and it becomes '1' when turned off
00669         ((fmod(PIC_FullIndex(),0.030) > 0.015)? 0x10:0));
00670     return dbg;
00671 }
00672 
00673 static void write_p61(Bitu, Bitu val, Bitu) {
00674     Bit8u diff = port_61_data ^ (Bit8u)val;
00675     if (diff & 0x1) TIMER_SetGate2(val & 0x1);
00676     if ((diff & 0x3) && !IS_PC98_ARCH) {
00677         bool pit_clock_gate_enabled = val & 0x1;
00678         bool pit_output_enabled = !!(val & 0x2);
00679         PCSPEAKER_SetType(pit_clock_gate_enabled, pit_output_enabled);
00680     }
00681     port_61_data = val;
00682 }
00683 
00684 static void write_p64(Bitu port,Bitu val,Bitu iolen) {
00685     (void)port;//UNUSED
00686     (void)iolen;//UNUSED
00687     if (keyb.reset)
00688         return;
00689 
00690     switch (val) {
00691     case 0x20:      /* read command byte */
00692         /* TODO: If biosps2=true and aux=false, mask AUX port bits as if AUX isn't there */
00693         KEYBOARD_Add8042Response(
00694             (keyb.cb_xlat << 6)      | ((!keyb.auxactive) << 5) |
00695             ((!keyb.active) << 4)    | (keyb.cb_sys << 2) |
00696             (keyb.cb_irq12 << 1)     | (keyb.cb_irq1?1:0));
00697         break;
00698     case 0x60:
00699         keyb.command=CMD_SETCOMMAND;
00700         break;
00701     case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
00702     case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
00703         /* TODO: If bit 0 == 0, trigger system reset */
00704         break;
00705     case 0xa7:      /* disable aux */
00706         /* TODO: If biosps2=true and aux=false do not respond */
00707         if (keyb.enable_aux) {
00708             //keyb.auxactive=false;
00709             //LOG(LOG_KEYBOARD,LOG_NORMAL)("AUX De-Activated");
00710         }
00711         break;
00712     case 0xa8:      /* enable aux */
00713         /* TODO: If biosps2=true and aux=false do not respond */
00714         if (keyb.enable_aux) {
00715             keyb.auxactive=true;
00716             if (keyb.used && !keyb.scheduled && !keyb.p60changed) {
00717                 keyb.scheduled=true;
00718                 PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY);
00719             }
00720             LOG(LOG_KEYBOARD,LOG_NORMAL)("AUX Activated");
00721         }
00722         break;
00723     case 0xa9:      /* mouse interface test */
00724         /* TODO: If biosps2=true and aux=false do not respond */
00725         KEYBOARD_Add8042Response(0x00); /* OK */
00726         break;
00727     case 0xaa:      /* Self test */
00728         keyb.active=false; /* on real h/w it also seems to disable the keyboard */
00729         KEYBOARD_Add8042Response(0xaa); /* OK */
00730         break;
00731     case 0xab:      /* interface test */
00732         keyb.active=false; /* on real h/w it also seems to disable the keyboard */
00733         KEYBOARD_Add8042Response(0x00); /* no error */
00734         break;
00735     case 0xae:      /* Activate keyboard */
00736         keyb.active=true;
00737         if (keyb.used && !keyb.scheduled && !keyb.p60changed) {
00738             keyb.scheduled=true;
00739             PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY);
00740         }
00741         LOG(LOG_KEYBOARD,LOG_NORMAL)("Activated");
00742         break;
00743     case 0xad:      /* Deactivate keyboard */
00744         keyb.active=false;
00745         LOG(LOG_KEYBOARD,LOG_NORMAL)("De-Activated");
00746         break;
00747     case 0xc0:      /* read input buffer */
00748         KEYBOARD_Add8042Response(0x40);
00749         break;
00750     case 0xd0:      /* Outport on buffer */
00751         KEYBOARD_SetPort60((MEM_A20_Enabled() ? 0x02 : 0) | 0x01/*some programs read the output port then write it back*/);
00752         break;
00753     case 0xd1:      /* Write to outport */
00754         keyb.command=CMD_SETOUTPORT;
00755         break;
00756     case 0xd2:      /* write output register */
00757         keyb.command=CMD_WRITEOUTPUT;
00758         break;
00759     case 0xd3:      /* write AUX output */
00760         if (keyb.enable_aux)
00761             keyb.command=CMD_WRITEAUXOUT;
00762         else if (aux_warning++ == 0)
00763             LOG(LOG_KEYBOARD,LOG_ERROR)("Program is writing 8042 AUX. If you intend to use PS/2 mouse emulation you may consider adding aux=1 to your dosbox.conf");
00764         break;
00765     case 0xd4:      /* send byte to AUX */
00766         if (keyb.enable_aux)
00767             keyb.command=CMD_WRITEAUX;
00768         else if (aux_warning++ == 0)
00769             LOG(LOG_KEYBOARD,LOG_ERROR)("Program is writing 8042 AUX. If you intend to use PS/2 mouse emulation you may consider adding aux=1 to your dosbox.conf");
00770         break;
00771     case 0xe0:      /* read test port */
00772         KEYBOARD_Add8042Response(0x00);
00773         break;
00774     case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
00775     case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
00776         /* pulse output register */
00777         if (!(val & 1)) {
00778             if (allow_keyb_reset) {
00779                 LOG_MSG("Restart by keyboard controller requested\n");
00780                 On_Software_CPU_Reset();
00781             }
00782             else {
00783                 LOG_MSG("WARNING: Keyboard output port written (pulsed) with bit 1 clear. Is the guest OS or application attempting to reset the system?\n");
00784             }
00785         }
00786         break;
00787     default:
00788         LOG(LOG_KEYBOARD,LOG_ERROR)("Port 64 write with val %d",(int)val);
00789         break;
00790     }
00791 }
00792 
00793 static Bitu read_p64(Bitu port,Bitu iolen) {
00794     (void)port;//UNUSED
00795     (void)iolen;//UNUSED
00796     Bit8u status= 0x1c | (keyb.p60changed?0x1:0x0) | (keyb.auxchanged?0x20:0x00);
00797     return status;
00798 }
00799 
00800 void KEYBOARD_AddKey3(KBD_KEYS keytype,bool pressed) {
00801     Bit8u ret=0,ret2=0;
00802 
00803     if (keyb.reset)
00804         return;
00805 
00806     /* if the keyboard is disabled, then store the keystroke but don't transmit yet */
00807     /*
00808     if (!keyb.active || !keyb.scanning) {
00809         keyb.pending_key = keytype;
00810         keyb.pending_key_state = pressed;
00811         return;
00812     }
00813     */
00814 
00815     switch (keytype) {
00816     case KBD_kor_hancha:
00817         keyb.repeat.key=KBD_NONE;
00818         keyb.repeat.wait=0;
00819         if (!pressed) return;
00820         KEYBOARD_AddBuffer(0xF1);
00821         break;
00822     case KBD_kor_hanyong:
00823         keyb.repeat.key=KBD_NONE;
00824         keyb.repeat.wait=0;
00825         if (!pressed) return;
00826         KEYBOARD_AddBuffer(0xF2);
00827         break;
00828     case KBD_esc:ret=0x08;break;
00829     case KBD_1:ret=0x16;break;
00830     case KBD_2:ret=0x1E;break;
00831     case KBD_3:ret=0x26;break;      
00832     case KBD_4:ret=0x25;break;
00833     case KBD_5:ret=0x2e;break;
00834     case KBD_6:ret=0x36;break;      
00835     case KBD_7:ret=0x3d;break;
00836     case KBD_8:ret=0x3e;break;
00837     case KBD_9:ret=0x46;break;      
00838     case KBD_0:ret=0x45;break;
00839 
00840     case KBD_minus:ret=0x4e;break;
00841     case KBD_equals:ret=0x55;break;
00842     case KBD_kpequals:ret=0x0F;break; /* According to Battler */
00843     case KBD_backspace:ret=0x66;break;
00844     case KBD_tab:ret=0x0d;break;
00845 
00846     case KBD_q:ret=0x15;break;      
00847     case KBD_w:ret=0x1d;break;
00848     case KBD_e:ret=0x24;break;      
00849     case KBD_r:ret=0x2d;break;
00850     case KBD_t:ret=0x2c;break;      
00851     case KBD_y:ret=0x35;break;
00852     case KBD_u:ret=0x3c;break;      
00853     case KBD_i:ret=0x43;break;
00854     case KBD_o:ret=0x44;break;      
00855     case KBD_p:ret=0x4d;break;
00856 
00857     case KBD_leftbracket:ret=0x54;break;
00858     case KBD_rightbracket:ret=0x5b;break;
00859     case KBD_enter:ret=0x5a;break;
00860     case KBD_leftctrl:ret=0x11;break;
00861 
00862     case KBD_a:ret=0x1c;break;
00863     case KBD_s:ret=0x1b;break;
00864     case KBD_d:ret=0x23;break;
00865     case KBD_f:ret=0x2b;break;
00866     case KBD_g:ret=0x34;break;      
00867     case KBD_h:ret=0x33;break;      
00868     case KBD_j:ret=0x3b;break;
00869     case KBD_k:ret=0x42;break;      
00870     case KBD_l:ret=0x4b;break;
00871 
00872     case KBD_semicolon:ret=0x4c;break;
00873     case KBD_quote:ret=0x52;break;
00874     case KBD_jp_hankaku:ret=0x0e;break;
00875     case KBD_grave:ret=0x0e;break;
00876     case KBD_leftshift:ret=0x12;break;
00877     case KBD_backslash:ret=0x5c;break;
00878     case KBD_z:ret=0x1a;break;
00879     case KBD_x:ret=0x22;break;
00880     case KBD_c:ret=0x21;break;
00881     case KBD_v:ret=0x2a;break;
00882     case KBD_b:ret=0x32;break;
00883     case KBD_n:ret=0x31;break;
00884     case KBD_m:ret=0x3a;break;
00885 
00886     case KBD_comma:ret=0x41;break;
00887     case KBD_period:ret=0x49;break;
00888     case KBD_slash:ret=0x4a;break;
00889     case KBD_rightshift:ret=0x59;break;
00890     case KBD_kpmultiply:ret=0x7e;break;
00891     case KBD_leftalt:ret=0x19;break;
00892     case KBD_space:ret=0x29;break;
00893     case KBD_capslock:ret=0x14;break;
00894 
00895     case KBD_f1:ret=0x07;break;
00896     case KBD_f2:ret=0x0f;break;
00897     case KBD_f3:ret=0x17;break;
00898     case KBD_f4:ret=0x1f;break;
00899     case KBD_f5:ret=0x27;break;
00900     case KBD_f6:ret=0x2f;break;
00901     case KBD_f7:ret=0x37;break;
00902     case KBD_f8:ret=0x3f;break;
00903     case KBD_f9:ret=0x47;break;
00904     case KBD_f10:ret=0x4f;break;
00905     case KBD_f11:ret=0x56;break;
00906     case KBD_f12:ret=0x5e;break;
00907 
00908     /* IBM F13-F24 = Shift F1-F12 */
00909     case KBD_f13:ret=0x12;ret2=0x07;break;
00910     case KBD_f14:ret=0x12;ret2=0x0F;break;
00911     case KBD_f15:ret=0x12;ret2=0x17;break;
00912     case KBD_f16:ret=0x12;ret2=0x1F;break;
00913     case KBD_f17:ret=0x12;ret2=0x27;break;
00914     case KBD_f18:ret=0x12;ret2=0x2F;break;
00915     case KBD_f19:ret=0x12;ret2=0x37;break;
00916     case KBD_f20:ret=0x12;ret2=0x3F;break;
00917     case KBD_f21:ret=0x12;ret2=0x47;break;
00918     case KBD_f22:ret=0x12;ret2=0x4F;break;
00919     case KBD_f23:ret=0x12;ret2=0x56;break;
00920     case KBD_f24:ret=0x12;ret2=0x5E;break;
00921 
00922     case KBD_numlock:ret=0x76;break;
00923     case KBD_scrolllock:ret=0x5f;break;
00924 
00925     case KBD_kp7:ret=0x6c;break;
00926     case KBD_kp8:ret=0x75;break;
00927     case KBD_kp9:ret=0x7d;break;
00928     case KBD_kpminus:ret=0x84;break;
00929     case KBD_kp4:ret=0x6b;break;
00930     case KBD_kp5:ret=0x73;break;
00931     case KBD_kp6:ret=0x74;break;
00932     case KBD_kpplus:ret=0x7c;break;
00933     case KBD_kp1:ret=0x69;break;
00934     case KBD_kp2:ret=0x72;break;
00935     case KBD_kp3:ret=0x7a;break;
00936     case KBD_kp0:ret=0x70;break;
00937     case KBD_kpperiod:ret=0x71;break;
00938 
00939 /*  case KBD_extra_lt_gt:ret=;break; */
00940 
00941     //The Extended keys
00942 
00943     case KBD_kpenter:ret=0x79;break;
00944     case KBD_rightctrl:ret=0x58;break;
00945     case KBD_kpdivide:ret=0x77;break;
00946     case KBD_rightalt:ret=0x39;break;
00947     case KBD_home:ret=0x6e;break;
00948     case KBD_up:ret=0x63;break;
00949     case KBD_pageup:ret=0x6f;break;
00950     case KBD_left:ret=0x61;break;
00951     case KBD_right:ret=0x6a;break;
00952     case KBD_end:ret=0x65;break;
00953     case KBD_down:ret=0x60;break;
00954     case KBD_pagedown:ret=0x6d;break;
00955     case KBD_insert:ret=0x67;break;
00956     case KBD_delete:ret=0x64;break;
00957     case KBD_pause:ret=0x62;break;
00958     case KBD_printscreen:ret=0x57;break;
00959     case KBD_lwindows:ret=0x8B;break;
00960     case KBD_rwindows:ret=0x8C;break;
00961     case KBD_rwinmenu:ret=0x8D;break;
00962     case KBD_jp_muhenkan:ret=0x85;break;
00963     case KBD_jp_henkan:ret=0x86;break;
00964     case KBD_jp_hiragana:ret=0x87;break;/*also Katakana */
00965     default:
00966         LOG(LOG_MISC, LOG_WARN)("Unsupported key press %lu", (unsigned long)keytype);
00967         return;
00968     }
00969 
00970     /* Add the actual key in the keyboard queue */
00971     if (pressed) {
00972         if (keyb.repeat.key==keytype) keyb.repeat.wait=keyb.repeat.rate;        
00973         else keyb.repeat.wait=keyb.repeat.pause;
00974         keyb.repeat.key=keytype;
00975     } else {
00976         if (keytype >= KBD_f13 && keytype <= KBD_f24) {
00977             unsigned int t = ret;
00978             ret = ret2;
00979             ret2 = t;
00980         }
00981 
00982         keyb.repeat.key=KBD_NONE;
00983         keyb.repeat.wait=0;
00984     }
00985 
00986     if (!pressed) KEYBOARD_AddBuffer(0xf0);
00987     KEYBOARD_AddBuffer(ret);
00988     if (ret2 != 0) {
00989         if (!pressed) KEYBOARD_AddBuffer(0xf0);
00990         KEYBOARD_AddBuffer(ret2);
00991     }
00992 }
00993 
00994 void KEYBOARD_AddKey2(KBD_KEYS keytype,bool pressed) {
00995     Bit8u ret=0,ret2=0;bool extend=false;
00996 
00997     if (keyb.reset)
00998         return;
00999 
01000     /* if the keyboard is disabled, then store the keystroke but don't transmit yet */
01001     /*if (!keyb.active || !keyb.scanning) {
01002         keyb.pending_key = keytype;
01003         keyb.pending_key_state = pressed;
01004         return;
01005     }*/
01006 
01007     switch (keytype) {
01008     case KBD_kor_hancha:
01009         keyb.repeat.key=KBD_NONE;
01010         keyb.repeat.wait=0;
01011         if (!pressed) return;
01012         KEYBOARD_AddBuffer(0xF1);
01013         break;
01014     case KBD_kor_hanyong:
01015         keyb.repeat.key=KBD_NONE;
01016         keyb.repeat.wait=0;
01017         if (!pressed) return;
01018         KEYBOARD_AddBuffer(0xF2);
01019         break;
01020     case KBD_esc:ret=0x76;break;
01021     case KBD_1:ret=0x16;break;
01022     case KBD_2:ret=0x1e;break;
01023     case KBD_3:ret=0x26;break;      
01024     case KBD_4:ret=0x25;break;
01025     case KBD_5:ret=0x2e;break;
01026     case KBD_6:ret=0x36;break;      
01027     case KBD_7:ret=0x3d;break;
01028     case KBD_8:ret=0x3e;break;
01029     case KBD_9:ret=0x46;break;      
01030     case KBD_0:ret=0x45;break;
01031 
01032     case KBD_minus:ret=0x4e;break;
01033     case KBD_equals:ret=0x55;break;
01034     case KBD_kpequals:ret=0x0F;break; /* According to Battler */
01035     case KBD_backspace:ret=0x66;break;
01036     case KBD_tab:ret=0x0d;break;
01037 
01038     case KBD_q:ret=0x15;break;      
01039     case KBD_w:ret=0x1d;break;
01040     case KBD_e:ret=0x24;break;      
01041     case KBD_r:ret=0x2d;break;
01042     case KBD_t:ret=0x2c;break;      
01043     case KBD_y:ret=0x35;break;
01044     case KBD_u:ret=0x3c;break;      
01045     case KBD_i:ret=0x43;break;
01046     case KBD_o:ret=0x44;break;      
01047     case KBD_p:ret=0x4d;break;
01048 
01049     case KBD_leftbracket:ret=0x54;break;
01050     case KBD_rightbracket:ret=0x5b;break;
01051     case KBD_enter:ret=0x5a;break;
01052     case KBD_leftctrl:ret=0x14;break;
01053 
01054     case KBD_a:ret=0x1c;break;
01055     case KBD_s:ret=0x1b;break;
01056     case KBD_d:ret=0x23;break;
01057     case KBD_f:ret=0x2b;break;
01058     case KBD_g:ret=0x34;break;      
01059     case KBD_h:ret=0x33;break;      
01060     case KBD_j:ret=0x3b;break;
01061     case KBD_k:ret=0x42;break;      
01062     case KBD_l:ret=0x4b;break;
01063 
01064     case KBD_semicolon:ret=0x4c;break;
01065     case KBD_quote:ret=0x52;break;
01066     case KBD_jp_hankaku:ret=0x0e;break;
01067     case KBD_grave:ret=0x0e;break;
01068     case KBD_leftshift:ret=0x12;break;
01069     case KBD_backslash:ret=0x5d;break;
01070     case KBD_z:ret=0x1a;break;
01071     case KBD_x:ret=0x22;break;
01072     case KBD_c:ret=0x21;break;
01073     case KBD_v:ret=0x2a;break;
01074     case KBD_b:ret=0x32;break;
01075     case KBD_n:ret=0x31;break;
01076     case KBD_m:ret=0x3a;break;
01077 
01078     case KBD_comma:ret=0x41;break;
01079     case KBD_period:ret=0x49;break;
01080     case KBD_slash:ret=0x4a;break;
01081     case KBD_rightshift:ret=0x59;break;
01082     case KBD_kpmultiply:ret=0x7c;break;
01083     case KBD_leftalt:ret=0x11;break;
01084     case KBD_space:ret=0x29;break;
01085     case KBD_capslock:ret=0x58;break;
01086 
01087     case KBD_f1:ret=0x05;break;
01088     case KBD_f2:ret=0x06;break;
01089     case KBD_f3:ret=0x04;break;
01090     case KBD_f4:ret=0x0c;break;
01091     case KBD_f5:ret=0x03;break;
01092     case KBD_f6:ret=0x0b;break;
01093     case KBD_f7:ret=0x83;break;
01094     case KBD_f8:ret=0x0a;break;
01095     case KBD_f9:ret=0x01;break;
01096     case KBD_f10:ret=0x09;break;
01097     case KBD_f11:ret=0x78;break;
01098     case KBD_f12:ret=0x07;break;
01099 
01100     /* IBM F13-F24 = Shift F1-F12 */
01101     case KBD_f13:ret=0x12;ret2=0x05;break;
01102     case KBD_f14:ret=0x12;ret2=0x06;break;
01103     case KBD_f15:ret=0x12;ret2=0x04;break;
01104     case KBD_f16:ret=0x12;ret2=0x0c;break;
01105     case KBD_f17:ret=0x12;ret2=0x03;break;
01106     case KBD_f18:ret=0x12;ret2=0x0b;break;
01107     case KBD_f19:ret=0x12;ret2=0x83;break;
01108     case KBD_f20:ret=0x12;ret2=0x0a;break;
01109     case KBD_f21:ret=0x12;ret2=0x01;break;
01110     case KBD_f22:ret=0x12;ret2=0x09;break;
01111     case KBD_f23:ret=0x12;ret2=0x78;break;
01112     case KBD_f24:ret=0x12;ret2=0x07;break;
01113 
01114     case KBD_numlock:ret=0x77;break;
01115     case KBD_scrolllock:ret=0x7e;break;
01116 
01117     case KBD_kp7:ret=0x6c;break;
01118     case KBD_kp8:ret=0x75;break;
01119     case KBD_kp9:ret=0x7d;break;
01120     case KBD_kpminus:ret=0x7b;break;
01121     case KBD_kp4:ret=0x6b;break;
01122     case KBD_kp5:ret=0x73;break;
01123     case KBD_kp6:ret=0x74;break;
01124     case KBD_kpplus:ret=0x79;break;
01125     case KBD_kp1:ret=0x69;break;
01126     case KBD_kp2:ret=0x72;break;
01127     case KBD_kp3:ret=0x7a;break;
01128     case KBD_kp0:ret=0x70;break;
01129     case KBD_kpperiod:ret=0x71;break;
01130 
01131 /*  case KBD_extra_lt_gt:ret=;break; */
01132 
01133     //The Extended keys
01134 
01135     case KBD_kpenter:extend=true;ret=0x5a;break;
01136     case KBD_rightctrl:extend=true;ret=0x14;break;
01137     case KBD_kpdivide:extend=true;ret=0x4a;break;
01138     case KBD_rightalt:extend=true;ret=0x11;break;
01139     case KBD_home:extend=true;ret=0x6c;break;
01140     case KBD_up:extend=true;ret=0x75;break;
01141     case KBD_pageup:extend=true;ret=0x7d;break;
01142     case KBD_left:extend=true;ret=0x6b;break;
01143     case KBD_right:extend=true;ret=0x74;break;
01144     case KBD_end:extend=true;ret=0x69;break;
01145     case KBD_down:extend=true;ret=0x72;break;
01146     case KBD_pagedown:extend=true;ret=0x7a;break;
01147     case KBD_insert:extend=true;ret=0x70;break;
01148     case KBD_delete:extend=true;ret=0x71;break;
01149     case KBD_pause:
01150         KEYBOARD_AddBuffer(0xe1);
01151         KEYBOARD_AddBuffer(0x14);
01152         KEYBOARD_AddBuffer(0x77);
01153         KEYBOARD_AddBuffer(0xe1);
01154         KEYBOARD_AddBuffer(0xf0);
01155         KEYBOARD_AddBuffer(0x14);
01156         KEYBOARD_AddBuffer(0xf0);
01157         KEYBOARD_AddBuffer(0x77);
01158         return;
01159     case KBD_printscreen:
01160         extend=true;
01161         if (pressed) { ret=0x12; ret2=0x7c; }
01162         else         { ret=0x7c; ret2=0x12; }
01163         return;
01164     case KBD_lwindows:extend=true;ret=0x1f;break;
01165     case KBD_rwindows:extend=true;ret=0x27;break;
01166     case KBD_rwinmenu:extend=true;ret=0x2f;break;
01167     case KBD_jp_muhenkan:ret=0x67;break;
01168     case KBD_jp_henkan:ret=0x64;break;
01169     case KBD_jp_hiragana:ret=0x13;break;/*also Katakana */
01170     default:
01171         LOG(LOG_MISC, LOG_WARN)("Unsupported key press %lu", (unsigned long)keytype);
01172         return;
01173     }
01174     /* Add the actual key in the keyboard queue */
01175     if (pressed) {
01176         if (keyb.repeat.key==keytype) keyb.repeat.wait=keyb.repeat.rate;        
01177         else keyb.repeat.wait=keyb.repeat.pause;
01178         keyb.repeat.key=keytype;
01179     } else {
01180         if (keytype >= KBD_f13 && keytype <= KBD_f24) {
01181             unsigned int t = ret;
01182             ret = ret2;
01183             ret2 = t;
01184         }
01185 
01186         keyb.repeat.key=KBD_NONE;
01187         keyb.repeat.wait=0;
01188     }
01189 
01190     if (extend) KEYBOARD_AddBuffer(0xe0);
01191     if (!pressed) KEYBOARD_AddBuffer(0xf0);
01192     KEYBOARD_AddBuffer(ret);
01193     if (ret2 != 0) {
01194         if (extend) KEYBOARD_AddBuffer(0xe0); 
01195         if (!pressed) KEYBOARD_AddBuffer(0xf0);
01196         KEYBOARD_AddBuffer(ret2);
01197     }
01198 }
01199 
01200 bool pc98_caps(void);
01201 bool pc98_kana(void);
01202 void pc98_caps_toggle(void);
01203 void pc98_kana_toggle(void);
01204 void pc98_numlock_toggle(void);
01205 void pc98_keyboard_send(const unsigned char b);
01206 bool pc98_force_ibm_layout = false;
01207 
01208 /* this version sends to the PC-98 8251 emulation NOT the AT 8042 emulation */
01209 void KEYBOARD_PC98_AddKey(KBD_KEYS keytype,bool pressed) {
01210     Bit8u ret=0;
01211 
01212     switch (keytype) {                          // NAME or
01213                                                 // NM SH KA KA+SH       NM=no-mod SH=shift KA=kana KA+SH=kana+shift
01214     case KBD_esc:           ret=0x00;break;     // ESC
01215     case KBD_1:             ret=0x01;break;     // 1  !  ヌ
01216     case KBD_2:             ret=0x02;break;     // 2  "  フ
01217     case KBD_3:             ret=0x03;break;     // 3  #  ア ァ
01218     case KBD_4:             ret=0x04;break;     // 4  $  ウ ゥ
01219     case KBD_5:             ret=0x05;break;     // 5  %  エ ェ
01220     case KBD_6:             ret=0x06;break;     // 6  &  オ ォ
01221     case KBD_7:             ret=0x07;break;     // 7  '  ヤ ャ
01222     case KBD_8:             ret=0x08;break;     // 8  (  ユ ュ
01223     case KBD_9:             ret=0x09;break;     // 9  )  ヨ ョ
01224     case KBD_0:             ret=0x0A;break;     // 0     ワ ヲ
01225     case KBD_minus:         ret=0x0B;break;     // -  =  ホ
01226     case KBD_equals:        ret=0x0C;break;     // ^  `  ヘ             US keyboard layout hack
01227     case KBD_caret:         ret=0x0C;break;     // ^  `  ヘ
01228     case KBD_backslash:     ret=0x0D;break;     // ¥  |  ー
01229     case KBD_jp_yen:        ret=0x0D;break;     // ¥  |  ー
01230     case KBD_backspace:     ret=0x0E;break;     // BS (BACKSPACE)
01231     case KBD_tab:           ret=0x0F;break;     // TAB
01232     case KBD_q:             ret=0x10;break;     // q  Q  タ
01233     case KBD_w:             ret=0x11;break;     // w  W  テ
01234     case KBD_e:             ret=0x12;break;     // e  E  イ ィ
01235     case KBD_r:             ret=0x13;break;     // r  R  ス
01236     case KBD_t:             ret=0x14;break;     // t  T  カ
01237     case KBD_y:             ret=0x15;break;     // y  Y  ン
01238     case KBD_u:             ret=0x16;break;     // u  U  ナ
01239     case KBD_i:             ret=0x17;break;     // i  I  ニ
01240     case KBD_o:             ret=0x18;break;     // o  O  ラ
01241     case KBD_p:             ret=0x19;break;     // p  P  セ
01242     case KBD_atsign:        ret=0x1A;break;     // @  ~  ゙
01243     case KBD_leftbracket:   ret=0x1B;break;     // [  {  ゚  「
01244     case KBD_enter:         ret=0x1C;break;     // ENTER/RETURN
01245     case KBD_kpenter:       ret=0x1C;break;     // ENTER/RETURN (KEYPAD)
01246     case KBD_a:             ret=0x1D;break;     // a  A  チ
01247     case KBD_s:             ret=0x1E;break;     // s  S  ト
01248     case KBD_d:             ret=0x1F;break;     // d  D  シ
01249     case KBD_f:             ret=0x20;break;     // f  F  ハ
01250     case KBD_g:             ret=0x21;break;     // g  G  キ
01251     case KBD_h:             ret=0x22;break;     // h  H  ク
01252     case KBD_j:             ret=0x23;break;     // j  J  マ
01253     case KBD_k:             ret=0x24;break;     // k  K  ノ
01254     case KBD_l:             ret=0x25;break;     // l  L  リ
01255     case KBD_semicolon:     ret=0x26;break;     // ;  +  レ
01256     case KBD_quote:         ret=0x27;break;     // :  *  ケ         American US keyboard layout hack
01257     case KBD_colon:         ret=0x27;break;     // :  *  ケ
01258     case KBD_rightbracket:  ret=0x28;break;     // ]  }  ム 」
01259     case KBD_z:             ret=0x29;break;     // z  Z  ツ ッ
01260     case KBD_x:             ret=0x2A;break;     // x  X  サ
01261     case KBD_c:             ret=0x2B;break;     // c  C  ソ
01262     case KBD_v:             ret=0x2C;break;     // v  V  ヒ
01263     case KBD_b:             ret=0x2D;break;     // b  B  コ
01264     case KBD_n:             ret=0x2E;break;     // n  N  ミ
01265     case KBD_m:             ret=0x2F;break;     // m  M  モ
01266     case KBD_comma:         ret=0x30;break;     // ,  <  ネ 、
01267     case KBD_period:        ret=0x31;break;     // .  >  ル 。
01268     case KBD_slash:         ret=0x32;break;     // /  ?  メ ・
01269     case KBD_jp_ro:         ret=0x33;break;     //    _  ロ
01270     case KBD_space:         ret=0x34;break;     // SPACEBAR
01271     case KBD_xfer:          ret=0x35;break;     // XFER
01272     case KBD_pageup:        ret=0x36;break;     // ROLL UP
01273     case KBD_pagedown:      ret=0x37;break;     // ROLL DOWN
01274     case KBD_insert:        ret=0x38;break;     // INS
01275     case KBD_delete:        ret=0x39;break;     // DEL
01276     case KBD_up:            ret=0x3A;break;     // UP ARROW
01277     case KBD_left:          ret=0x3B;break;     // LEFT ARROW
01278     case KBD_right:         ret=0x3C;break;     // RIGHT ARROW
01279     case KBD_down:          ret=0x3D;break;     // DOWN ARROW
01280     case KBD_home:          ret=0x3E;break;     // HOME / CLR
01281     case KBD_help:          ret=0x3F;break;     // HELP
01282     case KBD_kpminus:       ret=0x40;break;     // - (KEYPAD)
01283     case KBD_kpdivide:      ret=0x41;break;     // / (KEYPAD)
01284     case KBD_kp7:           ret=0x42;break;     // 7 (KEYPAD)
01285     case KBD_kp8:           ret=0x43;break;     // 8 (KEYPAD)
01286     case KBD_kp9:           ret=0x44;break;     // 9 (KEYPAD)
01287     case KBD_kpmultiply:    ret=0x45;break;     // * (KEYPAD)
01288     case KBD_kp4:           ret=0x46;break;     // 4 (KEYPAD)
01289     case KBD_kp5:           ret=0x47;break;     // 5 (KEYPAD)
01290     case KBD_kp6:           ret=0x48;break;     // 6 (KEYPAD)
01291     case KBD_kpplus:        ret=0x49;break;     // + (KEYPAD)
01292     case KBD_kp1:           ret=0x4A;break;     // 1 (KEYPAD)
01293     case KBD_kp2:           ret=0x4B;break;     // 2 (KEYPAD)
01294     case KBD_kp3:           ret=0x4C;break;     // 3 (KEYPAD)
01295     case KBD_kpequals:      ret=0x4D;break;     // = (KEYPAD)
01296     case KBD_kp0:           ret=0x4E;break;     // 0 (KEYPAD)
01297     case KBD_kpcomma:       ret=0x4F;break;     // , (KEYPAD)
01298     case KBD_kpperiod:      ret=0x50;break;     // . (KEYPAD)
01299     case KBD_nfer:          ret=0x51;break;     // NFER
01300     case KBD_vf1:           ret=0x52;break;     // vf・1
01301     case KBD_vf2:           ret=0x53;break;     // vf・2
01302     case KBD_vf3:           ret=0x54;break;     // vf・3
01303     case KBD_vf4:           ret=0x55;break;     // vf・4
01304     case KBD_vf5:           ret=0x56;break;     // vf・5
01305     case KBD_stop:          ret=0x60;break;     // STOP
01306     case KBD_copy:          ret=0x61;break;     // COPY
01307     case KBD_f1:            ret=0x62;break;     // f・1
01308     case KBD_f2:            ret=0x63;break;     // f・2
01309     case KBD_f3:            ret=0x64;break;     // f・3
01310     case KBD_f4:            ret=0x65;break;     // f・4
01311     case KBD_f5:            ret=0x66;break;     // f・5
01312     case KBD_f6:            ret=0x67;break;     // f・6
01313     case KBD_f7:            ret=0x68;break;     // f・7
01314     case KBD_f8:            ret=0x69;break;     // f・8
01315     case KBD_f9:            ret=0x6A;break;     // f・9
01316     case KBD_f10:           ret=0x6B;break;     // f・10
01317     case KBD_leftshift:     ret=0x70;break;     // SHIFT
01318     case KBD_rightshift:    ret=0x70;break;     // SHIFT
01319     case KBD_leftalt:       ret=0x73;break;     // GRPH (handled by Windows as if ALT key)
01320     case KBD_rightalt:      ret=0x73;break;     // GRPH (handled by Windows as if ALT key)
01321     case KBD_leftctrl:      ret=0x74;break;     // CTRL
01322     case KBD_rightctrl:     ret=0x74;break;     // CTRL
01323     case KBD_grave:
01324         if(pc98_force_ibm_layout)
01325             ret=0x1A; //HACK, reuse @ key
01326         break;
01327     
01328     case KBD_capslock:                          // CAPS
01329         if (pressed) {                          // sends only on keypress, does not resend if held down
01330             pc98_caps_toggle();
01331             pc98_keyboard_send(0x71 | (!pc98_caps() ? 0x80 : 0x00)); // make code if caps switched on, break if caps switched off
01332         }
01333         return;
01334 
01335     case KBD_numlock:                           // NUM
01336         pc98_numlock_toggle();
01337         return;
01338 
01339     case KBD_kana:                              // KANA
01340         if (pressed) {                          // sends only on keypress, does not resend if held down
01341             pc98_kana_toggle();
01342             pc98_keyboard_send(0x72 | (!pc98_kana() ? 0x80 : 0x00)); // make code if caps switched on, break if caps switched off
01343         }
01344         return;
01345 
01346     default: return;
01347     };
01348 
01349     /* PC-98 keyboards appear to repeat make/break codes when the key is held down */
01350     if (pressed && keyb.repeat.key == keytype)
01351         pc98_keyboard_send(ret | 0x80);
01352 
01353     /* Add the actual key in the keyboard queue */
01354     if (pressed) {
01355         if (keyb.repeat.key == keytype) keyb.repeat.wait = keyb.repeat.rate;        
01356         else keyb.repeat.wait = keyb.repeat.pause;
01357         keyb.repeat.key = keytype;
01358     } else {
01359         if (keyb.repeat.key == keytype) {
01360             /* repeated key being released */
01361             keyb.repeat.key  = KBD_NONE;
01362             keyb.repeat.wait = 0;
01363         }
01364     }
01365 
01366     if (!pressed) ret |= 0x80;
01367 
01368     pc98_keyboard_send(ret | (!pressed ? 0x80 : 0x00));
01369 }
01370 
01371 void KEYBOARD_AddKey1(KBD_KEYS keytype,bool pressed) {
01372     Bit8u ret=0,ret2=0;bool extend=false;
01373 
01374     if (keyb.reset)
01375         return;
01376 
01377     /* if the keyboard is disabled, then store the keystroke but don't transmit yet */
01378     /*if (!keyb.active || !keyb.scanning) {
01379         keyb.pending_key = keytype;
01380         keyb.pending_key_state = pressed;
01381         return;
01382     }*/
01383 
01384     switch (keytype) {
01385     case KBD_kor_hancha:
01386         keyb.repeat.key=KBD_NONE;
01387         keyb.repeat.wait=0;
01388         if (!pressed) return;
01389         KEYBOARD_AddBuffer(0xF1);
01390         break;
01391     case KBD_kor_hanyong:
01392         keyb.repeat.key=KBD_NONE;
01393         keyb.repeat.wait=0;
01394         if (!pressed) return;
01395         KEYBOARD_AddBuffer(0xF2);
01396         break;
01397     case KBD_esc:ret=1;break;
01398     case KBD_1:ret=2;break;
01399     case KBD_2:ret=3;break;
01400     case KBD_3:ret=4;break;     
01401     case KBD_4:ret=5;break;
01402     case KBD_5:ret=6;break;
01403     case KBD_6:ret=7;break;     
01404     case KBD_7:ret=8;break;
01405     case KBD_8:ret=9;break;
01406     case KBD_9:ret=10;break;        
01407     case KBD_0:ret=11;break;
01408 
01409     case KBD_minus:ret=12;break;
01410     case KBD_equals:ret=13;break;
01411     case KBD_kpequals:ret=0x59;break; /* According to Battler */
01412     case KBD_backspace:ret=14;break;
01413     case KBD_tab:ret=15;break;
01414 
01415     case KBD_q:ret=16;break;        
01416     case KBD_w:ret=17;break;
01417     case KBD_e:ret=18;break;        
01418     case KBD_r:ret=19;break;
01419     case KBD_t:ret=20;break;        
01420     case KBD_y:ret=21;break;
01421     case KBD_u:ret=22;break;        
01422     case KBD_i:ret=23;break;
01423     case KBD_o:ret=24;break;        
01424     case KBD_p:ret=25;break;
01425 
01426     case KBD_leftbracket:ret=26;break;
01427     case KBD_rightbracket:ret=27;break;
01428     case KBD_enter:ret=28;break;
01429     case KBD_leftctrl:
01430         ret=29;
01431         keyb.leftctrl_pressed=pressed;
01432         break;
01433 
01434     case KBD_a:ret=30;break;
01435     case KBD_s:ret=31;break;
01436     case KBD_d:ret=32;break;
01437     case KBD_f:ret=33;break;
01438     case KBD_g:ret=34;break;        
01439     case KBD_h:ret=35;break;        
01440     case KBD_j:ret=36;break;
01441     case KBD_k:ret=37;break;        
01442     case KBD_l:ret=38;break;
01443 
01444     case KBD_semicolon:ret=39;break;
01445     case KBD_quote:ret=40;break;
01446     case KBD_jp_hankaku:ret=41;break;
01447     case KBD_grave:ret=41;break;
01448     case KBD_leftshift:ret=42;break;
01449     case KBD_backslash:ret=43;break;
01450     case KBD_z:ret=44;break;
01451     case KBD_x:ret=45;break;
01452     case KBD_c:ret=46;break;
01453     case KBD_v:ret=47;break;
01454     case KBD_b:ret=48;break;
01455     case KBD_n:ret=49;break;
01456     case KBD_m:ret=50;break;
01457 
01458     case KBD_comma:ret=51;break;
01459     case KBD_period:ret=52;break;
01460     case KBD_slash:ret=53;break;
01461     case KBD_rightshift:ret=54;break;
01462     case KBD_kpmultiply:ret=55;break;
01463     case KBD_leftalt:ret=56;break;
01464     case KBD_space:ret=57;break;
01465     case KBD_capslock:ret=58;break;
01466 
01467     case KBD_f1:ret=59;break;
01468     case KBD_f2:ret=60;break;
01469     case KBD_f3:ret=61;break;
01470     case KBD_f4:ret=62;break;
01471     case KBD_f5:ret=63;break;
01472     case KBD_f6:ret=64;break;
01473     case KBD_f7:ret=65;break;
01474     case KBD_f8:ret=66;break;
01475     case KBD_f9:ret=67;break;
01476     case KBD_f10:ret=68;break;
01477     case KBD_f11:ret=87;break;
01478     case KBD_f12:ret=88;break;
01479 
01480     /* IBM F13-F24 apparently map to Shift + F1-F12 */
01481     case KBD_f13:ret=0x2A;ret2=59;break;
01482     case KBD_f14:ret=0x2A;ret2=60;break;
01483     case KBD_f15:ret=0x2A;ret2=61;break;
01484     case KBD_f16:ret=0x2A;ret2=62;break;
01485     case KBD_f17:ret=0x2A;ret2=63;break;
01486     case KBD_f18:ret=0x2A;ret2=64;break;
01487     case KBD_f19:ret=0x2A;ret2=65;break;
01488     case KBD_f20:ret=0x2A;ret2=66;break;
01489     case KBD_f21:ret=0x2A;ret2=67;break;
01490     case KBD_f22:ret=0x2A;ret2=68;break;
01491     case KBD_f23:ret=0x2A;ret2=87;break;
01492     case KBD_f24:ret=0x2A;ret2=88;break;
01493 
01494     case KBD_numlock:ret=69;break;
01495     case KBD_scrolllock:ret=70;break;
01496 
01497     case KBD_kp7:ret=71;break;
01498     case KBD_kp8:ret=72;break;
01499     case KBD_kp9:ret=73;break;
01500     case KBD_kpminus:ret=74;break;
01501     case KBD_kp4:ret=75;break;
01502     case KBD_kp5:ret=76;break;
01503     case KBD_kp6:ret=77;break;
01504     case KBD_kpplus:ret=78;break;
01505     case KBD_kp1:ret=79;break;
01506     case KBD_kp2:ret=80;break;
01507     case KBD_kp3:ret=81;break;
01508     case KBD_kp0:ret=82;break;
01509     case KBD_kpperiod:ret=83;break;
01510 
01511     case KBD_extra_lt_gt:ret=86;break;
01512 
01513     //The Extended keys
01514 
01515     case KBD_kpenter:extend=true;ret=28;break;
01516     case KBD_rightctrl:
01517         extend=true;ret=29;
01518         keyb.rightctrl_pressed=pressed;
01519         break;
01520     case KBD_kpdivide:extend=true;ret=53;break;
01521     case KBD_rightalt:extend=true;ret=56;break;
01522     case KBD_home:extend=true;ret=71;break;
01523     case KBD_up:extend=true;ret=72;break;
01524     case KBD_pageup:extend=true;ret=73;break;
01525     case KBD_left:extend=true;ret=75;break;
01526     case KBD_right:extend=true;ret=77;break;
01527     case KBD_end:extend=true;ret=79;break;
01528     case KBD_down:extend=true;ret=80;break;
01529     case KBD_pagedown:extend=true;ret=81;break;
01530     case KBD_insert:extend=true;ret=82;break;
01531     case KBD_delete:extend=true;ret=83;break;
01532     case KBD_pause:
01533         if (!pressed) {
01534             /* keyboards send both make&break codes for this key on
01535                key press and nothing on key release */
01536             return;
01537         }
01538         if (!keyb.leftctrl_pressed && !keyb.rightctrl_pressed) {
01539             /* neither leftctrl, nor rightctrl pressed -> PAUSE key */
01540             KEYBOARD_AddBuffer(0xe1);
01541             KEYBOARD_AddBuffer(29);
01542             KEYBOARD_AddBuffer(69);
01543             KEYBOARD_AddBuffer(0xe1);
01544             KEYBOARD_AddBuffer(29|0x80);
01545             KEYBOARD_AddBuffer(69|0x80);
01546         } else if (!keyb.leftctrl_pressed || !keyb.rightctrl_pressed) {
01547             /* exactly one of [leftctrl, rightctrl] is pressed -> Ctrl+BREAK */
01548             KEYBOARD_AddBuffer(0xe0);
01549             KEYBOARD_AddBuffer(70);
01550             KEYBOARD_AddBuffer(0xe0);
01551             KEYBOARD_AddBuffer(70|0x80);
01552         }
01553         /* pressing this key also disables any previous key repeat */
01554         keyb.repeat.key=KBD_NONE;
01555         keyb.repeat.wait=0;
01556         return;
01557     case KBD_printscreen:
01558         extend=true;
01559         if (pressed) { ret=0x2a; ret2=0x37; }
01560         else         { ret=0xb7; ret2=0xaa; }
01561         return;
01562     case KBD_lwindows:extend=true;ret=0x5B;break;
01563     case KBD_rwindows:extend=true;ret=0x5C;break;
01564     case KBD_rwinmenu:extend=true;ret=0x5D;break;
01565     case KBD_jp_muhenkan:ret=0x7B;break;
01566     case KBD_jp_henkan:ret=0x79;break;
01567     case KBD_jp_hiragana:ret=0x70;break;/*also Katakana */
01568     case KBD_jp_backslash:ret=0x73;break;/*JP 106-key: _ \ or ろ (ro)  <-- WARNING: UTF-8 unicode */
01569     case KBD_jp_yen:ret=0x7d;break;/*JP 106-key: | ¥ (yen) or ー (prolonged sound mark)  <-- WARNING: UTF-8 unicode */
01570     default:
01571         LOG(LOG_MISC, LOG_WARN)("Unsupported key press %lu", (unsigned long)keytype);
01572         return;
01573     }
01574 
01575     /* Add the actual key in the keyboard queue */
01576     if (pressed) {
01577         if (keyb.repeat.key == keytype) keyb.repeat.wait = keyb.repeat.rate;        
01578         else keyb.repeat.wait = keyb.repeat.pause;
01579         keyb.repeat.key = keytype;
01580     } else {
01581         if (keyb.repeat.key == keytype) {
01582             /* repeated key being released */
01583             keyb.repeat.key  = KBD_NONE;
01584             keyb.repeat.wait = 0;
01585         }
01586 
01587         if (keytype >= KBD_f13 && keytype <= KBD_f24) {
01588             unsigned int t = ret;
01589             ret = ret2;
01590             ret2 = t;
01591         }
01592 
01593         ret += 128;
01594         if (ret2 != 0) ret2 += 128;
01595     }
01596     if (extend) KEYBOARD_AddBuffer(0xe0);
01597     KEYBOARD_AddBuffer(ret);
01598     if (ret2 != 0) {
01599         if (extend) KEYBOARD_AddBuffer(0xe0); 
01600         KEYBOARD_AddBuffer(ret2);
01601     }
01602 }
01603 
01604 static void KEYBOARD_TickHandler(void) {
01605     if (keyb.reset)
01606         return;
01607 
01608     if (keyb.active && keyb.scanning) {
01609         if (keyb.pending_key >= 0) {
01610             KEYBOARD_AddKey((KBD_KEYS)keyb.pending_key,keyb.pending_key_state);
01611             keyb.pending_key = -1;
01612         }
01613         else if (keyb.repeat.wait) {
01614             keyb.repeat.wait--;
01615             if (!keyb.repeat.wait) KEYBOARD_AddKey(keyb.repeat.key,true);
01616         }
01617     }
01618 }
01619 
01620 void KEYBOARD_AddKey(KBD_KEYS keytype,bool pressed) {
01621     if (IS_PC98_ARCH) {
01622         KEYBOARD_PC98_AddKey(keytype,pressed);
01623     }
01624     else if (keyb.cb_xlat) {
01625         /* emulate typical setup where keyboard generates scan set 2 and controller translates to scan set 1 */
01626         /* yeah I know... yuck */
01627         KEYBOARD_AddKey1(keytype,pressed);
01628     }
01629     else {
01630         switch (keyb.scanset) {
01631             case 1: KEYBOARD_AddKey1(keytype,pressed); break;
01632             case 2: KEYBOARD_AddKey2(keytype,pressed); break;
01633             case 3: KEYBOARD_AddKey3(keytype,pressed); break;
01634         }
01635     };
01636 }
01637     
01638 static void KEYBOARD_ShutDown(Section * sec) {
01639     (void)sec;//UNUSED
01640     TIMER_DelTickHandler(&KEYBOARD_TickHandler);
01641 }
01642 
01643 bool KEYBOARD_Report_BIOS_PS2Mouse() {
01644     return keyb.enable_aux && (keyb.ps2mouse.type != MOUSE_NONE);
01645 }
01646 
01647 static IO_ReadHandleObject ReadHandler_8255_PC98[4];
01648 static IO_WriteHandleObject WriteHandler_8255_PC98[4];
01649 static IO_WriteHandleObject Reset_PC98;
01650 
01651 extern bool gdc_5mhz_mode;
01652 
01653 bool PC98_SHUT0=true,PC98_SHUT1=true;
01654 
01693 class PC98_System_8255 : public Intel8255 {
01694 public:
01695     PC98_System_8255() : Intel8255() {
01696         ppiName = "System 8255";
01697         portNames[PortA] = "DIP switches 2-1 through 2-8";
01698         portNames[PortB] = "Various system status";
01699         portNames[PortC] = "System control bits";
01700         pinNames[PortA][0] = "DIP switch 2-1";
01701         pinNames[PortA][1] = "DIP switch 2-2";
01702         pinNames[PortA][2] = "DIP switch 2-3";
01703         pinNames[PortA][3] = "DIP switch 2-4";
01704         pinNames[PortA][4] = "DIP switch 2-5";
01705         pinNames[PortA][5] = "DIP switch 2-6";
01706         pinNames[PortA][6] = "DIP switch 2-7";
01707         pinNames[PortA][7] = "DIP switch 2-8";
01708         pinNames[PortB][0] = "Read data of calendar clock (CDAT)";
01709         pinNames[PortB][1] = "Expansion RAM parity error (EMCK)";
01710         pinNames[PortB][2] = "Internal RAM parity error (IMCK)";
01711         pinNames[PortB][3] = "DIP switch 1-1 High resolution CRT type";
01712         pinNames[PortB][4] = "Expansion bus INT 3 signal";
01713         pinNames[PortB][5] = "RS-232C CD signal";
01714         pinNames[PortB][6] = "RS-232C CS signal";
01715         pinNames[PortB][7] = "RS-232C CI signal";
01716         pinNames[PortC][0] = "RS-232C enable RXRDY interrupt";
01717         pinNames[PortC][1] = "RS-232C enable TXEMPTY interrupt";
01718         pinNames[PortC][2] = "RS-232C enable TXRDY interrupt";
01719         pinNames[PortC][3] = "Buzzer inhibit";
01720         pinNames[PortC][4] = "RAM parity check enable";
01721         pinNames[PortC][5] = "Shutdown flag 1"; /* <- 286 or later */
01722         pinNames[PortC][6] = "PSTB printer signal inhibit (mask if set)";
01723         pinNames[PortC][7] = "Shutdown flag 0"; /* <- 286 or later */
01724     }
01725     virtual ~PC98_System_8255() {
01726     }
01727 public:
01728     /* port A is input */
01729     virtual uint8_t inPortA(void) const {
01730         /* TODO: Improve this! What do the various 2-1 to 2-8 switches do?
01731          *       It might help to look at the BIOS setup menus of 1990s PC-98 systems
01732          *       that offer toggling virtual versions of these DIP switches to see
01733          *       what the BIOS menu text says. */
01734         return 0x63 | (gdc_5mhz_mode ? 0x00 : 0x80); // taken from a PC-9821 Lt2
01735     }
01736     /* port B is input */
01737     virtual uint8_t inPortB(void) const {
01738         /* TODO: Improve this! */
01739         return 0xF9; // taken from a PC-9821 Lt2
01740     }
01741     /* port C is output (both halves) */
01742     virtual void outPortC(const uint8_t mask) {
01743         if (mask & 0x80) /* Shutdown flag 0 */
01744             PC98_SHUT0 = !!(latchOutPortC & 0x80);
01745 
01746         if (mask & 0x20) /* Shutdown flag 1 */
01747             PC98_SHUT1 = !!(latchOutPortC & 0x20);
01748 
01749         if (mask & 0x08) { /* PC speaker aka "buzzer". Note this bit is an inhibit, set to zero to turn on */
01750             port_61_data = (latchOutPortC & 0x08) ? 0 : 3;
01751             TIMER_SetGate2(!!port_61_data);
01752             PCSPEAKER_SetType(!!port_61_data,!!port_61_data);
01753         }
01754     }
01755 };
01756 
01757 static PC98_System_8255 pc98_sys_8255;
01758 
01759 static void pc98_reset_write(Bitu port,Bitu val,Bitu /*iolen*/) {
01760     (void)port;//UNUSED
01761     LOG_MSG("Restart by port F0h requested: val=%02x SHUT0=%u SHUT1=%u\n",(unsigned int)val,PC98_SHUT0,PC98_SHUT1);
01762     On_Software_CPU_Reset();
01763 }
01764 
01765 static void pc98_8255_write(Bitu port,Bitu val,Bitu /*iolen*/) {
01766     /* 0x31-0x37 odd */
01767     pc98_sys_8255.writeByPort((port - 0x31) >> 1U,val);
01768 }
01769 
01770 static Bitu pc98_8255_read(Bitu port,Bitu /*iolen*/) {
01771     /* 0x31-0x37 odd */
01772     return pc98_sys_8255.readByPort((port - 0x31) >> 1U);
01773 }
01774 
01775 static struct pc98_keyboard {
01776     pc98_keyboard() : caps(false), kana(false), num(false) {
01777     }
01778 
01779     bool                        caps;
01780     bool                        kana;
01781     bool                        num;
01782 } pc98_keyboard_state;
01783 
01784 bool pc98_caps(void) {
01785     return pc98_keyboard_state.caps;
01786 }
01787 
01788 bool pc98_kana(void) {
01789     return pc98_keyboard_state.kana;
01790 }
01791 
01792 void pc98_caps_toggle(void) {
01793     pc98_keyboard_state.caps = !pc98_keyboard_state.caps;
01794 }
01795 
01796 void pc98_kana_toggle(void) {
01797     pc98_keyboard_state.kana = !pc98_keyboard_state.kana;
01798 }
01799 
01800 void pc98_numlock_toggle(void) {
01801     pc98_keyboard_state.num = !pc98_keyboard_state.num;
01802 }
01803 
01804 void uart_rx_load(Bitu val);
01805 void uart_tx_load(Bitu val);
01806 void pc98_keyboard_recv_byte(Bitu val);
01807 
01808 static struct pc98_8251_keyboard_uart {
01809     enum cmdreg_state {
01810         MODE_STATE=0,
01811         SYNC_CHAR1,
01812         SYNC_CHAR2,
01813         COMMAND_STATE
01814     };
01815 
01816     unsigned char               data;
01817     unsigned char               txdata;
01818     enum cmdreg_state           state;
01819     unsigned char               mode_byte;
01820     bool                        keyboard_reset;
01821     bool                        rx_enable;
01822     bool                        tx_enable;
01823     bool                        valid_state;
01824 
01825     bool                        rx_busy;
01826     bool                        rx_ready;
01827     bool                        tx_busy;
01828     bool                        tx_empty;
01829 
01830     /* io_delay in milliseconds for use with PIC delay code */
01831     double                      io_delay_ms;
01832     double                      tx_load_ms;
01833 
01834     /* recv data from keyboard */
01835     unsigned char               recv_buffer[32];
01836     unsigned char               recv_in,recv_out;
01837 
01838     pc98_8251_keyboard_uart() : data(0xFF), txdata(0xFF), state(MODE_STATE), mode_byte(0), keyboard_reset(false), rx_enable(false), tx_enable(false), valid_state(false), rx_busy(false), rx_ready(false), tx_busy(false), tx_empty(true), recv_in(0), recv_out(0) {
01839         io_delay_ms = (((1/*start*/+8/*data*/+1/*parity*/+1/*stop*/) * 1000.0) / 19200);
01840         tx_load_ms = (((1/*start*/+8/*data*/) * 1000.0) / 19200);
01841     }
01842 
01843     void reset(void) {
01844         PIC_RemoveEvents(uart_tx_load);
01845         PIC_RemoveEvents(uart_rx_load);
01846         PIC_RemoveEvents(pc98_keyboard_recv_byte);
01847 
01848         state = MODE_STATE;
01849         rx_busy = false;
01850         rx_ready = false;
01851         tx_empty = true;
01852         tx_busy = false;
01853         mode_byte = 0;
01854         recv_out = 0;
01855         recv_in = 0;
01856     }
01857 
01858     void device_send_data(unsigned char b) {
01859         unsigned char nidx;
01860 
01861         nidx = (recv_in + 1) % 32;
01862         if (nidx == recv_out) {
01863             LOG_MSG("8251 device send recv overrun");
01864             return;
01865         }
01866 
01867         recv_buffer[recv_in] = b;
01868         recv_in = nidx;
01869 
01870         if (!rx_busy) {
01871             rx_busy = true;
01872             PIC_AddEvent(uart_rx_load,io_delay_ms,0);
01873         }
01874     }
01875 
01876     unsigned char read_data(void) {
01877         rx_ready = false;
01878         return data;
01879     }
01880 
01881     void write_data(unsigned char b) {
01882         if (!valid_state)
01883             return;
01884 
01885         if (!tx_busy) {
01886             txdata = b;
01887             tx_busy = true;
01888 
01889             PIC_AddEvent(uart_tx_load,tx_load_ms,0);
01890             PIC_AddEvent(pc98_keyboard_recv_byte,io_delay_ms,txdata);
01891         }
01892     }
01893 
01894     void tx_load_complete(void) {
01895         tx_busy = false;
01896     }
01897 
01898     void rx_load_complete(void) {
01899         if (!rx_ready) {
01900             rx_ready = true;
01901             data = recv_buffer[recv_out];
01902             recv_out = (recv_out + 1) % 32;
01903 
01904 //            LOG_MSG("8251 recv %02X",data);
01905             PIC_ActivateIRQ(1);
01906 
01907             if (recv_out != recv_in) {
01908                 PIC_AddEvent(uart_rx_load,io_delay_ms,0);
01909                 rx_busy = true;
01910             }
01911             else {
01912                 rx_busy = false;
01913             }
01914         }
01915         else {
01916             LOG_MSG("8251 warning: RX overrun");
01917             rx_busy = false;
01918         }
01919     }
01920 
01921     void xmit_finish(void) {
01922         tx_empty = true;
01923         tx_busy = false;
01924     }
01925 
01926     unsigned char read_status(void) {
01927         unsigned char r = 0;
01928 
01929         /* bit[7:7] = DSR (1=DSR at zero level)
01930          * bit[6:6] = syndet/brkdet
01931          * bit[5:5] = framing error
01932          * bit[4:4] = overrun error
01933          * bit[3:3] = parity error
01934          * bit[2:2] = TxEMPTY
01935          * bit[1:1] = RxRDY
01936          * bit[0:0] = TxRDY */
01937         r |= (!tx_busy ? 0x01 : 0x00) |
01938              (rx_ready ? 0x02 : 0x00) |
01939              (tx_empty ? 0x04 : 0x00);
01940 
01941         return r;
01942     }
01943 
01944     void writecmd(const unsigned char b) { /* write to command register */
01945         if (state == MODE_STATE) {
01946             mode_byte = b;
01947 
01948             if ((b&3) != 0) {
01949                 /* bit[7:6] = number of stop bits  (0=invalid 1=1-bit 2=1.5-bit 3=2-bit)
01950                  * bit[5:5] = even/odd parity      (1=even 0=odd)
01951                  * bit[4:4] = parity enable        (1=enable 0=disable)
01952                  * bit[3:2] = character length     (0=5  1=6  2=7  3=8)
01953                  * bit[1:0] = baud rate factor     (0=sync mode   1=1X   2=16X   3=64X)
01954                  *
01955                  * note that "baud rate factor" means how much to divide the baud rate clock to determine
01956                  * the bit rate that bits are transmitted. Typical PC-98 programming practice is to set
01957                  * the baud rate clock fed to the chip at 16X the baud rate and then specify 16X baud rate factor. */
01958                 /* async mode */
01959                 state = COMMAND_STATE;
01960 
01961                 /* keyboard must operate at 19200 baud 8 bits odd parity 16X baud rate factor */
01962                 valid_state = (b == 0x5E); /* bit[7:0] = 01 0 1 11 10 */
01963                                            /*            |  | | |  |  */
01964                                            /*            |  | | |  +---- 16X baud rate factor */
01965                                            /*            |  | | +------- 8 bits per character */
01966                                            /*            |  | +--------- parity enable */
01967                                            /*            |  +----------- odd parity */
01968                                            /*            +-------------- 1 stop bit */
01969             }
01970             else {
01971                 /* bit[7:7] = single character sync(1=single  0=double)
01972                  * bit[6:6] = external sync detect (1=syndet is an input   0=syndet is an output)
01973                  * bit[5:5] = even/odd parity      (1=even 0=odd)
01974                  * bit[4:4] = parity enable        (1=enable 0=disable)
01975                  * bit[3:2] = character length     (0=5  1=6  2=7  3=8)
01976                  * bit[1:0] = baud rate factor     (0=sync mode)
01977                  *
01978                  * I don't think anything uses the keyboard in this manner, therefore, not supported in this emulation. */
01979                 LOG_MSG("8251 keyboard warning: Mode byte synchronous mode not supported");
01980                 state = SYNC_CHAR1;
01981                 valid_state = false;
01982             }
01983         }
01984         else if (state == COMMAND_STATE) {
01985             /* bit[7:7] = Enter hunt mode (not used here)
01986              * bit[6:6] = internal reset (8251 resets, prepares to accept mode byte)
01987              * bit[5:5] = RTS inhibit (1=force RTS to zero, else RTS reflects RxRDY state of the chip)
01988              * bit[4:4] = error reset
01989              * bit[3:3] = send break character (0=normal  1=force TxD low). On PC-98 keyboard this is wired to reset pin of the keyboard CPU.
01990              * bit[2:2] = receive enable
01991              * bit[1:1] = DTR inhibit (1=force DTR to zero). Connected to PC-98 RTY pin.
01992              * bit[0:0] = transmit enable */
01993             if (b & 0x40) {
01994                 /* internal reset, returns 8251 to mode state */
01995                 state = MODE_STATE;
01996             }
01997 
01998             /* TODO: Does the 8251 take any other bits if bit 6 was set to reset the 8251? */
01999             keyboard_reset = !!(b & 0x08);
02000             rx_enable = !!(b & 0x04);
02001             tx_enable = !!(b & 0x01);
02002         }
02003     }
02004 } pc98_8251_keyboard_uart_state;
02005 
02006 void uart_tx_load(Bitu val) {
02007     (void)val;//UNUSED
02008     pc98_8251_keyboard_uart_state.tx_load_complete();
02009 }
02010 
02011 void uart_rx_load(Bitu val) {
02012     (void)val;//UNUSED
02013     pc98_8251_keyboard_uart_state.rx_load_complete();
02014 }
02015 
02016 void pc98_keyboard_send(const unsigned char b) {
02017     pc98_8251_keyboard_uart_state.device_send_data(b);
02018 }
02019 
02020 void pc98_keyboard_recv_byte(Bitu val) {
02021     pc98_8251_keyboard_uart_state.xmit_finish();
02022     LOG_MSG("PC-98 recv 0x%02x",(unsigned int)val);
02023 }
02024 
02025 static Bitu keyboard_pc98_8251_uart_41_read(Bitu port,Bitu /*iolen*/) {
02026     (void)port;//UNUSED
02027     return pc98_8251_keyboard_uart_state.read_data();
02028 }
02029 
02030 static void keyboard_pc98_8251_uart_41_write(Bitu port,Bitu val,Bitu /*iolen*/) {
02031     (void)port;//UNUSED
02032     pc98_8251_keyboard_uart_state.write_data((unsigned char)val);
02033 }
02034 
02035 static Bitu keyboard_pc98_8251_uart_43_read(Bitu port,Bitu /*iolen*/) {
02036     (void)port;//UNUSED
02037     return pc98_8251_keyboard_uart_state.read_status();
02038 }
02039 
02040 static void keyboard_pc98_8251_uart_43_write(Bitu port,Bitu val,Bitu /*iolen*/) {
02041     (void)port;//UNUSED
02042     pc98_8251_keyboard_uart_state.writecmd((unsigned char)val);
02043 }
02044 
02045 int8_t p7fd9_8255_mouse_x = 0;
02046 int8_t p7fd9_8255_mouse_y = 0;
02047 int8_t p7fd9_8255_mouse_x_latch = 0;
02048 int8_t p7fd9_8255_mouse_y_latch = 0;
02049 uint8_t p7fd9_8255_mouse_sel = 0;
02050 uint8_t p7fd9_8255_mouse_latch = 0;
02051 uint8_t p7fd8_8255_mouse_int_enable = 0;
02052 
02053 void pc98_mouse_movement_apply(int x,int y) {
02054     x += p7fd9_8255_mouse_x; if (x < -128) x = -128; if (x > 127) x = 127;
02055     y += p7fd9_8255_mouse_y; if (y < -128) y = -128; if (y > 127) y = 127;
02056     p7fd9_8255_mouse_x = (int8_t)x;
02057     p7fd9_8255_mouse_y = (int8_t)y;
02058 }
02059 
02060 void MOUSE_DummyEvent(void);
02061 
02062 bool p7fd8_8255_mouse_irq_signal = false;
02063 
02064 extern uint8_t MOUSE_IRQ;
02065 
02098 class PC98_Mouse_8255 : public Intel8255 {
02099 public:
02100     PC98_Mouse_8255() : Intel8255() {
02101         ppiName = "Mouse 8255";
02102         portNames[PortA] = "Mouse input";
02103         portNames[PortB] = "TODO";
02104         portNames[PortC] = "TODO";
02105         pinNames[PortA][0] = "MD0 (counter latch bit 0)";
02106         pinNames[PortA][1] = "MD1 (counter latch bit 1)";
02107         pinNames[PortA][2] = "MD2 (counter latch bit 2)";
02108         pinNames[PortA][3] = "MD3 (counter latch bit 3)";
02109         pinNames[PortA][4] = "?";
02110         pinNames[PortA][5] = "!Right mouse button";
02111         pinNames[PortA][6] = "!Middle mouse button";
02112         pinNames[PortA][7] = "!Left mouse button";
02113         pinNames[PortB][0] = "?";
02114         pinNames[PortB][1] = "?";
02115         pinNames[PortB][2] = "?";
02116         pinNames[PortB][3] = "?";
02117         pinNames[PortB][4] = "?";
02118         pinNames[PortB][5] = "?";
02119         pinNames[PortB][6] = "?";
02120         pinNames[PortB][7] = "?";
02121         pinNames[PortC][0] = "?";                               // read
02122         pinNames[PortC][1] = "?";                               // read
02123         pinNames[PortC][2] = "DIP SW 3-8 80286 select V30";     // read
02124         pinNames[PortC][3] = "?";                               // read
02125         pinNames[PortC][4] = "Mouse interrupt inhibit";         // write
02126         pinNames[PortC][5] = "SHL, Counter latch upper nibble"; // write
02127         pinNames[PortC][6] = "SXY, Counter latch Y (X if 0)";   // write
02128         pinNames[PortC][7] = "Counter latch and clear";         // write
02129     }
02130     virtual ~PC98_Mouse_8255() {
02131     }
02132 public:
02133     /* port A is input */
02134     virtual uint8_t inPortA(void) const {
02135         uint8_t bs;
02136         Bitu r;
02137 
02138         // bits [7:7] = !(LEFT BUTTON)
02139         // bits [6:6] = !(MIDDLE BUTTON)
02140         // bits [5:5] = !(RIGHT BUTTON)
02141         // bits [4:4] = 0 unused
02142         // bits [3:0] = 4 bit nibble latched via Port C
02143         bs = Mouse_GetButtonState();
02144         r = 0x00;
02145 
02146         if (!(bs & 1)) r |= 0x80;       // left button (inverted bit)
02147         if (!(bs & 2)) r |= 0x20;       // right button (inverted bit)
02148         if (!(bs & 4)) r |= 0x40;       // middle button (inverted bit)
02149 
02150         if (!p7fd9_8255_mouse_latch) {
02151             p7fd9_8255_mouse_x_latch = p7fd9_8255_mouse_x;
02152             p7fd9_8255_mouse_y_latch = p7fd9_8255_mouse_y;
02153         }
02154 
02155         switch (p7fd9_8255_mouse_sel) {
02156             case 0: // X delta
02157             case 1:
02158                 r |= (uint8_t)(p7fd9_8255_mouse_x_latch >> ((p7fd9_8255_mouse_sel & 1U) * 4U)) & 0xF; // sign extend is intentional
02159                 break;
02160             case 2: // Y delta
02161             case 3:
02162                 r |= (uint8_t)(p7fd9_8255_mouse_y_latch >> ((p7fd9_8255_mouse_sel & 1U) * 4U)) & 0xF; // sign extend is intentional
02163                 break;
02164         };
02165 
02166         return r;
02167     }
02168     /* port B is input */
02169     virtual uint8_t inPortB(void) const {
02170         /* TODO */
02171         return 0x00;
02172     }
02173     /* port C is input[3:0] and output[7:4] */
02174     virtual uint8_t inPortC(void) const {
02175         /* TODO */
02176         return 0x00;
02177     }
02178     /* port C is input[3:0] and output[7:4] */
02179     virtual void outPortC(const uint8_t mask) {
02180         if (mask & 0x80) { /* bit 7 */
02181             /* changing from 0 to 1 latches counters and clears them */
02182             if ((latchOutPortC & 0x80) && !p7fd9_8255_mouse_latch) { // change from 0 to 1 latches counters and clears them
02183                 p7fd9_8255_mouse_x_latch = p7fd9_8255_mouse_x;
02184                 p7fd9_8255_mouse_y_latch = p7fd9_8255_mouse_y;
02185                 p7fd9_8255_mouse_x = 0;
02186                 p7fd9_8255_mouse_y = 0;
02187             }
02188 
02189             p7fd9_8255_mouse_latch = (latchOutPortC >> 7) & 1;
02190             p7fd8_8255_mouse_irq_signal = false;//This is a GUESS
02191         }
02192         if (mask & 0x60) { /* bits 6-5 */
02193             p7fd9_8255_mouse_sel = (latchOutPortC >> 5) & 3;
02194         }
02195         if (mask & 0x10) { /* bit 4 */
02196             uint8_t p = p7fd8_8255_mouse_int_enable;
02197 
02198             p7fd8_8255_mouse_int_enable = ((latchOutPortC >> 4) & 1) ^ 1; // bit 4 is interrupt MASK
02199 
02200             if (mode == 0x90 && mask == 0xFF) {
02201                 /* Metal Force (PC-98) likes to use the bus mouse as a periodic interrupt source
02202                  * by setting mode byte 0x90 and re-sending that mode byte once per interrupt.
02203                  * Does real hardware do this?? */
02204                 if (p7fd8_8255_mouse_int_enable)
02205                     MOUSE_DummyEvent();
02206             }
02207             else if (p != p7fd8_8255_mouse_int_enable) {
02208                 /* FIXME: If a mouse interrupt is pending but not yet read this should re-signal the IRQ */
02209                 if (p7fd8_8255_mouse_int_enable && p7fd8_8255_mouse_irq_signal)
02210                     PIC_ActivateIRQ(MOUSE_IRQ);
02211                 else
02212                     PIC_DeActivateIRQ(MOUSE_IRQ);
02213             }
02214         }
02215     }
02216 };
02217 
02218 static PC98_Mouse_8255 pc98_mouse_8255;
02219 
02221 static void write_p7fd9_mouse(Bitu port,Bitu val,Bitu /*iolen*/) {
02222     /* 0x7FD9-0x7FDF odd */
02223     pc98_mouse_8255.writeByPort((port - 0x7FD9) >> 1U,val);
02224 }
02225 
02226 static Bitu read_p7fd9_mouse(Bitu port,Bitu /*iolen*/) {
02227     /* 0x7FD9-0x7FDF odd */
02228     return pc98_mouse_8255.readByPort((port - 0x7FD9) >> 1U);
02229 }
02231 
02232 void KEYBOARD_OnEnterPC98(Section *sec) {
02233     (void)sec;//UNUSED
02234     unsigned int i;
02235 
02236     /* TODO: Keyboard interface change, layout change. */
02237 
02238     /* PC-98 uses the 8255 programmable peripheral interface. Install that here.
02239      * Sometime in the future, move 8255 emulation to a separate file.
02240      *
02241      * The 8255 appears at I/O ports 0x31, 0x33, 0x35, 0x37 */
02242     if (IS_PC98_ARCH) {
02243         for (i=0;i < 4;i++) {
02244             ReadHandler_8255_PC98[i].Uninstall();
02245             WriteHandler_8255_PC98[i].Uninstall();
02246         }
02247         
02248         Section_prop *section=static_cast<Section_prop *>(control->GetSection("dosbox"));
02249         pc98_force_ibm_layout = section->Get_bool("pc-98 force ibm keyboard layout");
02250         if(pc98_force_ibm_layout)
02251             LOG_MSG("Forcing PC-98 keyboard to use IBM US-English like default layout");
02252     }
02253 
02254     if (!IS_PC98_ARCH) {
02255         /* remove 60h-63h */
02256         IO_FreeWriteHandler(0x60,IO_MB);
02257         IO_FreeReadHandler(0x60,IO_MB);
02258         IO_FreeWriteHandler(0x61,IO_MB);
02259         IO_FreeReadHandler(0x61,IO_MB);
02260         IO_FreeWriteHandler(0x64,IO_MB);
02261         IO_FreeReadHandler(0x64,IO_MB);
02262     }   
02263 }
02264 
02265 void KEYBOARD_OnEnterPC98_phase2(Section *sec) {
02266     (void)sec;//UNUSED
02267     unsigned int i;
02268 
02269     /* Keyboard UART (8251) is at 0x41, 0x43. */
02270     IO_RegisterWriteHandler(0x41,keyboard_pc98_8251_uart_41_write,IO_MB);
02271     IO_RegisterReadHandler(0x41,keyboard_pc98_8251_uart_41_read,IO_MB);
02272     IO_RegisterWriteHandler(0x43,keyboard_pc98_8251_uart_43_write,IO_MB);
02273     IO_RegisterReadHandler(0x43,keyboard_pc98_8251_uart_43_read,IO_MB);
02274 
02275     /* PC-98 uses the 8255 programmable peripheral interface. Install that here.
02276      * Sometime in the future, move 8255 emulation to a separate file.
02277      *
02278      * The 8255 appears at I/O ports 0x31, 0x33, 0x35, 0x37 */
02279 
02280     /* Port A = input
02281      * Port B = input
02282      * Port C = output */
02283     /* bit[7:7] =  1 = mode set
02284      * bit[6:5] = 00 = port A mode 0
02285      * bit[4:4] =  1 = port A input
02286      * bit[3:3] =  0 = port C upper output              1001 0010 = 0x92
02287      * bit[2:2] =  0 = port B mode 0
02288      * bit[1:1] =  1 = port B input
02289      * bit[0:0] =  0 = port C lower output */
02290     pc98_sys_8255.writeControl(0x92);
02291     pc98_sys_8255.writePortC(0xF8); /* SHUT0=1 SHUT1=1 mask printer RAM parity check buzzer inhibit */
02292 
02293     for (i=0;i < 4;i++) {
02294         ReadHandler_8255_PC98[i].Uninstall();
02295         ReadHandler_8255_PC98[i].Install(0x31 + (i * 2),pc98_8255_read,IO_MB);
02296 
02297         WriteHandler_8255_PC98[i].Uninstall();
02298         WriteHandler_8255_PC98[i].Install(0x31 + (i * 2),pc98_8255_write,IO_MB);
02299     }
02300 
02301     /* reset port */
02302     Reset_PC98.Uninstall();
02303     Reset_PC98.Install(0xF0,pc98_reset_write,IO_MB);
02304 
02305     /* Mouse */
02306     for (i=0;i < 4;i++) {
02307         IO_RegisterWriteHandler(0x7FD9+(i*2),write_p7fd9_mouse,IO_MB);
02308         IO_RegisterReadHandler(0x7FD9+(i*2),read_p7fd9_mouse,IO_MB);
02309     }
02310 
02311     /* Port A = input
02312      * Port B = input
02313      * Port C = output */
02314     /* bit[7:7] =  1 = mode set
02315      * bit[6:5] = 00 = port A mode 0
02316      * bit[4:4] =  1 = port A input
02317      * bit[3:3] =  0 = port C upper output              1001 0010 = 0x92
02318      * bit[2:2] =  0 = port B mode 0
02319      * bit[1:1] =  1 = port B input
02320      * bit[0:0] =  1 = port C lower input */
02321     pc98_mouse_8255.writeControl(0x93);
02322     pc98_mouse_8255.writePortC(0x00);
02323 }
02324 
02325 void KEYBOARD_OnReset(Section *sec) {
02326     (void)sec;//UNUSED
02327     Section_prop *section=static_cast<Section_prop *>(control->GetSection("keyboard"));
02328 
02329     LOG(LOG_MISC,LOG_DEBUG)("Keyboard reinitializing");
02330 
02331     if ((keyb.enable_aux=section->Get_bool("aux")) != false) {
02332         LOG(LOG_KEYBOARD,LOG_NORMAL)("Keyboard AUX emulation enabled");
02333     }
02334 
02335     TIMER_DelTickHandler(&KEYBOARD_TickHandler);
02336 
02337     allow_keyb_reset = section->Get_bool("allow output port reset");
02338 
02339     keyb.ps2mouse.int33_taken = 0;
02340     keyb.ps2mouse.reset_mode = MM_STREAM; /* NTS: I was wrong: PS/2 mice default to streaming after reset */
02341 
02342     const char * sbtype=section->Get_string("auxdevice");
02343     keyb.ps2mouse.type = MOUSE_NONE;
02344     if (sbtype != NULL) {
02345         if (!strcasecmp(sbtype,"2button"))
02346             keyb.ps2mouse.type=MOUSE_2BUTTON;
02347         else if (!strcasecmp(sbtype,"3button"))
02348             keyb.ps2mouse.type=MOUSE_3BUTTON;
02349         else if (!strcasecmp(sbtype,"intellimouse"))
02350             keyb.ps2mouse.type=MOUSE_INTELLIMOUSE;
02351         else if (!strcasecmp(sbtype,"intellimouse45"))
02352             keyb.ps2mouse.type=MOUSE_INTELLIMOUSE45;
02353         else if (!strcasecmp(sbtype,"none"))
02354             keyb.ps2mouse.type=MOUSE_NONE;
02355         else {
02356             keyb.ps2mouse.type=MOUSE_INTELLIMOUSE;
02357             LOG(LOG_KEYBOARD,LOG_ERROR)("Assuming PS/2 intellimouse, I don't know what '%s' is",sbtype);
02358         }
02359     }
02360 
02361     if (IS_PC98_ARCH) {
02362         KEYBOARD_OnEnterPC98(NULL);
02363         KEYBOARD_OnEnterPC98_phase2(NULL);
02364     }
02365     else {
02366         IO_RegisterWriteHandler(0x60,write_p60,IO_MB);
02367         IO_RegisterReadHandler(0x60,read_p60,IO_MB);
02368         IO_RegisterWriteHandler(0x61,write_p61,IO_MB);
02369         IO_RegisterReadHandler(0x61,read_p61,IO_MB);
02370         IO_RegisterWriteHandler(0x64,write_p64,IO_MB);
02371         IO_RegisterReadHandler(0x64,read_p64,IO_MB);
02372     }
02373 
02374     TIMER_AddTickHandler(&KEYBOARD_TickHandler);
02375     write_p61(0,0,0);
02376     KEYBOARD_Reset();
02377     AUX_Reset();
02378 }
02379 
02380 void KEYBOARD_Init() {
02381     LOG(LOG_MISC,LOG_DEBUG)("Initializing keyboard emulation");
02382 
02383     AddExitFunction(AddExitFunctionFuncPair(KEYBOARD_ShutDown));
02384 
02385     AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(KEYBOARD_OnReset));
02386 }
02387 
02388 void AUX_Reset() {
02389     keyb.ps2mouse.mode = keyb.ps2mouse.reset_mode;
02390     keyb.ps2mouse.acx = 0;
02391     keyb.ps2mouse.acy = 0;
02392     keyb.ps2mouse.samplerate = 80;
02393     keyb.ps2mouse.last_srate[0] = keyb.ps2mouse.last_srate[1] = keyb.ps2mouse.last_srate[2] = 0;
02394     keyb.ps2mouse.intellimouse_btn45 = false;
02395     keyb.ps2mouse.intellimouse_mode = false;
02396     keyb.ps2mouse.reporting = false;
02397     keyb.ps2mouse.scale21 = false;
02398     keyb.ps2mouse.resolution = 1;
02399     if (keyb.ps2mouse.type != MOUSE_NONE && keyb.ps2mouse.int33_taken)
02400         LOG(LOG_KEYBOARD,LOG_NORMAL)("PS/2 mouse emulation: taking over from INT 33h");
02401     keyb.ps2mouse.int33_taken = 0;
02402     keyb.ps2mouse.l = keyb.ps2mouse.m = keyb.ps2mouse.r = false;
02403 }
02404 
02405 void AUX_INT33_Takeover() {
02406     if (keyb.ps2mouse.type != MOUSE_NONE && keyb.ps2mouse.int33_taken)
02407         LOG(LOG_KEYBOARD,LOG_NORMAL)("PS/2 mouse emulation: Program is using INT 33h, disabling direct AUX emulation");
02408     keyb.ps2mouse.int33_taken = 1;
02409 }
02410 
02411 void KEYBOARD_Reset() {
02412     /* Init the keyb struct */
02413     keyb.active=true;
02414     keyb.scanning=true;
02415     keyb.pending_key=-1;
02416     keyb.auxactive=false;
02417     keyb.pending_key_state=false;
02418     keyb.command=CMD_NONE;
02419     keyb.aux_command=ACMD_NONE;
02420     keyb.p60changed=false;
02421     keyb.auxchanged=false;
02422     keyb.led_state = 0x00;
02423     keyb.repeat.key=KBD_NONE;
02424     keyb.repeat.pause=200;
02425     keyb.repeat.rate=33;
02426     keyb.repeat.wait=0;
02427     keyb.leftctrl_pressed=false;
02428     keyb.rightctrl_pressed=false;
02429     keyb.scanset=1;
02430     /* command byte */
02431     keyb.cb_override_inhibit=false;
02432     keyb.cb_irq12=false;
02433     keyb.cb_irq1=true;
02434     keyb.cb_xlat=true;
02435     keyb.cb_sys=true;
02436     keyb.reset=false;
02437     /* OK */
02438     KEYBOARD_ClrBuffer();
02439     KEYBOARD_SetLEDs(0);
02440 }
02441