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