|
|
1.1 root 1: /*
1.1.1.6 root 2: Hatari - ikbd.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
1.1 root 6:
1.1.1.12 root 7: The keyboard processor(6301) handles any joystick/mouse task and sends bytes
8: to the ACIA(6850). When a byte arrives in the ACIA (which takes just over
9: 7000 CPU cycles) an MFP interrupt is flagged. The CPU can now read the byte
10: from the ACIA by reading address $fffc02.
11: An annoying bug can be found in Dungeon Master. This, when run, turns off the
12: mouse input - but of course then you are unable to play the game! A bodge
13: flag has been added so we need to be told twice to turn off the mouse input
14: (although I think this causes errors in other games...).
15: Also, the ACIA_CYCLES time is very important for games such as Carrier
16: Command. The keyboard handler in this game has a bug in it, which corrupts
17: its own registers if more than one byte is queued up. This value was found by
18: a test program on a real ST and has correctly emulated the behaviour.
19: */
1.1.1.13! root 20: const char IKBD_rcsid[] = "Hatari $Id: ikbd.c,v 1.53 2008/11/16 16:27:28 eerot Exp $";
1.1.1.12 root 21:
22: /* 2007/09/29 [NP] Use the new int.c to add interrupts with INT_CPU_CYCLE / INT_MFP_CYCLE. */
23: /* 2007/12/09 [NP] If reset is written to ACIA control register, we must call ACIA_Reset to reset */
24: /* RX/TX status. Reading the control register fffc00 just after a reset should */
25: /* return the value 0x02 (used in Transbeauce 2 demo loader). */
1.1.1.13! root 26: /* 2008/07/06 [NP] Add support for executing 8 bit code sent to the 6301 processor. */
! 27: /* Instead of implementing a full 6301 emulator, we compute a checksum for each */
! 28: /* program sent to the 6301 RAM. If the checksum is recognized, we call some */
! 29: /* functions to emulate the behaviour of the 6301 in that case. */
! 30: /* When the 6301 is in 'Execute' mode (command 0x22), we must stop the normal */
! 31: /* reporting of key/mouse/joystick and use our custom handlers for each read or */
! 32: /* write to $fffc02. */
! 33: /* After a reset command, returns $F1 after $F0 (needed by Dragonnels Demo). */
! 34: /* This fixes the Transbeauce 2 demo menu, the Dragonnels demo menu and the */
! 35: /* Froggies Over The Fence demo menu (yeah ! enjoy this master piece of demo !). */
! 36:
1.1.1.6 root 37:
38: #include <time.h>
1.1 root 39:
40: #include "main.h"
41: #include "ikbd.h"
42: #include "int.h"
1.1.1.10 root 43: #include "ioMem.h"
1.1 root 44: #include "joy.h"
45: #include "m68000.h"
46: #include "memorySnapShot.h"
47: #include "mfp.h"
48: #include "video.h"
1.1.1.13! root 49: #include "utils.h"
1.1.1.10 root 50:
1.1 root 51:
52: #define DBL_CLICK_HISTORY 0x07 /* Number of frames since last click to see if need to send one or two clicks */
1.1.1.9 root 53: #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) */
1.1 root 54:
1.1.1.13! root 55: #define IKBD_RESET_CYCLES 223500 /* Cycles after RESET before complete */
1.1 root 56:
57: #define ABS_X_ONRESET 0 /* Initial XY for absolute mouse position after RESET command */
58: #define ABS_Y_ONRESET 0
59: #define ABS_MAX_X_ONRESET 320 /* Initial absolute mouse limits after RESET command */
60: #define ABS_MAY_Y_ONRESET 200 /* These values are never actually used as user MUST call 'IKBD_Cmd_AbsMouseMode' before ever using them */
61:
1.1.1.10 root 62: #define ABS_PREVBUTTONS (0x02|0x8) /* Don't report any buttons up on first call to 'IKBD_Cmd_ReadAbsMousePos' */
1.1 root 63:
64:
65: /* Keyboard state */
66: KEYBOARD Keyboard;
67:
68: /* Keyboard processor */
69: KEYBOARD_PROCESSOR KeyboardProcessor; /* Keyboard processor details */
1.1.1.11 root 70:
71: /* Pattern of mouse button up/down in ST frames (run off a double-click message) */
1.1.1.13! root 72: static const uint8_t DoubleClickPattern[] =
1.1.1.12 root 73: {
74: BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,
75: 0,0,0,0,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE,BUTTON_MOUSE
76: };
1.1.1.6 root 77:
1.1.1.13! root 78: static bool bMouseDisabled, bJoystickDisabled;
! 79: static bool bDuringResetCriticalTime, bBothMouseAndJoy;
1.1 root 80:
81: /* ACIA */
1.1.1.10 root 82: static Uint8 ACIAControlRegister = 0;
83: static Uint8 ACIAStatusRegister = ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY; /* Pass when read 0xfffc00 */
1.1.1.13! root 84: static Uint8 ACIAByte; /* When a byte has arrived at the ACIA (from the keyboard) it is stored here */
! 85: static bool bByteInTransitToACIA = FALSE; /* Is a byte being sent to the ACIA from the keyboard? */
1.1 root 86:
87: /*
88: 6850 ACIA (Asynchronous Communications Inferface Apdater)
89: Page 41, ST Internals. Also ST Update Magazine, February 1989 (I glad I kept that!)
90:
91: Pins:-
92: Vss
93: RX DATA Receive Data
94: RX CLK Receive Clock
95: TX CLK Transmitter Clock
96: RTS Request To Send
97: TX DATA Transmitter Data
98: IRQ Interrupt Request
99: CS 0,1,2 Chip Select
100: RS Register Select
101: Vcc Voltage
102: R/W Read/Write
103: E Enable
104: D0-D7 Data
105: DCD Data Carrier Detect
106: CTS Clear To Send
107:
108: Registers:-
109: 0xfffc00 Keyboard ACIA Control (write)/Status(read)
110: 0xfffc02 Keyboard ACIA Data
111: 0xfffc04 MIDI ACIA Control (write)/Status(read)
112: 0xfffc06 MIDI ACIA Data
113:
114: Control Register (0xfffc00 write):-
115: Bits 0,1 - These bits determine by which factor the transmitter and receiver
116: clock will be divided. These bits also are joined with a master reset
117: function. The 6850 has no separate reset line, so it must be
118: accomplished though software.
119: 0 0 RXCLK/TXCLK without division
120: 0 1 RXCLK/TXCLK by 16 (MIDI)
121: 1 0 RXCLK/TXCLK by 64 (Keyboard)
122: 1 1 Master RESET
123: Bits 2,3,4 - These so-called Word Select bits tell whether 7 or 8 data-bits are
124: involved; whether 1 or 2 stop-bits are transferred; and the type of parity
125: Bits 5,6 - These Transmitter Control bits set the RTS output pin, and allow or prevent
126: an interrupt through the ACIA when the send register is emptied. Also, BREAK signals
127: can be sent over the serial output by this line. A BREAK signal is nothing more than
128: a long seqence of null bits
129: 0 0 RTS low, transmitter IRQ disabled
130: 0 1 RTS low, transmitter IRQ enabled
131: 1 0 RTS high, transmitter IRQ disabled
132: 1 1 RTS low, transmitter IRQ disabled, BREAK sent
133: Bit 7 - The Receiver Interrupt Enable bit determines whether the receiver interrupt
134: will be on. An interrupt can be caused by the DCD line chaning from low to high, or
135: by the receiver data buffer filling. Besides that, an interrupt can occur from an
136: OVERRUN ( a received character isn't properly read from the processior).
137: 0 Interrupt disabled
138: 1 Interrupt enabled
139:
140: Status Register (0xfffc00 read):-
141: Bit 0 - When this bit is high, the RX data register is full. The byte must be read
142: before a new character is received (otherwise an OVERRUN happens)
143: Bit 1 - This bit reflects the status of the TX data buffer. An empty register
144: set the bit.
145: Bit 2 - A low-high change in pin DCD sets bit 2. If the receiver interrupt is allowable, the IRQ
146: is cancelled. The bit is cleared when the status register and the receiver register are
147: read. This also cancels the IRQ. Bit 2 register remains highis the signal on the DCD pin
148: is still high; Bit 2 register low if DCD becomes low.
149: Bit 3 - This line shows the status of CTS. This signal cannot be altered by a mater reset,
150: or by ACIA programming.
151: Bit 4 - Shows 'Frame Errors'. Frame errors are when no stop-bit is recognized in receiver
152: switching. It can be set with every new character.
153: Bit 5 - This bit display the previously mentioned OVERRUN condition. Bit 5 is reset when the
154: RX buffer is read.
155: Bit 6 - This bit recognizes whether the parity of a received character is correct. The bit is
156: set on an error.
157: Bit 7 - This signals the state of the IRQ pins; this bit make it possible to switch several
158: IRQ lines on one interrupt input. In cases where an interrupt is program-generated, bit 7
159: can tell which IC cut off the interrupt.
1.1.1.7 root 160:
1.1 root 161: ST ACIA:-
162: Note CTS,DCD and RTS are not connected! Phew!
163: The keyboard ACIA are address 0xfffc000 and 0xfffc02.
164: Default parameters are :- 8-bit word, 1 stopbit, no parity, 77812.5 baud; 500KHz/64 (keyboard clock div)
165: Default MIDI parameters are are above but :- 31250 baud; 500KHz/16 (MIDI clock div)
166: */
167:
1.1.1.2 root 168: /* List of possible keyboard commands, others are seen as NOPs by keyboard processor */
1.1.1.13! root 169: static void IKBD_Cmd_Reset(void);
! 170: static void IKBD_Cmd_MouseAction(void);
! 171: static void IKBD_Cmd_RelMouseMode(void);
! 172: static void IKBD_Cmd_AbsMouseMode(void);
! 173: static void IKBD_Cmd_MouseCursorKeycodes(void);
! 174: static void IKBD_Cmd_SetMouseThreshold(void);
! 175: static void IKBD_Cmd_SetMouseScale(void);
! 176: static void IKBD_Cmd_ReadAbsMousePos(void);
! 177: static void IKBD_Cmd_SetInternalMousePos(void);
! 178: static void IKBD_Cmd_SetYAxisDown(void);
! 179: static void IKBD_Cmd_SetYAxisUp(void);
! 180: static void IKBD_Cmd_StartKeyboardTransfer(void);
! 181: static void IKBD_Cmd_TurnMouseOff(void);
! 182: static void IKBD_Cmd_StopKeyboardTransfer(void);
! 183: static void IKBD_Cmd_ReturnJoystickAuto(void);
! 184: static void IKBD_Cmd_StopJoystick(void);
! 185: static void IKBD_Cmd_ReturnJoystick(void);
! 186: static void IKBD_Cmd_SetJoystickDuration(void);
! 187: static void IKBD_Cmd_SetJoystickFireDuration(void);
! 188: static void IKBD_Cmd_SetCursorForJoystick(void);
! 189: static void IKBD_Cmd_DisableJoysticks(void);
! 190: static void IKBD_Cmd_SetClock(void);
! 191: static void IKBD_Cmd_ReadClock(void);
! 192: static void IKBD_Cmd_LoadMemory(void);
! 193: static void IKBD_Cmd_ReadMemory(void);
! 194: static void IKBD_Cmd_Execute(void);
! 195: static void IKBD_Cmd_ReportMouseAction(void);
! 196: static void IKBD_Cmd_ReportMouseMode(void);
! 197: static void IKBD_Cmd_ReportMouseThreshold(void);
! 198: static void IKBD_Cmd_ReportMouseScale(void);
! 199: static void IKBD_Cmd_ReportMouseVertical(void);
! 200: static void IKBD_Cmd_ReportMouseAvailability(void);
! 201: static void IKBD_Cmd_ReportJoystickMode(void);
! 202: static void IKBD_Cmd_ReportJoystickAvailability(void);
! 203:
1.1.1.12 root 204: static const IKBD_COMMAND_PARAMS KeyboardCommands[] =
205: {
206: /* Known messages, counts include command byte */
207: { 0x80,2, IKBD_Cmd_Reset },
208: { 0x07,2, IKBD_Cmd_MouseAction },
209: { 0x08,1, IKBD_Cmd_RelMouseMode },
210: { 0x09,5, IKBD_Cmd_AbsMouseMode },
211: { 0x0A,3, IKBD_Cmd_MouseCursorKeycodes },
212: { 0x0B,3, IKBD_Cmd_SetMouseThreshold },
213: { 0x0C,3, IKBD_Cmd_SetMouseScale },
214: { 0x0D,1, IKBD_Cmd_ReadAbsMousePos },
215: { 0x0E,6, IKBD_Cmd_SetInternalMousePos },
216: { 0x0F,1, IKBD_Cmd_SetYAxisDown },
217: { 0x10,1, IKBD_Cmd_SetYAxisUp },
218: { 0x11,1, IKBD_Cmd_StartKeyboardTransfer },
219: { 0x12,1, IKBD_Cmd_TurnMouseOff },
220: { 0x13,1, IKBD_Cmd_StopKeyboardTransfer },
221: { 0x14,1, IKBD_Cmd_ReturnJoystickAuto },
222: { 0x15,1, IKBD_Cmd_StopJoystick },
223: { 0x16,1, IKBD_Cmd_ReturnJoystick },
224: { 0x17,2, IKBD_Cmd_SetJoystickDuration },
225: { 0x18,1, IKBD_Cmd_SetJoystickFireDuration },
226: { 0x19,7, IKBD_Cmd_SetCursorForJoystick },
227: { 0x1A,1, IKBD_Cmd_DisableJoysticks },
228: { 0x1B,7, IKBD_Cmd_SetClock },
229: { 0x1C,1, IKBD_Cmd_ReadClock },
230: { 0x20,4, IKBD_Cmd_LoadMemory },
231: { 0x21,3, IKBD_Cmd_ReadMemory },
232: { 0x22,3, IKBD_Cmd_Execute },
233:
1.1.1.13! root 234: /* Report message (top bit set) */
! 235: { 0x87,1, IKBD_Cmd_ReportMouseAction },
! 236: { 0x88,1, IKBD_Cmd_ReportMouseMode },
! 237: { 0x89,1, IKBD_Cmd_ReportMouseMode },
! 238: { 0x8A,1, IKBD_Cmd_ReportMouseMode },
! 239: { 0x8B,1, IKBD_Cmd_ReportMouseThreshold },
! 240: { 0x8C,1, IKBD_Cmd_ReportMouseScale },
! 241: { 0x8F,1, IKBD_Cmd_ReportMouseVertical },
! 242: { 0x90,1, IKBD_Cmd_ReportMouseVertical },
! 243: { 0x92,1, IKBD_Cmd_ReportMouseAvailability },
! 244: { 0x94,1, IKBD_Cmd_ReportJoystickMode },
! 245: { 0x95,1, IKBD_Cmd_ReportJoystickMode },
! 246: { 0x99,1, IKBD_Cmd_ReportJoystickMode },
! 247: { 0x9A,1, IKBD_Cmd_ReportJoystickAvailability },
1.1 root 248:
1.1.1.12 root 249: { 0xFF,0, NULL } /* Term */
1.1 root 250: };
251:
1.1.1.2 root 252:
1.1.1.13! root 253: static void IKBD_SendByteToKeyboardProcessor(Uint16 bl);
! 254: static Uint16 IKBD_GetByteFromACIA(void);
! 255: static void IKBD_SendByteToACIA(int nAciaCycles);
! 256: static void IKBD_AddKeyToKeyboardBuffer(Uint8 Data);
! 257: static void IKBD_AddKeyToKeyboardBufferWithDelay(Uint8 Data, int nAciaCycles);
! 258: static void IKBD_AddKeyToKeyboardBuffer_Real(Uint8 Data, int nAciaCycles);
! 259:
! 260:
! 261: /* Belows part is used to emulate the behaviour of custom 6301 programs */
! 262: /* sent to the ikbd RAM. */
! 263:
! 264: static void IKBD_LoadMemoryByte ( Uint8 aciabyte );
! 265:
! 266: static void IKBD_CustomCodeHandler_CommonBoot ( Uint8 aciabyte );
! 267:
! 268: static void IKBD_CustomCodeHandler_FroggiesMenu_Read ( void );
! 269: static void IKBD_CustomCodeHandler_FroggiesMenu_Write ( Uint8 aciabyte );
! 270: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Read ( void );
! 271: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Write ( Uint8 aciabyte );
! 272: static void IKBD_CustomCodeHandler_DragonnelsMenu_Read ( void );
! 273: static void IKBD_CustomCodeHandler_DragonnelsMenu_Write ( Uint8 aciabyte );
! 274:
! 275:
! 276: int MemoryLoadNbBytesTotal = 0; /* total number of bytes to send with the command 0x20 */
! 277: int MemoryLoadNbBytesLeft = 0; /* number of bytes that remain to be sent */
! 278: Uint32 MemoryLoadCrc = 0xffffffff; /* CRC of the bytes sent to the ikbd */
! 279: int MemoryExeNbBytes = 0; /* current number of bytes sent to the ikbd when IKBD_ExeMode is TRUE */
! 280:
! 281: void (*pIKBD_CustomCodeHandler_Read) ( void );
! 282: void (*pIKBD_CustomCodeHandler_Write) ( Uint8 );
! 283: bool IKBD_ExeMode = FALSE;
! 284:
! 285: Uint8 ScanCodeState[ 128 ]; /* state of each key : 0=released 1=pressed */
! 286:
! 287: /* This array contains all known custom 6301 programs, with their CRC */
! 288: struct
! 289: {
! 290: Uint32 LoadMemCrc; /* CRC of the bytes sent using the command 0x20 */
! 291: void (*ExeBootHandler) ( Uint8 ); /* function handling write to $fffc02 during the 'boot' mode */
! 292: int MainProgNbBytes; /* number of bytes of the main 6301 program */
! 293: Uint32 MainProgCrc; /* CRC of the main 6301 program */
! 294: void (*ExeMainHandler_Read) ( void );/* function handling read to $fffc02 in the main 6301 program */
! 295: void (*ExeMainHandler_Write) ( Uint8 ); /* funciton handling write to $fffc02 in the main 6301 program */
! 296: const char *Name;
! 297: }
! 298: CustomCodeDefinitions[] =
! 299: {
! 300: {
! 301: 0x2efb11b1 ,
! 302: IKBD_CustomCodeHandler_CommonBoot ,
! 303: 167,
! 304: 0xe7110b6d ,
! 305: IKBD_CustomCodeHandler_FroggiesMenu_Read ,
! 306: IKBD_CustomCodeHandler_FroggiesMenu_Write ,
! 307: "Froggies Over The Fence Main Menu"
! 308: } ,
! 309: {
! 310: 0xadb6b503 ,
! 311: IKBD_CustomCodeHandler_CommonBoot ,
! 312: 165,
! 313: 0x5617c33c ,
! 314: IKBD_CustomCodeHandler_Transbeauce2Menu_Read ,
! 315: IKBD_CustomCodeHandler_Transbeauce2Menu_Write ,
! 316: "Transbeauce 2 Main Menu"
! 317: } ,
! 318: {
! 319: 0x33c23cdf ,
! 320: IKBD_CustomCodeHandler_CommonBoot ,
! 321: 83 ,
! 322: 0xdf3e5a88 ,
! 323: IKBD_CustomCodeHandler_DragonnelsMenu_Read ,
! 324: IKBD_CustomCodeHandler_DragonnelsMenu_Write ,
! 325: "Dragonnels Main Menu"
! 326: }
! 327: };
! 328:
! 329:
! 330:
1.1.1.2 root 331: /*-----------------------------------------------------------------------*/
1.1.1.12 root 332: /**
333: * Reset the ACIA
334: */
335: void ACIA_Reset(void)
336: {
337: bByteInTransitToACIA = FALSE;
338: ACIAControlRegister = 0;
339: ACIAStatusRegister = ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY;
340: }
341:
342:
343: /*-----------------------------------------------------------------------*/
344: /**
345: * Reset the IKBD processor
346: */
1.1.1.13! root 347:
! 348: /* Cancel execution of any program that was uploaded to the 6301's RAM */
! 349: /* This function is also called when performing a 68000 'reset' ; in that */
! 350: /* case we need to return $F0 and $F1. */
! 351:
! 352: void IKBD_Reset_ExeMode ( void )
1.1 root 353: {
1.1.1.13! root 354: HATARI_TRACE ( HATARI_TRACE_IKBD_EXEC, "ikbd custom exe off\n" );
! 355:
! 356: /* Reset any custom code run with the Execute command 0x22 */
! 357: MemoryLoadNbBytesLeft = 0;
! 358: pIKBD_CustomCodeHandler_Read = NULL;
! 359: pIKBD_CustomCodeHandler_Write = NULL;
! 360: IKBD_ExeMode = FALSE;
! 361:
! 362: Keyboard.BufferHead = Keyboard.BufferTail = 0; /* flush all queued bytes that would be read in $fffc02 */
! 363: bByteInTransitToACIA = FALSE;
! 364: IKBD_AddKeyToKeyboardBuffer(0xF0); /* Assume OK, return correct code */
! 365: IKBD_AddKeyToKeyboardBuffer(0xF1); /* [NP] Dragonnels demo needs this */
! 366: }
! 367:
! 368:
! 369: void IKBD_Reset(bool bCold)
! 370: {
! 371: int i;
! 372:
! 373:
1.1.1.12 root 374: /* Reset internal keyboard processor details */
375: if (bCold)
376: {
377: KeyboardProcessor.bReset = FALSE;
378: if (Int_InterruptActive(INTERRUPT_IKBD_RESETTIMER))
379: Int_RemovePendingInterrupt(INTERRUPT_IKBD_RESETTIMER);
380: }
381:
382: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
383: KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
384:
385: KeyboardProcessor.Abs.X = ABS_X_ONRESET;
386: KeyboardProcessor.Abs.Y = ABS_Y_ONRESET;
387: KeyboardProcessor.Abs.MaxX = ABS_MAX_X_ONRESET;
388: KeyboardProcessor.Abs.MaxY = ABS_MAY_Y_ONRESET;
389: KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
390:
391: KeyboardProcessor.Mouse.DeltaX = KeyboardProcessor.Mouse.DeltaY = 0;
392: KeyboardProcessor.Mouse.XScale = KeyboardProcessor.Mouse.YScale = 0;
393: KeyboardProcessor.Mouse.XThreshold = KeyboardProcessor.Mouse.YThreshold = 1;
394: KeyboardProcessor.Mouse.YAxis = 1; /* Y origin at top */
395: KeyboardProcessor.Mouse.Action = 0;
396:
397: KeyboardProcessor.Joy.PrevJoyData[0] = KeyboardProcessor.Joy.PrevJoyData[1] = 0;
398:
1.1.1.13! root 399: for ( i=0 ; i<128 ; i++ )
! 400: ScanCodeState[ i ] = 0; /* key is released */
! 401:
1.1.1.12 root 402: /* Reset our ACIA status */
403: ACIA_Reset();
404: /* And our keyboard states and clear key state table */
405: Keyboard.BufferHead = Keyboard.BufferTail = 0;
406: Keyboard.nBytesInInputBuffer = 0;
407: memset(Keyboard.KeyStates, 0, sizeof(Keyboard.KeyStates));
408: Keyboard.bLButtonDown = BUTTON_NULL;
409: Keyboard.bRButtonDown = BUTTON_NULL;
410: Keyboard.bOldLButtonDown = Keyboard.bOldRButtonDown = BUTTON_NULL;
411: Keyboard.LButtonDblClk = Keyboard.RButtonDblClk = 0;
412: Keyboard.LButtonHistory = Keyboard.RButtonHistory = 0;
413:
1.1.1.13! root 414: /* Store bool for when disable mouse or joystick */
1.1.1.12 root 415: bMouseDisabled = bJoystickDisabled = FALSE;
416: /* do emulate hardware 'quirk' where if disable both with 'x' time
417: * of a RESET command they are ignored! */
418: bDuringResetCriticalTime = bBothMouseAndJoy = FALSE;
1.1.1.13! root 419:
! 420: /* Remove any custom handlers used to emulate code loaded to the 6301's RAM */
! 421: IKBD_Reset_ExeMode ();
1.1 root 422: }
423:
1.1.1.2 root 424:
425: /*-----------------------------------------------------------------------*/
1.1.1.12 root 426: /**
427: * Save/Restore snapshot of local variables
428: * ('MemorySnapShot_Store' handles type)
429: */
1.1.1.13! root 430: void IKBD_MemorySnapShot_Capture(bool bSave)
1.1 root 431: {
1.1.1.13! root 432: unsigned int i;
! 433:
1.1.1.12 root 434: /* Save/Restore details */
435: MemorySnapShot_Store(&Keyboard, sizeof(Keyboard));
436: MemorySnapShot_Store(&KeyboardProcessor, sizeof(KeyboardProcessor));
437: MemorySnapShot_Store(&ACIAControlRegister, sizeof(ACIAControlRegister));
438: MemorySnapShot_Store(&ACIAStatusRegister, sizeof(ACIAStatusRegister));
439: MemorySnapShot_Store(&ACIAByte, sizeof(ACIAByte));
440: MemorySnapShot_Store(&bByteInTransitToACIA, sizeof(bByteInTransitToACIA));
441: MemorySnapShot_Store(&bMouseDisabled, sizeof(bMouseDisabled));
442: MemorySnapShot_Store(&bJoystickDisabled, sizeof(bJoystickDisabled));
443: MemorySnapShot_Store(&bDuringResetCriticalTime, sizeof(bDuringResetCriticalTime));
444: MemorySnapShot_Store(&bBothMouseAndJoy, sizeof(bBothMouseAndJoy));
1.1.1.13! root 445:
! 446: /* restore custom 6301 program if needed */
! 447: MemorySnapShot_Store(&IKBD_ExeMode, sizeof(IKBD_ExeMode));
! 448: MemorySnapShot_Store(&MemoryLoadCrc, sizeof(MemoryLoadCrc));
! 449: if ( ( bSave == FALSE ) && ( IKBD_ExeMode == TRUE ) ) /* restoring a snapshot with active 6301 emulation */
! 450: {
! 451: for ( i = 0 ; i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ); i++ )
! 452: if ( CustomCodeDefinitions[ i ].MainProgCrc == MemoryLoadCrc )
! 453: {
! 454: pIKBD_CustomCodeHandler_Read = CustomCodeDefinitions[ i ].ExeMainHandler_Read;
! 455: pIKBD_CustomCodeHandler_Write = CustomCodeDefinitions[ i ].ExeMainHandler_Write;
! 456: Keyboard.BufferHead = Keyboard.BufferTail = 0; /* flush all queued bytes that would be read in $fffc02 */
! 457: // (*pIKBD_CustomCodeHandler_Read) (); /* initialize ACIAByte */
! 458: ACIAByte = 0; /* initialize ACIAByte, don't call IKBD_AddKeyToKeyboardBuffer_Real now */
! 459: break;
! 460: }
! 461:
! 462: if ( i >= sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ) /* not found (should not happen) */
! 463: IKBD_ExeMode = FALSE; /* turn off exe mode */
! 464: }
1.1 root 465: }
466:
1.1.1.2 root 467:
468: /*-----------------------------------------------------------------------*/
1.1.1.12 root 469: /**
470: * Calculate out 'delta' that mouse has moved by each frame, and add this to our internal keyboard position
471: */
1.1.1.8 root 472: static void IKBD_UpdateInternalMousePosition(void)
1.1 root 473: {
474:
1.1.1.12 root 475: KeyboardProcessor.Mouse.DeltaX = KeyboardProcessor.Mouse.dx;
476: KeyboardProcessor.Mouse.DeltaY = KeyboardProcessor.Mouse.dy;
477: KeyboardProcessor.Mouse.dx = 0;
478: KeyboardProcessor.Mouse.dy = 0;
479:
480: /* Update internal mouse coords - Y axis moves according to YAxis setting(up/down) */
481: /* Limit to Max X/Y(inclusive) */
482: KeyboardProcessor.Abs.X += KeyboardProcessor.Mouse.DeltaX;
483: if (KeyboardProcessor.Abs.X < 0)
484: KeyboardProcessor.Abs.X = 0;
485: if (KeyboardProcessor.Abs.X > KeyboardProcessor.Abs.MaxX)
486: KeyboardProcessor.Abs.X = KeyboardProcessor.Abs.MaxX;
487:
488: KeyboardProcessor.Abs.Y += KeyboardProcessor.Mouse.DeltaY*KeyboardProcessor.Mouse.YAxis; /* Needed '+' for Falcon... */
489: if (KeyboardProcessor.Abs.Y < 0)
490: KeyboardProcessor.Abs.Y = 0;
491: if (KeyboardProcessor.Abs.Y > KeyboardProcessor.Abs.MaxY)
492: KeyboardProcessor.Abs.Y = KeyboardProcessor.Abs.MaxY;
1.1.1.4 root 493:
1.1 root 494: }
495:
1.1.1.2 root 496:
497: /*-----------------------------------------------------------------------*/
1.1.1.12 root 498: /**
499: * When running in maximum speed the emulation will not see 'double-clicks'
500: * of the mouse as it is running so fast. In this case, we check for a
501: * double-click and pass the 'up'/'down' messages in emulation time to
502: * simulate the double-click effect!
503: */
1.1.1.8 root 504: static void IKBD_CheckForDoubleClicks(void)
1.1 root 505: {
1.1.1.12 root 506: /*
507: Things get a little complicated when running max speed as a normal
508: double-click is a load of 1's, followed by 0's, 1's and 0's - But the
509: ST does not see this as a double click as the space in 'ST' time
510: between changes is so great.
511: Now, when we see a real double-click in max speed we actually send
512: the down/up/down/up in ST time. To get this correct (and not send
513: three clicks) we look in a history buffer and start at an index which
514: gives the correct number of clicks! Phew!
515: */
516:
517: /* Handle double clicks!!! */
518: if (Keyboard.LButtonDblClk)
519: {
520: if (Keyboard.LButtonDblClk == 1) /* First pressed! */
521: {
522: if ((Keyboard.LButtonHistory&0x3f) == 0) /* If not pressed button in long time do full dbl-click pattern */
523: Keyboard.LButtonDblClk = 1;
524: else
525: {
526: Keyboard.LButtonDblClk = 4; /* Otherwise, check where to begin to give 1111000011110000 pattern */
527: if ((Keyboard.LButtonHistory&0x7) == 0)
528: Keyboard.LButtonDblClk = 8;
529: else if ((Keyboard.LButtonHistory&0x3) == 0)
530: Keyboard.LButtonDblClk = 7;
531: else if ((Keyboard.LButtonHistory&0x1) == 0)
532: Keyboard.LButtonDblClk = 6;
533: }
534: }
535:
536: Keyboard.bLButtonDown = DoubleClickPattern[Keyboard.LButtonDblClk];
537: Keyboard.LButtonDblClk++;
538: if (Keyboard.LButtonDblClk >= 13) /* Check for end of sequence */
539: {
540: Keyboard.LButtonDblClk = 0;
541: Keyboard.bLButtonDown = FALSE;
542: }
543: }
544: if (Keyboard.RButtonDblClk)
545: {
546: if (Keyboard.RButtonDblClk == 1) /* First pressed! */
547: {
548: if ((Keyboard.RButtonHistory&0x3f) == 0) /* If not pressed button in long time do full dbl-click pattern */
549: Keyboard.RButtonDblClk = 1;
550: else
551: {
552: Keyboard.RButtonDblClk = 4; /* Otherwise, check where to begin to give 1111000011110000 pattern */
553: if ((Keyboard.RButtonHistory&0x7) == 0)
554: Keyboard.RButtonDblClk = 8;
555: else if ((Keyboard.RButtonHistory&0x3) == 0)
556: Keyboard.RButtonDblClk = 7;
557: else if ((Keyboard.RButtonHistory&0x1) == 0)
558: Keyboard.RButtonDblClk = 6;
559: }
560: }
561:
562: Keyboard.bRButtonDown = DoubleClickPattern[Keyboard.RButtonDblClk];
563: Keyboard.RButtonDblClk++;
564: if (Keyboard.RButtonDblClk >= 13) /* Check for end of sequence */
565: {
566: Keyboard.RButtonDblClk = 0;
567: Keyboard.bRButtonDown = FALSE;
568: }
569: }
570:
571: /* Store presses into history */
572: Keyboard.LButtonHistory = (Keyboard.LButtonHistory<<1);
573: if (Keyboard.bLButtonDown)
574: Keyboard.LButtonHistory |= 0x1;
575: Keyboard.RButtonHistory = (Keyboard.RButtonHistory<<1);
576: if (Keyboard.bRButtonDown)
577: Keyboard.RButtonHistory |= 0x1;
578: }
579:
580:
581: /*-----------------------------------------------------------------------*/
582: /**
1.1.1.13! root 583: * Convert button to bool value
1.1.1.12 root 584: */
1.1.1.13! root 585: static bool IKBD_ButtonBool(int Button)
1.1 root 586: {
1.1.1.12 root 587: /* Button pressed? */
588: if (Button)
589: return TRUE;
590: return FALSE;
1.1 root 591: }
592:
1.1.1.2 root 593:
594: /*-----------------------------------------------------------------------*/
1.1.1.12 root 595: /**
1.1.1.13! root 596: * Return TRUE if buttons match, use this as buttons are a mask and not boolean
1.1.1.12 root 597: */
1.1.1.13! root 598: static bool IKBD_ButtonsEqual(int Button1,int Button2)
1.1 root 599: {
1.1.1.13! root 600: /* Return bool compare */
1.1.1.12 root 601: return (IKBD_ButtonBool(Button1) == IKBD_ButtonBool(Button2));
1.1 root 602: }
603:
1.1.1.2 root 604:
605: /*-----------------------------------------------------------------------*/
1.1.1.12 root 606: /**
1.1.1.13! root 607: * According to if the mouse is enabled or not the joystick 1 fire
! 608: * button/right mouse button will become the same button. That means
! 609: * pressing one will also press the other and vice-versa.
! 610: * If both mouse and joystick are enabled, report it as a mouse button
! 611: * (needed by the game Big Run for example).
1.1.1.12 root 612: */
1.1.1.8 root 613: static void IKBD_DuplicateMouseFireButtons(void)
1.1 root 614: {
1.1.1.12 root 615: /* If mouse is off then joystick fire button goes to joystick */
1.1.1.13! root 616: if (!bBothMouseAndJoy && KeyboardProcessor.MouseMode==AUTOMODE_OFF)
1.1.1.12 root 617: {
618: /* If pressed right mouse button, should go to joystick 1 */
619: if (Keyboard.bRButtonDown&BUTTON_MOUSE)
620: KeyboardProcessor.Joy.JoyData[1] |= 0x80;
621: /* And left mouse button, should go to joystick 0 */
622: if (Keyboard.bLButtonDown&BUTTON_MOUSE)
623: KeyboardProcessor.Joy.JoyData[0] |= 0x80;
624: }
1.1.1.13! root 625: /* If mouse is on, joystick 1 fire button goes to the mouse instead */
1.1.1.12 root 626: else
627: {
628: /* Is fire button pressed? */
629: if (KeyboardProcessor.Joy.JoyData[1]&0x80)
630: {
631: KeyboardProcessor.Joy.JoyData[1] &= 0x7f; /* Clear fire button bit */
632: Keyboard.bRButtonDown |= BUTTON_JOYSTICK; /* Mimick on mouse right button */
633: }
634: else
635: Keyboard.bRButtonDown &= ~BUTTON_JOYSTICK;
636: }
1.1 root 637: }
638:
1.1.1.2 root 639:
640: /*-----------------------------------------------------------------------*/
1.1.1.12 root 641: /**
642: * Send 'relative' mouse position
643: */
1.1.1.8 root 644: static void IKBD_SendRelMousePacket(void)
1.1 root 645: {
1.1.1.12 root 646: int ByteRelX,ByteRelY;
647: Uint8 Header;
1.1 root 648:
1.1.1.12 root 649: if ( (KeyboardProcessor.Mouse.DeltaX!=0) || (KeyboardProcessor.Mouse.DeltaY!=0)
650: || (!IKBD_ButtonsEqual(Keyboard.bOldLButtonDown,Keyboard.bLButtonDown)) || (!IKBD_ButtonsEqual(Keyboard.bOldRButtonDown,Keyboard.bRButtonDown)) )
651: {
652: /* Send packet to keyboard process */
653: while (TRUE)
654: {
655: ByteRelX = KeyboardProcessor.Mouse.DeltaX;
656: if (ByteRelX>127) ByteRelX = 127;
657: if (ByteRelX<-128) ByteRelX = -128;
658: ByteRelY = KeyboardProcessor.Mouse.DeltaY;
659: if (ByteRelY>127) ByteRelY = 127;
660: if (ByteRelY<-128) ByteRelY = -128;
661:
662: Header = 0xf8;
663: if (Keyboard.bLButtonDown)
664: Header |= 0x02;
665: if (Keyboard.bRButtonDown)
666: Header |= 0x01;
667: IKBD_AddKeyToKeyboardBuffer(Header);
668: IKBD_AddKeyToKeyboardBuffer(ByteRelX);
669: IKBD_AddKeyToKeyboardBuffer(ByteRelY*KeyboardProcessor.Mouse.YAxis);
670:
671: KeyboardProcessor.Mouse.DeltaX -= ByteRelX;
672: KeyboardProcessor.Mouse.DeltaY -= ByteRelY;
673:
674: if ( (KeyboardProcessor.Mouse.DeltaX==0) && (KeyboardProcessor.Mouse.DeltaY==0) )
675: break;
676:
677: /* Store buttons for next time around */
678: Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
679: Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
680: }
681: }
1.1 root 682: }
683:
1.1.1.2 root 684:
1.1.1.13! root 685: /**
! 686: * Get joystick data
! 687: */
! 688: static void IKBD_GetJoystickData(void)
! 689: {
! 690: /* Joystick 1 */
! 691: KeyboardProcessor.Joy.JoyData[1] = Joy_GetStickData(1);
! 692:
! 693: /* If mouse is on, joystick 0 is not connected */
! 694: if (KeyboardProcessor.MouseMode==AUTOMODE_OFF
! 695: || (bBothMouseAndJoy && KeyboardProcessor.MouseMode==AUTOMODE_MOUSEREL))
! 696: KeyboardProcessor.Joy.JoyData[0] = Joy_GetStickData(0);
! 697: else
! 698: KeyboardProcessor.Joy.JoyData[0] = 0x00;
! 699: }
! 700:
! 701:
1.1.1.2 root 702: /*-----------------------------------------------------------------------*/
1.1.1.12 root 703: /**
704: * Send 'joysticks' bit masks
705: */
1.1.1.8 root 706: static void IKBD_SelAutoJoysticks(void)
1.1 root 707: {
1.1.1.12 root 708: Uint8 JoyData;
1.1 root 709:
1.1.1.12 root 710: /* Did joystick 0/mouse change? */
711: JoyData = KeyboardProcessor.Joy.JoyData[0];
712: if (JoyData!=KeyboardProcessor.Joy.PrevJoyData[0])
713: {
714: IKBD_AddKeyToKeyboardBuffer(0xFE); /* Joystick 0/Mouse */
715: IKBD_AddKeyToKeyboardBuffer(JoyData);
716:
717: KeyboardProcessor.Joy.PrevJoyData[0] = JoyData;
718: }
719:
720: /* Did joystick 1(default) change? */
721: JoyData = KeyboardProcessor.Joy.JoyData[1];
722: if (JoyData!=KeyboardProcessor.Joy.PrevJoyData[1])
723: {
724: IKBD_AddKeyToKeyboardBuffer(0xFF); /* Joystick 1 */
725: IKBD_AddKeyToKeyboardBuffer(JoyData);
726:
727: KeyboardProcessor.Joy.PrevJoyData[1] = JoyData;
728: }
1.1 root 729: }
730:
731: /*-----------------------------------------------------------------------*/
1.1.1.12 root 732: /**
733: * Send packets which are generated from the mouse action settings
734: * If relative mode is on, still generate these packets
735: */
1.1.1.8 root 736: static void IKBD_SendOnMouseAction(void)
1.1 root 737: {
1.1.1.13! root 738: bool bReportPosition = FALSE;
1.1 root 739:
1.1.1.12 root 740: /* Report buttons as keys? Do in relative/absolute mode */
741: if (KeyboardProcessor.Mouse.Action&0x4)
742: {
743: /* Left button? */
744: if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) )
745: IKBD_AddKeyToKeyboardBuffer(0x74); /* Left */
746: else if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) )
747: IKBD_AddKeyToKeyboardBuffer(0x74|0x80);
748: /* Right button? */
749: if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
750: IKBD_AddKeyToKeyboardBuffer(0x75); /* Right */
751: else if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
752: IKBD_AddKeyToKeyboardBuffer(0x75|0x80);
753:
754: /* Ignore bottom two bits, so return now */
755: return;
756: }
757:
758: /* Check MouseAction - report position on press/release */
759: /* MUST do this before update relative positions as buttons get reset */
760: if (KeyboardProcessor.Mouse.Action&0x3)
761: {
762: /* Check for 'press'? */
763: if (KeyboardProcessor.Mouse.Action&0x1)
764: {
765: /* Did 'press' mouse buttons? */
766: if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) )
767: {
768: bReportPosition = TRUE;
769: KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x04;
770: KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x02;
771: }
772: if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
773: {
774: bReportPosition = TRUE;
775: KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x01;
776: KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x08;
777: }
778: }
779: /* Check for 'release'? */
780: if (KeyboardProcessor.Mouse.Action&0x2)
781: {
782: /* Did 'release' mouse buttons? */
783: if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) )
784: {
785: bReportPosition = TRUE;
786: KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x08;
787: KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x01;
788: }
789: if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
790: {
791: bReportPosition = TRUE;
792: KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x02;
793: KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x04;
794: }
795: }
796:
797: /* Do need to report? */
798: if (bReportPosition)
799: {
800: /* Only report if mouse in absolute mode */
801: if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSEABS)
802: {
1.1.1.13! root 803: HATARI_TRACE(HATARI_TRACE_IKBD_ALL, "Report ABS on MouseAction\n");
1.1.1.12 root 804: IKBD_Cmd_ReadAbsMousePos();
805: }
806: }
807: }
808: }
809:
810:
811: /*-----------------------------------------------------------------------*/
812: /**
813: * Send mouse movements as cursor keys
814: */
1.1.1.8 root 815: static void IKBD_SendCursorMousePacket(void)
1.1 root 816: {
1.1.1.12 root 817: int i=0;
1.1 root 818:
1.1.1.12 root 819: /* Run each 'Delta' as cursor presses */
820: /* Limit to '10' loops as host mouse cursor might have a VERY poor quality. */
821: /* Eg, a single mouse movement on and ST gives delta's of '1', mostly, */
822: /* but host mouse might go as high as 20+! */
823: while ( (i<10) && ((KeyboardProcessor.Mouse.DeltaX!=0) || (KeyboardProcessor.Mouse.DeltaY!=0)
824: || (!IKBD_ButtonsEqual(Keyboard.bOldLButtonDown,Keyboard.bLButtonDown)) || (!IKBD_ButtonsEqual(Keyboard.bOldRButtonDown,Keyboard.bRButtonDown))) )
825: {
826: /* Left? */
827: if (KeyboardProcessor.Mouse.DeltaX<0)
828: {
829: IKBD_AddKeyToKeyboardBuffer(75); /* Left cursor */
830: IKBD_AddKeyToKeyboardBuffer(75|0x80);
831: KeyboardProcessor.Mouse.DeltaX++;
832: }
833: /* Right? */
834: if (KeyboardProcessor.Mouse.DeltaX>0)
835: {
836: IKBD_AddKeyToKeyboardBuffer(77); /* Right cursor */
837: IKBD_AddKeyToKeyboardBuffer(77|0x80);
838: KeyboardProcessor.Mouse.DeltaX--;
839: }
840: /* Up? */
841: if (KeyboardProcessor.Mouse.DeltaY<0)
842: {
843: IKBD_AddKeyToKeyboardBuffer(72); /* Up cursor */
844: IKBD_AddKeyToKeyboardBuffer(72|0x80);
845: KeyboardProcessor.Mouse.DeltaY++;
846: }
847: /* Down? */
848: if (KeyboardProcessor.Mouse.DeltaY>0)
849: {
850: IKBD_AddKeyToKeyboardBuffer(80); /* Down cursor */
851: IKBD_AddKeyToKeyboardBuffer(80|0x80);
852: KeyboardProcessor.Mouse.DeltaY--;
853: }
854:
855: /* Left button? */
856: if ( (IKBD_ButtonBool(Keyboard.bLButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldLButtonDown))) )
857: IKBD_AddKeyToKeyboardBuffer(0x74); /* Left */
858: else if ( (IKBD_ButtonBool(Keyboard.bOldLButtonDown) && (!IKBD_ButtonBool(Keyboard.bLButtonDown))) )
859: IKBD_AddKeyToKeyboardBuffer(0x74|0x80);
860: /* Right button? */
861: if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
862: IKBD_AddKeyToKeyboardBuffer(0x75); /* Right */
863: else if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
864: IKBD_AddKeyToKeyboardBuffer(0x75|0x80);
865:
866: Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
867: Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
868:
869: /* Count, so exit if try too many times! */
870: i++;
871: }
1.1 root 872: }
873:
1.1.1.2 root 874:
875: /*-----------------------------------------------------------------------*/
1.1.1.12 root 876: /**
877: * Return packets from keyboard for auto, rel mouse, joystick etc...
878: */
1.1 root 879: void IKBD_SendAutoKeyboardCommands(void)
880: {
1.1.1.12 root 881: /* Don't do anything until processor is first reset */
882: if (!KeyboardProcessor.bReset)
883: return;
884:
885: /* Read joysticks for this frame */
1.1.1.13! root 886: IKBD_GetJoystickData();
1.1.1.12 root 887:
888: /* Check for double-clicks in maximum speed mode */
889: IKBD_CheckForDoubleClicks();
890:
891: /* Handle Joystick/Mouse fire buttons */
892: IKBD_DuplicateMouseFireButtons();
893:
894: /* Send any packets which are to be reported by mouse action */
895: IKBD_SendOnMouseAction();
896:
897: /* Update internal mouse absolute position by find 'delta' of mouse movement */
898: IKBD_UpdateInternalMousePosition();
899:
900: /* Send automatic joystick packets */
901: if (KeyboardProcessor.JoystickMode==AUTOMODE_JOYSTICK)
902: IKBD_SelAutoJoysticks();
903: /* Send automatic relative mouse positions(absolute are not send automatically) */
904: if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSEREL)
905: IKBD_SendRelMousePacket();
906: /* Send cursor key directions for movements */
907: else if (KeyboardProcessor.MouseMode==AUTOMODE_MOUSECURSOR)
908: IKBD_SendCursorMousePacket();
909:
910: /* Store buttons for next time around */
911: Keyboard.bOldLButtonDown = Keyboard.bLButtonDown;
912: Keyboard.bOldRButtonDown = Keyboard.bRButtonDown;
913:
914: /* Send joystick button '2' as 'Space bar' key - MUST do here so does not get mixed up in middle of joystick packets! */
915: if (JoystickSpaceBar)
916: {
917: /* As we simulating space bar? */
918: if (JoystickSpaceBar==JOYSTICK_SPACE_DOWN)
919: {
920: IKBD_PressSTKey(57,TRUE); /* Press */
921: JoystickSpaceBar = JOYSTICK_SPACE_UP;
922: }
923: else //if (JoystickSpaceBar==JOYSTICK_SPACE_UP) {
924: {
925: IKBD_PressSTKey(57,FALSE); /* Release */
926: JoystickSpaceBar = FALSE; /* Complete */
927: }
928: }
1.1 root 929: }
930:
1.1.1.2 root 931:
932: /*-----------------------------------------------------------------------*/
1.1.1.12 root 933: /**
934: * On ST if disable Mouse AND Joystick with a set time of a RESET command they are
935: * actually turned back on! (A number of games do this so can get mouse and joystick
936: * packets at the same time)
937: */
1.1.1.8 root 938: static void IKBD_CheckResetDisableBug(void)
1.1 root 939: {
1.1.1.12 root 940: /* Have disabled BOTH mouse and joystick? */
941: if (bMouseDisabled && bJoystickDisabled)
942: {
943: /* And in critical time? */
944: if (bDuringResetCriticalTime)
945: {
946: /* Emulate relative mouse and joystick reports being turned back on */
947: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
948: KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
949: bBothMouseAndJoy = TRUE;
1.1.1.6 root 950:
1.1.1.13! root 951: HATARI_TRACE(HATARI_TRACE_IKBD_ALL, "IKBD Mouse+Joystick disabled "
! 952: "during RESET. Revert.\n");
1.1.1.12 root 953: }
954: }
1.1 root 955: }
956:
1.1.1.2 root 957:
958: /*-----------------------------------------------------------------------*/
1.1.1.12 root 959: /**
960: * Start timer after keyboard RESET command to emulate 'quirk'
961: * If some IKBD commands are sent during time after a RESET they may be ignored
962: */
1.1 root 963: void IKBD_InterruptHandler_ResetTimer(void)
964: {
1.1.1.12 root 965: /* Remove this interrupt from list and re-order */
966: Int_AcknowledgeInterrupt();
1.1 root 967:
1.1.1.12 root 968: /* Turn processor on; can now process commands */
969: KeyboardProcessor.bReset = TRUE;
1.1.1.9 root 970:
1.1.1.12 root 971: /* Critical timer is over */
972: bDuringResetCriticalTime = FALSE;
1.1 root 973: }
974:
975:
976:
1.1.1.2 root 977: /*-----------------------------------------------------------------------*/
1.1 root 978: /*
979: List of keyboard commands
980: */
981:
982:
1.1.1.2 root 983: /*-----------------------------------------------------------------------*/
1.1.1.12 root 984: /**
985: * RESET
986: *
987: * 0x80
988: * 0x01
989: *
990: * Performs self test and checks for stuck (closed) keys, if OK returns 0xF0. Otherwise
991: * returns break codes for keys
992: */
1.1.1.13! root 993: static void IKBD_Cmd_Reset(void)
1.1 root 994: {
1.1.1.12 root 995: /* Check for error series of bytes, eg 0x80,0x01 */
996: if (Keyboard.InputBuffer[1] == 0x01)
997: {
1.1.1.13! root 998: HATARI_TRACE(HATARI_TRACE_IKBD_ALL, "KEYBOARD ON\n");
1.1.1.12 root 999:
1000: /* Set defaults */
1001: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1002: KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
1003: KeyboardProcessor.Abs.X = ABS_X_ONRESET;
1004: KeyboardProcessor.Abs.Y = ABS_Y_ONRESET;
1005: KeyboardProcessor.Abs.MaxX = ABS_MAX_X_ONRESET;
1006: KeyboardProcessor.Abs.MaxY = ABS_MAY_Y_ONRESET;
1007: KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
1008:
1.1.1.13! root 1009: Keyboard.BufferHead = Keyboard.BufferTail = 0; /* flush all queued bytes that would be read in $fffc02 */
! 1010: IKBD_AddKeyToKeyboardBuffer(0xF0); /* Assume OK, return correct code */
! 1011: IKBD_AddKeyToKeyboardBuffer(0xF1); /* [NP] Dragonnels demo needs this */
1.1.1.12 root 1012:
1013: /* Start timer - some commands are send during this time they may be ignored (see real ST!) */
1.1.1.13! root 1014: Int_AddRelativeInterrupt(IKBD_RESET_CYCLES, INT_CPU_CYCLE, INTERRUPT_IKBD_RESETTIMER);
1.1.1.12 root 1015:
1016: /* Set this 'critical' flag, gets reset when timer expires */
1017: bDuringResetCriticalTime = TRUE;
1018: bMouseDisabled = bJoystickDisabled = FALSE;
1019: bBothMouseAndJoy = FALSE;
1020: }
1021: /* else if not 0x80,0x01 just ignore */
1.1.1.13! root 1022: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_Reset\n");
1.1 root 1023: }
1024:
1.1.1.2 root 1025:
1026: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1027: /**
1028: * SET MOUSE BUTTON ACTION
1029: *
1030: * 0x07
1031: * %00000mss ; mouse button action
1032: * ; (m is presumed =1 when in MOUSE KEYCODE mode)
1033: * ; mss=0xy, mouse button press or release causes mouse
1034: * ; position report
1035: * ; where y=1, mouse key press causes absolute report
1036: * ; and x=1, mouse key release causes absolute report
1037: * ; mss=100, mouse buttons act like keys
1038: */
1.1.1.13! root 1039: static void IKBD_Cmd_MouseAction(void)
1.1 root 1040: {
1.1.1.12 root 1041: KeyboardProcessor.Mouse.Action = Keyboard.InputBuffer[1];
1042: KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
1.1.1.13! root 1043:
! 1044: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_MouseAction %d\n",
! 1045: (unsigned int)KeyboardProcessor.Mouse.Action);
1.1 root 1046: }
1047:
1.1.1.2 root 1048:
1049: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1050: /**
1051: * SET RELATIVE MOUSE POSITION REPORTING
1052: *
1053: * 0x08
1054: */
1.1.1.13! root 1055: static void IKBD_Cmd_RelMouseMode(void)
1.1 root 1056: {
1.1.1.12 root 1057: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1.1.1.13! root 1058:
! 1059: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_RelMouseMode\n");
1.1 root 1060: }
1061:
1.1.1.2 root 1062:
1063: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1064: /**
1065: * SET ABSOLUTE MOUSE POSITIONING
1066: *
1067: * 0x09
1068: * XMSB ;X maximum (in scaled mouse clicks)
1069: * XLSB
1070: * YMSB ;Y maximum (in scaled mouse clicks)
1071: * YLSB
1072: */
1.1.1.13! root 1073: static void IKBD_Cmd_AbsMouseMode(void)
1.1 root 1074: {
1.1.1.12 root 1075: /* These maximums are 'inclusive' */
1076: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEABS;
1077: KeyboardProcessor.Abs.MaxX = (((unsigned int)Keyboard.InputBuffer[1])<<8) | (unsigned int)Keyboard.InputBuffer[2];
1078: KeyboardProcessor.Abs.MaxY = (((unsigned int)Keyboard.InputBuffer[3])<<8) | (unsigned int)Keyboard.InputBuffer[4];
1.1.1.13! root 1079:
! 1080: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_AbsMouseMode %d,%d\n",
! 1081: KeyboardProcessor.Abs.MaxX, KeyboardProcessor.Abs.MaxY);
1.1 root 1082: }
1083:
1.1.1.2 root 1084:
1085: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1086: /**
1087: * SET MOUSE KEYCODE MODE
1088: *
1089: * 0x0A
1090: * deltax ; distance in X clicks to return (LEFT) or (RIGHT)
1091: * deltay ; distance in Y clicks to return (UP) or (DOWN)
1092: */
1.1.1.13! root 1093: static void IKBD_Cmd_MouseCursorKeycodes(void)
1.1 root 1094: {
1.1.1.12 root 1095: KeyboardProcessor.MouseMode = AUTOMODE_MOUSECURSOR;
1096: KeyboardProcessor.Mouse.KeyCodeDeltaX = Keyboard.InputBuffer[1];
1097: KeyboardProcessor.Mouse.KeyCodeDeltaY = Keyboard.InputBuffer[2];
1.1.1.13! root 1098:
! 1099: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_MouseCursorKeycodes %d,%d\n",
! 1100: (int)KeyboardProcessor.Mouse.KeyCodeDeltaX,
! 1101: (int)KeyboardProcessor.Mouse.KeyCodeDeltaY);
1.1 root 1102: }
1103:
1.1.1.2 root 1104:
1105: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1106: /**
1107: * SET MOUSE THRESHOLD
1108: *
1109: * 0x0B
1110: * X ; x threshold in mouse ticks (positive integers)
1111: * Y ; y threshold in mouse ticks (positive integers)
1112: */
1.1.1.13! root 1113: static void IKBD_Cmd_SetMouseThreshold(void)
1.1 root 1114: {
1.1.1.12 root 1115: KeyboardProcessor.Mouse.XThreshold = (unsigned int)Keyboard.InputBuffer[1];
1116: KeyboardProcessor.Mouse.YThreshold = (unsigned int)Keyboard.InputBuffer[2];
1.1.1.13! root 1117:
! 1118: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetMouseThreshold %d,%d\n",
! 1119: KeyboardProcessor.Mouse.XThreshold, KeyboardProcessor.Mouse.YThreshold);
1.1 root 1120: }
1121:
1.1.1.2 root 1122:
1123: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1124: /**
1125: * SET MOUSE SCALE
1126: *
1127: * 0x0C
1128: * X ; horizontal mouse ticks per internel X
1129: * Y ; vertical mouse ticks per internel Y
1130: */
1.1.1.13! root 1131: static void IKBD_Cmd_SetMouseScale(void)
1.1 root 1132: {
1.1.1.12 root 1133: KeyboardProcessor.Mouse.XScale = (unsigned int)Keyboard.InputBuffer[1];
1134: KeyboardProcessor.Mouse.YScale = (unsigned int)Keyboard.InputBuffer[2];
1.1.1.13! root 1135:
! 1136: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetMouseScale %d,%d\n",
! 1137: KeyboardProcessor.Mouse.XScale, KeyboardProcessor.Mouse.YScale);
1.1 root 1138: }
1139:
1140:
1.1.1.12 root 1141: /*-----------------------------------------------------------------------*/
1142: /**
1143: * INTERROGATE MOUSE POSITION
1144: *
1145: * 0x0D
1146: * Returns: 0xF7 ; absolute mouse position header
1147: * BUTTONS
1148: * 0000dcba
1149: * where a is right button down since last interrogation
1150: * b is right button up since last
1151: * c is left button down since last
1152: * d is left button up since last
1153: * XMSB ; X coordinate
1154: * XLSB
1155: * YMSB ; Y coordinate
1156: * YLSB
1157: */
1.1.1.13! root 1158: static void IKBD_Cmd_ReadAbsMousePos(void)
1.1 root 1159: {
1.1.1.12 root 1160: Uint8 Buttons,PrevButtons;
1.1 root 1161:
1.1.1.12 root 1162: /* Test buttons */
1163: Buttons = 0;
1164: /* Set buttons to show if up/down */
1165: if (Keyboard.bRButtonDown)
1166: Buttons |= 0x01;
1167: else
1168: Buttons |= 0x02;
1169: if (Keyboard.bLButtonDown)
1170: Buttons |= 0x04;
1171: else
1172: Buttons |= 0x08;
1173: /* Mask off it didn't send last time */
1174: PrevButtons = KeyboardProcessor.Abs.PrevReadAbsMouseButtons;
1175: KeyboardProcessor.Abs.PrevReadAbsMouseButtons = Buttons;
1176: Buttons &= ~PrevButtons;
1177:
1178: /* And send packet */
1.1.1.13! root 1179: IKBD_AddKeyToKeyboardBufferWithDelay(0xf7, 18000);
1.1.1.12 root 1180: IKBD_AddKeyToKeyboardBuffer(Buttons);
1181: IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.X>>8);
1182: IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.X&0xff);
1183: IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.Y>>8);
1184: IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.Y&0xff);
1185:
1.1.1.13! root 1186: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReadAbsMousePos %d,%d 0x%X\n",
! 1187: KeyboardProcessor.Abs.X, KeyboardProcessor.Abs.Y, Buttons);
1.1 root 1188: }
1189:
1190:
1.1.1.12 root 1191: /*-----------------------------------------------------------------------*/
1192: /**
1193: * LOAD MOUSE POSITION
1194: *
1195: * 0x0E
1196: * 0x00 ; filler
1197: * XMSB ; X coordinate
1198: * XLSB ; (in scaled coordinate system)
1199: * YMSB ; Y coordinate
1200: * YLSB
1201: */
1.1.1.13! root 1202: static void IKBD_Cmd_SetInternalMousePos(void)
1.1.1.7 root 1203: {
1.1.1.12 root 1204: /* Setting these do not clip internal position(this happens on next update) */
1205: KeyboardProcessor.Abs.X = (((unsigned int)Keyboard.InputBuffer[2])<<8) | (unsigned int)Keyboard.InputBuffer[3];
1206: KeyboardProcessor.Abs.Y = (((unsigned int)Keyboard.InputBuffer[4])<<8) | (unsigned int)Keyboard.InputBuffer[5];
1.1.1.13! root 1207:
! 1208: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetInternalMousePos %d,%d\n",
! 1209: KeyboardProcessor.Abs.X, KeyboardProcessor.Abs.Y);
1.1 root 1210: }
1211:
1.1.1.2 root 1212:
1213: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1214: /**
1215: * SET Y=0 AT BOTTOM
1216: *
1217: * 0x0F
1218: */
1.1.1.13! root 1219: static void IKBD_Cmd_SetYAxisDown(void)
1.1 root 1220: {
1.1.1.12 root 1221: KeyboardProcessor.Mouse.YAxis = -1;
1.1.1.13! root 1222:
! 1223: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetYAxisDown\n");
1.1 root 1224: }
1225:
1.1.1.2 root 1226:
1227: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1228: /**
1229: * SET Y=0 AT TOP
1230: *
1231: * 0x10
1232: */
1.1.1.13! root 1233: static void IKBD_Cmd_SetYAxisUp(void)
1.1 root 1234: {
1.1.1.12 root 1235: KeyboardProcessor.Mouse.YAxis = 1;
1.1.1.13! root 1236:
! 1237: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetYAxisUp\n");
1.1 root 1238: }
1239:
1.1.1.2 root 1240:
1241: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1242: /**
1243: * RESUME
1244: *
1245: * 0x11
1246: */
1.1.1.13! root 1247: static void IKBD_Cmd_StartKeyboardTransfer(void)
1.1 root 1248: {
1.1.1.13! root 1249: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_StartKeyboardTransfer\n");
1.1 root 1250: }
1251:
1.1.1.2 root 1252:
1253: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1254: /**
1255: * DISABLE MOUSE
1256: *
1257: * 0x12
1258: */
1.1.1.13! root 1259: static void IKBD_Cmd_TurnMouseOff(void)
1.1 root 1260: {
1.1.1.12 root 1261: KeyboardProcessor.MouseMode = AUTOMODE_OFF;
1262: bMouseDisabled = TRUE;
1.1.1.13! root 1263:
! 1264: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_TurnMouseOff\n");
1.1 root 1265:
1.1.1.12 root 1266: IKBD_CheckResetDisableBug();
1.1 root 1267: }
1268:
1.1.1.2 root 1269:
1270: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1271: /**
1272: * PAUSE OUTPUT
1273: *
1274: * 0x13
1275: */
1.1.1.13! root 1276: static void IKBD_Cmd_StopKeyboardTransfer(void)
1.1 root 1277: {
1.1.1.13! root 1278: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_StopKeyboardTransfer\n");
1.1 root 1279: }
1280:
1.1.1.2 root 1281:
1282: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1283: /**
1284: * SET JOYSTICK EVENT REPORTING
1285: *
1286: * 0x14
1287: */
1.1.1.13! root 1288: static void IKBD_Cmd_ReturnJoystickAuto(void)
1.1 root 1289: {
1.1.1.12 root 1290: KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
1291: KeyboardProcessor.MouseMode = AUTOMODE_OFF;
1.1.1.6 root 1292:
1.1.1.12 root 1293: /* Again, if try to disable mouse within time of a reset it isn't disabled! */
1294: if (bDuringResetCriticalTime)
1295: {
1296: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1297: bBothMouseAndJoy = TRUE;
1298: }
1.1.1.6 root 1299:
1.1.1.13! root 1300: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReturnJoystickAuto\n");
! 1301:
! 1302: /* This command resets the internally previously stored joystick states */
! 1303: KeyboardProcessor.Joy.PrevJoyData[0] = KeyboardProcessor.Joy.PrevJoyData[1] = 0;
! 1304:
! 1305: /* This is a hack for the STE Utopos (=> v1.50) and Falcon Double Bubble
! 1306: * 2000 games. They expect the joystick data to be sent within a certain
! 1307: * amount of time after this command, without checking the ACIA control
! 1308: * register first.
! 1309: */
! 1310: IKBD_GetJoystickData();
! 1311: IKBD_SelAutoJoysticks();
1.1 root 1312: }
1313:
1.1.1.2 root 1314:
1315: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1316: /**
1317: * SET JOYSTICK INTERROGATION MODE
1318: *
1319: * 0x15
1320: */
1.1.1.13! root 1321: static void IKBD_Cmd_StopJoystick(void)
1.1 root 1322: {
1.1.1.12 root 1323: KeyboardProcessor.JoystickMode = AUTOMODE_OFF;
1.1.1.13! root 1324: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_StopJoystick\n");
1.1 root 1325: }
1326:
1.1.1.2 root 1327:
1328: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1329: /**
1330: * JOYSTICK INTERROGATE
1331: *
1332: * 0x16
1333: */
1.1.1.13! root 1334: static void IKBD_Cmd_ReturnJoystick(void)
1.1 root 1335: {
1.1.1.13! root 1336: IKBD_AddKeyToKeyboardBufferWithDelay(0xFD, 35000);
1.1.1.12 root 1337: IKBD_AddKeyToKeyboardBuffer(Joy_GetStickData(0));
1338: IKBD_AddKeyToKeyboardBuffer(Joy_GetStickData(1));
1.1.1.13! root 1339:
! 1340: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReturnJoystick\n");
1.1 root 1341: }
1342:
1.1.1.2 root 1343:
1344: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1345: /**
1346: * SET JOYSTICK MONITORING
1347: *
1348: * 0x17
1349: * rate ; time between samples in hundreths of a second
1350: * Returns: (in packets of two as long as in mode)
1351: * %000000xy where y is JOYSTICK1 Fire button
1352: * and x is JOYSTICK0 Fire button
1353: * %nnnnmmmm where m is JOYSTICK1 state
1354: * and n is JOYSTICK0 state
1355: */
1.1.1.13! root 1356: static void IKBD_Cmd_SetJoystickDuration(void)
1.1 root 1357: {
1.1.1.13! root 1358: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetJoystickDuration\n");
1.1 root 1359: }
1360:
1.1.1.2 root 1361:
1362: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1363: /**
1364: * SET FIRE BUTTON MONITORING
1365: *
1366: * 0x18
1367: * Returns: (as long as in mode)
1368: * %bbbbbbbb ; state of the JOYSTICK1 fire button packed
1369: * ; 8 bits per byte, the first sample if the MSB
1370: */
1.1.1.13! root 1371: static void IKBD_Cmd_SetJoystickFireDuration(void)
1.1 root 1372: {
1.1.1.13! root 1373: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetJoystickFireDuration\n");
1.1 root 1374: }
1375:
1.1.1.2 root 1376:
1377: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1378: /**
1379: * SET JOYSTICK KEYCODE MODE
1380: *
1381: * 0x19
1382: * RX ; length of time (in tenths of seconds) until
1383: * ; horizontal velocity breakpoint is reached
1384: * RY ; length of time (in tenths of seconds) until
1385: * ; vertical velocity breakpoint is reached
1386: * TX ; length (in tenths of seconds) of joystick closure
1387: * ; until horizontal cursor key is generated before RX
1388: * ; has elapsed
1389: * TY ; length (in tenths of seconds) of joystick closure
1390: * ; until vertical cursor key is generated before RY
1391: * ; has elapsed
1392: * VX ; length (in tenths of seconds) of joystick closure
1393: * ; until horizontal cursor keystokes are generated after RX
1394: * ; has elapsed
1395: * VY ; length (in tenths of seconds) of joystick closure
1396: * ; until vertical cursor keystokes are generated after RY
1397: * ; has elapsed
1398: */
1.1.1.13! root 1399: static void IKBD_Cmd_SetCursorForJoystick(void)
1.1 root 1400: {
1.1.1.13! root 1401: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetCursorForJoystick\n");
1.1 root 1402: }
1403:
1.1.1.2 root 1404:
1405: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1406: /**
1407: * DISABLE JOYSTICKS
1408: *
1409: * 0x1A
1410: */
1.1.1.13! root 1411: static void IKBD_Cmd_DisableJoysticks(void)
1.1 root 1412: {
1.1.1.12 root 1413: KeyboardProcessor.JoystickMode = AUTOMODE_OFF;
1414: bJoystickDisabled = TRUE;
1.1.1.13! root 1415:
! 1416: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_DisableJoysticks\n");
1.1 root 1417:
1.1.1.12 root 1418: IKBD_CheckResetDisableBug();
1.1 root 1419: }
1420:
1.1.1.2 root 1421:
1422: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1423: /**
1424: * TIME-OF-DAY CLOCK SET
1425: *
1426: * 0x1B
1427: * YY ; year (2 least significant digits)
1428: * MM ; month
1429: * DD ; day
1430: * hh ; hour
1431: * mm ; minute
1432: * ss ; second
1433: */
1.1.1.13! root 1434: static void IKBD_Cmd_SetClock(void)
1.1 root 1435: {
1.1.1.13! root 1436: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetClock\n");
! 1437: }
! 1438:
! 1439:
! 1440: /*-----------------------------------------------------------------------*/
! 1441: /**
! 1442: * Convert value to 2-digit BCD
! 1443: */
! 1444: static unsigned char IKBD_ConvertToBCD(unsigned short int Value)
! 1445: {
! 1446: return (((Value/10))<<4) | (Value%10);
1.1 root 1447: }
1448:
1.1.1.2 root 1449:
1450: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1451: /**
1452: * INTERROGATE TIME-OF-DAT CLOCK
1453: *
1454: * 0x1C
1455: * Returns:
1456: * 0xFC ; time-of-day event header
1457: * YY ; year (2 least significant digits)
1458: * There seems to be a problem with the bcd conversion of the year
1459: * when year/10 >= 10. So the bcd conversion keeps the part > 10.
1460: * If you put year%100 here (as says the doc), and put a real bcd
1461: * conversion function in misc.c, then you end up with year 2031
1462: * instead of 2003...
1463: *
1464: * MM ; month
1465: * DD ; day
1466: * hh ; hour
1467: * mm ; minute
1468: * ss ; second
1469: */
1.1.1.13! root 1470: static void IKBD_Cmd_ReadClock(void)
1.1 root 1471: {
1.1.1.12 root 1472: struct tm *SystemTime;
1473: time_t nTimeTicks;
1.1 root 1474:
1.1.1.12 root 1475: /* Get system time */
1476: nTimeTicks = time(NULL);
1477: SystemTime = localtime(&nTimeTicks);
1478:
1479: /* Return packet */
1.1.1.13! root 1480: IKBD_AddKeyToKeyboardBufferWithDelay(0xFC, 32000);
1.1.1.12 root 1481: /* Return time-of-day clock as yy-mm-dd-hh-mm-ss as BCD */
1.1.1.13! root 1482: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_year)); /* yy - year (2 least significant digits) */
! 1483: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_mon+1)); /* mm - Month */
! 1484: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_mday)); /* dd - Day */
! 1485: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_hour)); /* hh - Hour */
! 1486: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_min)); /* mm - Minute */
! 1487: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_sec)); /* ss - Second */
! 1488:
! 1489: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReadClock\n");
1.1 root 1490: }
1491:
1.1.1.2 root 1492:
1493: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1494: /**
1495: * MEMORY LOAD
1496: *
1497: * 0x20
1498: * ADRMSB ; address in controller
1499: * ADRLSB ; memory to be loaded
1500: * NUM ; number of bytes (0-128)
1501: * { data }
1502: */
1.1.1.13! root 1503: static void IKBD_Cmd_LoadMemory(void)
1.1 root 1504: {
1.1.1.13! root 1505: HATARI_TRACE ( HATARI_TRACE_IKBD_CMDS , "IKBD_Cmd_LoadMemory addr 0x%x count %d\n" ,
! 1506: ( Keyboard.InputBuffer[1]<<8 ) + Keyboard.InputBuffer[2] , Keyboard.InputBuffer[3] );
! 1507:
! 1508: MemoryLoadNbBytesTotal = Keyboard.InputBuffer[3];
! 1509: MemoryLoadNbBytesLeft = MemoryLoadNbBytesTotal;
! 1510: crc32_reset ( &MemoryLoadCrc );
1.1 root 1511: }
1512:
1.1.1.2 root 1513:
1514: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1515: /**
1516: * MEMORY READ
1517: *
1518: * 0x21
1519: * ADRMSB ; address in controller
1520: * ADRLSB ; memory to be read
1521: * Returns:
1522: * 0xF6 ; status header
1523: * 0x20 ; memory access
1524: * { data } ; 6 data bytes starting at ADR
1525: */
1.1.1.13! root 1526: static void IKBD_Cmd_ReadMemory(void)
1.1 root 1527: {
1.1.1.13! root 1528: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReadMemory\n");
1.1 root 1529: }
1530:
1.1.1.2 root 1531:
1532: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1533: /**
1534: * CONTROLLER EXECUTE
1535: *
1536: * 0x22
1537: * ADRMSB ; address of subroutine in
1538: * ADRLSB ; controller memory to be called
1539: */
1.1.1.13! root 1540: static void IKBD_Cmd_Execute(void)
! 1541: {
! 1542: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_Execute\n");
! 1543:
! 1544: if ( pIKBD_CustomCodeHandler_Write )
! 1545: {
! 1546: HATARI_TRACE ( HATARI_TRACE_IKBD_EXEC, "ikbd execute addr 0x%x using custom handler\n" ,
! 1547: ( Keyboard.InputBuffer[1]<<8 ) + Keyboard.InputBuffer[2] );
! 1548:
! 1549: IKBD_ExeMode = TRUE; /* turn 6301's custom mode ON */
! 1550: }
! 1551: else /* unknown code uploaded to ikbd RAM */
! 1552: {
! 1553: HATARI_TRACE ( HATARI_TRACE_IKBD_EXEC, "ikbd execute addr 0x%x ignored, no custom handler found\n" ,
! 1554: ( Keyboard.InputBuffer[1]<<8 ) + Keyboard.InputBuffer[2] );
! 1555: }
! 1556: }
! 1557:
! 1558:
! 1559: /*-----------------------------------------------------------------------*/
! 1560: /**
! 1561: * REPORT MOUSE BUTTON ACTION
! 1562: *
! 1563: * 0x87
! 1564: */
! 1565: static void IKBD_Cmd_ReportMouseAction(void)
! 1566: {
! 1567: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseAction\n");
! 1568:
! 1569: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
! 1570: IKBD_AddKeyToKeyboardBuffer(7);
! 1571: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.Action);
! 1572: IKBD_AddKeyToKeyboardBuffer(0);
! 1573: IKBD_AddKeyToKeyboardBuffer(0);
! 1574: IKBD_AddKeyToKeyboardBuffer(0);
! 1575: IKBD_AddKeyToKeyboardBuffer(0);
! 1576: IKBD_AddKeyToKeyboardBuffer(0);
! 1577: }
! 1578:
! 1579:
! 1580: /*-----------------------------------------------------------------------*/
! 1581: /**
! 1582: * REPORT MOUSE MODE
! 1583: *
! 1584: * 0x88 or 0x89 or 0x8A
! 1585: */
! 1586: static void IKBD_Cmd_ReportMouseMode(void)
! 1587: {
! 1588: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseMode\n");
! 1589:
! 1590: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
! 1591: switch (KeyboardProcessor.MouseMode)
! 1592: {
! 1593: case AUTOMODE_MOUSEREL:
! 1594: IKBD_AddKeyToKeyboardBuffer(8);
! 1595: IKBD_AddKeyToKeyboardBuffer(0);
! 1596: IKBD_AddKeyToKeyboardBuffer(0);
! 1597: IKBD_AddKeyToKeyboardBuffer(0);
! 1598: IKBD_AddKeyToKeyboardBuffer(0);
! 1599: IKBD_AddKeyToKeyboardBuffer(0);
! 1600: IKBD_AddKeyToKeyboardBuffer(0);
! 1601: break;
! 1602: case AUTOMODE_MOUSEABS:
! 1603: IKBD_AddKeyToKeyboardBuffer(9);
! 1604: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxX >> 8);
! 1605: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxX);
! 1606: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxY >> 8);
! 1607: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxY);
! 1608: IKBD_AddKeyToKeyboardBuffer(0);
! 1609: IKBD_AddKeyToKeyboardBuffer(0);
! 1610: break;
! 1611: case AUTOMODE_MOUSECURSOR:
! 1612: IKBD_AddKeyToKeyboardBuffer(10);
! 1613: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.KeyCodeDeltaX);
! 1614: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.KeyCodeDeltaY);
! 1615: IKBD_AddKeyToKeyboardBuffer(0);
! 1616: IKBD_AddKeyToKeyboardBuffer(0);
! 1617: IKBD_AddKeyToKeyboardBuffer(0);
! 1618: IKBD_AddKeyToKeyboardBuffer(0);
! 1619: break;
! 1620: }
! 1621: }
! 1622:
! 1623:
! 1624: /*-----------------------------------------------------------------------*/
! 1625: /**
! 1626: * REPORT MOUSE THRESHOLD
! 1627: *
! 1628: * 0x8B
! 1629: */
! 1630: static void IKBD_Cmd_ReportMouseThreshold(void)
! 1631: {
! 1632: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseThreshold\n");
! 1633:
! 1634: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
! 1635: IKBD_AddKeyToKeyboardBuffer(0x0B);
! 1636: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.XThreshold);
! 1637: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.YThreshold);
! 1638: IKBD_AddKeyToKeyboardBuffer(0);
! 1639: IKBD_AddKeyToKeyboardBuffer(0);
! 1640: IKBD_AddKeyToKeyboardBuffer(0);
! 1641: IKBD_AddKeyToKeyboardBuffer(0);
! 1642: }
! 1643:
! 1644:
! 1645: /*-----------------------------------------------------------------------*/
! 1646: /**
! 1647: * REPORT MOUSE SCALE
! 1648: *
! 1649: * 0x8C
! 1650: */
! 1651: static void IKBD_Cmd_ReportMouseScale(void)
! 1652: {
! 1653: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseScale\n");
! 1654:
! 1655: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
! 1656: IKBD_AddKeyToKeyboardBuffer(0x0C);
! 1657: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.XScale);
! 1658: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.YScale);
! 1659: IKBD_AddKeyToKeyboardBuffer(0);
! 1660: IKBD_AddKeyToKeyboardBuffer(0);
! 1661: IKBD_AddKeyToKeyboardBuffer(0);
! 1662: IKBD_AddKeyToKeyboardBuffer(0);
! 1663: }
! 1664:
! 1665:
! 1666: /*-----------------------------------------------------------------------*/
! 1667: /**
! 1668: * REPORT MOUSE VERTICAL COORDINATES
! 1669: *
! 1670: * 0x8F and 0x90
! 1671: */
! 1672: static void IKBD_Cmd_ReportMouseVertical(void)
! 1673: {
! 1674: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseVertical\n");
! 1675:
! 1676: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
! 1677: if (KeyboardProcessor.Mouse.YAxis == -1)
! 1678: IKBD_AddKeyToKeyboardBuffer(0x0F);
! 1679: else
! 1680: IKBD_AddKeyToKeyboardBuffer(0x10);
! 1681: IKBD_AddKeyToKeyboardBuffer(0);
! 1682: IKBD_AddKeyToKeyboardBuffer(0);
! 1683: IKBD_AddKeyToKeyboardBuffer(0);
! 1684: IKBD_AddKeyToKeyboardBuffer(0);
! 1685: IKBD_AddKeyToKeyboardBuffer(0);
! 1686: IKBD_AddKeyToKeyboardBuffer(0);
! 1687: }
! 1688:
! 1689:
! 1690: /*-----------------------------------------------------------------------*/
! 1691: /**
! 1692: * REPORT MOUSE AVAILABILITY
! 1693: *
! 1694: * 0x92
! 1695: */
! 1696: static void IKBD_Cmd_ReportMouseAvailability(void)
! 1697: {
! 1698: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseAvailability\n");
! 1699:
! 1700: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
! 1701: if (KeyboardProcessor.MouseMode == AUTOMODE_OFF)
! 1702: IKBD_AddKeyToKeyboardBuffer(0x12);
! 1703: else
! 1704: IKBD_AddKeyToKeyboardBuffer(0x00);
! 1705: IKBD_AddKeyToKeyboardBuffer(0);
! 1706: IKBD_AddKeyToKeyboardBuffer(0);
! 1707: IKBD_AddKeyToKeyboardBuffer(0);
! 1708: IKBD_AddKeyToKeyboardBuffer(0);
! 1709: IKBD_AddKeyToKeyboardBuffer(0);
! 1710: IKBD_AddKeyToKeyboardBuffer(0);
! 1711: }
! 1712:
! 1713:
! 1714: /*-----------------------------------------------------------------------*/
! 1715: /**
! 1716: * REPORT JOYSTICK MODE
! 1717: *
! 1718: * 0x94 or 0x95 or 0x99
! 1719: */
! 1720: static void IKBD_Cmd_ReportJoystickMode(void)
1.1 root 1721: {
1.1.1.13! root 1722: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportJoystickMode\n");
! 1723:
! 1724: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
! 1725: switch (KeyboardProcessor.JoystickMode)
! 1726: {
! 1727: case AUTOMODE_JOYSTICK:
! 1728: IKBD_AddKeyToKeyboardBuffer(0x14);
! 1729: IKBD_AddKeyToKeyboardBuffer(0);
! 1730: IKBD_AddKeyToKeyboardBuffer(0);
! 1731: IKBD_AddKeyToKeyboardBuffer(0);
! 1732: IKBD_AddKeyToKeyboardBuffer(0);
! 1733: IKBD_AddKeyToKeyboardBuffer(0);
! 1734: IKBD_AddKeyToKeyboardBuffer(0);
! 1735: break;
! 1736: default: /* TODO: Joystick keycodes mode not supported yet! */
! 1737: IKBD_AddKeyToKeyboardBuffer(0x15);
! 1738: IKBD_AddKeyToKeyboardBuffer(0);
! 1739: IKBD_AddKeyToKeyboardBuffer(0);
! 1740: IKBD_AddKeyToKeyboardBuffer(0);
! 1741: IKBD_AddKeyToKeyboardBuffer(0);
! 1742: IKBD_AddKeyToKeyboardBuffer(0);
! 1743: IKBD_AddKeyToKeyboardBuffer(0);
! 1744: break;
! 1745: }
! 1746: }
! 1747:
! 1748:
! 1749: /*-----------------------------------------------------------------------*/
! 1750: /**
! 1751: * REPORT JOYSTICK AVAILABILITY
! 1752: *
! 1753: * 0x9A
! 1754: */
! 1755: static void IKBD_Cmd_ReportJoystickAvailability(void)
! 1756: {
! 1757: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportJoystickAvailability\n");
! 1758:
! 1759: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
! 1760: if (KeyboardProcessor.JoystickMode == AUTOMODE_OFF)
! 1761: IKBD_AddKeyToKeyboardBuffer(0x1A);
! 1762: else
! 1763: IKBD_AddKeyToKeyboardBuffer(0x00);
! 1764: IKBD_AddKeyToKeyboardBuffer(0);
! 1765: IKBD_AddKeyToKeyboardBuffer(0);
! 1766: IKBD_AddKeyToKeyboardBuffer(0);
! 1767: IKBD_AddKeyToKeyboardBuffer(0);
! 1768: IKBD_AddKeyToKeyboardBuffer(0);
! 1769: IKBD_AddKeyToKeyboardBuffer(0);
1.1 root 1770: }
1771:
1772:
1.1.1.2 root 1773: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1774: /**
1775: * Send data to keyboard processor via ACIA by writing to address 0xfffc02.
1776: * For our emulation we bypass the ACIA (I've yet to see anything check for this)
1777: * and add the byte directly into the keyboard input buffer.
1778: */
1.1.1.11 root 1779: static void IKBD_RunKeyboardCommand(Uint16 aciabyte)
1.1 root 1780: {
1.1.1.12 root 1781: int i=0;
1.1 root 1782:
1.1.1.12 root 1783: /* Write into our keyboard input buffer */
1784: Keyboard.InputBuffer[Keyboard.nBytesInInputBuffer++] = aciabyte;
1.1 root 1785:
1.1.1.12 root 1786: /* Now check bytes to see if we have a valid/in-valid command string set */
1787: while (KeyboardCommands[i].Command!=0xff)
1788: {
1789: /* Found command? */
1790: if (KeyboardCommands[i].Command==Keyboard.InputBuffer[0])
1791: {
1792: /* Is string complete, then can execute? */
1793: if (KeyboardCommands[i].NumParameters==Keyboard.nBytesInInputBuffer)
1794: {
1795: CALL_VAR(KeyboardCommands[i].pCallFunction);
1796: Keyboard.nBytesInInputBuffer = 0;
1797: }
1.1 root 1798:
1.1.1.12 root 1799: return;
1800: }
1.1.1.7 root 1801:
1.1.1.12 root 1802: i++;
1803: }
1.1 root 1804:
1.1.1.12 root 1805: /* Command not known, reset buffer(IKBD assumes a NOP) */
1806: Keyboard.nBytesInInputBuffer = 0;
1.1 root 1807: }
1808:
1.1.1.2 root 1809:
1810: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1811: /**
1812: * Send byte to our keyboard processor, and execute
1813: */
1.1.1.13! root 1814: static void IKBD_SendByteToKeyboardProcessor(Uint16 bl)
1.1 root 1815: {
1.1.1.13! root 1816: /* If IKBD is executing custom code, send the byte to the function handling this code */
! 1817: if ( IKBD_ExeMode && pIKBD_CustomCodeHandler_Write )
! 1818: {
! 1819: (*pIKBD_CustomCodeHandler_Write) ( (Uint8) bl );
! 1820: return;
! 1821: }
! 1822:
! 1823: if ( MemoryLoadNbBytesLeft == 0 ) /* No pending MemoryLoad command */
! 1824: IKBD_RunKeyboardCommand ( bl ); /* check for known commands */
! 1825:
! 1826: else /* MemoryLoad command is not finished yet */
! 1827: IKBD_LoadMemoryByte ( (Uint8) bl ); /* process bytes sent to the ikbd RAM */
1.1 root 1828: }
1829:
1.1.1.2 root 1830:
1831: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1832: /**
1833: * The byte stored in the ACIA 'ACIAByte' has been read by the CPU by reading from
1834: * address $fffc02. We clear the status flag and set the GPIP register to signal read.
1835: */
1.1.1.11 root 1836: Uint16 IKBD_GetByteFromACIA(void)
1.1 root 1837: {
1.1.1.12 root 1838: /* ACIA is now reset */
1839: ACIAStatusRegister &= ~(ACIA_STATUS_REGISTER__RX_BUFFER_FULL | ACIA_STATUS_REGISTER__INTERRUPT_REQUEST | ACIA_STATUS_REGISTER__OVERRUN_ERROR);
1.1 root 1840:
1.1.1.12 root 1841: /* GPIP I4 - General Purpose Pin Keyboard/MIDI interrupt */
1842: MFP_GPIP |= 0x10;
1843: return ACIAByte; /* Return byte from keyboard */
1.1 root 1844: }
1845:
1.1.1.2 root 1846:
1847: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1848: /**
1.1.1.13! root 1849: * Byte received in the ACIA from the keyboard processor. Store byte for read
! 1850: * from $fffc02 and schedule MFP interrupt to be triggered later.
1.1.1.12 root 1851: */
1.1 root 1852: void IKBD_InterruptHandler_ACIA(void)
1853: {
1.1.1.12 root 1854: /* Remove this interrupt from list and re-order */
1855: Int_AcknowledgeInterrupt();
1.1 root 1856:
1.1.1.12 root 1857: /* Copy keyboard byte, ready for read from $fffc02 */
1858: ACIAByte = Keyboard.Buffer[Keyboard.BufferHead++];
1859: Keyboard.BufferHead &= KEYBOARD_BUFFER_MASK;
1860:
1861: /* Did we get an over-run? Ie byte has arrived from keyboard processor BEFORE CPU has read previous one from ACIA */
1862: if (ACIAStatusRegister&ACIA_STATUS_REGISTER__RX_BUFFER_FULL)
1863: ACIAStatusRegister |= ACIA_STATUS_REGISTER__OVERRUN_ERROR; /* Set over-run */
1864:
1865: /* ACIA buffer is now full */
1866: ACIAStatusRegister |= ACIA_STATUS_REGISTER__RX_BUFFER_FULL;
1867: /* Signal interrupt pending */
1868: ACIAStatusRegister |= ACIA_STATUS_REGISTER__INTERRUPT_REQUEST;
1.1.1.13! root 1869:
1.1.1.12 root 1870: /* GPIP I4 - General Purpose Pin Keyboard/MIDI interrupt */
1871: /* NOTE: GPIP will remain low(0) until keyboard data is read from $fffc02. */
1872: MFP_GPIP &= ~0x10;
1873:
1.1.1.13! root 1874: /* There seems to be a small gap on a real ST between the point in time
! 1875: * the ACIA_STATUS_REGISTER__RX_BUFFER_FULL bit is set and the MFP
! 1876: * interrupt is triggered - for example the "V8 music system" demo
! 1877: * depends on this behaviour. To emulate this, we simply start another
! 1878: * Int which triggers the MFP interrupt later: */
! 1879: Int_AddRelativeInterrupt(18, INT_CPU_CYCLE, INTERRUPT_IKBD_MFP);
! 1880: }
! 1881:
! 1882:
! 1883: /**
! 1884: * Start MFP interrupt after byte has been received in the ACIA.
! 1885: */
! 1886: void IKBD_InterruptHandler_MFP(void)
! 1887: {
! 1888: /* Remove this interrupt from list and re-order */
! 1889: Int_AcknowledgeInterrupt();
! 1890:
1.1.1.12 root 1891: /* Acknowledge in MFP circuit, pass bit,enable,pending */
1892: MFP_InputOnChannel(MFP_ACIA_BIT, MFP_IERB, &MFP_IPRB);
1893:
1894: /* Clear flag so can allow another byte to be sent along serial line */
1895: bByteInTransitToACIA = FALSE;
1.1.1.13! root 1896:
1.1.1.12 root 1897: /* If another key is waiting, start sending from keyboard processor now */
1898: if (Keyboard.BufferHead!=Keyboard.BufferTail)
1.1.1.13! root 1899: IKBD_SendByteToACIA(ACIA_CYCLES);
1.1 root 1900: }
1901:
1902:
1.1.1.2 root 1903: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1904: /**
1905: * Send a byte from the keyboard buffer to the ACIA. On a real ST this takes some time to send
1906: * so we must be as accurate in the timing as possible - bytes do not appear to the 68000 instantly!
1907: * We do this via an internal interrupt - neat!
1908: */
1.1.1.13! root 1909: static void IKBD_SendByteToACIA(int nAciaCycles)
1.1 root 1910: {
1.1.1.13! root 1911: /* Transmit byte from keyboard processor to ACIA.
! 1912: * This takes approx ACIA_CYCLES CPU clock cycles to complete */
1.1.1.12 root 1913: if (!bByteInTransitToACIA)
1914: {
1915: /* Send byte to ACIA */
1.1.1.13! root 1916: Int_AddRelativeInterrupt(nAciaCycles, INT_CPU_CYCLE, INTERRUPT_IKBD_ACIA);
1.1.1.12 root 1917: /* Set flag so only transmit one byte at a time */
1918: bByteInTransitToACIA = TRUE;
1919: }
1.1 root 1920: }
1921:
1.1.1.2 root 1922:
1923: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1924: /**
1.1.1.13! root 1925: * Add character to our internal keyboard buffer, with default ACIA_CYCLES
! 1926: * timing.
! 1927: */
! 1928: static void IKBD_AddKeyToKeyboardBuffer(Uint8 Data)
! 1929: {
! 1930: if ( IKBD_ExeMode ) /* if IKBD is executing custom code, don't add */
! 1931: return; /* anything to the buffer */
! 1932:
! 1933: IKBD_AddKeyToKeyboardBuffer_Real(Data, ACIA_CYCLES);
! 1934: }
! 1935:
! 1936:
! 1937: /**
! 1938: * Add character to our internal keyboard buffer, with additional delay.
! 1939: * This is required for some keyboard commands like ReadAbsMousePos (0x0d)
! 1940: * where it takes a little bit longer than the typical ACIA_CYCLES until
! 1941: * the first byte arrives from the IKBD (for example the "Unlimited bobs"
! 1942: * screen in the Dragonnels demo depends on this behaviour.
! 1943: */
! 1944: static void IKBD_AddKeyToKeyboardBufferWithDelay(Uint8 Data, int nAciaCycles)
! 1945: {
! 1946: if (IKBD_ExeMode) /* if IKBD is executing custom code, */
! 1947: return; /* don't add anything to the buffer */
! 1948:
! 1949: IKBD_AddKeyToKeyboardBuffer_Real(Data, nAciaCycles);
! 1950: }
! 1951:
! 1952:
! 1953: /**
! 1954: * Add character to our internal keyboard buffer. These bytes are then sent
! 1955: * one at a time to the ACIA. This is done via a delay to mimick the STs
! 1956: * internal workings, as this is needed for games such as Carrier Command.
1.1.1.12 root 1957: */
1.1.1.13! root 1958: static void IKBD_AddKeyToKeyboardBuffer_Real(Uint8 Data, int nAciaCycles)
1.1 root 1959: {
1.1.1.12 root 1960: /* Is keyboard initialised yet? Ignore any bytes until it is */
1961: if (!KeyboardProcessor.bReset)
1962: return;
1963:
1964: /* Check we have space to add byte */
1965: if (Keyboard.BufferHead!=((Keyboard.BufferTail+1)&KEYBOARD_BUFFER_MASK))
1966: {
1967: /* Add byte to our buffer */
1968: Keyboard.Buffer[Keyboard.BufferTail++] = Data;
1969: Keyboard.BufferTail &= KEYBOARD_BUFFER_MASK;
1970:
1971: /* We have character ready to transmit from the ACIA - see if can send it now */
1.1.1.13! root 1972: IKBD_SendByteToACIA(nAciaCycles);
1.1.1.12 root 1973: }
1.1 root 1974: }
1975:
1.1.1.2 root 1976:
1977: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1978: /**
1979: * When press/release key under host OS, execute this function.
1980: */
1.1.1.13! root 1981: void IKBD_PressSTKey(Uint8 ScanCode, bool bPress)
1.1 root 1982: {
1.1.1.13! root 1983: /* Store the state of each ST scancode : 1=pressed 0=released */
! 1984: if ( bPress ) ScanCodeState[ ScanCode & 0x7f ] = 1;
! 1985: else ScanCodeState[ ScanCode & 0x7f ] = 0;
! 1986:
1.1.1.12 root 1987: if (!bPress)
1988: ScanCode |= 0x80; /* Set top bit if released key */
1989: IKBD_AddKeyToKeyboardBuffer(ScanCode); /* And send to keyboard processor */
1.1 root 1990: }
1.1.1.10 root 1991:
1992:
1993: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1994: /**
1995: * Handle read from keyboard control ACIA register (0xfffc00)
1996: */
1.1.1.10 root 1997: void IKBD_KeyboardControl_ReadByte(void)
1998: {
1.1.1.11 root 1999: /* ACIA registers need wait states - but the value seems to vary in certain cases */
2000: M68000_WaitState(8);
2001:
1.1.1.13! root 2002: IoMem[0xfffc00] = ACIAStatusRegister;
1.1.1.12 root 2003:
1.1.1.13! root 2004: /* For our emulation send is immediate, so let's set the acknowledge
! 2005: * buffer empty bit for the next time the program polls the register */
! 2006: ACIAStatusRegister |= ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY;
! 2007:
! 2008: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_IKBD_ACIA ) )
1.1.1.12 root 2009: {
1.1.1.13! root 2010: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1.1.1.12 root 2011: int nLineCycles = nFrameCycles % nCyclesPerLine;
1.1.1.13! root 2012: HATARI_TRACE_PRINT ( "ikbd read fffc00 ctrl=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
1.1.1.12 root 2013: IoMem[0xfffc00], nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
2014: }
1.1.1.10 root 2015: }
2016:
2017: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2018: /**
2019: * Handle read from keyboard data ACIA register (0xfffc02)
2020: */
1.1.1.10 root 2021: void IKBD_KeyboardData_ReadByte(void)
2022: {
1.1.1.11 root 2023: /* ACIA registers need wait states - but the value seems to vary in certain cases */
2024: M68000_WaitState(8);
2025:
1.1.1.13! root 2026: /* If IKBD is executing custom code, call the function to update the byte read in $fffc02 */
! 2027: if ( IKBD_ExeMode && pIKBD_CustomCodeHandler_Read )
! 2028: {
! 2029: (*pIKBD_CustomCodeHandler_Read) ();
! 2030: }
! 2031:
! 2032:
1.1.1.10 root 2033: IoMem[0xfffc02] = IKBD_GetByteFromACIA(); /* Return our byte from keyboard processor */
1.1.1.12 root 2034:
1.1.1.13! root 2035: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_IKBD_ACIA ) )
1.1.1.12 root 2036: {
1.1.1.13! root 2037: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1.1.1.12 root 2038: int nLineCycles = nFrameCycles % nCyclesPerLine;
1.1.1.13! root 2039: HATARI_TRACE_PRINT ( "ikbd read fffc02 data=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
1.1.1.12 root 2040: IoMem[0xfffc02], nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
2041: }
1.1.1.10 root 2042: }
2043:
2044:
2045: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2046: /**
2047: * Handle write to keyboard control ACIA register (0xfffc00)
2048: */
1.1.1.10 root 2049: void IKBD_KeyboardControl_WriteByte(void)
2050: {
1.1.1.11 root 2051: /* ACIA registers need wait states - but the value seems to vary in certain cases */
2052: M68000_WaitState(8);
2053:
1.1.1.13! root 2054: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_IKBD_ACIA ) )
1.1.1.12 root 2055: {
1.1.1.13! root 2056: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1.1.1.12 root 2057: int nLineCycles = nFrameCycles % nCyclesPerLine;
1.1.1.13! root 2058: HATARI_TRACE_PRINT ( "ikbd write fffc00 ctrl=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
1.1.1.12 root 2059: IoMem[0xfffc00], nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
2060: }
2061:
2062: /* [NP] We only handle reset of the ACIA */
2063: if ( ( IoMem[0xfffc00] & 0x03 ) == 0x03 )
2064: ACIA_Reset();
2065:
1.1.1.10 root 2066: /* Nothing... */
2067: }
2068:
2069: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2070: /**
2071: * Handle write to keyboard data ACIA register (0xfffc02)
2072: */
1.1.1.10 root 2073: void IKBD_KeyboardData_WriteByte(void)
2074: {
1.1.1.11 root 2075: /* ACIA registers need wait states - but the value seems to vary in certain cases */
2076: M68000_WaitState(8);
2077:
1.1.1.13! root 2078: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_IKBD_ACIA ) )
1.1.1.12 root 2079: {
1.1.1.13! root 2080: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1.1.1.12 root 2081: int nLineCycles = nFrameCycles % nCyclesPerLine;
1.1.1.13! root 2082: HATARI_TRACE_PRINT ( "ikbd write fffc02 data=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
1.1.1.12 root 2083: IoMem[0xfffc02], nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
2084: }
2085:
1.1.1.10 root 2086: IKBD_SendByteToKeyboardProcessor(IoMem[0xfffc02]); /* Pass our byte to the keyboard processor */
1.1.1.13! root 2087:
! 2088: /* Some games like USS John Young / FOF54 actually check whether the
! 2089: * transmit-buffer-empty bit is really cleared after writing a data
! 2090: * byte to the IKBD, so we have to temporarily clear this bit, too,
! 2091: * although the byte is send immediately to our virtual IKBD. */
! 2092: ACIAStatusRegister &= ~ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY;
1.1.1.10 root 2093: }
1.1.1.13! root 2094:
! 2095:
! 2096: /*************************************************************************/
! 2097: /**
! 2098: * Below part is for emulating custom 6301 program sent to the ikbd RAM
! 2099: * Specific read/write functions for each demo/game should be added here,
! 2100: * after being defined in the CustomCodeDefinitions[] array.
! 2101: *
! 2102: * The 6301 has 256 bytes of RAM, but only 128 bytes are available to
! 2103: * put a program (from $80 to $ff).
! 2104: *
! 2105: * Executing a program in the 6301 is a 2 steps process :
! 2106: * 1) a very small program is sent to the RAM using the 0x20 command.
! 2107: * This is often loaded at address $b0.
! 2108: * This program will stop interruptions in the 6301 and will accept
! 2109: * a second small program that will relocate itself to $80.
! 2110: * 2) the relocated program at address $80 will accept a third (main)
! 2111: * program and will execute it once reception is complete.
! 2112: *
! 2113: * Writes during step 1 are handled with the ExeBootHandler matching the
! 2114: * LoadMemory CRC.
! 2115: * ExeBootHandler will compute a 2nd CRC for the writes corresponding to
! 2116: * the 2nd and 3rd programs sent to the 6301's RAM.
! 2117: *
! 2118: * If a match is found for this 2nd CRC, we will override default ikbd's behaviour
! 2119: * for reading/writing to $fffc02 with ExeMainHandler_Read / ExeMainHandler_Write
! 2120: * (once the Execute command 0x22 is received).
! 2121: *
! 2122: * When using custom program (ExeMode==TRUE), we must ignore all keyboard/mouse/joystick
! 2123: * events sent to IKBD_AddKeyToKeyboardBuffer. Only our functions can add bytes
! 2124: * to the keyboard buffer.
! 2125: *
! 2126: * To exit 6301's execution mode, we can use the 68000 'reset' instruction.
! 2127: * Some 6301's programs also handle a write to $fffc02 as an exit signal.
! 2128: */
! 2129:
! 2130:
! 2131: /*-----------------------------------------------------------------------*/
! 2132: /**
! 2133: * Handle writes to $fffc02 when loading bytes in the ikbd RAM.
! 2134: * We compute a CRC of the bytes that are sent until MemoryLoadNbBytesLeft
! 2135: * reaches 0.
! 2136: * When all bytes are loaded, we look for a matching CRC ; if found, we
! 2137: * use the ExeBootHandler defined for this CRC to process the next writes
! 2138: * that will occur in $fffc02.
! 2139: * LoadMemory is often used to load a small boot code into the 6301's RAM.
! 2140: * This small program will be executed later using the command 0x22.
! 2141: */
! 2142:
! 2143: static void IKBD_LoadMemoryByte ( Uint8 aciabyte )
! 2144: {
! 2145: unsigned int i;
! 2146:
! 2147: crc32_add_byte ( &MemoryLoadCrc , aciabyte );
! 2148:
! 2149: MemoryLoadNbBytesLeft--;
! 2150: if ( MemoryLoadNbBytesLeft == 0 ) /* all bytes were received */
! 2151: {
! 2152: /* Search for a match amongst the known custom routines */
! 2153: for ( i = 0 ; i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ; i++ )
! 2154: if ( CustomCodeDefinitions[ i ].LoadMemCrc == MemoryLoadCrc )
! 2155: break;
! 2156:
! 2157: if ( i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ) /* found */
! 2158: {
! 2159: HATARI_TRACE ( HATARI_TRACE_IKBD_EXEC, "ikbd loadmemory %d bytes crc=0x%x matches <%s>\n" ,
! 2160: MemoryLoadNbBytesTotal , MemoryLoadCrc , CustomCodeDefinitions[ i ].Name );
! 2161:
! 2162: crc32_reset ( &MemoryLoadCrc );
! 2163: MemoryExeNbBytes = 0;
! 2164: pIKBD_CustomCodeHandler_Read = NULL;
! 2165: pIKBD_CustomCodeHandler_Write = CustomCodeDefinitions[ i ].ExeBootHandler;
! 2166: }
! 2167:
! 2168: else /* unknown code uploaded to ikbd RAM */
! 2169: {
! 2170: HATARI_TRACE ( HATARI_TRACE_IKBD_EXEC, "ikbd loadmemory %d bytes crc=0x%x : unknown code\n" ,
! 2171: MemoryLoadNbBytesTotal , MemoryLoadCrc );
! 2172:
! 2173: pIKBD_CustomCodeHandler_Read = NULL;
! 2174: pIKBD_CustomCodeHandler_Write = NULL;
! 2175: }
! 2176: }
! 2177: }
! 2178:
! 2179:
! 2180:
! 2181: /*-----------------------------------------------------------------------*/
! 2182: /**
! 2183: * Handle writes to $fffc02 when executing custom code in the ikbd RAM.
! 2184: * This is used to send the small ikdb program that will handle keyboard/mouse/joystick
! 2185: * input.
! 2186: * We compute a CRC of the bytes that are sent until we found a match
! 2187: * with a known custom ikbd program.
! 2188: */
! 2189:
! 2190: static void IKBD_CustomCodeHandler_CommonBoot ( Uint8 aciabyte )
! 2191: {
! 2192: unsigned int i;
! 2193:
! 2194: crc32_add_byte ( &MemoryLoadCrc , aciabyte );
! 2195: MemoryExeNbBytes++;
! 2196:
! 2197: HATARI_TRACE ( HATARI_TRACE_IKBD_EXEC, "ikbd custom exe common boot write 0x%02x count %d crc=0x%x\n" ,
! 2198: aciabyte , MemoryExeNbBytes , MemoryLoadCrc );
! 2199:
! 2200: /* Search for a match amongst the known custom routines */
! 2201: for ( i = 0 ; i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ; i++ )
! 2202: if ( ( CustomCodeDefinitions[ i ].MainProgNbBytes == MemoryExeNbBytes )
! 2203: && ( CustomCodeDefinitions[ i ].MainProgCrc == MemoryLoadCrc ) )
! 2204: break;
! 2205:
! 2206: if ( i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ) /* found */
! 2207: {
! 2208: HATARI_TRACE ( HATARI_TRACE_IKBD_EXEC, "ikbd custom exe common boot, uploaded code matches <%s>\n" ,
! 2209: CustomCodeDefinitions[ i ].Name );
! 2210:
! 2211: pIKBD_CustomCodeHandler_Read = CustomCodeDefinitions[ i ].ExeMainHandler_Read;
! 2212: pIKBD_CustomCodeHandler_Write = CustomCodeDefinitions[ i ].ExeMainHandler_Write;
! 2213:
! 2214: Keyboard.BufferHead = Keyboard.BufferTail = 0; /* flush all queued bytes that would be read in $fffc02 */
! 2215: (*pIKBD_CustomCodeHandler_Read) (); /* initialize ACIAByte */
! 2216: }
! 2217:
! 2218: /* If not found, we keep on accumulating bytes until we find a matching crc */
! 2219: }
! 2220:
! 2221:
! 2222:
! 2223: /*----------------------------------------------------------------------*/
! 2224: /* Froggies Over The Fence menu. */
! 2225: /* Returns 2 bytes with the mouse position, keyboard can be used too. */
! 2226: /* Writing 0xff to $fffc02 will cause the 6301 to exit custom exe mode. */
! 2227: /*----------------------------------------------------------------------*/
! 2228:
! 2229: static void IKBD_CustomCodeHandler_FroggiesMenu_Read ( void )
! 2230: {
! 2231: Uint8 res1 = 0;
! 2232: Uint8 res2 = 0;
! 2233:
! 2234: if ( KeyboardProcessor.Mouse.DeltaX < 0 ) res1 = 0x7a; /* mouse left */
! 2235: if ( KeyboardProcessor.Mouse.DeltaX > 0 ) res1 = 0x06; /* mouse right */
! 2236: if ( KeyboardProcessor.Mouse.DeltaY < 0 ) res2 = 0x7a; /* mouse up */
! 2237: if ( KeyboardProcessor.Mouse.DeltaY > 0 ) res2 = 0x06; /* mouse down */
! 2238: if ( Keyboard.bLButtonDown & BUTTON_MOUSE ) res1 |= 0x80; /* left mouse button */
! 2239:
! 2240: if ( ScanCodeState[ 0x4b ] ) res1 |= 0x7a; /* left */
! 2241: if ( ScanCodeState[ 0x4d ] ) res1 |= 0x06; /* right */
! 2242: if ( ScanCodeState[ 0x48 ] ) res2 |= 0x7a; /* up */
! 2243: if ( ScanCodeState[ 0x50 ] ) res2 |= 0x06; /* down */
! 2244: if ( ScanCodeState[ 0x70 ] ) res1 |= 0x80; /* keypad 0 */
! 2245:
! 2246: IKBD_AddKeyToKeyboardBuffer_Real(res1, ACIA_CYCLES);
! 2247: IKBD_AddKeyToKeyboardBuffer_Real(res2, ACIA_CYCLES);
! 2248: }
! 2249:
! 2250: static void IKBD_CustomCodeHandler_FroggiesMenu_Write ( Uint8 aciabyte )
! 2251: {
! 2252: /* When writing 0xff to $fffc02, Froggies ikbd's program will terminate itself */
! 2253: /* and leave Execution mode */
! 2254: if ( aciabyte == 0xff )
! 2255: IKBD_Reset_ExeMode ();
! 2256: }
! 2257:
! 2258:
! 2259:
! 2260: /*----------------------------------------------------------------------*/
! 2261: /* Transbeauce II menu. */
! 2262: /* Returns 1 byte with the joystick position, keyboard can be used too. */
! 2263: /*----------------------------------------------------------------------*/
! 2264:
! 2265: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Read ( void )
! 2266: {
! 2267: Uint8 res = 0;
! 2268:
! 2269: /* keyboard emulation */
! 2270: if ( ScanCodeState[ 0x48 ] ) res |= 0x01; /* up */
! 2271: if ( ScanCodeState[ 0x50 ] ) res |= 0x02; /* down */
! 2272: if ( ScanCodeState[ 0x4b ] ) res |= 0x04; /* left */
! 2273: if ( ScanCodeState[ 0x4d ] ) res |= 0x08; /* right */
! 2274: if ( ScanCodeState[ 0x62 ] ) res |= 0x40; /* help */
! 2275: if ( ScanCodeState[ 0x39 ] ) res |= 0x80; /* space */
! 2276:
! 2277: /* joystick emulation (bit mapping is same as cursor above, with bit 7 = fire button */
! 2278: res |= ( Joy_GetStickData(1) & 0x8f ) ; /* keep bits 0-3 and 7 */
! 2279:
! 2280: IKBD_AddKeyToKeyboardBuffer_Real(res, ACIA_CYCLES);
! 2281: }
! 2282:
! 2283: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Write ( Uint8 aciabyte )
! 2284: {
! 2285: /* Ignore write */
! 2286: }
! 2287:
! 2288:
! 2289:
! 2290: /*----------------------------------------------------------------------*/
! 2291: /* Dragonnels demo menu. */
! 2292: /* Returns 1 byte with the Y position of the mouse. */
! 2293: /*----------------------------------------------------------------------*/
! 2294:
! 2295: static void IKBD_CustomCodeHandler_DragonnelsMenu_Read ( void )
! 2296: {
! 2297: Uint8 res = 0;
! 2298:
! 2299: if ( KeyboardProcessor.Mouse.DeltaY < 0 ) res = 0xfc; /* mouse up */
! 2300: if ( KeyboardProcessor.Mouse.DeltaY > 0 ) res = 0x04; /* mouse down */
! 2301:
! 2302: if ( Keyboard.bLButtonDown & BUTTON_MOUSE ) res = 0x80; /* left mouse button */
! 2303:
! 2304: IKBD_AddKeyToKeyboardBuffer_Real(res, ACIA_CYCLES);
! 2305: }
! 2306:
! 2307: static void IKBD_CustomCodeHandler_DragonnelsMenu_Write ( Uint8 aciabyte )
! 2308: {
! 2309: /* Ignore write */
! 2310: }
! 2311:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.