Minor fixes to comments.
[AROS.git] / rom / devs / input / processevents.c
bloba0468fbbfe53e99c7dbc71cb661d7075e911627f
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: english
7 */
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)
63 #define DEBUG 0
64 #include <aros/debug.h>
66 AROS_INTH1(ResetHandler, struct inputbase *, InputDevice)
68 AROS_INTFUNC_INIT
70 if (InputDevice->ResetSig)
72 Signal(InputDevice->InputTask, InputDevice->ResetSig);
75 return FALSE;
77 AROS_INTFUNC_EXIT
80 /**********************
81 ** ForwardEvents() **
82 **********************/
84 #ifdef __mc68000
85 extern APTR is_Code_Wrapper(void);
86 asm (
87 ".global is_Code_Wrapper\n"
88 "is_Code_Wrapper:\n"
89 "movem.l %d2-%d4/%a2,%sp@-\n"
90 "jsr (%a2)\n"
91 "movem.l %sp@+,%d2-%d4/%a2\n"
92 "rts\n"
94 #endif
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);
103 if (ie_chain)
105 ForeachNode(&(InputDevice->HandlerList), ihiterator)
107 D(bug("ipe: calling inputhandler %s at %p\n",
108 ihiterator->is_Node.ln_Name, ihiterator->is_Code));
110 #ifdef __mc68000
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))
120 #else
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));
124 #endif
125 D(bug("ipe: returned from inputhandler\n"));
127 } /* for each input handler */
131 return;
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();
185 if (!kbdmp)
186 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
188 kbdio = (struct IOStdReq *)CreateIORequest(kbdmp, sizeof(struct IOStdReq));
189 if (!kbdio)
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);
211 if (!kbdie)
212 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
215 /************** Open gameport.device *******************/
216 gpdmp = CreateMsgPort();
217 if (!gpdmp)
218 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
220 gpdio = (struct IOStdReq *)CreateIORequest(gpdmp, sizeof(struct IOStdReq));
221 if (!gpdio)
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);
240 if (!gpdie)
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;
260 for (;;)
262 wakeupsigs = Wait (commandsig |
263 kbdsig |
264 gpdsig |
265 timersig |
266 keytimersig |
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;
276 GetMsg(timermp);
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)
304 case IND_ADDHANDLER:
305 #ifdef __mc68000
306 /* Older m68k programs copied input handler code without
307 * flushing caches, causing crashes on 68040/060.
309 CacheClearU();
310 #endif
311 Enqueue((struct List *)&(InputDevice->HandlerList),
312 (struct Node *)ioreq->io_Data);
313 break;
315 case IND_REMHANDLER:
316 Remove((struct Node *)ioreq->io_Data);
317 break;
319 case IND_SETMTRIG:
320 break;
322 case IND_SETMTYPE:
323 break;
325 case IND_ADDEVENT: {
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;
356 keyrepeat_state = 0;
359 if (!(ie->ie_Code & IECODE_UP_PREFIX))
361 if (IsRepeatableKey(ie->ie_Code))
363 keyrepeatie = *ie;
365 SEND_KEYTIMER_REQUEST(keytimerio, InputDevice->KeyRepeatThreshold);
366 keyrepeat_state = 1;
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 ));
385 /* and enqueue */
386 AddEQTail(ie, InputDevice);
389 /* In case some events are still in the queue, fire them all up */
390 ForwardQueuedEvents(InputDevice);
391 } break;
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,
406 InputDevice);
408 /* Forward event (and possible others in the queue) */
409 ForwardQueuedEvents(InputDevice);
410 } break;
412 case IND_SETTHRESH:
413 InputDevice->KeyRepeatThreshold = ((struct timerequest *)ioreq)->tr_time;
414 break;
416 case IND_SETPERIOD:
417 InputDevice->KeyRepeatInterval = ((struct timerequest *)ioreq)->tr_time;
418 break;
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;
432 GetMsg(keytimermp);
434 keyrepeat_state = 2;
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)
454 continue;
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;
470 keyrepeat_state = 0;
473 if (!(kbdie->ie_Code & IECODE_UP_PREFIX))
475 if (IsRepeatableKey(kbdie->ie_Code))
477 keyrepeatie = *kbdie;
479 SEND_KEYTIMER_REQUEST(keytimerio, InputDevice->KeyRepeatThreshold);
480 keyrepeat_state = 1;
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)
503 continue;
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. */
549 if (GfxBase) {
550 #ifndef __mc68000
551 LoadView(NULL);
552 #endif
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);
565 } /* Forever */
567 } /* ProcessEvents */