2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
9 #include <proto/exec.h>
10 #include <proto/timer.h>
11 #include <proto/graphics.h>
13 #include <exec/lists.h>
14 #include <exec/interrupts.h>
15 #include <exec/alerts.h>
16 #include <exec/memory.h>
17 #include <devices/inputevent.h>
18 #include <devices/input.h>
19 #include <devices/timer.h>
20 #include <devices/keyboard.h>
21 #include <devices/gameport.h>
22 #include <intuition/intuition.h>
23 #include <aros/asmcall.h>
25 #include "input_intern.h"
27 #define SEND_INPUT_REQUEST(io, ie, cmd) \
28 io->io_Command = cmd; \
29 io->io_Data = (APTR)ie; \
30 io->io_Length = sizeof (struct InputEvent); \
31 SendIO((struct IORequest *)io)
34 #define SEND_KBD_REQUEST(kbdio, kbdie) SEND_INPUT_REQUEST(kbdio, kbdie, KBD_READEVENT)
35 #define SEND_GPD_REQUEST(gpdio, gpdie) SEND_INPUT_REQUEST(gpdio, gpdie, GPD_READEVENT)
37 #define SEND_TIMER_REQUEST(timerio) \
38 timerio->tr_node.io_Command = TR_ADDREQUEST; \
39 timerio->tr_time.tv_secs = 0; \
40 timerio->tr_time.tv_micro = 100000; \
41 SendIO((struct IORequest *)timerio)
43 #define SEND_KEYTIMER_REQUEST(timerio,time) \
44 timerio->tr_node.io_Command = TR_ADDREQUEST; \
45 timerio->tr_time = time; \
46 SendIO((struct IORequest *)timerio)
48 #define ABORT_KEYTIMER_REQUEST \
49 if (!CheckIO(&keytimerio->tr_node)) AbortIO(&keytimerio->tr_node); \
50 WaitIO(&keytimerio->tr_node); \
51 SetSignal(0, keytimersig);
53 #define KEY_QUALIFIERS (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT | \
54 IEQUALIFIER_CAPSLOCK | IEQUALIFIER_CONTROL | \
55 IEQUALIFIER_RALT | IEQUALIFIER_LALT | \
56 IEQUALIFIER_RCOMMAND | IEQUALIFIER_RCOMMAND | \
57 IEQUALIFIER_NUMERICPAD /* | IEQUALIFIER_REPEAT */)
59 #define MOUSE_QUALIFIERS (IEQUALIFIER_LEFTBUTTON | IEQUALIFIER_RBUTTON | \
60 IEQUALIFIER_MIDBUTTON)
64 #include <aros/debug.h>
66 AROS_INTH1(ResetHandler
, struct inputbase
*, InputDevice
)
70 if (InputDevice
->ResetSig
)
72 Signal(InputDevice
->InputTask
, InputDevice
->ResetSig
);
80 /**********************
82 **********************/
85 extern APTR
is_Code_Wrapper(void);
87 ".global is_Code_Wrapper\n"
89 "movem.l %d2-%d4/%a2,%sp@-\n"
91 "movem.l %sp@+,%d2-%d4/%a2\n"
96 /* Forwards a chain of events to the inputhandlers */
97 VOID
ForwardQueuedEvents(struct inputbase
*InputDevice
)
99 struct InputEvent
*ie_chain
;
100 struct Interrupt
*ihiterator
;
102 ie_chain
= GetEventsFromQueue(InputDevice
);
105 ForeachNode(&(InputDevice
->HandlerList
), ihiterator
)
107 D(bug("ipe: calling inputhandler %s at %p\n",
108 ihiterator
->is_Node
.ln_Name
, ihiterator
->is_Code
));
111 /* There are many m68k applications that expect to be able
112 * to clobber a number of registers in their code.
114 * We need the wrapper to save/restore those registers.
116 ie_chain
= AROS_UFC3(struct InputEvent
*, is_Code_Wrapper
,
117 AROS_UFCA(struct InputEvent
*, ie_chain
, A0
),
118 AROS_UFCA(APTR
, ihiterator
->is_Data
, A1
),
119 AROS_UFCA(APTR
, ihiterator
->is_Code
, A2
))
121 ie_chain
= AROS_UFC2(struct InputEvent
*, ihiterator
->is_Code
,
122 AROS_UFCA(struct InputEvent
*, ie_chain
, A0
),
123 AROS_UFCA(APTR
, ihiterator
->is_Data
, A1
));
125 D(bug("ipe: returned from inputhandler\n"));
127 } /* for each input handler */
135 /***********************************
136 ** Input device task entry point **
137 ***********************************/
138 void ProcessEvents (struct inputbase
*InputDevice
)
140 ULONG commandsig
, kbdsig
, wakeupsigs
;
141 ULONG gpdsig
, timersig
, keytimersig
;
142 struct MsgPort
*timermp
, *keytimermp
;
143 struct timerequest
*timerio
, *keytimerio
;
145 struct MsgPort
*kbdmp
, *gpdmp
;
146 struct IOStdReq
*kbdio
, *gpdio
;
147 struct InputEvent
*kbdie
, *gpdie
, keyrepeatie
;
148 struct Interrupt resethandler
;
149 struct Library
*TimerBase
;
151 struct GamePortTrigger mouseTrigger
=
153 GPTF_DOWNKEYS
| GPTF_UPKEYS
,
154 9999, /* We dont really care about time triggers */
155 0, /* Report any mouse change */
159 BYTE controllerType
= GPCT_MOUSE
;
160 BYTE keyrepeat_state
= 0;
162 /************** Open timer.device *******************/
164 timermp
= CreateMsgPort();
165 keytimermp
= CreateMsgPort();
167 if (!timermp
|| !keytimermp
)
168 Alert(AT_DeadEnd
| AG_NoMemory
| AN_Unknown
);
170 timerio
= (struct timerequest
*)CreateIORequest(timermp
, sizeof(struct timerequest
));
171 keytimerio
= (struct timerequest
*)CreateIORequest(keytimermp
, sizeof(struct timerequest
));
172 if (!timerio
|| !keytimerio
)
173 Alert(AT_DeadEnd
| AG_NoMemory
| AN_Unknown
);
175 if ( 0 != OpenDevice(TIMERNAME
, UNIT_VBLANK
, (struct IORequest
*)timerio
, 0))
176 Alert(AT_DeadEnd
| AG_OpenDev
| AN_Unknown
);
178 TimerBase
= (struct Library
*)timerio
->tr_node
.io_Device
;
180 *keytimerio
= *timerio
;
181 keytimerio
->tr_node
.io_Message
.mn_ReplyPort
= keytimermp
;
183 /************** Open keyboard.device *******************/
184 kbdmp
= CreateMsgPort();
186 Alert(AT_DeadEnd
| AG_NoMemory
| AN_Unknown
);
188 kbdio
= (struct IOStdReq
*)CreateIORequest(kbdmp
, sizeof(struct IOStdReq
));
190 Alert(AT_DeadEnd
| AG_NoMemory
| AN_Unknown
);
192 if ( 0 != OpenDevice("keyboard.device", 0, (struct IORequest
*)kbdio
, 0))
193 Alert(AT_DeadEnd
| AG_OpenDev
| AN_Unknown
);
195 /* Install RESET Handler */
197 InputDevice
->ResetSig
= 1L << AllocSignal(-1);
199 resethandler
.is_Node
.ln_Name
= "input.device reset handler";
200 resethandler
.is_Node
.ln_Type
= NT_INTERRUPT
;
201 resethandler
.is_Node
.ln_Pri
= -128;
203 resethandler
.is_Code
= (VOID_FUNC
)ResetHandler
;
204 resethandler
.is_Data
= InputDevice
;
206 kbdio
->io_Command
= KBD_ADDRESETHANDLER
;
207 kbdio
->io_Data
= &resethandler
;
208 DoIO((struct IORequest
*)kbdio
);
210 kbdie
= AllocMem(sizeof (struct InputEvent
), MEMF_PUBLIC
| MEMF_CLEAR
);
212 Alert(AT_DeadEnd
| AG_NoMemory
| AN_Unknown
);
215 /************** Open gameport.device *******************/
216 gpdmp
= CreateMsgPort();
218 Alert(AT_DeadEnd
| AG_NoMemory
| AN_Unknown
);
220 gpdio
= (struct IOStdReq
*)CreateIORequest(gpdmp
, sizeof(struct IOStdReq
));
222 Alert(AT_DeadEnd
| AG_NoMemory
| AN_Unknown
);
224 if ( 0 != OpenDevice("gameport.device", 0, (struct IORequest
*)gpdio
, 0))
225 Alert(AT_DeadEnd
| AG_OpenDev
| AN_Unknown
);
227 /* Set the controller type */
228 gpdio
->io_Command
= GPD_SETCTYPE
;
229 gpdio
->io_Data
= (APTR
)&controllerType
;
230 gpdio
->io_Length
= sizeof(BYTE
);
231 DoIO((struct IORequest
*)gpdio
);
233 /* Set the gameport trigger */
234 gpdio
->io_Command
= GPD_SETTRIGGER
;
235 gpdio
->io_Data
= &mouseTrigger
;
236 gpdio
->io_Length
= sizeof(struct GamePortTrigger
);
237 DoIO((struct IORequest
*)gpdio
);
239 gpdie
= AllocMem(sizeof (struct InputEvent
), MEMF_PUBLIC
| MEMF_CLEAR
);
241 Alert(AT_DeadEnd
| AG_NoMemory
| AN_Unknown
);
244 /* Send an initial request to the keyboard device */
245 SEND_KBD_REQUEST(kbdio
, kbdie
);
247 /* .. and to the gameport.device */
248 SEND_GPD_REQUEST(gpdio
, gpdie
);
250 /* .. and to the timer device */
251 SEND_TIMER_REQUEST(timerio
);
253 commandsig
= 1 << InputDevice
->CommandPort
->mp_SigBit
;
255 kbdsig
= 1 << kbdmp
->mp_SigBit
;
256 gpdsig
= 1 << gpdmp
->mp_SigBit
;
257 timersig
= 1 << timermp
->mp_SigBit
;
258 keytimersig
= 1 << keytimermp
->mp_SigBit
;
262 wakeupsigs
= Wait (commandsig
|
267 InputDevice
->ResetSig
);
269 D(bug("Wakeup sig: %x, cmdsig: %x, kbdsig: %x\n, timersig: %x"
270 , wakeupsigs
, commandsig
, kbdsig
, timersig
));
272 if (wakeupsigs
& timersig
)
274 struct InputEvent timer_ie
;
278 timer_ie
.ie_NextEvent
= NULL
;
279 timer_ie
.ie_Class
= IECLASS_TIMER
;
280 timer_ie
.ie_SubClass
= 0;
281 timer_ie
.ie_Code
= 0;
282 timer_ie
.ie_Qualifier
= InputDevice
->ActQualifier
;
283 timer_ie
.ie_position
.ie_addr
= 0;
285 /* Add a timestamp to the event */
286 GetSysTime( &(timer_ie
.ie_TimeStamp
));
288 AddEQTail(&timer_ie
, InputDevice
);
289 ForwardQueuedEvents(InputDevice
);
291 SEND_TIMER_REQUEST(timerio
);
294 if (wakeupsigs
& commandsig
)
296 struct IOStdReq
*ioreq
;
298 /* Get all commands from the port */
299 while ((ioreq
= (struct IOStdReq
*)GetMsg(InputDevice
->CommandPort
)))
302 switch (ioreq
->io_Command
)
306 /* Older m68k programs copied input handler code without
307 * flushing caches, causing crashes on 68040/060.
311 Enqueue((struct List
*)&(InputDevice
->HandlerList
),
312 (struct Node
*)ioreq
->io_Data
);
316 Remove((struct Node
*)ioreq
->io_Data
);
327 * IND_ADDEVENT command allows client to send multiple RAWKEY or RAWMOUSE
328 * events to the input.device. All other classes will be ignored.
330 struct InputEvent
*ie
= (struct InputEvent
*)ioreq
->io_Data
;
331 ULONG ie_cnt
= ioreq
->io_Length
/ sizeof(struct InputEvent
);
333 D(bug("[input.device] ie_cnt=%d, ie=%d\n", ie_cnt
, ie
));
335 /* Update the current qualifier */
336 InputDevice
->ActQualifier
= ie
->ie_Qualifier
;
338 /* For each event... */
339 for (; ie_cnt
; ie_cnt
--, ie
++)
341 D(bug("[input.device] ie_Class=%02x ie_Code=%04x ie_Qualifier=%04x\n",
342 ie
->ie_Class
, ie
->ie_Code
, ie
->ie_Qualifier
));
344 /* Of class RAWMOUSE or RAWKEY... */
345 if (ie
->ie_Class
== IECLASS_RAWMOUSE
|| ie
->ie_Class
== IECLASS_RAWKEY
)
347 ie
->ie_NextEvent
= NULL
;
349 if (ie
->ie_Class
== IECLASS_RAWKEY
)
351 if (!IsQualifierKey(ie
->ie_Code
))
353 if (keyrepeat_state
> 0)
355 ABORT_KEYTIMER_REQUEST
;
359 if (!(ie
->ie_Code
& IECODE_UP_PREFIX
))
361 if (IsRepeatableKey(ie
->ie_Code
))
365 SEND_KEYTIMER_REQUEST(keytimerio
, InputDevice
->KeyRepeatThreshold
);
370 } /* if (!IsQualifierKey(ie->ie_Code)) */
373 /* If the event's qualifier differs from the current one, fire the events */
374 if (InputDevice
->ActQualifier
== ie
->ie_Qualifier
) {
375 UWORD q
= ie
->ie_Qualifier
;
376 ForwardQueuedEvents(InputDevice
);
378 /* And set new qualifier */
379 InputDevice
->ActQualifier
= q
;
382 /* Set the timestamp */
383 GetSysTime( &(ie
->ie_TimeStamp
));
386 AddEQTail(ie
, InputDevice
);
389 /* In case some events are still in the queue, fire them all up */
390 ForwardQueuedEvents(InputDevice
);
393 case IND_WRITEEVENT
: {
394 struct InputEvent
*ie
;
396 ie
= (struct InputEvent
*)ioreq
->io_Data
;
398 ie
->ie_NextEvent
= NULL
;
399 /* Add a timestamp to the event */
400 GetSysTime( &(ie
->ie_TimeStamp
));
402 D(bug("id: %d\n", ie
->ie_Class
));
404 /* Add event to queue */
405 AddEQTail((struct InputEvent
*)ioreq
->io_Data
,
408 /* Forward event (and possible others in the queue) */
409 ForwardQueuedEvents(InputDevice
);
413 InputDevice
->KeyRepeatThreshold
= ((struct timerequest
*)ioreq
)->tr_time
;
417 InputDevice
->KeyRepeatInterval
= ((struct timerequest
*)ioreq
)->tr_time
;
420 } /* switch (IO command) */
422 ReplyMsg((struct Message
*)ioreq
);
424 } /* while (messages in the command port) */
426 } /* if (IO command received) */
428 if (wakeupsigs
& keytimersig
)
430 struct InputEvent ie
;
436 ie
= keyrepeatie
; /* InputHandlers can change inputevents, so send a clone!! */
437 ie
.ie_NextEvent
= NULL
; /* !! */
438 ie
.ie_Qualifier
|= IEQUALIFIER_REPEAT
;
439 GetSysTime(&ie
.ie_TimeStamp
);
441 AddEQTail(&ie
, InputDevice
);
443 /* Forward event (and possible others in the queue) */
444 ForwardQueuedEvents(InputDevice
);
446 SEND_KEYTIMER_REQUEST(keytimerio
, InputDevice
->KeyRepeatInterval
);
448 } /* if (wakeupsigs & keytimersig) */
450 if (wakeupsigs
& kbdsig
)
452 GetMsg(kbdmp
); /* Only one message */
453 if (kbdio
->io_Error
!= 0)
456 InputDevice
->ActQualifier
&= ~KEY_QUALIFIERS
;
457 InputDevice
->ActQualifier
|= (kbdie
->ie_Qualifier
& KEY_QUALIFIERS
);
459 kbdie
->ie_Qualifier
&= ~MOUSE_QUALIFIERS
;
460 kbdie
->ie_Qualifier
|= (InputDevice
->ActQualifier
& MOUSE_QUALIFIERS
);
462 /* Add event to queue */
463 AddEQTail(kbdie
, InputDevice
);
465 if (!IsQualifierKey(kbdie
->ie_Code
))
467 if (keyrepeat_state
> 0)
469 ABORT_KEYTIMER_REQUEST
;
473 if (!(kbdie
->ie_Code
& IECODE_UP_PREFIX
))
475 if (IsRepeatableKey(kbdie
->ie_Code
))
477 keyrepeatie
= *kbdie
;
479 SEND_KEYTIMER_REQUEST(keytimerio
, InputDevice
->KeyRepeatThreshold
);
484 } /* if (!IsQualifierKey(kbdie->ie_Code)) */
486 /* New event from keyboard device */
487 D(bug("id: Keyboard event\n"));
488 D(bug("id: Events forwarded\n"));
490 /* Forward event (and possible others in the queue) */
491 ForwardQueuedEvents(InputDevice
);
492 D(bug("id: Events forwarded\n"));
494 /* Wit for some more events */
495 SEND_KBD_REQUEST(kbdio
, kbdie
);
497 } /* if (wakeupsigs & kbdsig) */
499 if (wakeupsigs
& gpdsig
)
501 GetMsg(gpdmp
); /* Only one message */
502 if (gpdio
->io_Error
!= 0)
505 InputDevice
->ActQualifier
&= ~MOUSE_QUALIFIERS
;
506 InputDevice
->ActQualifier
|= (gpdie
->ie_Qualifier
& MOUSE_QUALIFIERS
);
508 gpdie
->ie_Qualifier
&= ~KEY_QUALIFIERS
;
509 gpdie
->ie_Qualifier
|= (InputDevice
->ActQualifier
& KEY_QUALIFIERS
);
511 /* Gameport just returns the frame count since the last
512 report in ie_TimeStamp.tv_secs; we therefore must add
513 a real timestamp ourselves */
514 GetSysTime(&gpdie
->ie_TimeStamp
);
516 /* Wheel events come in as IECLASS_NEWMOUSE, so fix ie_Class and ie_Qualifier) */
517 if (gpdie
->ie_Class
== IECLASS_NEWMOUSE
)
519 /* The NewMouse standard seems to send both a IECLASS_NEWMOUSE and a IECLASS_RAWKEY event */
520 gpdie
->ie_Class
= IECLASS_RAWKEY
;
521 gpdie
->ie_Qualifier
= InputDevice
->ActQualifier
& KEY_QUALIFIERS
;
524 /* Add event to queue */
525 AddEQTail(gpdie
, InputDevice
);
527 /* New event from gameport device */
528 D(bug("id: Gameport event\n"));
529 D(bug("id: Forwarding events\n"));
531 /* Forward event (and possible others in the queue) */
532 ForwardQueuedEvents(InputDevice
);
533 D(bug("id: Events forwarded\n"));
535 /* Wit for some more events */
536 SEND_GPD_REQUEST(gpdio
, gpdie
);
538 } /* if (wakeupsigs & gpdsig) */
540 if (wakeupsigs
& InputDevice
->ResetSig
)
542 struct IOStdReq resetio
= *kbdio
;
543 struct Library
*GfxBase
= TaggedOpenLibrary(TAGGEDOPEN_GRAPHICS
);
545 InputDevice
->ResetSig
= 0;
547 /* Blank screen(s) in order to indicate upcoming machine reset */
548 /* Don't blank on m68k because we have programs that shows status information while waiting for reset. */
553 CloseLibrary(GfxBase
);
556 resetio
.io_Command
= KBD_RESETHANDLERDONE
;
557 resetio
.io_Data
= &resethandler
;
559 /* Relying on this cmd being done quick, here */
561 DoIO((struct IORequest
*)&resetio
);
567 } /* ProcessEvents */