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