Annotation of hatari/src/ikbd.c, revision 1.1

1.1     ! root        1: /*
        !             2:   Hatari
        !             3: 
        !             4:   The keyboard processor(6301) handles any joystick/mouse task and sends bytes to the ACIA(6850)
        !             5:   When a byte arrives in the ACIA (which takes just over 7000 CPU cycles) an MFP interrupt is flagged.
        !             6:   The CPU can now read the byte from the ACIA by reading address $fffc02.
        !             7:   An annoying bug can be found in Dungeon Master. This, when run, turns off the mouse input - but of course
        !             8:   then you are unable to play the game! A bodge flag has been added so we need to be told twice to turn off
        !             9:   the mouse input(although I think this causes errors in other games...)
        !            10:   Also, the ACIA_CYCLES time is very important for games such as Carrier Command. The keyboard handler
        !            11:   in this game has a bug in it, which corrupts its own registers if more than one byte is queued up. This
        !            12:   value was found by a test program on a real ST and has correctly emulated the behaviour.
        !            13: */
        !            14: 
        !            15: #include "main.h"
        !            16: #include "debug.h"
        !            17: #include "decode.h"
        !            18: #include "gemdos.h"
        !            19: #include "ikbd.h"
        !            20: #include "int.h"
        !            21: #include "joy.h"
        !            22: #include "m68000.h"
        !            23: #include "memAlloc.h"
        !            24: #include "memorySnapShot.h"
        !            25: #include "mfp.h"
        !            26: #include "misc.h"
        !            27: #include "screen.h"
        !            28: #include "video.h"
        !            29: #include "vdi.h"
        !            30: 
        !            31: #define DBL_CLICK_HISTORY  0x07     /* Number of frames since last click to see if need to send one or two clicks */
        !            32: #define ACIA_CYCLES    7200         /* Cycles(Multiple of 4) between sent to ACIA from keyboard along serial line - 500Hz/64, (approx' 6920-7200cycles from test program) */
        !            33: 
        !            34: #define IKBD_RESET_CYCLES  400000   /* Cycles after RESET before complete */
        !            35: 
        !            36: #define ABS_X_ONRESET    0          /* Initial XY for absolute mouse position after RESET command */
        !            37: #define ABS_Y_ONRESET    0
        !            38: #define ABS_MAX_X_ONRESET  320      /* Initial absolute mouse limits after RESET command */
        !            39: #define ABS_MAY_Y_ONRESET  200      /* These values are never actually used as user MUST call 'IKBD_Cmd_AbsMouseMode' before ever using them */
        !            40: 
        !            41: #define ABS_PREVBUTTONS    (0x02|0x8)  /* Don't report any buttons up on first call to 'IKBD_Cmd_ReadAbsMousePos' */
        !            42: 
        !            43: #define SCALE_MOUSE_INPUT           /* Scale mouse so correct aspect ratio when in 320x200, 640x200, 640x400 */
        !            44: 
        !            45: /* Keyboard state */
        !            46: KEYBOARD Keyboard;
        !            47: 
        !            48: /* Keyboard processor */
        !            49: KEYBOARD_PROCESSOR KeyboardProcessor;   /* Keyboard processor details */
        !            50: BOOL DoubleClickPattern[] = {           /* Pattern of mouse button up/down in ST frames(run off a Windows double-click message) */
        !            51:  BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,0,0,0,0,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE };
        !            52: BOOL bMouseDisabled,bJoystickDisabled,bDuringResetCriticalTime;
        !            53: 
        !            54: /* ACIA */
        !            55: unsigned char ACIAControlRegister = 0;
        !            56: unsigned char ACIAStatusRegister = ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY;  /* Pass when read 0xfffc00 */
        !            57: unsigned char ACIAByte;                 /* When a byte has arrived at the ACIA(from the keyboard) it is stored here */
        !            58: BOOL bByteInTransitToACIA = FALSE;      /* Is a byte being sent to the ACIA from the keyboard? */
        !            59: 
        !            60: /*
        !            61:   6850 ACIA (Asynchronous Communications Inferface Apdater)
        !            62:   Page 41, ST Internals. Also ST Update Magazine, February 1989 (I glad I kept that!)
        !            63: 
        !            64:   Pins:-
        !            65:     Vss
        !            66:     RX DATA Receive Data
        !            67:     RX CLK Receive Clock
        !            68:     TX CLK Transmitter Clock
        !            69:     RTS Request To Send
        !            70:     TX DATA Transmitter Data
        !            71:     IRQ Interrupt Request
        !            72:     CS 0,1,2 Chip Select
        !            73:     RS Register Select
        !            74:     Vcc Voltage
        !            75:     R/W Read/Write
        !            76:     E Enable
        !            77:     D0-D7 Data
        !            78:     DCD Data Carrier Detect
        !            79:     CTS Clear To Send
        !            80: 
        !            81:   Registers:-
        !            82:     0xfffc00 Keyboard ACIA Control (write)/Status(read)
        !            83:     0xfffc02 Keyboard ACIA Data
        !            84:     0xfffc04 MIDI ACIA Control (write)/Status(read)
        !            85:     0xfffc06 MIDI ACIA Data
        !            86: 
        !            87:   Control Register (0xfffc00 write):-
        !            88:     Bits 0,1 - These bits determine by which factor the transmitter and receiver
        !            89:       clock will be divided. These bits also are joined with a master reset
        !            90:       function. The 6850 has no separate reset line, so it must be
        !            91:       accomplished though software.
        !            92:         0 0    RXCLK/TXCLK without division
        !            93:         0 1    RXCLK/TXCLK by 16 (MIDI)
        !            94:         1 0    RXCLK/TXCLK by 64 (Keyboard)
        !            95:         1 1    Master RESET
        !            96:     Bits 2,3,4 - These so-called Word Select bits tell whether 7 or 8 data-bits are
        !            97:       involved; whether 1 or 2 stop-bits are transferred; and the type of parity
        !            98:     Bits 5,6 - These Transmitter Control bits set the RTS output pin, and allow or prevent
        !            99:       an interrupt through the ACIA when the send register is emptied. Also, BREAK signals
        !           100:       can be sent over the serial output by this line. A BREAK signal is nothing more than
        !           101:       a long seqence of null bits
        !           102:         0 0    RTS low, transmitter IRQ disabled
        !           103:         0 1    RTS low, transmitter IRQ enabled
        !           104:         1 0    RTS high, transmitter IRQ disabled
        !           105:         1 1    RTS low, transmitter IRQ disabled, BREAK sent
        !           106:     Bit 7 - The Receiver Interrupt Enable bit determines whether the receiver interrupt
        !           107:       will be on. An interrupt can be caused by the DCD line chaning from low to high, or
        !           108:       by the receiver data buffer filling. Besides that, an interrupt can occur from an
        !           109:       OVERRUN ( a received character isn't properly read from the processior).
        !           110:         0 Interrupt disabled
        !           111:         1 Interrupt enabled
        !           112: 
        !           113:   Status Register (0xfffc00 read):-
        !           114:     Bit 0 - When this bit is high, the RX data register is full. The byte must be read
        !           115:       before a new character is received (otherwise an OVERRUN happens)
        !           116:     Bit 1 - This bit reflects the status of the TX data buffer. An empty register
        !           117:       set the bit.
        !           118:     Bit 2 - A low-high change in pin DCD sets bit 2. If the receiver interrupt is allowable, the IRQ
        !           119:       is cancelled. The bit is cleared when the status register and the receiver register are
        !           120:       read. This also cancels the IRQ. Bit 2 register remains highis the signal on the DCD pin
        !           121:       is still high; Bit 2 register low if DCD becomes low.
        !           122:     Bit 3 - This line shows the status of CTS. This signal cannot be altered by a mater reset,
        !           123:       or by ACIA programming.
        !           124:     Bit 4 - Shows 'Frame Errors'. Frame errors are when no stop-bit is recognized in receiver
        !           125:       switching. It can be set with every new character.
        !           126:     Bit 5 - This bit display the previously mentioned OVERRUN condition. Bit 5 is reset when the
        !           127:       RX buffer is read.
        !           128:     Bit 6 - This bit recognizes whether the parity of a received character is correct. The bit is
        !           129:       set on an error.
        !           130:     Bit 7 - This signals the state of the IRQ pins; this bit make it possible to switch several
        !           131:       IRQ lines on one interrupt input. In cases where an interrupt is program-generated, bit 7
        !           132:       can tell which IC cut off the interrupt.
        !           133:         
        !           134:   ST ACIA:-
        !           135:     Note CTS,DCD and RTS are not connected! Phew!
        !           136:     The keyboard ACIA are address 0xfffc000 and 0xfffc02.
        !           137:     Default parameters are :- 8-bit word, 1 stopbit, no parity, 77812.5 baud; 500KHz/64 (keyboard clock div)
        !           138:     Default MIDI parameters are are above but :- 31250 baud; 500KHz/16 (MIDI clock div)
        !           139: */
        !           140: 
        !           141: // List of possible keyboard commands, others are seen as NOPs by keyboard processor
        !           142: IKBD_COMMAND_PARAMS KeyboardCommands[] = {
        !           143:   // Known messages, counts include command byte
        !           144:   0x80,2,  IKBD_Cmd_Reset,
        !           145:   0x07,2,  IKBD_Cmd_MouseAction,
        !           146:   0x08,1,  IKBD_Cmd_RelMouseMode,
        !           147:   0x09,5,  IKBD_Cmd_AbsMouseMode,
        !           148:   0x0A,3,  IKBD_Cmd_MouseCursorKeycodes,
        !           149:   0x0B,3,  IKBD_Cmd_SetMouseThreshold,
        !           150:   0x0C,3,  IKBD_Cmd_SetMouseScale,
        !           151:   0x0D,1,  IKBD_Cmd_ReadAbsMousePos,
        !           152:   0x0E,6,  IKBD_Cmd_SetInternalMousePos,
        !           153:   0x0F,1,  IKBD_Cmd_SetYAxisDown,
        !           154:   0x10,1,  IKBD_Cmd_SetYAxisUp,
        !           155:   0x11,1,  IKBD_Cmd_StartKeyboardTransfer,
        !           156:   0x12,1,  IKBD_Cmd_TurnMouseOff,
        !           157:   0x13,1,  IKBD_Cmd_StopKeyboardTransfer,
        !           158:   0x14,1,  IKBD_Cmd_ReturnJoystickAuto,
        !           159:   0x15,1,  IKBD_Cmd_StopJoystick,
        !           160:   0x16,1,  IKBD_Cmd_ReturnJoystick,
        !           161:   0x17,2,  IKBD_Cmd_SetJoystickDuration,
        !           162:   0x18,1,  IKBD_Cmd_SetJoystickFireDuration,
        !           163:   0x19,7,  IKBD_Cmd_SetCursorForJoystick,
        !           164:   0x1A,1,  IKBD_Cmd_DisableJoysticks,
        !           165:   0x1B,7,  IKBD_Cmd_SetClock,
        !           166:   0x1C,1,  IKBD_Cmd_ReadClock,
        !           167:   0x20,4,  IKBD_Cmd_LoadMemory,
        !           168:   0x21,3,  IKBD_Cmd_ReadMemory,
        !           169:   0x22,3,  IKBD_Cmd_Execute,
        !           170: 
        !           171:   // Report message (top bit set) - ignore for now...
        !           172:   0x88,1,  IKBD_Cmd_NullFunction,
        !           173:   0x89,1,  IKBD_Cmd_NullFunction,
        !           174:   0x8A,1,  IKBD_Cmd_NullFunction,
        !           175:   0x8B,1,  IKBD_Cmd_NullFunction,
        !           176:   0x8C,1,  IKBD_Cmd_NullFunction,
        !           177:   0x8F,1,  IKBD_Cmd_NullFunction,
        !           178:   0x90,1,  IKBD_Cmd_NullFunction,
        !           179:   0x92,1,  IKBD_Cmd_NullFunction,
        !           180:   0x94,1,  IKBD_Cmd_NullFunction,
        !           181:   0x95,1,  IKBD_Cmd_NullFunction,
        !           182:   0x99,1,  IKBD_Cmd_NullFunction,
        !           183: 
        !           184:   0xFF  // Term
        !           185: };
        !           186: 
        !           187: //-----------------------------------------------------------------------
        !           188: /*
        !           189:   Reset the IKBD processor
        !           190: */
        !           191: void IKBD_Reset(BOOL bCold)
        !           192: {
        !           193:   // Reset internal keyboard processor details
        !           194:   if (bCold)
        !           195:     KeyboardProcessor.bReset = FALSE;
        !           196:   KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
        !           197:   KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
        !           198: 
        !           199:   KeyboardProcessor.Rel.X =  KeyboardProcessor.Rel.Y = 0;
        !           200:   KeyboardProcessor.Rel.PrevX = KeyboardProcessor.Rel.PrevY = 0;
        !           201:   KeyboardProcessor.Abs.X = ABS_X_ONRESET;  KeyboardProcessor.Abs.Y = ABS_Y_ONRESET;
        !           202:   KeyboardProcessor.Abs.MaxX = ABS_MAX_X_ONRESET;  KeyboardProcessor.Abs.MaxY = ABS_MAY_Y_ONRESET;
        !           203:   KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
        !           204: 
        !           205:   KeyboardProcessor.Mouse.DeltaX = KeyboardProcessor.Mouse.DeltaY = 0;
        !           206:   KeyboardProcessor.Mouse.XScale = KeyboardProcessor.Mouse.YScale = 0;
        !           207:   KeyboardProcessor.Mouse.XThreshold = KeyboardProcessor.Mouse.YThreshold = 1;
        !           208:   KeyboardProcessor.Mouse.YAxis = 1;          // Y origin at top
        !           209:   KeyboardProcessor.Mouse.Action = 0;
        !           210: 
        !           211:   KeyboardProcessor.Joy.PrevJoyData[0] = KeyboardProcessor.Joy.PrevJoyData[1] = 0;
        !           212: 
        !           213:   // Reset our ACIA status
        !           214:   bByteInTransitToACIA = FALSE;
        !           215:   ACIAControlRegister = 0;
        !           216:   ACIAStatusRegister = ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY;
        !           217:   // And our keyboard states and clear key state table
        !           218:   Keyboard.BufferHead = Keyboard.BufferTail = 0;
        !           219:   Keyboard.nBytesInInputBuffer = 0;
        !           220:   Memory_Clear(Keyboard.KeyStates,sizeof(Keyboard.KeyStates));
        !           221:   Keyboard.bLButtonDown = BUTTON_NULL;
        !           222:   Keyboard.bRButtonDown = BUTTON_NULL;
        !           223:   Keyboard.bOldLButtonDown = Keyboard.bOldRButtonDown = BUTTON_NULL;
        !           224:   Keyboard.LButtonDblClk = Keyboard.RButtonDblClk = 0;
        !           225:   Keyboard.LButtonHistory = Keyboard.RButtonHistory = 0;
        !           226: 
        !           227:   // Store BOOL for when disable mouse or joystick - do emulate hardware 'quirk' where
        !           228:   // if disable both with 'x' time of a RESET command they are ignored!
        !           229:   bMouseDisabled = bJoystickDisabled = bDuringResetCriticalTime = FALSE;
        !           230: }
        !           231: 
        !           232: //-----------------------------------------------------------------------
        !           233: /*
        !           234:   Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
        !           235: */
        !           236: void IKBD_MemorySnapShot_Capture(BOOL bSave)
        !           237: {
        !           238:   // Save/Restore details
        !           239:   MemorySnapShot_Store(&Keyboard,sizeof(Keyboard));
        !           240:   MemorySnapShot_Store(&KeyboardProcessor,sizeof(KeyboardProcessor));
        !           241:   MemorySnapShot_Store(&ACIAControlRegister,sizeof(ACIAControlRegister));
        !           242:   MemorySnapShot_Store(&ACIAStatusRegister,sizeof(ACIAStatusRegister));
        !           243:   MemorySnapShot_Store(&ACIAByte,sizeof(ACIAByte));
        !           244:   MemorySnapShot_Store(&bByteInTransitToACIA,sizeof(bByteInTransitToACIA));
        !           245: }
        !           246: 
        !           247: //-----------------------------------------------------------------------
        !           248: /*
        !           249:   Calculate out 'delta' that mouse has moved by each frame, and add this to our internal keyboard position
        !           250: */
        !           251: void IKBD_UpdateInternalMousePosition(void)
        !           252: {
        !           253:   BOOL bHalveX=FALSE,bHalveY=FALSE;
        !           254: 
        !           255: #ifdef SCALE_MOUSE_INPUT
        !           256:   // According to chosen resolution, halve XY axis to give smoother mouse movement!
        !           257:   // When using VDI or mono leave mouse as is
        !           258:   if (!bUseVDIRes) {
        !           259:     if (STRes==ST_LOW_RES) {
        !           260:       bHalveX = bHalveY = TRUE;
        !           261:     }
        !           262:     if ( (STRes==ST_MEDIUM_RES) || (STRes==ST_LOWMEDIUM_MIX_RES) ) {
        !           263:       bHalveY = TRUE;
        !           264:     }
        !           265:   }
        !           266: 
        !           267:   if (bHalveX)
        !           268:     KeyboardProcessor.Mouse.DeltaX = (KeyboardProcessor.Rel.X-KeyboardProcessor.Rel.PrevX)>>1;
        !           269:   else
        !           270:     KeyboardProcessor.Mouse.DeltaX = KeyboardProcessor.Rel.X-KeyboardProcessor.Rel.PrevX;
        !           271:   if (bHalveY)
        !           272:     KeyboardProcessor.Mouse.DeltaY = (KeyboardProcessor.Rel.Y-KeyboardProcessor.Rel.PrevY)>>1;
        !           273:   else
        !           274:     KeyboardProcessor.Mouse.DeltaY = KeyboardProcessor.Rel.Y-KeyboardProcessor.Rel.PrevY;
        !           275: #else
        !           276:   KeyboardProcessor.Mouse.DeltaX = KeyboardProcessor.Rel.X-KeyboardProcessor.Rel.PrevX;
        !           277:   KeyboardProcessor.Mouse.DeltaY = KeyboardProcessor.Rel.Y-KeyboardProcessor.Rel.PrevY;
        !           278: #endif
        !           279:         /* Accellerating mouse in ST-Low - is this a good idea? */
        !           280:         if(!bUseHighRes) {  KeyboardProcessor.Mouse.DeltaX*=2; KeyboardProcessor.Mouse.DeltaY*=2;  }
        !           281: 
        !           282:   /* Retain fraction for next time around!?? */
        !           283:   if (bHalveX)
        !           284:     KeyboardProcessor.Rel.PrevX = KeyboardProcessor.Rel.X&~0x1;
        !           285:   else
        !           286:     KeyboardProcessor.Rel.PrevX = KeyboardProcessor.Rel.X;
        !           287:   if (bHalveY)
        !           288:     KeyboardProcessor.Rel.PrevY = KeyboardProcessor.Rel.Y&~0x1;
        !           289:   else
        !           290:     KeyboardProcessor.Rel.PrevY = KeyboardProcessor.Rel.Y;
        !           291: 
        !           292:   // Update internal mouse coords - Y axis moves according to YAxis setting(up/down)
        !           293:   // Limit to Max X/Y(inclusive)
        !           294:   KeyboardProcessor.Abs.X += KeyboardProcessor.Mouse.DeltaX;
        !           295:   if (KeyboardProcessor.Abs.X<0)
        !           296:     KeyboardProcessor.Abs.X = 0;
        !           297:   if (KeyboardProcessor.Abs.X>KeyboardProcessor.Abs.MaxX)
        !           298:     KeyboardProcessor.Abs.X = KeyboardProcessor.Abs.MaxX;
        !           299:   KeyboardProcessor.Abs.Y += KeyboardProcessor.Mouse.DeltaY*KeyboardProcessor.Mouse.YAxis;  // Needed '+' for Falcon...
        !           300:   if (KeyboardProcessor.Abs.Y<0)
        !           301:     KeyboardProcessor.Abs.Y = 0;
        !           302:   if (KeyboardProcessor.Abs.Y>KeyboardProcessor.Abs.MaxY)
        !           303:     KeyboardProcessor.Abs.Y = KeyboardProcessor.Abs.MaxY;
        !           304: }
        !           305: 
        !           306: //-----------------------------------------------------------------------
        !           307: /*
        !           308:   When running in maximum speed the emulation will not see 'double-clicks' of the mouse
        !           309:   as it is running so fast. In this case, we check for a Windows double-click and pass
        !           310:   the 'up'/'down' messages in emulation time to simulate the double-click effect!
        !           311: */
        !           312: void IKBD_CheckForDoubleClicks(void)
        !           313: {
        !           314:   // OK, our Window responds to double-clicks but this sends the WM_xxxxx messages:-
        !           315:   // WM_LBUTTONDOWN,WM_LBUTTONUP,WM_LBUTTONDBLCLK,WM_LBUTTONUP. When running emulation
        !           316:   // in normal speed we simply interpret the WM_LBUTTONDBLCLK as a WM_LBUTTONDOWN and
        !           317:   // all runs well. Things get a little complicated when running max speed as a normal
        !           318:   // double-click is a load of 1's, followed by 0's, 1's and 0's - But the ST does
        !           319:   // not see this as a double click as the space in 'ST' time between changes is so great.
        !           320:   // Now, when we see a WM_LBUTTONDBLCLK in max speed we actually send the down/up/down/up
        !           321:   // in ST time. To get this correct(and not send three clicks) we look in a history buffer
        !           322:   // and start at an index which gives the correct number of clicks! Phew!
        !           323: 
        !           324:   // Handle double clicks!!!
        !           325:   if (Keyboard.LButtonDblClk) {
        !           326:     if (Keyboard.LButtonDblClk==1) {          /* First pressed! */
        !           327:       if ((Keyboard.LButtonHistory&0x3f)==0)  /* If not pressed button in long time do full dbl-click pattern */
        !           328:         Keyboard.LButtonDblClk = 1;
        !           329:       else {
        !           330:         Keyboard.LButtonDblClk = 4;           /* Otherwise, check where to begin to give 1111000011110000 pattern */
        !           331:         if ((Keyboard.LButtonHistory&0x7)==0) 
        !           332:           Keyboard.LButtonDblClk = 8;
        !           333:         else if ((Keyboard.LButtonHistory&0x3)==0) 
        !           334:           Keyboard.LButtonDblClk = 7;
        !           335:         else if ((Keyboard.LButtonHistory&0x1)==0) 
        !           336:           Keyboard.LButtonDblClk = 6;
        !           337:       }
        !           338:     }
        !           339: 
        !           340:     Keyboard.bLButtonDown = DoubleClickPattern[Keyboard.LButtonDblClk];
        !           341:     Keyboard.LButtonDblClk++;
        !           342:     if (Keyboard.LButtonDblClk>=13) {         /* Check for end of sequence */
        !           343:       Keyboard.LButtonDblClk = 0;
        !           344:       Keyboard.bLButtonDown = FALSE;
        !           345:     }
        !           346:   }
        !           347:   if (Keyboard.RButtonDblClk) {
        !           348:     if (Keyboard.RButtonDblClk==1) {          /* First pressed! */
        !           349:       if ((Keyboard.RButtonHistory&0x3f)==0)  /* If not pressed button in long time do full dbl-click pattern */
        !           350:         Keyboard.RButtonDblClk = 1;
        !           351:       else {
        !           352:         Keyboard.RButtonDblClk = 4;           /* Otherwise, check where to begin to give 1111000011110000 pattern */
        !           353:         if ((Keyboard.RButtonHistory&0x7)==0) 
        !           354:           Keyboard.RButtonDblClk = 8;
        !           355:         else if ((Keyboard.RButtonHistory&0x3)==0) 
        !           356:           Keyboard.RButtonDblClk = 7;
        !           357:         else if ((Keyboard.RButtonHistory&0x1)==0) 
        !           358:           Keyboard.RButtonDblClk = 6;
        !           359:       }
        !           360:     }
        !           361: 
        !           362:     Keyboard.bRButtonDown = DoubleClickPattern[Keyboard.RButtonDblClk];
        !           363:     Keyboard.RButtonDblClk++;
        !           364:     if (Keyboard.RButtonDblClk>=13) {         /* Check for end of sequence */
        !           365:       Keyboard.RButtonDblClk = 0;
        !           366:       Keyboard.bRButtonDown = FALSE;
        !           367:     }
        !           368:   }
        !           369: 
        !           370:   // Store presses into history
        !           371:   Keyboard.LButtonHistory = (Keyboard.LButtonHistory<<1);
        !           372:   if (Keyboard.bLButtonDown)
        !           373:     Keyboard.LButtonHistory |= 0x1;
        !           374:   Keyboard.RButtonHistory = (Keyboard.RButtonHistory<<1);
        !           375:   if (Keyboard.bRButtonDown)
        !           376:     Keyboard.RButtonHistory |= 0x1;
        !           377: }
        !           378: 
        !           379: //-----------------------------------------------------------------------
        !           380: /*
        !           381:   Convert button to BOOL value
        !           382: */
        !           383: BOOL IKBD_ButtonBool(int Button)
        !           384: {
        !           385:   // Button pressed?
        !           386:   if (Button)
        !           387:     return(TRUE);
        !           388:   return(FALSE);
        !           389: }
        !           390: 
        !           391: //-----------------------------------------------------------------------
        !           392: /*
        !           393:   Return TRUE if buttons match, use this as buttons are a mask and not BOOLean
        !           394: */
        !           395: BOOL IKBD_ButtonsEqual(int Button1,int Button2)
        !           396: {
        !           397:   // Return BOOL compare
        !           398:   return(IKBD_ButtonBool(Button1)==IKBD_ButtonBool(Button2));
        !           399: }
        !           400: 
        !           401: //-----------------------------------------------------------------------
        !           402: /*
        !           403:   According to if the mouse if enabled or not the joystick 1 fire button/right mouse button
        !           404:   will become the same button, ie pressing one will also press the other and vise-versa
        !           405: */
        !           406: void IKBD_DuplicateMouseFireButtons(void)
        !           407: {
        !           408:   // If mouse is off then joystick fire button goes to joystick
        !           409:   if (KeyboardProcessor.MouseMode==AUTOMODE_OFF) {
        !           410:     // If pressed right mouse button, should go to joystick 1
        !           411:     if (Keyboard.bRButtonDown&BUTTON_MOUSE)
        !           412:       KeyboardProcessor.Joy.JoyData[1] |= 0x80;
        !           413:     // And left mouse button, should go to joystick 0
        !           414:     if (Keyboard.bLButtonDown&BUTTON_MOUSE)
        !           415:       KeyboardProcessor.Joy.JoyData[0] |= 0x80;
        !           416:   }
        !           417:   // If mouse if on, joystick 1 fire button goes to mouse not to the joystick
        !           418:   else {
        !           419:     // Is fire button pressed?
        !           420:     if (KeyboardProcessor.Joy.JoyData[1]&0x80) {
        !           421:       KeyboardProcessor.Joy.JoyData[1] &= 0x7f;  // Clear fire button bit
        !           422:       Keyboard.bRButtonDown |= BUTTON_JOYSTICK;  // Mimick on mouse right button
        !           423:     }
        !           424:     else
        !           425:       Keyboard.bRButtonDown &= ~BUTTON_JOYSTICK;
        !           426:   }
        !           427: }
        !           428: 
        !           429: //-----------------------------------------------------------------------
        !           430: /*
        !           431:   Send 'relative' mouse position
        !           432: */
        !           433: void IKBD_SendRelMousePacket(void)
        !           434: {
        !           435:   int ByteRelX,ByteRelY;
        !           436:   unsigned char Header;
        !           437: 
        !           438:   if ( (KeyboardProcessor.Mouse.DeltaX!=0) || (KeyboardProcessor.Mouse.DeltaY!=0)
        !           439:    || (!IKBD_ButtonsEqual(Keyboard.bOldLButtonDown,Keyboard.bLButtonDown)) || (!IKBD_ButtonsEqual(Keyboard.bOldRButtonDown,Keyboard.bRButtonDown)) ) {
        !           440:     // Send packet to keyboard process
        !           441:     while(TRUE) {
        !           442:       ByteRelX = KeyboardProcessor.Mouse.DeltaX;
        !           443:       if (ByteRelX>127)  ByteRelX = 127;
        !           444:       if (ByteRelX<-128)  ByteRelX = -128;
        !           445:       ByteRelY = KeyboardProcessor.Mouse.DeltaY;
        !           446:       if (ByteRelY>127)  ByteRelY = 127;
        !           447:       if (ByteRelY<-128)  ByteRelY = -128;
        !           448: 
        !           449:       Header = 0xf8;
        !           450:       if (Keyboard.bLButtonDown)
        !           451:         Header |= 0x02;
        !           452:       if (Keyboard.bRButtonDown)
        !           453:         Header |= 0x01;
        !           454:       IKBD_AddKeyToKeyboardBuffer(Header);
        !           455:       IKBD_AddKeyToKeyboardBuffer(ByteRelX);
        !           456:       IKBD_AddKeyToKeyboardBuffer(ByteRelY*KeyboardProcessor.Mouse.YAxis);
        !           457: 
        !           458:       KeyboardProcessor.Mouse.DeltaX -= ByteRelX;
        !           459:       KeyboardProcessor.Mouse.DeltaY -= ByteRelY;
        !           460: 
        !           461:       if ( (KeyboardProcessor.Mouse.DeltaX==0) && (KeyboardProcessor.Mouse.DeltaY==0) )
        !           462:         break;
        !           463: 
        !           464:       // Store buttons for next time around
        !           465:       Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
        !           466:       Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
        !           467:     }
        !           468:   }
        !           469: }
        !           470: 
        !           471: //-----------------------------------------------------------------------
        !           472: /*
        !           473:   Send 'joysticks' bit masks
        !           474: */
        !           475: void IKBD_SelAutoJoysticks(void)
        !           476: {
        !           477:   unsigned char JoyData;
        !           478: 
        !           479:   // Did joystick 0/mouse change?
        !           480:   JoyData = KeyboardProcessor.Joy.JoyData[0];
        !           481:   if (JoyData!=KeyboardProcessor.Joy.PrevJoyData[0]) {
        !           482:     IKBD_AddKeyToKeyboardBuffer(0xFE);    // Joystick 0/Mouse
        !           483:     IKBD_AddKeyToKeyboardBuffer(JoyData);
        !           484: 
        !           485:     KeyboardProcessor.Joy.PrevJoyData[0] = JoyData;
        !           486:   }
        !           487: 
        !           488:   // Did joystick 1(default) change?
        !           489:   JoyData = KeyboardProcessor.Joy.JoyData[1];
        !           490:   if (JoyData!=KeyboardProcessor.Joy.PrevJoyData[1]) {
        !           491:     IKBD_AddKeyToKeyboardBuffer(0xFF);    // Joystick 1
        !           492:     IKBD_AddKeyToKeyboardBuffer(JoyData);
        !           493: 
        !           494:     KeyboardProcessor.Joy.PrevJoyData[1] = JoyData;
        !           495:   }
        !           496: }
        !           497: 
        !           498: /*-----------------------------------------------------------------------*/
        !           499: /*
        !           500:   Send packets which are generated from the mouse action settings
        !           501:   If relative mode is on, still generate these packets
        !           502: */
        !           503: void IKBD_SendOnMouseAction(void)
        !           504: {
        !           505:   BOOL bReportPosition = FALSE;
        !           506: 
        !           507:   /* Report buttons as keys? Do in relative/absolute mode */
        !           508:   if (KeyboardProcessor.Mouse.Action&0x4) {
        !           509:     /* Left button? */
        !           510:     if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) )
        !           511:       IKBD_AddKeyToKeyboardBuffer(0x74);    /* Left */
        !           512:     else if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) )
        !           513:       IKBD_AddKeyToKeyboardBuffer(0x74|0x80);
        !           514:     /* Right button? */
        !           515:     if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
        !           516:       IKBD_AddKeyToKeyboardBuffer(0x75);    /* Right */
        !           517:     else if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
        !           518:       IKBD_AddKeyToKeyboardBuffer(0x75|0x80);
        !           519: 
        !           520:     /* Ignore bottom two bits, so return now */
        !           521:     return;
        !           522:   }
        !           523: 
        !           524:   /* Check MouseAction - report position on press/release */
        !           525:   /* MUST do this before update relative positions as buttons get reset */
        !           526:   if (KeyboardProcessor.Mouse.Action&0x3) {
        !           527:     /* Check for 'press'? */
        !           528:     if (KeyboardProcessor.Mouse.Action&0x1) {
        !           529:       /* Did 'press' mouse buttons? */
        !           530:       if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) ) {
        !           531:         bReportPosition = TRUE;
        !           532:         KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x04;
        !           533:         KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x02;
        !           534:       }
        !           535:       if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) ) {
        !           536:         bReportPosition = TRUE;
        !           537:         KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x01;
        !           538:         KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x08;
        !           539:       }
        !           540:     }
        !           541:     /* Check for 'release'? */
        !           542:     if (KeyboardProcessor.Mouse.Action&0x2) {
        !           543:       /* Did 'release' mouse buttons? */
        !           544:       if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) ) {
        !           545:         bReportPosition = TRUE;
        !           546:         KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x08;
        !           547:         KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x01;
        !           548:       }
        !           549:       if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) ) {
        !           550:         bReportPosition = TRUE;
        !           551:         KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x02;
        !           552:         KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x04;
        !           553:       }
        !           554:     }
        !           555: 
        !           556:     /* Do need to report? */
        !           557:     if (bReportPosition) {
        !           558:       /* Only report if mouse in absolute mode */
        !           559:       if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSEABS) {
        !           560: #ifdef DEBUG_OUTPUT_IKBD
        !           561:         Debug_IKBD("Report ABS on MouseAction\n");
        !           562: #endif
        !           563:         IKBD_Cmd_ReadAbsMousePos();
        !           564:       }
        !           565:     }
        !           566:   }
        !           567: }
        !           568: 
        !           569: //-----------------------------------------------------------------------
        !           570: /*
        !           571:   Send mouse movements as cursor keys
        !           572: */
        !           573: void IKBD_SendCursorMousePacket(void)
        !           574: {
        !           575:   int i=0;
        !           576: 
        !           577:   // Run each 'Delta' as cursor presses
        !           578:   // Limit to '10' loops as Windows cursor is a VERY poor quality. Eg, a single mouse movement
        !           579:   // on and ST gives delta's of '1', mostly, but Windows goes as high as 20+!
        !           580:   while ( (i<10) && ((KeyboardProcessor.Mouse.DeltaX!=0) || (KeyboardProcessor.Mouse.DeltaY!=0)
        !           581:    || (!IKBD_ButtonsEqual(Keyboard.bOldLButtonDown,Keyboard.bLButtonDown)) || (!IKBD_ButtonsEqual(Keyboard.bOldRButtonDown,Keyboard.bRButtonDown))) ) {
        !           582:     // Left?
        !           583:     if (KeyboardProcessor.Mouse.DeltaX<0) {
        !           584:       IKBD_AddKeyToKeyboardBuffer(75);    // Left cursor
        !           585:       IKBD_AddKeyToKeyboardBuffer(75|0x80);
        !           586:       KeyboardProcessor.Mouse.DeltaX++;
        !           587:     }
        !           588:     // Right?
        !           589:     if (KeyboardProcessor.Mouse.DeltaX>0) {
        !           590:       IKBD_AddKeyToKeyboardBuffer(77);    // Right cursor
        !           591:       IKBD_AddKeyToKeyboardBuffer(77|0x80);
        !           592:       KeyboardProcessor.Mouse.DeltaX--;
        !           593:     }
        !           594:     // Up?
        !           595:     if (KeyboardProcessor.Mouse.DeltaY<0) {
        !           596:       IKBD_AddKeyToKeyboardBuffer(72);    // Up cursor
        !           597:       IKBD_AddKeyToKeyboardBuffer(72|0x80);
        !           598:       KeyboardProcessor.Mouse.DeltaY++;
        !           599:     }
        !           600:     // Down?
        !           601:     if (KeyboardProcessor.Mouse.DeltaY>0) {
        !           602:       IKBD_AddKeyToKeyboardBuffer(80);    // Down cursor
        !           603:       IKBD_AddKeyToKeyboardBuffer(80|0x80);
        !           604:       KeyboardProcessor.Mouse.DeltaY--;
        !           605:     }
        !           606: 
        !           607:     // Left button?
        !           608:     if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) )
        !           609:       IKBD_AddKeyToKeyboardBuffer(0x74);    // Left
        !           610:     else if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) )
        !           611:       IKBD_AddKeyToKeyboardBuffer(0x74|0x80);
        !           612:     // Right button?
        !           613:     if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
        !           614:       IKBD_AddKeyToKeyboardBuffer(0x75);    // Right
        !           615:     else if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
        !           616:       IKBD_AddKeyToKeyboardBuffer(0x75|0x80);
        !           617: 
        !           618:     Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
        !           619:     Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
        !           620: 
        !           621:     // Count, so exit if try too many times!
        !           622:     i++;
        !           623:   }
        !           624: }
        !           625: 
        !           626: //-----------------------------------------------------------------------
        !           627: /*
        !           628:   Return packets from keyboard for auto, rel mouse, joystick etc...
        !           629: */
        !           630: void IKBD_SendAutoKeyboardCommands(void)
        !           631: {
        !           632:   /* Ignore anything until we've redirected our GEM handlers */
        !           633: //FM  if (!bInitGemDOS)
        !           634: //FIXME    return;
        !           635: 
        !           636:   /* Don't do anything until processor is first reset */
        !           637:   if (!KeyboardProcessor.bReset)
        !           638:     return;
        !           639: 
        !           640:   /* Read joysticks for this frame */
        !           641:   /* If mouse is on, joystick 0 is not connected */
        !           642:   KeyboardProcessor.Joy.JoyData[0] = (KeyboardProcessor.MouseMode==AUTOMODE_OFF) ? Joy_GetStickData(0):0x00;
        !           643:   KeyboardProcessor.Joy.JoyData[1] = Joy_GetStickData(1);
        !           644: 
        !           645:   /* Check for double-clicks in maximum speed mode */
        !           646:   IKBD_CheckForDoubleClicks();
        !           647: 
        !           648:   /* Handle Joystick/Mouse fire buttons */
        !           649:   IKBD_DuplicateMouseFireButtons();
        !           650:   
        !           651:   /* Send any packets which are to be reported by mouse action */
        !           652:   IKBD_SendOnMouseAction();
        !           653: 
        !           654:   /* Update internal mouse absolute position by find 'delta' of mouse movement */
        !           655:   IKBD_UpdateInternalMousePosition();
        !           656: 
        !           657:   /* Send automatic joystick packets */
        !           658:   if (KeyboardProcessor.JoystickMode==AUTOMODE_JOYSTICK)
        !           659:     IKBD_SelAutoJoysticks();
        !           660:   /* Send automatic relative mouse positions(absolute are not send automatically) */
        !           661:   if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSEREL)
        !           662:     IKBD_SendRelMousePacket();
        !           663:   /* Send cursor key directions for movements */
        !           664:   else if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSECURSOR)
        !           665:     IKBD_SendCursorMousePacket();
        !           666: 
        !           667:   /* Store buttons for next time around */
        !           668:   Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
        !           669:   Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
        !           670: 
        !           671:   /* Send joystick button '2' as 'Space bar' key - MUST do here so does not get mixed up in middle of joystick packets! */
        !           672:   if (JoystickSpaceBar) {
        !           673:     /* As we simulating space bar? */
        !           674:     if (JoystickSpaceBar==JOYSTICK_SPACE_DOWN) {
        !           675:       IKBD_PressSTKey(57,TRUE);         // Press
        !           676:       JoystickSpaceBar = JOYSTICK_SPACE_UP;
        !           677:     }
        !           678:     else { //if (JoystickSpaceBar==JOYSTICK_SPACE_UP) {
        !           679:       IKBD_PressSTKey(57,FALSE);        // Release
        !           680:       JoystickSpaceBar = FALSE;         // Complete
        !           681:     }
        !           682:   }
        !           683: }
        !           684: 
        !           685: //-----------------------------------------------------------------------
        !           686: /*
        !           687:   On ST if disable Mouse AND Joystick with a set time of a RESET command they are
        !           688:   actually turned back on! (A number of games do this so can get mouse and joystick
        !           689:   packets at the same time)
        !           690: */
        !           691: void IKBD_CheckResetDisableBug(void)
        !           692: {
        !           693:   /* Have disabled BOTH mouse and joystick? */
        !           694:   if (bMouseDisabled && bJoystickDisabled) {
        !           695:     /* And in critical time? */
        !           696:     if (bDuringResetCriticalTime) {
        !           697:       /* Emulate relative mouse and joystick reports being turned back on */
        !           698:       KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
        !           699:       KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
        !           700: #ifdef DEBUG_OUTPUT_IKBD
        !           701:       Debug_IKBD("IKBD Mouse+Joystick disabled during RESET. Revert.\n");
        !           702:       Debugger_TabIKBD_AddListViewItem("( Mouse+Joystick disabled during RESET. Revert. )");
        !           703: #endif
        !           704:     }
        !           705:   }
        !           706: }
        !           707: 
        !           708: //-----------------------------------------------------------------------
        !           709: /*
        !           710:   Start timer after keyboard RESET command to emulate 'quirk'
        !           711:   If some IKBD commands are sent during time after a RESET they may be ignored
        !           712: */
        !           713: void IKBD_InterruptHandler_ResetTimer(void)
        !           714: {
        !           715:   // Remove this interrupt from list and re-order
        !           716:   Int_AcknowledgeInterrupt();
        !           717: 
        !           718:   // Critical timer is over
        !           719:   bDuringResetCriticalTime = FALSE;
        !           720: }
        !           721: 
        !           722: 
        !           723: 
        !           724: //-----------------------------------------------------------------------
        !           725: /*
        !           726:   List of keyboard commands
        !           727: */
        !           728: 
        !           729: 
        !           730: //-----------------------------------------------------------------------
        !           731: /*
        !           732:   Blank function for some keyboard commands - this can be used to find errors
        !           733: */
        !           734: void IKBD_Cmd_NullFunction(void)
        !           735: {
        !           736: #ifdef DEBUG_OUTPUT_IKBD
        !           737:   Debug_IKBD("IKBD_Cmd_NullFunction\n");
        !           738:   Debugger_TabIKBD_AddListViewItem("( NullFunction )");
        !           739: #endif
        !           740: }
        !           741: 
        !           742: //-----------------------------------------------------------------------
        !           743: /*
        !           744:   RESET
        !           745: 
        !           746:   0x80
        !           747:   0x01
        !           748: 
        !           749:   Performs self test and checks for stuck (closed) keys, if OK returns 0xF0. Otherwise
        !           750:   returns break codes for keys
        !           751: */
        !           752: void IKBD_Cmd_Reset(void)
        !           753: {
        !           754:   /* Check for error series of bytes, eg 0x80,0x01 */
        !           755:   if (Keyboard.InputBuffer[1]==0x01) {
        !           756: #ifdef DEBUG_OUTPUT_IKBD
        !           757:     Debug_IKBD("KEYBOARD ON\n");
        !           758: #endif
        !           759:     KeyboardProcessor.bReset = TRUE;      /* Turn processor on; can now process commands */
        !           760: 
        !           761:     /* Set defaults */
        !           762:     KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
        !           763:     KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
        !           764:     KeyboardProcessor.Abs.X = ABS_X_ONRESET;  KeyboardProcessor.Abs.Y = ABS_Y_ONRESET;
        !           765:     KeyboardProcessor.Abs.MaxX = ABS_MAX_X_ONRESET;  KeyboardProcessor.Abs.MaxY = ABS_MAY_Y_ONRESET;
        !           766:     KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
        !           767: 
        !           768:     IKBD_AddKeyToKeyboardBuffer(0xF0);    /* Assume OK, return correct code */
        !           769: 
        !           770:     /* Start timer - some commands are send during this time they may be ignored(see real ST!) */
        !           771:     Int_AddRelativeInterrupt(IKBD_RESET_CYCLES,INTERRUPT_IKBD_RESETTIMER);
        !           772:     /* Set this 'critical' flag, gets reset when timer expires */
        !           773:     bMouseDisabled = bJoystickDisabled = FALSE;
        !           774:     bDuringResetCriticalTime = TRUE;
        !           775:   }
        !           776:   /* else if not 0x80,0x01 just ignore */
        !           777: #ifdef DEBUG_OUTPUT_IKBD
        !           778:   Debug_IKBD("IKBD_Cmd_Reset\n");
        !           779:   Debugger_TabIKBD_AddListViewItem("RESET");
        !           780: #endif
        !           781: }
        !           782: 
        !           783: //-----------------------------------------------------------------------
        !           784: /*
        !           785:   SET MOUSE BUTTON ACTION
        !           786: 
        !           787:   0x07
        !           788:   %00000mss  ; mouse button action
        !           789:         ;  (m is presumed =1 when in MOUSE KEYCODE mode)
        !           790:         ; mss=0xy, mouse button press or release causes mouse
        !           791:         ;  position report
        !           792:         ;  where y=1, mouse key press causes absolute report
        !           793:         ;  and x=1, mouse key release causes absolute report
        !           794:         ; mss=100, mouse buttons act like keys 
        !           795: */
        !           796: void IKBD_Cmd_MouseAction(void)
        !           797: {
        !           798:   KeyboardProcessor.Mouse.Action = Keyboard.InputBuffer[1];
        !           799:   KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
        !           800: #ifdef DEBUG_OUTPUT_IKBD
        !           801:   Debug_IKBD("IKBD_Cmd_MouseAction %d\n",(unsigned int)KeyboardProcessor.Mouse.Action);
        !           802:   Debugger_TabIKBD_AddListViewItem("MouseAction %d",(unsigned int)KeyboardProcessor.Mouse.Action);
        !           803: #endif
        !           804: }
        !           805: 
        !           806: //-----------------------------------------------------------------------
        !           807: /*
        !           808:   SET RELATIVE MOUSE POSITION REPORTING
        !           809: 
        !           810:   0x08
        !           811: */
        !           812: void IKBD_Cmd_RelMouseMode(void)
        !           813: {
        !           814:   KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
        !           815: #ifdef DEBUG_OUTPUT_IKBD
        !           816:   Debug_IKBD("IKBD_Cmd_RelMouseMode\n");
        !           817:   Debugger_TabIKBD_AddListViewItem("RelMouseMode");
        !           818: #endif
        !           819: }
        !           820: 
        !           821: //-----------------------------------------------------------------------
        !           822: /*
        !           823:   SET ABSOLUTE MOUSE POSITIONING
        !           824: 
        !           825:   0x09
        !           826:   XMSB      ;X maximum (in scaled mouse clicks)
        !           827:   XLSB
        !           828:   YMSB      ;Y maximum (in scaled mouse clicks)
        !           829:   YLSB
        !           830: */
        !           831: void IKBD_Cmd_AbsMouseMode(void)
        !           832: {
        !           833:   /* These maximums are 'inclusive' */
        !           834:   KeyboardProcessor.MouseMode = AUTOMODE_MOUSEABS;
        !           835:   KeyboardProcessor.Abs.MaxX = (((unsigned int)Keyboard.InputBuffer[1])<<8) | (unsigned int)Keyboard.InputBuffer[2];
        !           836:   KeyboardProcessor.Abs.MaxY = (((unsigned int)Keyboard.InputBuffer[3])<<8) | (unsigned int)Keyboard.InputBuffer[4];
        !           837: #ifdef DEBUG_OUTPUT_IKBD
        !           838:   Debug_IKBD("IKBD_Cmd_AbsMouseMode %d,%d\n",KeyboardProcessor.Abs.MaxX,KeyboardProcessor.Abs.MaxY);
        !           839:   Debugger_TabIKBD_AddListViewItem("AbsMouseMode %d,%d",KeyboardProcessor.Abs.MaxX,KeyboardProcessor.Abs.MaxY);
        !           840: #endif
        !           841: }
        !           842: 
        !           843: //-----------------------------------------------------------------------
        !           844: /*
        !           845:   SET MOUSE KEYCODE MODE
        !           846: 
        !           847:   0x0A
        !           848:   deltax      ; distance in X clicks to return (LEFT) or (RIGHT)
        !           849:   deltay      ; distance in Y clicks to return (UP) or (DOWN)
        !           850: */
        !           851: void IKBD_Cmd_MouseCursorKeycodes(void)
        !           852: {
        !           853:   KeyboardProcessor.MouseMode = AUTOMODE_MOUSECURSOR;
        !           854:   KeyboardProcessor.Mouse.KeyCodeDeltaX = Keyboard.InputBuffer[1];
        !           855:   KeyboardProcessor.Mouse.KeyCodeDeltaY = Keyboard.InputBuffer[2];  
        !           856: #ifdef DEBUG_OUTPUT_IKBD
        !           857:   Debug_IKBD("IKBD_Cmd_MouseCursorKeycodes %d,%d\n",(int)KeyboardProcessor.Mouse.KeyCodeDeltaX,(int)KeyboardProcessor.Mouse.KeyCodeDeltaY);
        !           858:   Debugger_TabIKBD_AddListViewItem("MouseCursorKeycodes %d,%d",(int)KeyboardProcessor.Mouse.KeyCodeDeltaX,(int)KeyboardProcessor.Mouse.KeyCodeDeltaY);
        !           859: #endif
        !           860: }
        !           861: 
        !           862: //-----------------------------------------------------------------------
        !           863: /*
        !           864:   SET MOUSE THRESHOLD
        !           865: 
        !           866:   0x0B
        !           867:   X      ; x threshold in mouse ticks (positive integers)
        !           868:   Y      ; y threshold in mouse ticks (positive integers)
        !           869: */
        !           870: void IKBD_Cmd_SetMouseThreshold(void)
        !           871: {
        !           872:   KeyboardProcessor.Mouse.XThreshold = (unsigned int)Keyboard.InputBuffer[1];
        !           873:   KeyboardProcessor.Mouse.YThreshold = (unsigned int)Keyboard.InputBuffer[2];
        !           874: #ifdef DEBUG_OUTPUT_IKBD
        !           875:   Debug_IKBD("IKBD_Cmd_SetMouseThreshold %d,%d\n",KeyboardProcessor.Mouse.XThreshold,KeyboardProcessor.Mouse.YThreshold);
        !           876:   Debugger_TabIKBD_AddListViewItem("SetMouseThreshold %d,%d",KeyboardProcessor.Mouse.XThreshold,KeyboardProcessor.Mouse.YThreshold);
        !           877: #endif
        !           878: }
        !           879: 
        !           880: //-----------------------------------------------------------------------
        !           881: /*
        !           882:   SET MOUSE SCALE
        !           883: 
        !           884:   0x0C
        !           885:   X      ; horizontal mouse ticks per internel X
        !           886:   Y      ; vertical mouse ticks per internel Y
        !           887: */
        !           888: void IKBD_Cmd_SetMouseScale(void)
        !           889: {
        !           890:   KeyboardProcessor.Mouse.XScale = (unsigned int)Keyboard.InputBuffer[1];
        !           891:   KeyboardProcessor.Mouse.YScale = (unsigned int)Keyboard.InputBuffer[2];
        !           892: #ifdef DEBUG_OUTPUT_IKBD
        !           893:   Debug_IKBD("IKBD_Cmd_SetMouseScale %d,%d\n",KeyboardProcessor.Mouse.XScale,KeyboardProcessor.Mouse.YScale);
        !           894:   Debugger_TabIKBD_AddListViewItem("SetMouseScale %d,%d",KeyboardProcessor.Mouse.XScale,KeyboardProcessor.Mouse.YScale);
        !           895: #endif
        !           896: }
        !           897: 
        !           898: /*-----------------------------------------------------------------------*/
        !           899: /*
        !           900:   INTERROGATE MOUSE POSITION
        !           901: 
        !           902:   0x0D
        !           903:     Returns:  0xF7  ; absolute mouse position header
        !           904:       BUTTONS
        !           905:         0000dcba
        !           906:         where a is right button down since last interrogation
        !           907:         b is right button up since last
        !           908:         c is left button down since last
        !           909:         d is left button up since last
        !           910:       XMSB      ; X coordinate
        !           911:       XLSB
        !           912:       YMSB      ; Y coordinate
        !           913:       YLSB
        !           914: */
        !           915: void IKBD_Cmd_ReadAbsMousePos(void)
        !           916: {
        !           917:   unsigned char Buttons,PrevButtons;
        !           918: 
        !           919:   /* Test buttons */
        !           920:   Buttons = 0;
        !           921:   /* Set buttons to show if up/down */
        !           922:   if (Keyboard.bRButtonDown)
        !           923:     Buttons |= 0x01;
        !           924:   else
        !           925:     Buttons |= 0x02;
        !           926:   if (Keyboard.bLButtonDown)
        !           927:     Buttons |= 0x04;
        !           928:   else
        !           929:     Buttons |= 0x08;
        !           930:   /* Mask off it didn't send last time */
        !           931:   PrevButtons = KeyboardProcessor.Abs.PrevReadAbsMouseButtons;
        !           932:   KeyboardProcessor.Abs.PrevReadAbsMouseButtons = Buttons;
        !           933:   Buttons &= ~PrevButtons;
        !           934: 
        !           935:   /* And send packet */
        !           936:   IKBD_AddKeyToKeyboardBuffer(0xf7);
        !           937:   IKBD_AddKeyToKeyboardBuffer(Buttons);
        !           938:   IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.X>>8);
        !           939:   IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.X&0xff);
        !           940:   IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.Y>>8);
        !           941:   IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.Y&0xff);
        !           942: 
        !           943: #ifdef DEBUG_OUTPUT_IKBD
        !           944:   Debug_IKBD("IKBD_Cmd_ReadAbsMousePos %d,%d 0x%X\n",KeyboardProcessor.Abs.X,KeyboardProcessor.Abs.Y,Buttons);
        !           945:   Debugger_TabIKBD_AddListViewItem("ReadAbsMousePos %d,%d 0x%X",KeyboardProcessor.Abs.X,KeyboardProcessor.Abs.Y,Buttons);
        !           946: #endif
        !           947: }
        !           948: 
        !           949: /*-----------------------------------------------------------------------*/
        !           950: /*
        !           951:   LOAD MOUSE POSITION
        !           952: 
        !           953:   0x0E
        !           954:   0x00      ; filler
        !           955:   XMSB      ; X coordinate
        !           956:   XLSB      ; (in scaled coordinate system)
        !           957:   YMSB      ; Y coordinate
        !           958:   YLSB
        !           959: */
        !           960: void IKBD_Cmd_SetInternalMousePos(void)
        !           961: {  
        !           962:   /* Setting these do not clip internal position(this happens on next update) */
        !           963:   KeyboardProcessor.Abs.X = (((unsigned int)Keyboard.InputBuffer[2])<<8) | (unsigned int)Keyboard.InputBuffer[3];
        !           964:   KeyboardProcessor.Abs.Y = (((unsigned int)Keyboard.InputBuffer[4])<<8) | (unsigned int)Keyboard.InputBuffer[5];
        !           965: #ifdef DEBUG_OUTPUT_IKBD
        !           966:   Debug_IKBD("IKBD_Cmd_SetInternalMousePos %d,%d\n",KeyboardProcessor.Abs.X,KeyboardProcessor.Abs.Y);
        !           967:   Debugger_TabIKBD_AddListViewItem("SetInternalMousePos %d,%d",KeyboardProcessor.Abs.X,KeyboardProcessor.Abs.Y);
        !           968: #endif
        !           969: }
        !           970: 
        !           971: //-----------------------------------------------------------------------
        !           972: /*
        !           973:   SET Y=0 AT BOTTOM
        !           974: 
        !           975:   0x0F
        !           976: */
        !           977: void IKBD_Cmd_SetYAxisDown(void)
        !           978: {
        !           979:   KeyboardProcessor.Mouse.YAxis = -1;
        !           980: #ifdef DEBUG_OUTPUT_IKBD
        !           981:   Debug_IKBD("IKBD_Cmd_SetYAxisDown\n");
        !           982:   Debugger_TabIKBD_AddListViewItem("SetYAxisDown");
        !           983: #endif
        !           984: }
        !           985: 
        !           986: //-----------------------------------------------------------------------
        !           987: /*
        !           988:   SET Y=0 AT TOP
        !           989: 
        !           990:   0x10
        !           991: */
        !           992: void IKBD_Cmd_SetYAxisUp(void)
        !           993: {
        !           994:   KeyboardProcessor.Mouse.YAxis = 1;
        !           995: #ifdef DEBUG_OUTPUT_IKBD
        !           996:   Debug_IKBD("IKBD_Cmd_SetYAxisUp\n");
        !           997:   Debugger_TabIKBD_AddListViewItem("SetYAxisUp");
        !           998: #endif
        !           999: }
        !          1000: 
        !          1001: //-----------------------------------------------------------------------
        !          1002: /*
        !          1003:   RESUME
        !          1004: 
        !          1005:   0x11
        !          1006: */
        !          1007: void IKBD_Cmd_StartKeyboardTransfer(void)
        !          1008: {
        !          1009: #ifdef DEBUG_OUTPUT_IKBD
        !          1010:   Debug_IKBD("IKBD_Cmd_StartKeyboardTransfer\n");
        !          1011:   Debugger_TabIKBD_AddListViewItem("StartKeyboardTransfer");
        !          1012: #endif
        !          1013: }
        !          1014: 
        !          1015: //-----------------------------------------------------------------------
        !          1016: /*
        !          1017:   DISABLE MOUSE
        !          1018: 
        !          1019:   0x12
        !          1020: */
        !          1021: void IKBD_Cmd_TurnMouseOff(void)
        !          1022: {
        !          1023:   KeyboardProcessor.MouseMode = AUTOMODE_OFF;
        !          1024:   bMouseDisabled = TRUE;
        !          1025: #ifdef DEBUG_OUTPUT_IKBD
        !          1026:   Debug_IKBD("IKBD_Cmd_TurnMouseOff\n");
        !          1027:   Debugger_TabIKBD_AddListViewItem("TurnMouseOff");
        !          1028: #endif
        !          1029: 
        !          1030:   IKBD_CheckResetDisableBug();
        !          1031: }
        !          1032: 
        !          1033: //-----------------------------------------------------------------------
        !          1034: /*
        !          1035:   PAUSE OUTPUT
        !          1036: 
        !          1037:   0x13
        !          1038: */
        !          1039: void IKBD_Cmd_StopKeyboardTransfer(void)
        !          1040: {
        !          1041: #ifdef DEBUG_OUTPUT_IKBD
        !          1042:   Debug_IKBD("IKBD_Cmd_StopKeyboardTransfer\n");
        !          1043:   Debugger_TabIKBD_AddListViewItem("StopKeyboardTransfer");
        !          1044: #endif
        !          1045: }
        !          1046: 
        !          1047: //-----------------------------------------------------------------------
        !          1048: /*
        !          1049:   SET JOYSTICK EVENT REPORTING
        !          1050: 
        !          1051:   0x14
        !          1052: */
        !          1053: void IKBD_Cmd_ReturnJoystickAuto(void)
        !          1054: {
        !          1055:  KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
        !          1056:  KeyboardProcessor.MouseMode = AUTOMODE_OFF;
        !          1057:  /* Again, if try to disable mouse within time of a reset it isn't disabled! */
        !          1058:  if (bDuringResetCriticalTime)
        !          1059:    KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
        !          1060: #ifdef DEBUG_OUTPUT_IKBD
        !          1061:  Debug_IKBD("IKBD_Cmd_ReturnJoystickAuto\n");
        !          1062: #endif
        !          1063: }
        !          1064: 
        !          1065: //-----------------------------------------------------------------------
        !          1066: /*
        !          1067:   SET JOYSTICK INTERROGATION MODE
        !          1068: 
        !          1069:   0x15
        !          1070: */
        !          1071: void IKBD_Cmd_StopJoystick(void)
        !          1072: {
        !          1073:   KeyboardProcessor.JoystickMode = AUTOMODE_OFF;
        !          1074: //  Debug_IKBD("IKBD_Cmd_StopJoystick\n");
        !          1075: }
        !          1076: 
        !          1077: //-----------------------------------------------------------------------
        !          1078: /*
        !          1079:   JOYSTICK INTERROGATE
        !          1080: 
        !          1081:   0x16
        !          1082: */
        !          1083: void IKBD_Cmd_ReturnJoystick(void)
        !          1084: {
        !          1085:   IKBD_AddKeyToKeyboardBuffer(0xFD);
        !          1086:   IKBD_AddKeyToKeyboardBuffer(Joy_GetStickData(0));
        !          1087:   IKBD_AddKeyToKeyboardBuffer(Joy_GetStickData(1));
        !          1088: #ifdef DEBUG_OUTPUT_IKBD
        !          1089:   Debug_IKBD("IKBD_Cmd_ReturnJoystick\n");
        !          1090:   Debugger_TabIKBD_AddListViewItem("ReturnJoystick");
        !          1091: #endif
        !          1092: }
        !          1093: 
        !          1094: //-----------------------------------------------------------------------
        !          1095: /*
        !          1096:   SET JOYSTICK MONITORING
        !          1097: 
        !          1098:   0x17
        !          1099:   rate      ; time between samples in hundreths of a second
        !          1100:     Returns: (in packets of two as long as in mode)
        !          1101:       %000000xy  where y is JOYSTICK1 Fire button
        !          1102:           and x is JOYSTICK0 Fire button
        !          1103:       %nnnnmmmm  where m is JOYSTICK1 state
        !          1104:           and n is JOYSTICK0 state
        !          1105: */
        !          1106: void IKBD_Cmd_SetJoystickDuration(void)
        !          1107: {
        !          1108: #ifdef DEBUG_OUTPUT_IKBD
        !          1109:   Debug_IKBD("IKBD_Cmd_SetJoystickDuration\n");
        !          1110:   Debugger_TabIKBD_AddListViewItem("SetJoystickDuration");
        !          1111: #endif
        !          1112: }
        !          1113: 
        !          1114: //-----------------------------------------------------------------------
        !          1115: /*
        !          1116:   SET FIRE BUTTON MONITORING
        !          1117: 
        !          1118:   0x18
        !          1119:     Returns: (as long as in mode)
        !          1120:       %bbbbbbbb  ; state of the JOYSTICK1 fire button packed
        !          1121:             ; 8 bits per byte, the first sample if the MSB
        !          1122: */
        !          1123: void IKBD_Cmd_SetJoystickFireDuration(void)
        !          1124: {
        !          1125: #ifdef DEBUG_OUTPUT_IKBD
        !          1126:   Debug_IKBD("IKBD_Cmd_SetJoystickFireDuration\n");
        !          1127:   Debugger_TabIKBD_AddListViewItem("SetJoystickFireDuration");
        !          1128: #endif
        !          1129: }
        !          1130: 
        !          1131: //-----------------------------------------------------------------------
        !          1132: /*
        !          1133:   SET JOYSTICK KEYCODE MODE
        !          1134: 
        !          1135:   0x19
        !          1136:   RX        ; length of time (in tenths of seconds) until
        !          1137:           ; horizontal velocity breakpoint is reached
        !          1138:   RY        ; length of time (in tenths of seconds) until
        !          1139:           ; vertical velocity breakpoint is reached
        !          1140:   TX        ; length (in tenths of seconds) of joystick closure
        !          1141:           ; until horizontal cursor key is generated before RX
        !          1142:           ; has elapsed
        !          1143:   TY        ; length (in tenths of seconds) of joystick closure
        !          1144:           ; until vertical cursor key is generated before RY
        !          1145:           ; has elapsed
        !          1146:   VX        ; length (in tenths of seconds) of joystick closure
        !          1147:           ; until horizontal cursor keystokes are generated after RX
        !          1148:           ; has elapsed
        !          1149:   VY        ; length (in tenths of seconds) of joystick closure
        !          1150:           ; until vertical cursor keystokes are generated after RY
        !          1151:           ; has elapsed
        !          1152: */
        !          1153: void IKBD_Cmd_SetCursorForJoystick(void)
        !          1154: {
        !          1155: #ifdef DEBUG_OUTPUT_IKBD
        !          1156:   Debug_IKBD("IKBD_Cmd_SetCursorForJoystick\n");
        !          1157:   Debugger_TabIKBD_AddListViewItem("SetCursorForJoystick");
        !          1158: #endif
        !          1159: }
        !          1160: 
        !          1161: //-----------------------------------------------------------------------
        !          1162: /*
        !          1163:   DISABLE JOYSTICKS
        !          1164: 
        !          1165:   0x1A
        !          1166: */
        !          1167: void IKBD_Cmd_DisableJoysticks(void)
        !          1168: {
        !          1169:   KeyboardProcessor.JoystickMode = AUTOMODE_OFF;
        !          1170:   bJoystickDisabled = TRUE;
        !          1171: #ifdef DEBUG_OUTPUT_IKBD
        !          1172:   Debug_IKBD("IKBD_Cmd_DisableJoysticks\n");
        !          1173:   Debugger_TabIKBD_AddListViewItem("DisableJoysticks");
        !          1174: #endif
        !          1175: 
        !          1176:   IKBD_CheckResetDisableBug();
        !          1177: }
        !          1178: 
        !          1179: //-----------------------------------------------------------------------
        !          1180: /*
        !          1181:   TIME-OF-DAY CLOCK SET
        !          1182: 
        !          1183:   0x1B
        !          1184:   YY        ; year (2 least significant digits)
        !          1185:   MM        ; month
        !          1186:   DD        ; day
        !          1187:   hh        ; hour
        !          1188:   mm        ; minute
        !          1189:   ss        ; second
        !          1190: */
        !          1191: void IKBD_Cmd_SetClock(void)
        !          1192: {
        !          1193: #ifdef DEBUG_OUTPUT_IKBD
        !          1194:   Debug_IKBD("IKBD_Cmd_SetClock\n");
        !          1195:   Debugger_TabIKBD_AddListViewItem("SetClock");
        !          1196: #endif
        !          1197: }
        !          1198: 
        !          1199: //-----------------------------------------------------------------------
        !          1200: /*
        !          1201:   INTERROGATE TIME-OF-DAT CLOCK
        !          1202: 
        !          1203:   0x1C
        !          1204:     Returns:
        !          1205:       0xFC  ; time-of-day event header
        !          1206:       YY    ; year (2 least significant digits)
        !          1207:       MM    ; month
        !          1208:       DD    ; day
        !          1209:       hh    ; hour
        !          1210:       mm    ; minute
        !          1211:       ss    ; second
        !          1212: */
        !          1213: void IKBD_Cmd_ReadClock(void)
        !          1214: {
        !          1215: /* FIXME */
        !          1216: /*
        !          1217:   SYSTEMTIME SystemTime;
        !          1218: 
        !          1219:   // Get windows time
        !          1220:   GetSystemTime(&SystemTime);
        !          1221: 
        !          1222:   // Return packet
        !          1223:   IKBD_AddKeyToKeyboardBuffer(0xFC);
        !          1224:   // Return time-of-day clock as yy-mm-dd-hh-mm-ss as BCD
        !          1225:   IKBD_AddKeyToKeyboardBuffer(Misc_ConvertToBCD(SystemTime.wYear%100));  // yy - year(2 least significant digits)
        !          1226:   IKBD_AddKeyToKeyboardBuffer(Misc_ConvertToBCD(SystemTime.wMonth));     // mm - Month
        !          1227:   IKBD_AddKeyToKeyboardBuffer(Misc_ConvertToBCD(SystemTime.wDay));       // dd - Day
        !          1228:   IKBD_AddKeyToKeyboardBuffer(Misc_ConvertToBCD(SystemTime.wHour));      // hh - Hour
        !          1229:   IKBD_AddKeyToKeyboardBuffer(Misc_ConvertToBCD(SystemTime.wMinute));    // mm - Minute
        !          1230:   IKBD_AddKeyToKeyboardBuffer(Misc_ConvertToBCD(SystemTime.wSecond));    // ss - Second
        !          1231: */
        !          1232: #ifdef DEBUG_OUTPUT_IKBD
        !          1233:   Debug_IKBD("IKBD_Cmd_ReadClock\n");
        !          1234:   Debugger_TabIKBD_AddListViewItem("ReadClock");
        !          1235: #endif
        !          1236: }
        !          1237: 
        !          1238: //-----------------------------------------------------------------------
        !          1239: /*
        !          1240:   MEMORY LOAD
        !          1241: 
        !          1242:   0x20
        !          1243:   ADRMSB      ; address in controller
        !          1244:   ADRLSB      ; memory to be loaded
        !          1245:   NUM        ; number of bytes (0-128)
        !          1246:   { data }
        !          1247: */
        !          1248: void IKBD_Cmd_LoadMemory(void)
        !          1249: {
        !          1250: #ifdef DEBUG_OUTPUT_IKBD
        !          1251:   Debug_IKBD("IKBD_Cmd_LoadMemory\n");
        !          1252:   Debugger_TabIKBD_AddListViewItem("LoadMemory");
        !          1253: #endif
        !          1254: }
        !          1255: 
        !          1256: //-----------------------------------------------------------------------
        !          1257: /*
        !          1258:   MEMORY READ
        !          1259: 
        !          1260:   0x21
        !          1261:   ADRMSB        ; address in controller
        !          1262:   ADRLSB        ; memory to be read
        !          1263:     Returns:
        !          1264:       0xF6    ; status header
        !          1265:       0x20    ; memory access
        !          1266:       { data }  ; 6 data bytes starting at ADR
        !          1267: */
        !          1268: void IKBD_Cmd_ReadMemory(void)
        !          1269: {
        !          1270: #ifdef DEBUG_OUTPUT_IKBD
        !          1271:   Debug_IKBD("IKBD_Cmd_ReadMemory\n");
        !          1272:   Debugger_TabIKBD_AddListViewItem("ReadMemory");
        !          1273: #endif
        !          1274: }
        !          1275: 
        !          1276: //-----------------------------------------------------------------------
        !          1277: /*
        !          1278:   CONTROLLER EXECUTE
        !          1279: 
        !          1280:   0x22
        !          1281:   ADRMSB      ; address of subroutine in
        !          1282:   ADRLSB      ; controller memory to be called
        !          1283: */
        !          1284: void IKBD_Cmd_Execute(void)
        !          1285: {
        !          1286: #ifdef DEBUG_OUTPUT_IKBD
        !          1287:   Debug_IKBD("IKBD_Cmd_Execute\n");
        !          1288:   Debugger_TabIKBD_AddListViewItem("Execute");
        !          1289: #endif
        !          1290: }
        !          1291: 
        !          1292: 
        !          1293: //-----------------------------------------------------------------------
        !          1294: /*
        !          1295:   Send data to keyboard processor via ACIA by writing to address 0xfffc02.
        !          1296:   For our emulation we bypass the ACIA (I've yet to see anything check for this)
        !          1297:   and add the byte directly into the keyboard input buffer.
        !          1298: */
        !          1299: void IKBD_RunKeyboardCommand(void)
        !          1300: {
        !          1301:   int i=0;
        !          1302: 
        !          1303:   // Write into our keyboard input buffer
        !          1304:   Keyboard.InputBuffer[Keyboard.nBytesInInputBuffer++] = ACIAByte;
        !          1305: 
        !          1306:   // Now check bytes to see if we have a valid/in-valid command string set
        !          1307:   while(KeyboardCommands[i].Command!=0xff) {
        !          1308:     // Found command?
        !          1309:     if (KeyboardCommands[i].Command==Keyboard.InputBuffer[0]) {
        !          1310:       // Is string complete, then can execute?
        !          1311:       if (KeyboardCommands[i].NumParameters==Keyboard.nBytesInInputBuffer) {
        !          1312:         CALL_VAR(KeyboardCommands[i].pCallFunction);
        !          1313:         Keyboard.nBytesInInputBuffer = 0;
        !          1314:       }
        !          1315: 
        !          1316:       return;
        !          1317:     }
        !          1318:     
        !          1319:     i++;
        !          1320:   }
        !          1321: 
        !          1322:   // Command not known, reset buffer(IKBD assumes a NOP)
        !          1323:   Keyboard.nBytesInInputBuffer = 0;
        !          1324: }
        !          1325: 
        !          1326: //-----------------------------------------------------------------------
        !          1327: /*
        !          1328:   Send byte to our keyboard processor, and execute
        !          1329: */
        !          1330: void IKBD_SendByteToKeyboardProcessor(unsigned short bl)
        !          1331: {
        !          1332:  ACIAByte = bl;      /* Store byte to pass */
        !          1333:  IKBD_RunKeyboardCommand();  /* And send */
        !          1334: }
        !          1335: 
        !          1336: //-----------------------------------------------------------------------
        !          1337: /*
        !          1338:   The byte stored in the ACIA 'ACIAByte' has been read by the CPU by reading from
        !          1339:   address $fffc02. We clear the status flag and set the GPIP register to signal read.
        !          1340: */
        !          1341: unsigned short IKBD_GetByteFromACIA(void)
        !          1342: {
        !          1343:   // ACIA is now reset
        !          1344:   ACIAStatusRegister &= ~ACIA_STATUS_REGISTER__RX_BUFFER_FULL;
        !          1345:   ACIAStatusRegister &= ~ACIA_STATUS_REGISTER__INTERRUPT_REQUEST;
        !          1346:   ACIAStatusRegister &= ~ACIA_STATUS_REGISTER__OVERRUN_ERROR;
        !          1347: 
        !          1348:   // GPIP I4 - General Purpose Pin Keyboard/MIDI interrupt
        !          1349:   MFP_GPIP |= 0x10;
        !          1350:   return ACIAByte;  /* Return byte from keyboard */
        !          1351: }
        !          1352: 
        !          1353: //-----------------------------------------------------------------------
        !          1354: /*
        !          1355:   Byte received in the ACIA from the keyboard processor. Store byte for read from $fffc02
        !          1356:   and clear the GPIP I4 register. This register will be remain low until byte has been
        !          1357:   read from ACIA.
        !          1358: */
        !          1359: void IKBD_InterruptHandler_ACIA(void)
        !          1360: {
        !          1361:   // Remove this interrupt from list and re-order
        !          1362:   Int_AcknowledgeInterrupt();
        !          1363: 
        !          1364:   // Copy keyboard byte, ready for read from $fffc02
        !          1365:   ACIAByte = Keyboard.Buffer[Keyboard.BufferHead++];
        !          1366:   Keyboard.BufferHead &= KEYBOARD_BUFFER_MASK;
        !          1367:   
        !          1368:   // Did we get an over-run? Ie byte has arrived from keyboard processor BEFORE CPU has read previous one from ACIA
        !          1369:   if (ACIAStatusRegister&ACIA_STATUS_REGISTER__RX_BUFFER_FULL)
        !          1370:     ACIAStatusRegister |= ACIA_STATUS_REGISTER__OVERRUN_ERROR;  // Set over-run
        !          1371: 
        !          1372:   // ACIA buffer is now full
        !          1373:   ACIAStatusRegister |= ACIA_STATUS_REGISTER__RX_BUFFER_FULL;
        !          1374:   // Signal interrupt pending
        !          1375:   ACIAStatusRegister |= ACIA_STATUS_REGISTER__INTERRUPT_REQUEST;
        !          1376:   // GPIP I4 - General Purpose Pin Keyboard/MIDI interrupt
        !          1377:   // NOTE: GPIP will remain low(0) until keyboard data is read from $fffc02.
        !          1378:   MFP_GPIP &= ~0x10;
        !          1379: 
        !          1380:   // Acknowledge in MFP circuit, pass bit,enable,pending
        !          1381:   MFP_InputOnChannel(MFP_KEYBOARD_BIT,MFP_IERB,&MFP_IPRB);
        !          1382: 
        !          1383:   // Clear flag so can allow another byte to be sent along serial line
        !          1384:   bByteInTransitToACIA = FALSE;
        !          1385:   // If another key is waiting, start sending from keyboard processor now
        !          1386:   if (Keyboard.BufferHead!=Keyboard.BufferTail)
        !          1387:     IKBD_SendByteToACIA();
        !          1388: }
        !          1389: 
        !          1390: 
        !          1391: //-----------------------------------------------------------------------
        !          1392: /*
        !          1393:   Send a byte from the keyboard buffer to the ACIA. On a real ST this takes some time to send
        !          1394:   so we must be as accurate in the timing as possible - bytes do not appear to the 68000 instantly!
        !          1395:   We do this via an internal interrupt - neat!
        !          1396: */
        !          1397: void IKBD_SendByteToACIA(void)
        !          1398: {
        !          1399:   // Transmit byte from keyboard processor to ACIA. This takes approx ACIA_CYCLES CPU clock cycles to complete
        !          1400:   if (!bByteInTransitToACIA) {
        !          1401:     // Send byte to ACIA
        !          1402:     Int_AddRelativeInterrupt(ACIA_CYCLES,INTERRUPT_IKBD_ACIA);
        !          1403:     // Set flag so only transmit one byte at a time
        !          1404:     bByteInTransitToACIA = TRUE;
        !          1405:   }
        !          1406: }
        !          1407: 
        !          1408: //-----------------------------------------------------------------------
        !          1409: /*
        !          1410:   Add characer our internal keyboard buffer. These bytes are then sent one at a time to the ACIA.
        !          1411:   This is done via a delay to mimick the STs internal workings, as this is needed for games such
        !          1412:   as Carrier Command.
        !          1413: */
        !          1414: void IKBD_AddKeyToKeyboardBuffer(unsigned char Data)
        !          1415: {
        !          1416:   // Is keyboard initialised yet? Ignore any bytes until it is
        !          1417:   if (!KeyboardProcessor.bReset)
        !          1418:     return;
        !          1419: 
        !          1420:   // Check we have space to add byte
        !          1421:   if (Keyboard.BufferHead!=((Keyboard.BufferTail+1)&KEYBOARD_BUFFER_MASK)) {
        !          1422:     // Add byte to our buffer
        !          1423:     Keyboard.Buffer[Keyboard.BufferTail++] = Data;
        !          1424:     Keyboard.BufferTail &= KEYBOARD_BUFFER_MASK;
        !          1425:     
        !          1426:     // We have character ready to transmit from the ACIA - see if can send it now
        !          1427:     IKBD_SendByteToACIA();
        !          1428:   }
        !          1429: }
        !          1430: 
        !          1431: //-----------------------------------------------------------------------
        !          1432: /*
        !          1433:   When press/release key under Windows, execute this function
        !          1434: */
        !          1435: void IKBD_PressSTKey(unsigned char ScanCode,BOOL bPress)
        !          1436: {
        !          1437:   // Ignore anything until we've redirected our GEM handlers
        !          1438: //FM  if (!bInitGemDOS)
        !          1439: //FIXME    return;
        !          1440:   if (!bPress)
        !          1441:     ScanCode |= 0x80;    /* Set top bit if released key */
        !          1442:   IKBD_AddKeyToKeyboardBuffer(ScanCode);  /* And send to keyboard processor */
        !          1443: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.