Dropped ShowImminentReset()
[AROS.git] / rom / devs / input / processevents.c
blobf4beb7633b35585abe915627047f70928d977a78
1 /*
2 Copyright © 1995-2010, 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_UFH3S(void, ResetHandler,
67 AROS_UFHA(struct inputbase *, InputDevice, A1),
68 AROS_UFHA(APTR, code, A5),
69 AROS_UFHA(struct ExecBase *, sysBase, A6))
71 AROS_USERFUNC_INIT
73 if (InputDevice->ResetSig)
75 Signal(InputDevice->InputTask, InputDevice->ResetSig);
78 AROS_USERFUNC_EXIT
81 /**********************
82 ** ForwardEvents() **
83 **********************/
84 /* Forwards a chain of events to the inputhandlers */
85 VOID ForwardQueuedEvents(struct inputbase *InputDevice)
87 struct InputEvent *ie_chain;
88 struct Interrupt *ihiterator;
90 ie_chain = GetEventsFromQueue(InputDevice);
91 if (ie_chain)
93 ForeachNode(&(InputDevice->HandlerList), ihiterator)
95 D(bug("ipe: calling inputhandler %s at %p\n",
96 ihiterator->is_Node.ln_Name, ihiterator->is_Code));
98 ie_chain = AROS_UFC2(struct InputEvent *, ihiterator->is_Code,
99 AROS_UFCA(struct InputEvent *, ie_chain, A0),
100 AROS_UFCA(APTR, ihiterator->is_Data, A1));
102 D(bug("ipe: returned from inputhandler\n"));
104 } /* for each input handler */
108 return;
112 /***********************************
113 ** Input device task entry point **
114 ***********************************/
115 void ProcessEvents (struct inputbase *InputDevice)
117 ULONG commandsig, kbdsig, wakeupsigs;
118 ULONG gpdsig, timersig, keytimersig;
119 struct MsgPort *timermp, *keytimermp;
120 struct timerequest *timerio, *keytimerio;
122 struct MsgPort *kbdmp, *gpdmp;
123 struct IOStdReq *kbdio, *gpdio;
124 struct InputEvent *kbdie, *gpdie, keyrepeatie;
125 struct Interrupt resethandler;
126 struct Library *TimerBase;
128 struct GamePortTrigger mouseTrigger =
130 GPTF_DOWNKEYS | GPTF_UPKEYS,
131 9999, /* We dont really care about time triggers */
132 0, /* Report any mouse change */
136 BYTE controllerType = GPCT_MOUSE;
137 BYTE keyrepeat_state = 0;
139 /************** Open timer.device *******************/
141 timermp = CreateMsgPort();
142 keytimermp = CreateMsgPort();
144 if (!timermp || !keytimermp)
145 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
147 timerio = (struct timerequest *)CreateIORequest(timermp , sizeof(struct timerequest));
148 keytimerio = (struct timerequest *)CreateIORequest(keytimermp, sizeof(struct timerequest));
149 if (!timerio || !keytimerio)
150 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
152 if ( 0 != OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)timerio, 0))
153 Alert(AT_DeadEnd | AG_OpenDev | AN_Unknown);
155 TimerBase = (struct Library *)timerio->tr_node.io_Device;
157 *keytimerio = *timerio;
158 keytimerio->tr_node.io_Message.mn_ReplyPort = keytimermp;
160 /************** Open keyboard.device *******************/
161 kbdmp = CreateMsgPort();
162 if (!kbdmp)
163 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
165 kbdio = (struct IOStdReq *)CreateIORequest(kbdmp, sizeof(struct IOStdReq));
166 if (!kbdio)
167 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
169 if ( 0 != OpenDevice("keyboard.device", 0, (struct IORequest *)kbdio, 0))
170 Alert(AT_DeadEnd | AG_OpenDev | AN_Unknown);
172 /* Install RESET Handler */
174 InputDevice->ResetSig = 1L << AllocSignal(-1);
176 resethandler.is_Node.ln_Name = "input.device reset handler";
177 resethandler.is_Node.ln_Type = NT_INTERRUPT;
178 resethandler.is_Node.ln_Pri = -128;
180 resethandler.is_Code = (VOID (*)())ResetHandler;
181 resethandler.is_Data = InputDevice;
183 kbdio->io_Command = KBD_ADDRESETHANDLER;
184 kbdio->io_Data = &resethandler;
185 DoIO((struct IORequest *)kbdio);
187 kbdie = AllocMem(sizeof (struct InputEvent), MEMF_PUBLIC | MEMF_CLEAR);
188 if (!kbdie)
189 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
192 /************** Open gameport.device *******************/
193 gpdmp = CreateMsgPort();
194 if (!gpdmp)
195 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
197 gpdio = (struct IOStdReq *)CreateIORequest(gpdmp, sizeof(struct IOStdReq));
198 if (!gpdio)
199 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
201 if ( 0 != OpenDevice("gameport.device", 0, (struct IORequest *)gpdio, 0))
202 Alert(AT_DeadEnd | AG_OpenDev | AN_Unknown);
204 /* Set the controller type */
205 gpdio->io_Command = GPD_SETCTYPE;
206 gpdio->io_Data = (APTR)&controllerType;
207 gpdio->io_Length = sizeof(BYTE);
208 DoIO((struct IORequest *)gpdio);
210 /* Set the gameport trigger */
211 gpdio->io_Command = GPD_SETTRIGGER;
212 gpdio->io_Data = &mouseTrigger;
213 gpdio->io_Length = sizeof(struct GamePortTrigger);
214 DoIO((struct IORequest *)gpdio);
216 gpdie = AllocMem(sizeof (struct InputEvent), MEMF_PUBLIC | MEMF_CLEAR);
217 if (!gpdie)
218 Alert(AT_DeadEnd | AG_NoMemory | AN_Unknown);
221 /* Send an initial request to the keyboard device */
222 SEND_KBD_REQUEST(kbdio, kbdie);
224 /* .. and to the gameport.device */
225 SEND_GPD_REQUEST(gpdio, gpdie);
227 /* .. and to the timer device */
228 SEND_TIMER_REQUEST(timerio);
230 commandsig = 1 << InputDevice->CommandPort.mp_SigBit;
232 kbdsig = 1 << kbdmp->mp_SigBit;
233 gpdsig = 1 << gpdmp->mp_SigBit;
234 timersig = 1 << timermp->mp_SigBit;
235 keytimersig = 1 << keytimermp->mp_SigBit;
237 for (;;)
239 wakeupsigs = Wait (commandsig |
240 kbdsig |
241 gpdsig |
242 timersig |
243 keytimersig |
244 InputDevice->ResetSig |
245 SIGBREAKF_CTRL_F);
247 D(bug("Wakeup sig: %x, cmdsig: %x, kbdsig: %x\n, timersig: %x"
248 , wakeupsigs, commandsig, kbdsig, timersig));
250 if (wakeupsigs & SIGBREAKF_CTRL_F)
252 struct InputEvent null_ie;
254 null_ie.ie_NextEvent = NULL;
255 null_ie.ie_Class = IECLASS_NULL;
256 null_ie.ie_SubClass = 0;
257 null_ie.ie_Code = 0;
258 null_ie.ie_Qualifier = 0;
259 null_ie.ie_position.ie_addr = 0;
261 /* Add a timestamp to the event */
262 GetSysTime( &(null_ie.ie_TimeStamp ));
263 AddEQTail(&null_ie, InputDevice);
264 ForwardQueuedEvents(InputDevice);
267 if (wakeupsigs & timersig)
269 struct InputEvent timer_ie;
271 GetMsg(timermp);
273 timer_ie.ie_NextEvent = NULL;
274 timer_ie.ie_Class = IECLASS_TIMER;
275 timer_ie.ie_SubClass = 0;
276 timer_ie.ie_Code = 0;
277 timer_ie.ie_Qualifier = InputDevice->ActQualifier;
278 timer_ie.ie_position.ie_addr = 0;
280 /* Add a timestamp to the event */
281 GetSysTime( &(timer_ie.ie_TimeStamp ));
283 AddEQTail(&timer_ie, InputDevice);
284 ForwardQueuedEvents(InputDevice);
286 SEND_TIMER_REQUEST(timerio);
289 if (wakeupsigs & commandsig)
291 struct IOStdReq *ioreq;
293 /* Get all commands from the port */
294 while ((ioreq = (struct IOStdReq *)GetMsg(&InputDevice->CommandPort)))
297 switch (ioreq->io_Command)
299 case IND_ADDHANDLER:
300 Enqueue((struct List *)&(InputDevice->HandlerList),
301 (struct Node *)ioreq->io_Data);
302 break;
304 case IND_REMHANDLER:
305 Remove((struct Node *)ioreq->io_Data);
306 break;
308 case IND_SETMTRIG:
309 break;
311 case IND_SETMTYPE:
312 break;
314 case IND_ADDEVENT: {
316 * IND_ADDEVENT command allows client to send multiple RAWKEY or RAWMOUSE
317 * events to the input.device. All other classes will be ignored.
319 struct InputEvent *ie = (struct InputEvent *)ioreq->io_Data;
320 ULONG ie_cnt = ioreq->io_Length / sizeof(struct InputEvent);
322 D(bug("[input.device] ie_cnt=%d, ie=%d\n", ie_cnt, ie));
324 /* Update the current qualifier */
325 InputDevice->ActQualifier = ie->ie_Qualifier;
327 /* For each event... */
328 for (; ie_cnt; ie_cnt--, ie++)
330 D(bug("[input.device] ie_Class=%02x ie_Code=%04x ie_Qualifier=%04x\n",
331 ie->ie_Class, ie->ie_Code, ie->ie_Qualifier));
333 /* Of class RAWMOUSE or RAWKEY... */
334 if (ie->ie_Class == IECLASS_RAWMOUSE || ie->ie_Class == IECLASS_RAWKEY)
336 ie->ie_NextEvent = NULL;
338 if (ie->ie_Class == IECLASS_RAWKEY)
340 if (!IsQualifierKey(ie->ie_Code))
342 if (keyrepeat_state > 0)
344 ABORT_KEYTIMER_REQUEST;
345 keyrepeat_state = 0;
348 if (!(ie->ie_Code & IECODE_UP_PREFIX))
350 if (IsRepeatableKey(ie->ie_Code))
352 keyrepeatie = *ie;
354 SEND_KEYTIMER_REQUEST(keytimerio, InputDevice->KeyRepeatThreshold);
355 keyrepeat_state = 1;
359 } /* if (!IsQualifierKey(ie->ie_Code)) */
362 /* If the event's qualifier differs from the current one, fire the events */
363 if (InputDevice->ActQualifier == ie->ie_Qualifier) {
364 UWORD q = ie->ie_Qualifier;
365 ForwardQueuedEvents(InputDevice);
367 /* And set new qualifier */
368 InputDevice->ActQualifier = q;
371 /* Set the timestamp */
372 GetSysTime( &(ie->ie_TimeStamp ));
374 /* and enqueue */
375 AddEQTail(ie, InputDevice);
378 /* In case some events are still in the queue, fire them all up */
379 ForwardQueuedEvents(InputDevice);
380 } break;
382 case IND_WRITEEVENT: {
383 struct InputEvent *ie;
385 ie = (struct InputEvent *)ioreq->io_Data;
387 ie->ie_NextEvent = NULL;
388 /* Add a timestamp to the event */
389 GetSysTime( &(ie->ie_TimeStamp ));
391 D(bug("id: %d\n", ie->ie_Class));
393 /* Add event to queue */
394 AddEQTail((struct InputEvent *)ioreq->io_Data,
395 InputDevice);
397 /* Forward event (and possible others in the queue) */
398 ForwardQueuedEvents(InputDevice);
399 } break;
401 case IND_SETTHRESH:
402 InputDevice->KeyRepeatThreshold = ((struct timerequest *)ioreq)->tr_time;
403 break;
405 case IND_SETPERIOD:
406 InputDevice->KeyRepeatInterval = ((struct timerequest *)ioreq)->tr_time;
407 break;
409 } /* switch (IO command) */
411 ReplyMsg((struct Message *)ioreq);
413 } /* while (messages in the command port) */
415 } /* if (IO command received) */
417 if (wakeupsigs & keytimersig)
419 struct InputEvent ie;
421 GetMsg(keytimermp);
423 keyrepeat_state = 2;
425 ie = keyrepeatie; /* InputHandlers can change inputevents, so send a clone!! */
426 ie.ie_NextEvent = NULL; /* !! */
427 ie.ie_Qualifier |= IEQUALIFIER_REPEAT;
428 GetSysTime(&ie.ie_TimeStamp);
430 AddEQTail(&ie, InputDevice);
432 /* Forward event (and possible others in the queue) */
433 ForwardQueuedEvents(InputDevice);
435 SEND_KEYTIMER_REQUEST(keytimerio, InputDevice->KeyRepeatInterval);
437 } /* if (wakeupsigs & keytimersig) */
439 if (wakeupsigs & kbdsig)
441 GetMsg(kbdmp); /* Only one message */
442 if (kbdio->io_Error != 0)
443 continue;
445 InputDevice->ActQualifier &= ~KEY_QUALIFIERS;
446 InputDevice->ActQualifier |= (kbdie->ie_Qualifier & KEY_QUALIFIERS);
448 kbdie->ie_Qualifier &= ~MOUSE_QUALIFIERS;
449 kbdie->ie_Qualifier |= (InputDevice->ActQualifier & MOUSE_QUALIFIERS);
451 /* Add event to queue */
452 AddEQTail(kbdie, InputDevice);
454 if (!IsQualifierKey(kbdie->ie_Code))
456 if (keyrepeat_state > 0)
458 ABORT_KEYTIMER_REQUEST;
459 keyrepeat_state = 0;
462 if (!(kbdie->ie_Code & IECODE_UP_PREFIX))
464 if (IsRepeatableKey(kbdie->ie_Code))
466 keyrepeatie = *kbdie;
468 SEND_KEYTIMER_REQUEST(keytimerio, InputDevice->KeyRepeatThreshold);
469 keyrepeat_state = 1;
473 } /* if (!IsQualifierKey(kbdie->ie_Code)) */
475 /* New event from keyboard device */
476 D(bug("id: Keyboard event\n"));
477 D(bug("id: Events forwarded\n"));
479 /* Forward event (and possible others in the queue) */
480 ForwardQueuedEvents(InputDevice);
481 D(bug("id: Events forwarded\n"));
483 /* Wit for some more events */
484 SEND_KBD_REQUEST(kbdio, kbdie);
486 } /* if (wakeupsigs & kbdsig) */
488 if (wakeupsigs & gpdsig)
490 GetMsg(gpdmp); /* Only one message */
491 if (gpdio->io_Error != 0)
492 continue;
494 InputDevice->ActQualifier &= ~MOUSE_QUALIFIERS;
495 InputDevice->ActQualifier |= (gpdie->ie_Qualifier & MOUSE_QUALIFIERS);
497 gpdie->ie_Qualifier &= ~KEY_QUALIFIERS;
498 gpdie->ie_Qualifier |= (InputDevice->ActQualifier & KEY_QUALIFIERS);
500 /* Gameport just returns the frame count since the last
501 report in ie_TimeStamp.tv_secs; we therefore must add
502 a real timestamp ourselves */
503 GetSysTime(&gpdie->ie_TimeStamp);
505 /* Wheel events come in as IECLASS_NEWMOUSE, so fix ie_Class and ie_Qualifier) */
506 if (gpdie->ie_Class == IECLASS_NEWMOUSE)
508 #warning "The NewMouse standard seems to send both a IECLASS_NEWMOUSE and a IECLASS_RAWKEY event"
509 gpdie->ie_Class = IECLASS_RAWKEY;
510 gpdie->ie_Qualifier = InputDevice->ActQualifier & KEY_QUALIFIERS;
513 /* Add event to queue */
514 AddEQTail(gpdie, InputDevice);
516 /* New event from gameport device */
517 D(bug("id: Gameport event\n"));
518 D(bug("id: Forwarding events\n"));
520 /* Forward event (and possible others in the queue) */
521 ForwardQueuedEvents(InputDevice);
522 D(bug("id: Events forwarded\n"));
524 /* Wit for some more events */
525 SEND_GPD_REQUEST(gpdio, gpdie);
527 } /* if (wakeupsigs & gpdsig) */
529 if (wakeupsigs & InputDevice->ResetSig)
531 struct IOStdReq resetio = *kbdio;
533 InputDevice->ResetSig = 0;
535 /* Blank screen(s) in order to indicate upcoming machine reset */
536 LoadView(NULL);
538 resetio.io_Command = KBD_RESETHANDLERDONE;
539 resetio.io_Data = &resethandler;
541 /* Relying on this cmd being done quick, here */
543 DoIO((struct IORequest *)&resetio);
547 } /* Forever */
549 } /* ProcessEvents */