Indentation fix, cleanup.
[AROS.git] / rom / devs / input / processevents.c
blobc856fb19aafcc467033b53b6b46490f005abca7d
1 /*
2 Copyright © 1995-2014, 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) \
35 SEND_INPUT_REQUEST(kbdio, kbdie, KBD_READEVENT)
36 #define SEND_GPD_REQUEST(gpdio, gpdie) \
37 SEND_INPUT_REQUEST(gpdio, gpdie, GPD_READEVENT)
39 #define SEND_TIMER_REQUEST(timerio) \
40 timerio->tr_node.io_Command = TR_ADDREQUEST; \
41 timerio->tr_time.tv_secs = 0; \
42 timerio->tr_time.tv_micro = 100000; \
43 SendIO((struct IORequest *)timerio)
45 #define SEND_KEYTIMER_REQUEST(timerio,time) \
46 timerio->tr_node.io_Command = TR_ADDREQUEST; \
47 timerio->tr_time = time; \
48 SendIO((struct IORequest *)timerio)
50 #define ABORT_KEYTIMER_REQUEST \
51 if (!CheckIO(&keytimerio->tr_node)) AbortIO(&keytimerio->tr_node); \
52 WaitIO(&keytimerio->tr_node); \
53 SetSignal(0, keytimersig);
55 #define KEY_QUALIFIERS (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT | \
56 IEQUALIFIER_CAPSLOCK | IEQUALIFIER_CONTROL | \
57 IEQUALIFIER_RALT | IEQUALIFIER_LALT | \
58 IEQUALIFIER_RCOMMAND | IEQUALIFIER_RCOMMAND | \
59 IEQUALIFIER_NUMERICPAD /* | IEQUALIFIER_REPEAT */)
61 #define MOUSE_QUALIFIERS (IEQUALIFIER_LEFTBUTTON | IEQUALIFIER_RBUTTON | \
62 IEQUALIFIER_MIDBUTTON)
65 #define DEBUG 0
66 #include <aros/debug.h>
68 AROS_INTH1(ResetHandler, struct inputbase *, InputDevice)
70 AROS_INTFUNC_INIT
72 if (InputDevice->ResetSig)
74 Signal(InputDevice->InputTask, InputDevice->ResetSig);
77 return FALSE;
79 AROS_INTFUNC_EXIT
82 /**********************
83 ** ForwardEvents() **
84 **********************/
86 #ifdef __mc68000
87 extern APTR is_Code_Wrapper(void);
88 asm(".global is_Code_Wrapper\n"
89 "is_Code_Wrapper:\n"
90 "movem.l %d2-%d4/%a2,%sp@-\n"
91 "jsr (%a2)\n" "movem.l %sp@+,%d2-%d4/%a2\n" "rts\n");
92 #endif
94 /* Forwards a chain of events to the inputhandlers */
95 VOID ForwardQueuedEvents(struct inputbase *InputDevice)
97 struct InputEvent *ie_chain;
98 struct Interrupt *ihiterator;
100 ie_chain = GetEventsFromQueue(InputDevice);
101 if (ie_chain)
103 ForeachNode(&(InputDevice->HandlerList), ihiterator)
105 D(bug("ipe: calling inputhandler %s at %p\n",
106 ihiterator->is_Node.ln_Name, ihiterator->is_Code));
108 #ifdef __mc68000
109 /* There are many m68k applications that expect to be able
110 * to clobber a number of registers in their code.
112 * We need the wrapper to save/restore those registers.
114 ie_chain = AROS_UFC3(struct InputEvent *, is_Code_Wrapper,
115 AROS_UFCA(struct InputEvent *, ie_chain, A0),
116 AROS_UFCA(APTR, ihiterator->is_Data, A1),
117 AROS_UFCA(APTR, ihiterator->is_Code, A2))
118 #else
119 ie_chain = AROS_UFC2(struct InputEvent *, ihiterator->is_Code,
120 AROS_UFCA(struct InputEvent *, ie_chain, A0),
121 AROS_UFCA(APTR, ihiterator->is_Data, A1));
122 #endif
123 D(bug("ipe: returned from inputhandler\n"));
128 return;
132 /***********************************
133 ** Input device task entry point **
134 ***********************************/
135 void ProcessEvents(struct inputbase *InputDevice)
137 ULONG commandsig, kbdsig, wakeupsigs;
138 ULONG gpdsig, timersig, keytimersig;
139 struct MsgPort *timermp, *keytimermp;
140 struct timerequest *timerio, *keytimerio;
142 struct MsgPort *kbdmp, *gpdmp;
143 struct IOStdReq *kbdio, *gpdio;
144 struct InputEvent *kbdie, *gpdie, keyrepeatie;
145 struct Interrupt resethandler;
146 struct Library *TimerBase;
148 struct GamePortTrigger mouseTrigger = {
149 GPTF_DOWNKEYS | GPTF_UPKEYS,
150 9999, /* We don't really care about time triggers */
151 0, /* Report any mouse change */
155 BYTE controllerType = GPCT_MOUSE;
156 BYTE keyrepeat_state = 0;
158 /************** Open timer.device *******************/
160 timermp = CreateMsgPort();
161 keytimermp = CreateMsgPort();
163 if (!timermp || !keytimermp)
164 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
166 timerio =
167 (struct timerequest *)CreateIORequest(timermp,
168 sizeof(struct timerequest));
169 keytimerio =
170 (struct timerequest *)CreateIORequest(keytimermp,
171 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,
177 Alert(AT_DeadEnd | AG_OpenDev | AN_Unknown);
179 TimerBase = (struct Library *)timerio->tr_node.io_Device;
181 *keytimerio = *timerio;
182 keytimerio->tr_node.io_Message.mn_ReplyPort = keytimermp;
184 /************** Open keyboard.device *******************/
185 kbdmp = CreateMsgPort();
186 if (!kbdmp)
187 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
189 kbdio =
190 (struct IOStdReq *)CreateIORequest(kbdmp, sizeof(struct IOStdReq));
191 if (!kbdio)
192 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
194 if (0 != OpenDevice("keyboard.device", 0, (struct IORequest *)kbdio, 0))
195 Alert(AT_DeadEnd | AG_OpenDev | AN_Unknown);
197 /* Install RESET Handler */
199 InputDevice->ResetSig = 1L << AllocSignal(-1);
201 resethandler.is_Node.ln_Name = "input.device reset handler";
202 resethandler.is_Node.ln_Type = NT_INTERRUPT;
203 resethandler.is_Node.ln_Pri = -128;
205 resethandler.is_Code = (VOID_FUNC) ResetHandler;
206 resethandler.is_Data = InputDevice;
208 kbdio->io_Command = KBD_ADDRESETHANDLER;
209 kbdio->io_Data = &resethandler;
210 DoIO((struct IORequest *)kbdio);
212 kbdie = AllocMem(sizeof(struct InputEvent), MEMF_PUBLIC | MEMF_CLEAR);
213 if (!kbdie)
214 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
217 /************** Open gameport.device *******************/
218 gpdmp = CreateMsgPort();
219 if (!gpdmp)
220 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
222 gpdio =
223 (struct IOStdReq *)CreateIORequest(gpdmp, sizeof(struct IOStdReq));
224 if (!gpdio)
225 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
227 if (0 != OpenDevice("gameport.device", 0, (struct IORequest *)gpdio, 0))
228 Alert(AT_DeadEnd | AG_OpenDev | AN_Unknown);
230 /* Set the controller type */
231 gpdio->io_Command = GPD_SETCTYPE;
232 gpdio->io_Data = (APTR) &controllerType;
233 gpdio->io_Length = sizeof(BYTE);
234 DoIO((struct IORequest *)gpdio);
236 /* Set the gameport trigger */
237 gpdio->io_Command = GPD_SETTRIGGER;
238 gpdio->io_Data = &mouseTrigger;
239 gpdio->io_Length = sizeof(struct GamePortTrigger);
240 DoIO((struct IORequest *)gpdio);
242 gpdie = AllocMem(sizeof(struct InputEvent), MEMF_PUBLIC | MEMF_CLEAR);
243 if (!gpdie)
244 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
247 /* Send an initial request to the keyboard device */
248 SEND_KBD_REQUEST(kbdio, kbdie);
250 /* ...and to gameport.device */
251 SEND_GPD_REQUEST(gpdio, gpdie);
253 /* ...and to timer.device */
254 SEND_TIMER_REQUEST(timerio);
256 commandsig = 1 << InputDevice->CommandPort->mp_SigBit;
258 kbdsig = 1 << kbdmp->mp_SigBit;
259 gpdsig = 1 << gpdmp->mp_SigBit;
260 timersig = 1 << timermp->mp_SigBit;
261 keytimersig = 1 << keytimermp->mp_SigBit;
263 for (;;)
265 wakeupsigs = Wait(commandsig |
266 kbdsig |
267 gpdsig | timersig | keytimersig | 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 =
300 (struct IOStdReq *)GetMsg(InputDevice->CommandPort)))
303 switch (ioreq->io_Command)
305 case IND_ADDHANDLER:
306 #ifdef __mc68000
307 /* Older m68k programs copied input handler code without
308 * flushing caches, causing crashes on 68040/060.
310 CacheClearU();
311 #endif
312 Enqueue((struct List *)&(InputDevice->HandlerList),
313 (struct Node *)ioreq->io_Data);
314 break;
316 case IND_REMHANDLER:
317 Remove((struct Node *)ioreq->io_Data);
318 break;
320 case IND_SETMTRIG:
321 break;
323 case IND_SETMTYPE:
324 break;
326 case IND_ADDEVENT:
329 * IND_ADDEVENT command allows client to send multiple
330 * RAWKEY or RAWMOUSE events to the input.device. All
331 * other classes will be ignored.
333 struct InputEvent *ie =
334 (struct InputEvent *)ioreq->io_Data;
335 ULONG ie_cnt =
336 ioreq->io_Length / sizeof(struct InputEvent);
338 D(bug("[input.device] ie_cnt=%d, ie=%d\n", ie_cnt,
339 ie));
341 /* Update the current qualifier */
342 InputDevice->ActQualifier = ie->ie_Qualifier;
344 /* For each event... */
345 for (; ie_cnt; ie_cnt--, ie++)
347 D(bug("[input.device] ie_Class=%02x ie_Code=%04x"
348 " ie_Qualifier=%04x\n",
349 ie->ie_Class, ie->ie_Code,
350 ie->ie_Qualifier));
352 /* Of class RAWMOUSE or RAWKEY... */
353 if (ie->ie_Class == IECLASS_RAWMOUSE
354 || ie->ie_Class == IECLASS_RAWKEY)
356 ie->ie_NextEvent = NULL;
358 if (ie->ie_Class == IECLASS_RAWKEY)
360 if (!IsQualifierKey(ie->ie_Code))
362 if (keyrepeat_state > 0)
364 ABORT_KEYTIMER_REQUEST;
365 keyrepeat_state = 0;
368 if (!(ie->ie_Code & IECODE_UP_PREFIX))
370 if (IsRepeatableKey(ie->
371 ie_Code))
373 keyrepeatie = *ie;
375 SEND_KEYTIMER_REQUEST
376 (keytimerio,
377 InputDevice->
378 KeyRepeatThreshold);
379 keyrepeat_state = 1;
386 /* If the event's qualifier differs from the
387 current one, fire the events */
388 if (InputDevice->ActQualifier ==
389 ie->ie_Qualifier)
391 UWORD q = ie->ie_Qualifier;
392 ForwardQueuedEvents(InputDevice);
394 /* And set new qualifier */
395 InputDevice->ActQualifier = q;
398 /* Set the timestamp */
399 GetSysTime(&(ie->ie_TimeStamp));
401 /* and enqueue */
402 AddEQTail(ie, InputDevice);
405 /* In case some events are still in the queue, fire
406 them all up */
407 ForwardQueuedEvents(InputDevice);
409 break;
411 case IND_WRITEEVENT:
413 struct InputEvent *ie;
415 ie = (struct InputEvent *)ioreq->io_Data;
417 ie->ie_NextEvent = NULL;
418 /* Add a timestamp to the event */
419 GetSysTime(&(ie->ie_TimeStamp));
421 D(bug("id: %d\n", ie->ie_Class));
423 /* Add event to queue */
424 AddEQTail((struct InputEvent *)ioreq->io_Data,
425 InputDevice);
427 /* Forward event (and possible others in the queue) */
428 ForwardQueuedEvents(InputDevice);
429 } break;
431 case IND_SETTHRESH:
432 InputDevice->KeyRepeatThreshold =
433 ((struct timerequest *)ioreq)->tr_time;
434 break;
436 case IND_SETPERIOD:
437 InputDevice->KeyRepeatInterval =
438 ((struct timerequest *)ioreq)->tr_time;
439 break;
443 ReplyMsg((struct Message *)ioreq);
447 if (wakeupsigs & keytimersig)
449 struct InputEvent ie;
451 GetMsg(keytimermp);
453 keyrepeat_state = 2;
455 /* InputHandlers can change inputevents, so send a clone */
456 ie = keyrepeatie;
457 ie.ie_NextEvent = NULL; /* !! */
458 ie.ie_Qualifier |= IEQUALIFIER_REPEAT;
459 GetSysTime(&ie.ie_TimeStamp);
461 AddEQTail(&ie, InputDevice);
463 /* Forward event (and possible others in the queue) */
464 ForwardQueuedEvents(InputDevice);
466 SEND_KEYTIMER_REQUEST(keytimerio,
467 InputDevice->KeyRepeatInterval);
470 if (wakeupsigs & kbdsig)
472 GetMsg(kbdmp); /* Only one message */
473 if (kbdio->io_Error != 0)
474 continue;
476 InputDevice->ActQualifier &= ~KEY_QUALIFIERS;
477 InputDevice->ActQualifier |=
478 (kbdie->ie_Qualifier & KEY_QUALIFIERS);
480 kbdie->ie_Qualifier &= ~MOUSE_QUALIFIERS;
481 kbdie->ie_Qualifier |=
482 (InputDevice->ActQualifier & MOUSE_QUALIFIERS);
484 /* Add event to queue */
485 AddEQTail(kbdie, InputDevice);
487 if (!IsQualifierKey(kbdie->ie_Code))
489 if (keyrepeat_state > 0)
491 ABORT_KEYTIMER_REQUEST;
492 keyrepeat_state = 0;
495 if (!(kbdie->ie_Code & IECODE_UP_PREFIX))
497 if (IsRepeatableKey(kbdie->ie_Code))
499 keyrepeatie = *kbdie;
501 SEND_KEYTIMER_REQUEST(keytimerio,
502 InputDevice->KeyRepeatThreshold);
503 keyrepeat_state = 1;
509 /* New event from keyboard device */
510 D(bug("id: Keyboard event\n"));
511 D(bug("id: Events forwarded\n"));
513 /* Forward event (and possible others in the queue) */
514 ForwardQueuedEvents(InputDevice);
515 D(bug("id: Events forwarded\n"));
517 /* Wait for some more events */
518 SEND_KBD_REQUEST(kbdio, kbdie);
521 if (wakeupsigs & gpdsig)
523 GetMsg(gpdmp); /* Only one message */
524 if (gpdio->io_Error != 0)
525 continue;
527 InputDevice->ActQualifier &= ~MOUSE_QUALIFIERS;
528 InputDevice->ActQualifier |=
529 (gpdie->ie_Qualifier & MOUSE_QUALIFIERS);
531 gpdie->ie_Qualifier &= ~KEY_QUALIFIERS;
532 gpdie->ie_Qualifier |=
533 (InputDevice->ActQualifier & KEY_QUALIFIERS);
535 /* Gameport just returns the frame count since the last
536 report in ie_TimeStamp.tv_secs; we therefore must add
537 a real timestamp ourselves */
538 GetSysTime(&gpdie->ie_TimeStamp);
540 /* Wheel events come in as IECLASS_NEWMOUSE, so fix ie_Class
541 and ie_Qualifier) */
542 if (gpdie->ie_Class == IECLASS_NEWMOUSE)
544 /* The NewMouse standard seems to send both an
545 IECLASS_NEWMOUSE and an IECLASS_RAWKEY event */
546 gpdie->ie_Class = IECLASS_RAWKEY;
547 gpdie->ie_Qualifier =
548 InputDevice->ActQualifier & KEY_QUALIFIERS;
551 /* Add event to queue */
552 AddEQTail(gpdie, InputDevice);
554 /* New event from gameport device */
555 D(bug("id: Gameport event\n"));
556 D(bug("id: Forwarding events\n"));
558 /* Forward event (and possible others in the queue) */
559 ForwardQueuedEvents(InputDevice);
560 D(bug("id: Events forwarded\n"));
562 /* Wait for some more events */
563 SEND_GPD_REQUEST(gpdio, gpdie);
566 if (wakeupsigs & InputDevice->ResetSig)
568 struct IOStdReq resetio = *kbdio;
569 struct Library *GfxBase =
570 TaggedOpenLibrary(TAGGEDOPEN_GRAPHICS);
572 InputDevice->ResetSig = 0;
574 /* Blank screen(s) in order to indicate upcoming machine reset.
575 Don't blank on m68k because we have programs that show status
576 information while waiting for reset. */
577 if (GfxBase)
579 #ifndef __mc68000
580 LoadView(NULL);
581 #endif
582 CloseLibrary(GfxBase);
585 resetio.io_Command = KBD_RESETHANDLERDONE;
586 resetio.io_Data = &resethandler;
588 /* Relying on this cmd being done quick, here */
590 DoIO((struct IORequest *)&resetio);