|
|
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 */
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 */
280: int MemoryExeNbBytes = 0; /* current number of bytes sent to the ikbd when IKBD_ExeMode is TRUE */
281:
282: void (*pIKBD_CustomCodeHandler_Read) ( void );
283: void (*pIKBD_CustomCodeHandler_Write) ( Uint8 );
284: bool IKBD_ExeMode = FALSE;
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: {
338: bByteInTransitToACIA = FALSE;
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.13 root 355: HATARI_TRACE ( HATARI_TRACE_IKBD_EXEC, "ikbd custom exe off\n" );
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;
361: IKBD_ExeMode = FALSE;
362:
363: Keyboard.BufferHead = Keyboard.BufferTail = 0; /* flush all queued bytes that would be read in $fffc02 */
364: bByteInTransitToACIA = FALSE;
365: IKBD_AddKeyToKeyboardBuffer(0xF0); /* Assume OK, return correct code */
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: {
378: KeyboardProcessor.bReset = FALSE;
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.12 root 416: bMouseDisabled = bJoystickDisabled = FALSE;
417: /* do emulate hardware 'quirk' where if disable both with 'x' time
418: * of a RESET command they are ignored! */
419: bDuringResetCriticalTime = bBothMouseAndJoy = FALSE;
1.1.1.14! root 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 */
! 426: Int_AddRelativeInterrupt(80000, 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));
455: if ( ( bSave == FALSE ) && ( IKBD_ExeMode == TRUE ) ) /* restoring a snapshot with active 6301 emulation */
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) */
469: IKBD_ExeMode = FALSE; /* turn off exe mode */
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;
547: Keyboard.bLButtonDown = FALSE;
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;
573: Keyboard.bRButtonDown = FALSE;
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)
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.13 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 */
659: while (TRUE)
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.13 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: {
774: bReportPosition = TRUE;
775: KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x04;
776: KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x02;
777: }
778: if ( (IKBD_ButtonBool(Keyboard.bRButtonDown) && (!IKBD_ButtonBool(Keyboard.bOldRButtonDown))) )
779: {
780: bReportPosition = TRUE;
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: {
791: bReportPosition = TRUE;
792: KeyboardProcessor.Abs.PrevReadAbsMouseButtons &= ~0x08;
793: KeyboardProcessor.Abs.PrevReadAbsMouseButtons |= 0x01;
794: }
795: if ( (IKBD_ButtonBool(Keyboard.bOldRButtonDown) && (!IKBD_ButtonBool(Keyboard.bRButtonDown))) )
796: {
797: bReportPosition = TRUE;
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.13 root 809: HATARI_TRACE(HATARI_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: {
926: IKBD_PressSTKey(57,TRUE); /* Press */
927: JoystickSpaceBar = JOYSTICK_SPACE_UP;
928: }
929: else //if (JoystickSpaceBar==JOYSTICK_SPACE_UP) {
930: {
931: IKBD_PressSTKey(57,FALSE); /* Release */
932: JoystickSpaceBar = FALSE; /* Complete */
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 */
! 962: Int_AddRelativeInterrupt(60000, INT_CPU_CYCLE, INTERRUPT_IKBD_AUTOSEND);
! 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;
991: bBothMouseAndJoy = TRUE;
1.1.1.6 root 992:
1.1.1.13 root 993: HATARI_TRACE(HATARI_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 */
1011: KeyboardProcessor.bReset = TRUE;
1.1.1.9 root 1012:
1.1.1.12 root 1013: /* Critical timer is over */
1014: bDuringResetCriticalTime = FALSE;
1.1.1.14! root 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: *
1033: * Performs self test and checks for stuck (closed) keys, if OK returns 0xF0. Otherwise
1034: * returns break codes for keys
1035: */
1.1.1.13 root 1036: static void IKBD_Cmd_Reset(void)
1.1 root 1037: {
1.1.1.14! root 1038: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_Reset\n");
! 1039:
1.1.1.12 root 1040: /* Check for error series of bytes, eg 0x80,0x01 */
1041: if (Keyboard.InputBuffer[1] == 0x01)
1042: {
1043: /* Set defaults */
1044: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1045: KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
1046: KeyboardProcessor.Abs.X = ABS_X_ONRESET;
1047: KeyboardProcessor.Abs.Y = ABS_Y_ONRESET;
1048: KeyboardProcessor.Abs.MaxX = ABS_MAX_X_ONRESET;
1049: KeyboardProcessor.Abs.MaxY = ABS_MAY_Y_ONRESET;
1050: KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
1051:
1.1.1.13 root 1052: Keyboard.BufferHead = Keyboard.BufferTail = 0; /* flush all queued bytes that would be read in $fffc02 */
1053: IKBD_AddKeyToKeyboardBuffer(0xF0); /* Assume OK, return correct code */
1054: IKBD_AddKeyToKeyboardBuffer(0xF1); /* [NP] Dragonnels demo needs this */
1.1.1.12 root 1055:
1056: /* Start timer - some commands are send during this time they may be ignored (see real ST!) */
1.1.1.13 root 1057: Int_AddRelativeInterrupt(IKBD_RESET_CYCLES, INT_CPU_CYCLE, INTERRUPT_IKBD_RESETTIMER);
1.1.1.12 root 1058:
1059: /* Set this 'critical' flag, gets reset when timer expires */
1060: bDuringResetCriticalTime = TRUE;
1061: bMouseDisabled = bJoystickDisabled = FALSE;
1062: bBothMouseAndJoy = FALSE;
1.1.1.14! root 1063: bMouseEnabledDuringReset = FALSE;
! 1064:
! 1065: HATARI_TRACE(HATARI_TRACE_IKBD_ALL, "IKBD reset done.\n");
1.1.1.12 root 1066: }
1067: /* else if not 0x80,0x01 just ignore */
1.1 root 1068: }
1069:
1.1.1.2 root 1070:
1071: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1072: /**
1073: * SET MOUSE BUTTON ACTION
1074: *
1075: * 0x07
1076: * %00000mss ; mouse button action
1077: * ; (m is presumed =1 when in MOUSE KEYCODE mode)
1078: * ; mss=0xy, mouse button press or release causes mouse
1079: * ; position report
1080: * ; where y=1, mouse key press causes absolute report
1081: * ; and x=1, mouse key release causes absolute report
1082: * ; mss=100, mouse buttons act like keys
1083: */
1.1.1.13 root 1084: static void IKBD_Cmd_MouseAction(void)
1.1 root 1085: {
1.1.1.12 root 1086: KeyboardProcessor.Mouse.Action = Keyboard.InputBuffer[1];
1087: KeyboardProcessor.Abs.PrevReadAbsMouseButtons = ABS_PREVBUTTONS;
1.1.1.13 root 1088:
1089: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_MouseAction %d\n",
1090: (unsigned int)KeyboardProcessor.Mouse.Action);
1.1 root 1091: }
1092:
1.1.1.2 root 1093:
1094: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1095: /**
1096: * SET RELATIVE MOUSE POSITION REPORTING
1097: *
1098: * 0x08
1099: */
1.1.1.13 root 1100: static void IKBD_Cmd_RelMouseMode(void)
1.1 root 1101: {
1.1.1.12 root 1102: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1.1.1.13 root 1103:
1.1.1.14! root 1104: /* Some games (like Barbarian by Psygnosis) enable both, mouse and
! 1105: * joystick directly after a reset. This causes the IKBD to send both
! 1106: * type of packets. To emulate this feature, we've got to remember
! 1107: * that the mouse has been enabled during reset. */
! 1108: if (bDuringResetCriticalTime)
! 1109: bMouseEnabledDuringReset = TRUE;
! 1110:
1.1.1.13 root 1111: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_RelMouseMode\n");
1.1 root 1112: }
1113:
1.1.1.2 root 1114:
1115: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1116: /**
1117: * SET ABSOLUTE MOUSE POSITIONING
1118: *
1119: * 0x09
1120: * XMSB ;X maximum (in scaled mouse clicks)
1121: * XLSB
1122: * YMSB ;Y maximum (in scaled mouse clicks)
1123: * YLSB
1124: */
1.1.1.13 root 1125: static void IKBD_Cmd_AbsMouseMode(void)
1.1 root 1126: {
1.1.1.12 root 1127: /* These maximums are 'inclusive' */
1128: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEABS;
1129: KeyboardProcessor.Abs.MaxX = (((unsigned int)Keyboard.InputBuffer[1])<<8) | (unsigned int)Keyboard.InputBuffer[2];
1130: KeyboardProcessor.Abs.MaxY = (((unsigned int)Keyboard.InputBuffer[3])<<8) | (unsigned int)Keyboard.InputBuffer[4];
1.1.1.13 root 1131:
1132: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_AbsMouseMode %d,%d\n",
1133: KeyboardProcessor.Abs.MaxX, KeyboardProcessor.Abs.MaxY);
1.1 root 1134: }
1135:
1.1.1.2 root 1136:
1137: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1138: /**
1139: * SET MOUSE KEYCODE MODE
1140: *
1141: * 0x0A
1142: * deltax ; distance in X clicks to return (LEFT) or (RIGHT)
1143: * deltay ; distance in Y clicks to return (UP) or (DOWN)
1144: */
1.1.1.13 root 1145: static void IKBD_Cmd_MouseCursorKeycodes(void)
1.1 root 1146: {
1.1.1.12 root 1147: KeyboardProcessor.MouseMode = AUTOMODE_MOUSECURSOR;
1148: KeyboardProcessor.Mouse.KeyCodeDeltaX = Keyboard.InputBuffer[1];
1149: KeyboardProcessor.Mouse.KeyCodeDeltaY = Keyboard.InputBuffer[2];
1.1.1.13 root 1150:
1151: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_MouseCursorKeycodes %d,%d\n",
1152: (int)KeyboardProcessor.Mouse.KeyCodeDeltaX,
1153: (int)KeyboardProcessor.Mouse.KeyCodeDeltaY);
1.1 root 1154: }
1155:
1.1.1.2 root 1156:
1157: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1158: /**
1159: * SET MOUSE THRESHOLD
1160: *
1161: * 0x0B
1162: * X ; x threshold in mouse ticks (positive integers)
1163: * Y ; y threshold in mouse ticks (positive integers)
1164: */
1.1.1.13 root 1165: static void IKBD_Cmd_SetMouseThreshold(void)
1.1 root 1166: {
1.1.1.12 root 1167: KeyboardProcessor.Mouse.XThreshold = (unsigned int)Keyboard.InputBuffer[1];
1168: KeyboardProcessor.Mouse.YThreshold = (unsigned int)Keyboard.InputBuffer[2];
1.1.1.13 root 1169:
1170: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetMouseThreshold %d,%d\n",
1171: KeyboardProcessor.Mouse.XThreshold, KeyboardProcessor.Mouse.YThreshold);
1.1 root 1172: }
1173:
1.1.1.2 root 1174:
1175: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1176: /**
1177: * SET MOUSE SCALE
1178: *
1179: * 0x0C
1180: * X ; horizontal mouse ticks per internel X
1181: * Y ; vertical mouse ticks per internel Y
1182: */
1.1.1.13 root 1183: static void IKBD_Cmd_SetMouseScale(void)
1.1 root 1184: {
1.1.1.12 root 1185: KeyboardProcessor.Mouse.XScale = (unsigned int)Keyboard.InputBuffer[1];
1186: KeyboardProcessor.Mouse.YScale = (unsigned int)Keyboard.InputBuffer[2];
1.1.1.13 root 1187:
1188: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetMouseScale %d,%d\n",
1189: KeyboardProcessor.Mouse.XScale, KeyboardProcessor.Mouse.YScale);
1.1 root 1190: }
1191:
1192:
1.1.1.12 root 1193: /*-----------------------------------------------------------------------*/
1194: /**
1195: * INTERROGATE MOUSE POSITION
1196: *
1197: * 0x0D
1198: * Returns: 0xF7 ; absolute mouse position header
1199: * BUTTONS
1200: * 0000dcba
1201: * where a is right button down since last interrogation
1202: * b is right button up since last
1203: * c is left button down since last
1204: * d is left button up since last
1205: * XMSB ; X coordinate
1206: * XLSB
1207: * YMSB ; Y coordinate
1208: * YLSB
1209: */
1.1.1.13 root 1210: static void IKBD_Cmd_ReadAbsMousePos(void)
1.1 root 1211: {
1.1.1.12 root 1212: Uint8 Buttons,PrevButtons;
1.1 root 1213:
1.1.1.12 root 1214: /* Test buttons */
1215: Buttons = 0;
1216: /* Set buttons to show if up/down */
1217: if (Keyboard.bRButtonDown)
1218: Buttons |= 0x01;
1219: else
1220: Buttons |= 0x02;
1221: if (Keyboard.bLButtonDown)
1222: Buttons |= 0x04;
1223: else
1224: Buttons |= 0x08;
1225: /* Mask off it didn't send last time */
1226: PrevButtons = KeyboardProcessor.Abs.PrevReadAbsMouseButtons;
1227: KeyboardProcessor.Abs.PrevReadAbsMouseButtons = Buttons;
1228: Buttons &= ~PrevButtons;
1229:
1230: /* And send packet */
1.1.1.13 root 1231: IKBD_AddKeyToKeyboardBufferWithDelay(0xf7, 18000);
1.1.1.12 root 1232: IKBD_AddKeyToKeyboardBuffer(Buttons);
1233: IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.X>>8);
1234: IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.X&0xff);
1235: IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.Y>>8);
1236: IKBD_AddKeyToKeyboardBuffer((unsigned int)KeyboardProcessor.Abs.Y&0xff);
1237:
1.1.1.13 root 1238: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReadAbsMousePos %d,%d 0x%X\n",
1239: KeyboardProcessor.Abs.X, KeyboardProcessor.Abs.Y, Buttons);
1.1 root 1240: }
1241:
1242:
1.1.1.12 root 1243: /*-----------------------------------------------------------------------*/
1244: /**
1245: * LOAD MOUSE POSITION
1246: *
1247: * 0x0E
1248: * 0x00 ; filler
1249: * XMSB ; X coordinate
1250: * XLSB ; (in scaled coordinate system)
1251: * YMSB ; Y coordinate
1252: * YLSB
1253: */
1.1.1.13 root 1254: static void IKBD_Cmd_SetInternalMousePos(void)
1.1.1.7 root 1255: {
1.1.1.12 root 1256: /* Setting these do not clip internal position(this happens on next update) */
1257: KeyboardProcessor.Abs.X = (((unsigned int)Keyboard.InputBuffer[2])<<8) | (unsigned int)Keyboard.InputBuffer[3];
1258: KeyboardProcessor.Abs.Y = (((unsigned int)Keyboard.InputBuffer[4])<<8) | (unsigned int)Keyboard.InputBuffer[5];
1.1.1.13 root 1259:
1260: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetInternalMousePos %d,%d\n",
1261: KeyboardProcessor.Abs.X, KeyboardProcessor.Abs.Y);
1.1 root 1262: }
1263:
1.1.1.2 root 1264:
1265: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1266: /**
1267: * SET Y=0 AT BOTTOM
1268: *
1269: * 0x0F
1270: */
1.1.1.13 root 1271: static void IKBD_Cmd_SetYAxisDown(void)
1.1 root 1272: {
1.1.1.12 root 1273: KeyboardProcessor.Mouse.YAxis = -1;
1.1.1.13 root 1274:
1275: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetYAxisDown\n");
1.1 root 1276: }
1277:
1.1.1.2 root 1278:
1279: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1280: /**
1281: * SET Y=0 AT TOP
1282: *
1283: * 0x10
1284: */
1.1.1.13 root 1285: static void IKBD_Cmd_SetYAxisUp(void)
1.1 root 1286: {
1.1.1.12 root 1287: KeyboardProcessor.Mouse.YAxis = 1;
1.1.1.13 root 1288:
1289: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetYAxisUp\n");
1.1 root 1290: }
1291:
1.1.1.2 root 1292:
1293: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1294: /**
1295: * RESUME
1296: *
1297: * 0x11
1298: */
1.1.1.13 root 1299: static void IKBD_Cmd_StartKeyboardTransfer(void)
1.1 root 1300: {
1.1.1.13 root 1301: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_StartKeyboardTransfer\n");
1.1 root 1302: }
1303:
1.1.1.2 root 1304:
1305: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1306: /**
1307: * DISABLE MOUSE
1308: *
1309: * 0x12
1310: */
1.1.1.13 root 1311: static void IKBD_Cmd_TurnMouseOff(void)
1.1 root 1312: {
1.1.1.12 root 1313: KeyboardProcessor.MouseMode = AUTOMODE_OFF;
1314: bMouseDisabled = TRUE;
1.1.1.13 root 1315:
1316: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_TurnMouseOff\n");
1.1 root 1317:
1.1.1.12 root 1318: IKBD_CheckResetDisableBug();
1.1 root 1319: }
1320:
1.1.1.2 root 1321:
1322: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1323: /**
1324: * PAUSE OUTPUT
1325: *
1326: * 0x13
1327: */
1.1.1.13 root 1328: static void IKBD_Cmd_StopKeyboardTransfer(void)
1.1 root 1329: {
1.1.1.13 root 1330: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_StopKeyboardTransfer\n");
1.1 root 1331: }
1332:
1.1.1.2 root 1333:
1334: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1335: /**
1336: * SET JOYSTICK EVENT REPORTING
1337: *
1338: * 0x14
1339: */
1.1.1.13 root 1340: static void IKBD_Cmd_ReturnJoystickAuto(void)
1.1 root 1341: {
1.1.1.14! root 1342: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReturnJoystickAuto\n");
! 1343:
1.1.1.12 root 1344: KeyboardProcessor.JoystickMode = AUTOMODE_JOYSTICK;
1345: KeyboardProcessor.MouseMode = AUTOMODE_OFF;
1.1.1.6 root 1346:
1.1.1.14! root 1347: /* If mouse was also enabled within time of a reset it isn't disabled now!
! 1348: * (Used by the game Barbarian 1 by Psygnosis for example) */
! 1349: if (bMouseEnabledDuringReset)
1.1.1.12 root 1350: {
1351: KeyboardProcessor.MouseMode = AUTOMODE_MOUSEREL;
1352: bBothMouseAndJoy = TRUE;
1.1.1.14! root 1353: HATARI_TRACE(HATARI_TRACE_IKBD_ALL, "IKBD joystick and mouse "
! 1354: "enabled during RESET. Mouse not disabled!\n");
1.1.1.12 root 1355: }
1.1.1.6 root 1356:
1.1.1.13 root 1357: /* This command resets the internally previously stored joystick states */
1358: KeyboardProcessor.Joy.PrevJoyData[0] = KeyboardProcessor.Joy.PrevJoyData[1] = 0;
1359:
1360: /* This is a hack for the STE Utopos (=> v1.50) and Falcon Double Bubble
1361: * 2000 games. They expect the joystick data to be sent within a certain
1362: * amount of time after this command, without checking the ACIA control
1363: * register first.
1364: */
1365: IKBD_GetJoystickData();
1366: IKBD_SelAutoJoysticks();
1.1 root 1367: }
1368:
1.1.1.2 root 1369:
1370: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1371: /**
1372: * SET JOYSTICK INTERROGATION MODE
1373: *
1374: * 0x15
1375: */
1.1.1.13 root 1376: static void IKBD_Cmd_StopJoystick(void)
1.1 root 1377: {
1.1.1.12 root 1378: KeyboardProcessor.JoystickMode = AUTOMODE_OFF;
1.1.1.13 root 1379: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_StopJoystick\n");
1.1 root 1380: }
1381:
1.1.1.2 root 1382:
1383: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1384: /**
1385: * JOYSTICK INTERROGATE
1386: *
1387: * 0x16
1388: */
1.1.1.13 root 1389: static void IKBD_Cmd_ReturnJoystick(void)
1.1 root 1390: {
1.1.1.13 root 1391: IKBD_AddKeyToKeyboardBufferWithDelay(0xFD, 35000);
1.1.1.12 root 1392: IKBD_AddKeyToKeyboardBuffer(Joy_GetStickData(0));
1393: IKBD_AddKeyToKeyboardBuffer(Joy_GetStickData(1));
1.1.1.13 root 1394:
1395: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReturnJoystick\n");
1.1 root 1396: }
1397:
1.1.1.2 root 1398:
1399: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1400: /**
1401: * SET JOYSTICK MONITORING
1402: *
1403: * 0x17
1404: * rate ; time between samples in hundreths of a second
1405: * Returns: (in packets of two as long as in mode)
1406: * %000000xy where y is JOYSTICK1 Fire button
1407: * and x is JOYSTICK0 Fire button
1408: * %nnnnmmmm where m is JOYSTICK1 state
1409: * and n is JOYSTICK0 state
1410: */
1.1.1.13 root 1411: static void IKBD_Cmd_SetJoystickDuration(void)
1.1 root 1412: {
1.1.1.13 root 1413: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetJoystickDuration\n");
1.1 root 1414: }
1415:
1.1.1.2 root 1416:
1417: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1418: /**
1419: * SET FIRE BUTTON MONITORING
1420: *
1421: * 0x18
1422: * Returns: (as long as in mode)
1423: * %bbbbbbbb ; state of the JOYSTICK1 fire button packed
1424: * ; 8 bits per byte, the first sample if the MSB
1425: */
1.1.1.13 root 1426: static void IKBD_Cmd_SetJoystickFireDuration(void)
1.1 root 1427: {
1.1.1.13 root 1428: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetJoystickFireDuration\n");
1.1 root 1429: }
1430:
1.1.1.2 root 1431:
1432: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1433: /**
1434: * SET JOYSTICK KEYCODE MODE
1435: *
1436: * 0x19
1437: * RX ; length of time (in tenths of seconds) until
1438: * ; horizontal velocity breakpoint is reached
1439: * RY ; length of time (in tenths of seconds) until
1440: * ; vertical velocity breakpoint is reached
1441: * TX ; length (in tenths of seconds) of joystick closure
1442: * ; until horizontal cursor key is generated before RX
1443: * ; has elapsed
1444: * TY ; length (in tenths of seconds) of joystick closure
1445: * ; until vertical cursor key is generated before RY
1446: * ; has elapsed
1447: * VX ; length (in tenths of seconds) of joystick closure
1448: * ; until horizontal cursor keystokes are generated after RX
1449: * ; has elapsed
1450: * VY ; length (in tenths of seconds) of joystick closure
1451: * ; until vertical cursor keystokes are generated after RY
1452: * ; has elapsed
1453: */
1.1.1.13 root 1454: static void IKBD_Cmd_SetCursorForJoystick(void)
1.1 root 1455: {
1.1.1.13 root 1456: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetCursorForJoystick\n");
1.1 root 1457: }
1458:
1.1.1.2 root 1459:
1460: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1461: /**
1462: * DISABLE JOYSTICKS
1463: *
1464: * 0x1A
1465: */
1.1.1.13 root 1466: static void IKBD_Cmd_DisableJoysticks(void)
1.1 root 1467: {
1.1.1.12 root 1468: KeyboardProcessor.JoystickMode = AUTOMODE_OFF;
1469: bJoystickDisabled = TRUE;
1.1.1.13 root 1470:
1471: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_DisableJoysticks\n");
1.1 root 1472:
1.1.1.12 root 1473: IKBD_CheckResetDisableBug();
1.1 root 1474: }
1475:
1.1.1.2 root 1476:
1477: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1478: /**
1479: * TIME-OF-DAY CLOCK SET
1480: *
1481: * 0x1B
1482: * YY ; year (2 least significant digits)
1483: * MM ; month
1484: * DD ; day
1485: * hh ; hour
1486: * mm ; minute
1487: * ss ; second
1488: */
1.1.1.13 root 1489: static void IKBD_Cmd_SetClock(void)
1.1 root 1490: {
1.1.1.13 root 1491: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_SetClock\n");
1492: }
1493:
1494:
1495: /*-----------------------------------------------------------------------*/
1496: /**
1497: * Convert value to 2-digit BCD
1498: */
1499: static unsigned char IKBD_ConvertToBCD(unsigned short int Value)
1500: {
1501: return (((Value/10))<<4) | (Value%10);
1.1 root 1502: }
1503:
1.1.1.2 root 1504:
1505: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1506: /**
1507: * INTERROGATE TIME-OF-DAT CLOCK
1508: *
1509: * 0x1C
1510: * Returns:
1511: * 0xFC ; time-of-day event header
1512: * YY ; year (2 least significant digits)
1513: * There seems to be a problem with the bcd conversion of the year
1514: * when year/10 >= 10. So the bcd conversion keeps the part > 10.
1515: * If you put year%100 here (as says the doc), and put a real bcd
1516: * conversion function in misc.c, then you end up with year 2031
1517: * instead of 2003...
1518: *
1519: * MM ; month
1520: * DD ; day
1521: * hh ; hour
1522: * mm ; minute
1523: * ss ; second
1524: */
1.1.1.13 root 1525: static void IKBD_Cmd_ReadClock(void)
1.1 root 1526: {
1.1.1.12 root 1527: struct tm *SystemTime;
1528: time_t nTimeTicks;
1.1 root 1529:
1.1.1.12 root 1530: /* Get system time */
1531: nTimeTicks = time(NULL);
1532: SystemTime = localtime(&nTimeTicks);
1533:
1534: /* Return packet */
1.1.1.13 root 1535: IKBD_AddKeyToKeyboardBufferWithDelay(0xFC, 32000);
1.1.1.12 root 1536: /* Return time-of-day clock as yy-mm-dd-hh-mm-ss as BCD */
1.1.1.13 root 1537: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_year)); /* yy - year (2 least significant digits) */
1538: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_mon+1)); /* mm - Month */
1539: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_mday)); /* dd - Day */
1540: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_hour)); /* hh - Hour */
1541: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_min)); /* mm - Minute */
1542: IKBD_AddKeyToKeyboardBuffer(IKBD_ConvertToBCD(SystemTime->tm_sec)); /* ss - Second */
1543:
1544: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReadClock\n");
1.1 root 1545: }
1546:
1.1.1.2 root 1547:
1548: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1549: /**
1550: * MEMORY LOAD
1551: *
1552: * 0x20
1553: * ADRMSB ; address in controller
1554: * ADRLSB ; memory to be loaded
1555: * NUM ; number of bytes (0-128)
1556: * { data }
1557: */
1.1.1.13 root 1558: static void IKBD_Cmd_LoadMemory(void)
1.1 root 1559: {
1.1.1.13 root 1560: HATARI_TRACE ( HATARI_TRACE_IKBD_CMDS , "IKBD_Cmd_LoadMemory addr 0x%x count %d\n" ,
1561: ( Keyboard.InputBuffer[1]<<8 ) + Keyboard.InputBuffer[2] , Keyboard.InputBuffer[3] );
1562:
1563: MemoryLoadNbBytesTotal = Keyboard.InputBuffer[3];
1564: MemoryLoadNbBytesLeft = MemoryLoadNbBytesTotal;
1565: crc32_reset ( &MemoryLoadCrc );
1.1 root 1566: }
1567:
1.1.1.2 root 1568:
1569: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1570: /**
1571: * MEMORY READ
1572: *
1573: * 0x21
1574: * ADRMSB ; address in controller
1575: * ADRLSB ; memory to be read
1576: * Returns:
1577: * 0xF6 ; status header
1578: * 0x20 ; memory access
1579: * { data } ; 6 data bytes starting at ADR
1580: */
1.1.1.13 root 1581: static void IKBD_Cmd_ReadMemory(void)
1.1 root 1582: {
1.1.1.13 root 1583: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReadMemory\n");
1.1 root 1584: }
1585:
1.1.1.2 root 1586:
1587: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1588: /**
1589: * CONTROLLER EXECUTE
1590: *
1591: * 0x22
1592: * ADRMSB ; address of subroutine in
1593: * ADRLSB ; controller memory to be called
1594: */
1.1.1.13 root 1595: static void IKBD_Cmd_Execute(void)
1596: {
1597: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_Execute\n");
1598:
1599: if ( pIKBD_CustomCodeHandler_Write )
1600: {
1601: HATARI_TRACE ( HATARI_TRACE_IKBD_EXEC, "ikbd execute addr 0x%x using custom handler\n" ,
1602: ( Keyboard.InputBuffer[1]<<8 ) + Keyboard.InputBuffer[2] );
1603:
1604: IKBD_ExeMode = TRUE; /* turn 6301's custom mode ON */
1605: }
1606: else /* unknown code uploaded to ikbd RAM */
1607: {
1608: HATARI_TRACE ( HATARI_TRACE_IKBD_EXEC, "ikbd execute addr 0x%x ignored, no custom handler found\n" ,
1609: ( Keyboard.InputBuffer[1]<<8 ) + Keyboard.InputBuffer[2] );
1610: }
1611: }
1612:
1613:
1614: /*-----------------------------------------------------------------------*/
1615: /**
1616: * REPORT MOUSE BUTTON ACTION
1617: *
1618: * 0x87
1619: */
1620: static void IKBD_Cmd_ReportMouseAction(void)
1621: {
1622: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseAction\n");
1623:
1624: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1625: IKBD_AddKeyToKeyboardBuffer(7);
1626: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.Action);
1627: IKBD_AddKeyToKeyboardBuffer(0);
1628: IKBD_AddKeyToKeyboardBuffer(0);
1629: IKBD_AddKeyToKeyboardBuffer(0);
1630: IKBD_AddKeyToKeyboardBuffer(0);
1631: IKBD_AddKeyToKeyboardBuffer(0);
1632: }
1633:
1634:
1635: /*-----------------------------------------------------------------------*/
1636: /**
1637: * REPORT MOUSE MODE
1638: *
1639: * 0x88 or 0x89 or 0x8A
1640: */
1641: static void IKBD_Cmd_ReportMouseMode(void)
1642: {
1643: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseMode\n");
1644:
1645: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1646: switch (KeyboardProcessor.MouseMode)
1647: {
1648: case AUTOMODE_MOUSEREL:
1649: IKBD_AddKeyToKeyboardBuffer(8);
1650: IKBD_AddKeyToKeyboardBuffer(0);
1651: IKBD_AddKeyToKeyboardBuffer(0);
1652: IKBD_AddKeyToKeyboardBuffer(0);
1653: IKBD_AddKeyToKeyboardBuffer(0);
1654: IKBD_AddKeyToKeyboardBuffer(0);
1655: IKBD_AddKeyToKeyboardBuffer(0);
1656: break;
1657: case AUTOMODE_MOUSEABS:
1658: IKBD_AddKeyToKeyboardBuffer(9);
1659: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxX >> 8);
1660: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxX);
1661: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxY >> 8);
1662: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Abs.MaxY);
1663: IKBD_AddKeyToKeyboardBuffer(0);
1664: IKBD_AddKeyToKeyboardBuffer(0);
1665: break;
1666: case AUTOMODE_MOUSECURSOR:
1667: IKBD_AddKeyToKeyboardBuffer(10);
1668: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.KeyCodeDeltaX);
1669: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.KeyCodeDeltaY);
1670: IKBD_AddKeyToKeyboardBuffer(0);
1671: IKBD_AddKeyToKeyboardBuffer(0);
1672: IKBD_AddKeyToKeyboardBuffer(0);
1673: IKBD_AddKeyToKeyboardBuffer(0);
1674: break;
1675: }
1676: }
1677:
1678:
1679: /*-----------------------------------------------------------------------*/
1680: /**
1681: * REPORT MOUSE THRESHOLD
1682: *
1683: * 0x8B
1684: */
1685: static void IKBD_Cmd_ReportMouseThreshold(void)
1686: {
1687: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseThreshold\n");
1688:
1689: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1690: IKBD_AddKeyToKeyboardBuffer(0x0B);
1691: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.XThreshold);
1692: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.YThreshold);
1693: IKBD_AddKeyToKeyboardBuffer(0);
1694: IKBD_AddKeyToKeyboardBuffer(0);
1695: IKBD_AddKeyToKeyboardBuffer(0);
1696: IKBD_AddKeyToKeyboardBuffer(0);
1697: }
1698:
1699:
1700: /*-----------------------------------------------------------------------*/
1701: /**
1702: * REPORT MOUSE SCALE
1703: *
1704: * 0x8C
1705: */
1706: static void IKBD_Cmd_ReportMouseScale(void)
1707: {
1708: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseScale\n");
1709:
1710: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1711: IKBD_AddKeyToKeyboardBuffer(0x0C);
1712: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.XScale);
1713: IKBD_AddKeyToKeyboardBuffer(KeyboardProcessor.Mouse.YScale);
1714: IKBD_AddKeyToKeyboardBuffer(0);
1715: IKBD_AddKeyToKeyboardBuffer(0);
1716: IKBD_AddKeyToKeyboardBuffer(0);
1717: IKBD_AddKeyToKeyboardBuffer(0);
1718: }
1719:
1720:
1721: /*-----------------------------------------------------------------------*/
1722: /**
1723: * REPORT MOUSE VERTICAL COORDINATES
1724: *
1725: * 0x8F and 0x90
1726: */
1727: static void IKBD_Cmd_ReportMouseVertical(void)
1728: {
1729: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseVertical\n");
1730:
1731: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1732: if (KeyboardProcessor.Mouse.YAxis == -1)
1733: IKBD_AddKeyToKeyboardBuffer(0x0F);
1734: else
1735: IKBD_AddKeyToKeyboardBuffer(0x10);
1736: IKBD_AddKeyToKeyboardBuffer(0);
1737: IKBD_AddKeyToKeyboardBuffer(0);
1738: IKBD_AddKeyToKeyboardBuffer(0);
1739: IKBD_AddKeyToKeyboardBuffer(0);
1740: IKBD_AddKeyToKeyboardBuffer(0);
1741: IKBD_AddKeyToKeyboardBuffer(0);
1742: }
1743:
1744:
1745: /*-----------------------------------------------------------------------*/
1746: /**
1747: * REPORT MOUSE AVAILABILITY
1748: *
1749: * 0x92
1750: */
1751: static void IKBD_Cmd_ReportMouseAvailability(void)
1752: {
1753: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportMouseAvailability\n");
1754:
1755: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1756: if (KeyboardProcessor.MouseMode == AUTOMODE_OFF)
1757: IKBD_AddKeyToKeyboardBuffer(0x12);
1758: else
1759: IKBD_AddKeyToKeyboardBuffer(0x00);
1760: IKBD_AddKeyToKeyboardBuffer(0);
1761: IKBD_AddKeyToKeyboardBuffer(0);
1762: IKBD_AddKeyToKeyboardBuffer(0);
1763: IKBD_AddKeyToKeyboardBuffer(0);
1764: IKBD_AddKeyToKeyboardBuffer(0);
1765: IKBD_AddKeyToKeyboardBuffer(0);
1766: }
1767:
1768:
1769: /*-----------------------------------------------------------------------*/
1770: /**
1771: * REPORT JOYSTICK MODE
1772: *
1773: * 0x94 or 0x95 or 0x99
1774: */
1775: static void IKBD_Cmd_ReportJoystickMode(void)
1.1 root 1776: {
1.1.1.13 root 1777: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportJoystickMode\n");
1778:
1779: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1780: switch (KeyboardProcessor.JoystickMode)
1781: {
1782: case AUTOMODE_JOYSTICK:
1783: IKBD_AddKeyToKeyboardBuffer(0x14);
1784: IKBD_AddKeyToKeyboardBuffer(0);
1785: IKBD_AddKeyToKeyboardBuffer(0);
1786: IKBD_AddKeyToKeyboardBuffer(0);
1787: IKBD_AddKeyToKeyboardBuffer(0);
1788: IKBD_AddKeyToKeyboardBuffer(0);
1789: IKBD_AddKeyToKeyboardBuffer(0);
1790: break;
1791: default: /* TODO: Joystick keycodes mode not supported yet! */
1792: IKBD_AddKeyToKeyboardBuffer(0x15);
1793: IKBD_AddKeyToKeyboardBuffer(0);
1794: IKBD_AddKeyToKeyboardBuffer(0);
1795: IKBD_AddKeyToKeyboardBuffer(0);
1796: IKBD_AddKeyToKeyboardBuffer(0);
1797: IKBD_AddKeyToKeyboardBuffer(0);
1798: IKBD_AddKeyToKeyboardBuffer(0);
1799: break;
1800: }
1801: }
1802:
1803:
1804: /*-----------------------------------------------------------------------*/
1805: /**
1806: * REPORT JOYSTICK AVAILABILITY
1807: *
1808: * 0x9A
1809: */
1810: static void IKBD_Cmd_ReportJoystickAvailability(void)
1811: {
1812: HATARI_TRACE(HATARI_TRACE_IKBD_CMDS, "IKBD_Cmd_ReportJoystickAvailability\n");
1813:
1814: IKBD_AddKeyToKeyboardBufferWithDelay(0xf6, 30000);
1815: if (KeyboardProcessor.JoystickMode == AUTOMODE_OFF)
1816: IKBD_AddKeyToKeyboardBuffer(0x1A);
1817: else
1818: IKBD_AddKeyToKeyboardBuffer(0x00);
1819: IKBD_AddKeyToKeyboardBuffer(0);
1820: IKBD_AddKeyToKeyboardBuffer(0);
1821: IKBD_AddKeyToKeyboardBuffer(0);
1822: IKBD_AddKeyToKeyboardBuffer(0);
1823: IKBD_AddKeyToKeyboardBuffer(0);
1824: IKBD_AddKeyToKeyboardBuffer(0);
1.1 root 1825: }
1826:
1827:
1.1.1.2 root 1828: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1829: /**
1830: * Send data to keyboard processor via ACIA by writing to address 0xfffc02.
1831: * For our emulation we bypass the ACIA (I've yet to see anything check for this)
1832: * and add the byte directly into the keyboard input buffer.
1833: */
1.1.1.11 root 1834: static void IKBD_RunKeyboardCommand(Uint16 aciabyte)
1.1 root 1835: {
1.1.1.12 root 1836: int i=0;
1.1 root 1837:
1.1.1.12 root 1838: /* Write into our keyboard input buffer */
1839: Keyboard.InputBuffer[Keyboard.nBytesInInputBuffer++] = aciabyte;
1.1 root 1840:
1.1.1.12 root 1841: /* Now check bytes to see if we have a valid/in-valid command string set */
1842: while (KeyboardCommands[i].Command!=0xff)
1843: {
1844: /* Found command? */
1845: if (KeyboardCommands[i].Command==Keyboard.InputBuffer[0])
1846: {
1847: /* Is string complete, then can execute? */
1848: if (KeyboardCommands[i].NumParameters==Keyboard.nBytesInInputBuffer)
1849: {
1850: CALL_VAR(KeyboardCommands[i].pCallFunction);
1851: Keyboard.nBytesInInputBuffer = 0;
1852: }
1.1 root 1853:
1.1.1.12 root 1854: return;
1855: }
1.1.1.7 root 1856:
1.1.1.12 root 1857: i++;
1858: }
1.1 root 1859:
1.1.1.12 root 1860: /* Command not known, reset buffer(IKBD assumes a NOP) */
1861: Keyboard.nBytesInInputBuffer = 0;
1.1 root 1862: }
1863:
1.1.1.2 root 1864:
1865: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1866: /**
1867: * Send byte to our keyboard processor, and execute
1868: */
1.1.1.13 root 1869: static void IKBD_SendByteToKeyboardProcessor(Uint16 bl)
1.1 root 1870: {
1.1.1.13 root 1871: /* If IKBD is executing custom code, send the byte to the function handling this code */
1872: if ( IKBD_ExeMode && pIKBD_CustomCodeHandler_Write )
1873: {
1874: (*pIKBD_CustomCodeHandler_Write) ( (Uint8) bl );
1875: return;
1876: }
1877:
1878: if ( MemoryLoadNbBytesLeft == 0 ) /* No pending MemoryLoad command */
1879: IKBD_RunKeyboardCommand ( bl ); /* check for known commands */
1880:
1881: else /* MemoryLoad command is not finished yet */
1882: IKBD_LoadMemoryByte ( (Uint8) bl ); /* process bytes sent to the ikbd RAM */
1.1 root 1883: }
1884:
1.1.1.2 root 1885:
1886: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1887: /**
1888: * The byte stored in the ACIA 'ACIAByte' has been read by the CPU by reading from
1889: * address $fffc02. We clear the status flag and set the GPIP register to signal read.
1890: */
1.1.1.11 root 1891: Uint16 IKBD_GetByteFromACIA(void)
1.1 root 1892: {
1.1.1.12 root 1893: /* ACIA is now reset */
1894: ACIAStatusRegister &= ~(ACIA_STATUS_REGISTER__RX_BUFFER_FULL | ACIA_STATUS_REGISTER__INTERRUPT_REQUEST | ACIA_STATUS_REGISTER__OVERRUN_ERROR);
1.1 root 1895:
1.1.1.12 root 1896: /* GPIP I4 - General Purpose Pin Keyboard/MIDI interrupt */
1897: MFP_GPIP |= 0x10;
1898: return ACIAByte; /* Return byte from keyboard */
1.1 root 1899: }
1900:
1.1.1.2 root 1901:
1902: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1903: /**
1.1.1.13 root 1904: * Byte received in the ACIA from the keyboard processor. Store byte for read
1905: * from $fffc02 and schedule MFP interrupt to be triggered later.
1.1.1.12 root 1906: */
1.1 root 1907: void IKBD_InterruptHandler_ACIA(void)
1908: {
1.1.1.12 root 1909: /* Remove this interrupt from list and re-order */
1910: Int_AcknowledgeInterrupt();
1.1 root 1911:
1.1.1.12 root 1912: /* Copy keyboard byte, ready for read from $fffc02 */
1913: ACIAByte = Keyboard.Buffer[Keyboard.BufferHead++];
1914: Keyboard.BufferHead &= KEYBOARD_BUFFER_MASK;
1915:
1916: /* Did we get an over-run? Ie byte has arrived from keyboard processor BEFORE CPU has read previous one from ACIA */
1917: if (ACIAStatusRegister&ACIA_STATUS_REGISTER__RX_BUFFER_FULL)
1918: ACIAStatusRegister |= ACIA_STATUS_REGISTER__OVERRUN_ERROR; /* Set over-run */
1919:
1920: /* ACIA buffer is now full */
1921: ACIAStatusRegister |= ACIA_STATUS_REGISTER__RX_BUFFER_FULL;
1922: /* Signal interrupt pending */
1923: ACIAStatusRegister |= ACIA_STATUS_REGISTER__INTERRUPT_REQUEST;
1.1.1.13 root 1924:
1.1.1.12 root 1925: /* GPIP I4 - General Purpose Pin Keyboard/MIDI interrupt */
1926: /* NOTE: GPIP will remain low(0) until keyboard data is read from $fffc02. */
1927: MFP_GPIP &= ~0x10;
1928:
1.1.1.13 root 1929: /* There seems to be a small gap on a real ST between the point in time
1930: * the ACIA_STATUS_REGISTER__RX_BUFFER_FULL bit is set and the MFP
1931: * interrupt is triggered - for example the "V8 music system" demo
1932: * depends on this behaviour. To emulate this, we simply start another
1933: * Int which triggers the MFP interrupt later: */
1934: Int_AddRelativeInterrupt(18, INT_CPU_CYCLE, INTERRUPT_IKBD_MFP);
1935: }
1936:
1937:
1938: /**
1939: * Start MFP interrupt after byte has been received in the ACIA.
1940: */
1941: void IKBD_InterruptHandler_MFP(void)
1942: {
1943: /* Remove this interrupt from list and re-order */
1944: Int_AcknowledgeInterrupt();
1945:
1.1.1.12 root 1946: /* Acknowledge in MFP circuit, pass bit,enable,pending */
1947: MFP_InputOnChannel(MFP_ACIA_BIT, MFP_IERB, &MFP_IPRB);
1948:
1949: /* Clear flag so can allow another byte to be sent along serial line */
1950: bByteInTransitToACIA = FALSE;
1.1.1.13 root 1951:
1.1.1.12 root 1952: /* If another key is waiting, start sending from keyboard processor now */
1953: if (Keyboard.BufferHead!=Keyboard.BufferTail)
1.1.1.13 root 1954: IKBD_SendByteToACIA(ACIA_CYCLES);
1.1 root 1955: }
1956:
1957:
1.1.1.2 root 1958: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1959: /**
1960: * Send a byte from the keyboard buffer to the ACIA. On a real ST this takes some time to send
1961: * so we must be as accurate in the timing as possible - bytes do not appear to the 68000 instantly!
1962: * We do this via an internal interrupt - neat!
1963: */
1.1.1.13 root 1964: static void IKBD_SendByteToACIA(int nAciaCycles)
1.1 root 1965: {
1.1.1.13 root 1966: /* Transmit byte from keyboard processor to ACIA.
1967: * This takes approx ACIA_CYCLES CPU clock cycles to complete */
1.1.1.12 root 1968: if (!bByteInTransitToACIA)
1969: {
1970: /* Send byte to ACIA */
1.1.1.13 root 1971: Int_AddRelativeInterrupt(nAciaCycles, INT_CPU_CYCLE, INTERRUPT_IKBD_ACIA);
1.1.1.12 root 1972: /* Set flag so only transmit one byte at a time */
1973: bByteInTransitToACIA = TRUE;
1974: }
1.1 root 1975: }
1976:
1.1.1.2 root 1977:
1978: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1979: /**
1.1.1.13 root 1980: * Add character to our internal keyboard buffer, with default ACIA_CYCLES
1981: * timing.
1982: */
1983: static void IKBD_AddKeyToKeyboardBuffer(Uint8 Data)
1984: {
1985: if ( IKBD_ExeMode ) /* if IKBD is executing custom code, don't add */
1986: return; /* anything to the buffer */
1987:
1988: IKBD_AddKeyToKeyboardBuffer_Real(Data, ACIA_CYCLES);
1989: }
1990:
1991:
1992: /**
1993: * Add character to our internal keyboard buffer, with additional delay.
1994: * This is required for some keyboard commands like ReadAbsMousePos (0x0d)
1995: * where it takes a little bit longer than the typical ACIA_CYCLES until
1996: * the first byte arrives from the IKBD (for example the "Unlimited bobs"
1997: * screen in the Dragonnels demo depends on this behaviour.
1998: */
1999: static void IKBD_AddKeyToKeyboardBufferWithDelay(Uint8 Data, int nAciaCycles)
2000: {
2001: if (IKBD_ExeMode) /* if IKBD is executing custom code, */
2002: return; /* don't add anything to the buffer */
2003:
2004: IKBD_AddKeyToKeyboardBuffer_Real(Data, nAciaCycles);
2005: }
2006:
2007:
2008: /**
2009: * Add character to our internal keyboard buffer. These bytes are then sent
2010: * one at a time to the ACIA. This is done via a delay to mimick the STs
2011: * internal workings, as this is needed for games such as Carrier Command.
1.1.1.12 root 2012: */
1.1.1.13 root 2013: static void IKBD_AddKeyToKeyboardBuffer_Real(Uint8 Data, int nAciaCycles)
1.1 root 2014: {
1.1.1.12 root 2015: /* Is keyboard initialised yet? Ignore any bytes until it is */
2016: if (!KeyboardProcessor.bReset)
2017: return;
2018:
2019: /* Check we have space to add byte */
2020: if (Keyboard.BufferHead!=((Keyboard.BufferTail+1)&KEYBOARD_BUFFER_MASK))
2021: {
2022: /* Add byte to our buffer */
2023: Keyboard.Buffer[Keyboard.BufferTail++] = Data;
2024: Keyboard.BufferTail &= KEYBOARD_BUFFER_MASK;
2025:
2026: /* We have character ready to transmit from the ACIA - see if can send it now */
1.1.1.13 root 2027: IKBD_SendByteToACIA(nAciaCycles);
1.1.1.12 root 2028: }
1.1 root 2029: }
2030:
1.1.1.2 root 2031:
2032: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2033: /**
2034: * When press/release key under host OS, execute this function.
2035: */
1.1.1.13 root 2036: void IKBD_PressSTKey(Uint8 ScanCode, bool bPress)
1.1 root 2037: {
1.1.1.13 root 2038: /* Store the state of each ST scancode : 1=pressed 0=released */
2039: if ( bPress ) ScanCodeState[ ScanCode & 0x7f ] = 1;
2040: else ScanCodeState[ ScanCode & 0x7f ] = 0;
2041:
1.1.1.12 root 2042: if (!bPress)
2043: ScanCode |= 0x80; /* Set top bit if released key */
2044: IKBD_AddKeyToKeyboardBuffer(ScanCode); /* And send to keyboard processor */
1.1 root 2045: }
1.1.1.10 root 2046:
2047:
2048: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2049: /**
2050: * Handle read from keyboard control ACIA register (0xfffc00)
2051: */
1.1.1.10 root 2052: void IKBD_KeyboardControl_ReadByte(void)
2053: {
1.1.1.11 root 2054: /* ACIA registers need wait states - but the value seems to vary in certain cases */
2055: M68000_WaitState(8);
2056:
1.1.1.13 root 2057: IoMem[0xfffc00] = ACIAStatusRegister;
1.1.1.12 root 2058:
1.1.1.13 root 2059: /* For our emulation send is immediate, so let's set the acknowledge
2060: * buffer empty bit for the next time the program polls the register */
2061: ACIAStatusRegister |= ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY;
2062:
2063: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_IKBD_ACIA ) )
1.1.1.12 root 2064: {
1.1.1.13 root 2065: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1.1.1.12 root 2066: int nLineCycles = nFrameCycles % nCyclesPerLine;
1.1.1.13 root 2067: HATARI_TRACE_PRINT ( "ikbd read fffc00 ctrl=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
1.1.1.12 root 2068: IoMem[0xfffc00], nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
2069: }
1.1.1.10 root 2070: }
2071:
2072: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2073: /**
2074: * Handle read from keyboard data ACIA register (0xfffc02)
2075: */
1.1.1.10 root 2076: void IKBD_KeyboardData_ReadByte(void)
2077: {
1.1.1.11 root 2078: /* ACIA registers need wait states - but the value seems to vary in certain cases */
2079: M68000_WaitState(8);
2080:
1.1.1.13 root 2081: /* If IKBD is executing custom code, call the function to update the byte read in $fffc02 */
2082: if ( IKBD_ExeMode && pIKBD_CustomCodeHandler_Read )
2083: {
2084: (*pIKBD_CustomCodeHandler_Read) ();
2085: }
2086:
2087:
1.1.1.10 root 2088: IoMem[0xfffc02] = IKBD_GetByteFromACIA(); /* Return our byte from keyboard processor */
1.1.1.12 root 2089:
1.1.1.13 root 2090: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_IKBD_ACIA ) )
1.1.1.12 root 2091: {
1.1.1.13 root 2092: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1.1.1.12 root 2093: int nLineCycles = nFrameCycles % nCyclesPerLine;
1.1.1.13 root 2094: HATARI_TRACE_PRINT ( "ikbd read fffc02 data=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
1.1.1.12 root 2095: IoMem[0xfffc02], nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
2096: }
1.1.1.10 root 2097: }
2098:
2099:
2100: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2101: /**
2102: * Handle write to keyboard control ACIA register (0xfffc00)
2103: */
1.1.1.10 root 2104: void IKBD_KeyboardControl_WriteByte(void)
2105: {
1.1.1.11 root 2106: /* ACIA registers need wait states - but the value seems to vary in certain cases */
2107: M68000_WaitState(8);
2108:
1.1.1.13 root 2109: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_IKBD_ACIA ) )
1.1.1.12 root 2110: {
1.1.1.13 root 2111: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1.1.1.12 root 2112: int nLineCycles = nFrameCycles % nCyclesPerLine;
1.1.1.13 root 2113: HATARI_TRACE_PRINT ( "ikbd write fffc00 ctrl=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
1.1.1.12 root 2114: IoMem[0xfffc00], nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
2115: }
2116:
2117: /* [NP] We only handle reset of the ACIA */
2118: if ( ( IoMem[0xfffc00] & 0x03 ) == 0x03 )
2119: ACIA_Reset();
2120:
1.1.1.10 root 2121: /* Nothing... */
2122: }
2123:
2124: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2125: /**
2126: * Handle write to keyboard data ACIA register (0xfffc02)
2127: */
1.1.1.10 root 2128: void IKBD_KeyboardData_WriteByte(void)
2129: {
1.1.1.11 root 2130: /* ACIA registers need wait states - but the value seems to vary in certain cases */
2131: M68000_WaitState(8);
2132:
1.1.1.13 root 2133: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_IKBD_ACIA ) )
1.1.1.12 root 2134: {
1.1.1.13 root 2135: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1.1.1.12 root 2136: int nLineCycles = nFrameCycles % nCyclesPerLine;
1.1.1.13 root 2137: HATARI_TRACE_PRINT ( "ikbd write fffc02 data=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
1.1.1.12 root 2138: IoMem[0xfffc02], nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
2139: }
2140:
1.1.1.10 root 2141: IKBD_SendByteToKeyboardProcessor(IoMem[0xfffc02]); /* Pass our byte to the keyboard processor */
1.1.1.13 root 2142:
2143: /* Some games like USS John Young / FOF54 actually check whether the
2144: * transmit-buffer-empty bit is really cleared after writing a data
2145: * byte to the IKBD, so we have to temporarily clear this bit, too,
2146: * although the byte is send immediately to our virtual IKBD. */
2147: ACIAStatusRegister &= ~ACIA_STATUS_REGISTER__TX_BUFFER_EMPTY;
1.1.1.10 root 2148: }
1.1.1.13 root 2149:
2150:
2151: /*************************************************************************/
2152: /**
2153: * Below part is for emulating custom 6301 program sent to the ikbd RAM
2154: * Specific read/write functions for each demo/game should be added here,
2155: * after being defined in the CustomCodeDefinitions[] array.
2156: *
2157: * The 6301 has 256 bytes of RAM, but only 128 bytes are available to
2158: * put a program (from $80 to $ff).
2159: *
2160: * Executing a program in the 6301 is a 2 steps process :
2161: * 1) a very small program is sent to the RAM using the 0x20 command.
2162: * This is often loaded at address $b0.
2163: * This program will stop interruptions in the 6301 and will accept
2164: * a second small program that will relocate itself to $80.
2165: * 2) the relocated program at address $80 will accept a third (main)
2166: * program and will execute it once reception is complete.
2167: *
2168: * Writes during step 1 are handled with the ExeBootHandler matching the
2169: * LoadMemory CRC.
2170: * ExeBootHandler will compute a 2nd CRC for the writes corresponding to
2171: * the 2nd and 3rd programs sent to the 6301's RAM.
2172: *
2173: * If a match is found for this 2nd CRC, we will override default ikbd's behaviour
2174: * for reading/writing to $fffc02 with ExeMainHandler_Read / ExeMainHandler_Write
2175: * (once the Execute command 0x22 is received).
2176: *
2177: * When using custom program (ExeMode==TRUE), we must ignore all keyboard/mouse/joystick
2178: * events sent to IKBD_AddKeyToKeyboardBuffer. Only our functions can add bytes
2179: * to the keyboard buffer.
2180: *
2181: * To exit 6301's execution mode, we can use the 68000 'reset' instruction.
2182: * Some 6301's programs also handle a write to $fffc02 as an exit signal.
2183: */
2184:
2185:
2186: /*-----------------------------------------------------------------------*/
2187: /**
2188: * Handle writes to $fffc02 when loading bytes in the ikbd RAM.
2189: * We compute a CRC of the bytes that are sent until MemoryLoadNbBytesLeft
2190: * reaches 0.
2191: * When all bytes are loaded, we look for a matching CRC ; if found, we
2192: * use the ExeBootHandler defined for this CRC to process the next writes
2193: * that will occur in $fffc02.
2194: * LoadMemory is often used to load a small boot code into the 6301's RAM.
2195: * This small program will be executed later using the command 0x22.
2196: */
2197:
2198: static void IKBD_LoadMemoryByte ( Uint8 aciabyte )
2199: {
2200: unsigned int i;
2201:
2202: crc32_add_byte ( &MemoryLoadCrc , aciabyte );
2203:
2204: MemoryLoadNbBytesLeft--;
2205: if ( MemoryLoadNbBytesLeft == 0 ) /* all bytes were received */
2206: {
2207: /* Search for a match amongst the known custom routines */
2208: for ( i = 0 ; i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ; i++ )
2209: if ( CustomCodeDefinitions[ i ].LoadMemCrc == MemoryLoadCrc )
2210: break;
2211:
2212: if ( i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ) /* found */
2213: {
2214: HATARI_TRACE ( HATARI_TRACE_IKBD_EXEC, "ikbd loadmemory %d bytes crc=0x%x matches <%s>\n" ,
2215: MemoryLoadNbBytesTotal , MemoryLoadCrc , CustomCodeDefinitions[ i ].Name );
2216:
2217: crc32_reset ( &MemoryLoadCrc );
2218: MemoryExeNbBytes = 0;
2219: pIKBD_CustomCodeHandler_Read = NULL;
2220: pIKBD_CustomCodeHandler_Write = CustomCodeDefinitions[ i ].ExeBootHandler;
2221: }
2222:
2223: else /* unknown code uploaded to ikbd RAM */
2224: {
2225: HATARI_TRACE ( HATARI_TRACE_IKBD_EXEC, "ikbd loadmemory %d bytes crc=0x%x : unknown code\n" ,
2226: MemoryLoadNbBytesTotal , MemoryLoadCrc );
2227:
2228: pIKBD_CustomCodeHandler_Read = NULL;
2229: pIKBD_CustomCodeHandler_Write = NULL;
2230: }
2231: }
2232: }
2233:
2234:
2235:
2236: /*-----------------------------------------------------------------------*/
2237: /**
2238: * Handle writes to $fffc02 when executing custom code in the ikbd RAM.
2239: * This is used to send the small ikdb program that will handle keyboard/mouse/joystick
2240: * input.
2241: * We compute a CRC of the bytes that are sent until we found a match
2242: * with a known custom ikbd program.
2243: */
2244:
2245: static void IKBD_CustomCodeHandler_CommonBoot ( Uint8 aciabyte )
2246: {
2247: unsigned int i;
2248:
2249: crc32_add_byte ( &MemoryLoadCrc , aciabyte );
2250: MemoryExeNbBytes++;
2251:
2252: HATARI_TRACE ( HATARI_TRACE_IKBD_EXEC, "ikbd custom exe common boot write 0x%02x count %d crc=0x%x\n" ,
2253: aciabyte , MemoryExeNbBytes , MemoryLoadCrc );
2254:
2255: /* Search for a match amongst the known custom routines */
2256: for ( i = 0 ; i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ; i++ )
2257: if ( ( CustomCodeDefinitions[ i ].MainProgNbBytes == MemoryExeNbBytes )
2258: && ( CustomCodeDefinitions[ i ].MainProgCrc == MemoryLoadCrc ) )
2259: break;
2260:
2261: if ( i < sizeof ( CustomCodeDefinitions ) / sizeof ( CustomCodeDefinitions[0] ) ) /* found */
2262: {
2263: HATARI_TRACE ( HATARI_TRACE_IKBD_EXEC, "ikbd custom exe common boot, uploaded code matches <%s>\n" ,
2264: CustomCodeDefinitions[ i ].Name );
2265:
2266: pIKBD_CustomCodeHandler_Read = CustomCodeDefinitions[ i ].ExeMainHandler_Read;
2267: pIKBD_CustomCodeHandler_Write = CustomCodeDefinitions[ i ].ExeMainHandler_Write;
2268:
2269: Keyboard.BufferHead = Keyboard.BufferTail = 0; /* flush all queued bytes that would be read in $fffc02 */
2270: (*pIKBD_CustomCodeHandler_Read) (); /* initialize ACIAByte */
2271: }
2272:
2273: /* If not found, we keep on accumulating bytes until we find a matching crc */
2274: }
2275:
2276:
2277:
2278: /*----------------------------------------------------------------------*/
2279: /* Froggies Over The Fence menu. */
2280: /* Returns 2 bytes with the mouse position, keyboard can be used too. */
2281: /* Writing 0xff to $fffc02 will cause the 6301 to exit custom exe mode. */
2282: /*----------------------------------------------------------------------*/
2283:
2284: static void IKBD_CustomCodeHandler_FroggiesMenu_Read ( void )
2285: {
2286: Uint8 res1 = 0;
2287: Uint8 res2 = 0;
2288:
2289: if ( KeyboardProcessor.Mouse.DeltaX < 0 ) res1 = 0x7a; /* mouse left */
2290: if ( KeyboardProcessor.Mouse.DeltaX > 0 ) res1 = 0x06; /* mouse right */
2291: if ( KeyboardProcessor.Mouse.DeltaY < 0 ) res2 = 0x7a; /* mouse up */
2292: if ( KeyboardProcessor.Mouse.DeltaY > 0 ) res2 = 0x06; /* mouse down */
2293: if ( Keyboard.bLButtonDown & BUTTON_MOUSE ) res1 |= 0x80; /* left mouse button */
2294:
2295: if ( ScanCodeState[ 0x4b ] ) res1 |= 0x7a; /* left */
2296: if ( ScanCodeState[ 0x4d ] ) res1 |= 0x06; /* right */
2297: if ( ScanCodeState[ 0x48 ] ) res2 |= 0x7a; /* up */
2298: if ( ScanCodeState[ 0x50 ] ) res2 |= 0x06; /* down */
2299: if ( ScanCodeState[ 0x70 ] ) res1 |= 0x80; /* keypad 0 */
2300:
2301: IKBD_AddKeyToKeyboardBuffer_Real(res1, ACIA_CYCLES);
2302: IKBD_AddKeyToKeyboardBuffer_Real(res2, ACIA_CYCLES);
2303: }
2304:
2305: static void IKBD_CustomCodeHandler_FroggiesMenu_Write ( Uint8 aciabyte )
2306: {
2307: /* When writing 0xff to $fffc02, Froggies ikbd's program will terminate itself */
2308: /* and leave Execution mode */
2309: if ( aciabyte == 0xff )
2310: IKBD_Reset_ExeMode ();
2311: }
2312:
2313:
2314:
2315: /*----------------------------------------------------------------------*/
2316: /* Transbeauce II menu. */
2317: /* Returns 1 byte with the joystick position, keyboard can be used too. */
2318: /*----------------------------------------------------------------------*/
2319:
2320: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Read ( void )
2321: {
2322: Uint8 res = 0;
2323:
2324: /* keyboard emulation */
2325: if ( ScanCodeState[ 0x48 ] ) res |= 0x01; /* up */
2326: if ( ScanCodeState[ 0x50 ] ) res |= 0x02; /* down */
2327: if ( ScanCodeState[ 0x4b ] ) res |= 0x04; /* left */
2328: if ( ScanCodeState[ 0x4d ] ) res |= 0x08; /* right */
2329: if ( ScanCodeState[ 0x62 ] ) res |= 0x40; /* help */
2330: if ( ScanCodeState[ 0x39 ] ) res |= 0x80; /* space */
2331:
2332: /* joystick emulation (bit mapping is same as cursor above, with bit 7 = fire button */
2333: res |= ( Joy_GetStickData(1) & 0x8f ) ; /* keep bits 0-3 and 7 */
2334:
2335: IKBD_AddKeyToKeyboardBuffer_Real(res, ACIA_CYCLES);
2336: }
2337:
2338: static void IKBD_CustomCodeHandler_Transbeauce2Menu_Write ( Uint8 aciabyte )
2339: {
2340: /* Ignore write */
2341: }
2342:
2343:
2344:
2345: /*----------------------------------------------------------------------*/
2346: /* Dragonnels demo menu. */
2347: /* Returns 1 byte with the Y position of the mouse. */
2348: /*----------------------------------------------------------------------*/
2349:
2350: static void IKBD_CustomCodeHandler_DragonnelsMenu_Read ( void )
2351: {
2352: Uint8 res = 0;
2353:
2354: if ( KeyboardProcessor.Mouse.DeltaY < 0 ) res = 0xfc; /* mouse up */
2355: if ( KeyboardProcessor.Mouse.DeltaY > 0 ) res = 0x04; /* mouse down */
2356:
2357: if ( Keyboard.bLButtonDown & BUTTON_MOUSE ) res = 0x80; /* left mouse button */
2358:
2359: IKBD_AddKeyToKeyboardBuffer_Real(res, ACIA_CYCLES);
2360: }
2361:
2362: static void IKBD_CustomCodeHandler_DragonnelsMenu_Write ( Uint8 aciabyte )
2363: {
2364: /* Ignore write */
2365: }
2366:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.