INDICE Introduzione Come si comporta Intuition Come si comporta MUI Problemi Problema n. 1 (input.device bloccato; Intuition) Problema n. 2 (refresh della GUI bloccato; MUI) Ipotesi di soluzioni Possibile soluzione per il problema n. 1 (sotto-task IDCMP in parallelo) Possibile soluzione per il problema n. 2 (classe MUI con task asincrono) Considerazioni finali Funzionamento seriale dell'input.device Fattibilità di un patch per Intuition INTRODUZIONE Come si comporta Intuition -------------------------- L'input dell'utente viene letto, comunicando direttamente con l'hardware, da keyboard.device e gameport.device, che lo trasmettono all'input.device. Quest'ultimo unisce le diverse informazioni sull'input in un unico stream (flusso) di "eventi di input", omogeneo e sequenziale, rappresentato con una lista di strutture InputEvent. L'input.device passa poi tale lista ad una serie di "input handler", secondo un ordine basato sulla loro priorità. Ciascun handler può intraprendere delle azioni in base al contenuto della lista ricevuta in ingresso; può inoltre apporre modifiche alla lista stessa aggiungendo, rimuovendo o alterando eventi. In uscita l'handler restituisce la lista modificata, la quale diventerà l'ingresso per l'handler successivo. Il codice di un handler viene eseguito come una normale chiamata a funzione: di conseguenza esso gira sempre nel contesto del task dell'input.device. Normalmente l'handler con priorità massima è quello della commodities.library (che quindi intercetta gli eventi prima di chiunque altro), tranne che nel caso in cui essa non sia stata ancora aperta. L'handler immediatamente successivo è tipicamente quello di Intuition; la sua funzione è "interpretare", ed eventualmente filtrare, tutti quegli eventi che possono influire sullo stato della GUI o sulle attività dei programmi che ne fanno uso. Questo handler fondamentalmente si limita a chiamare la funzione Intuition() della intuition.library, passandole come unico argomento il puntatore alla lista di eventi ricevuto in ingresso. Intuition() verifica la natura di ogni singolo evento e, se necessario, reagisce ad esso eseguendo opportune azioni, come ad esempio attivare una finestra, modificare l'aspetto e lo stato di un gadget o inviare un messaggio ad un applicativo. La casistica più comune comprende: · Refresh automatico di una componente della GUI (bordo di una finestra, gadget non BOOPSI, barra del titolo di uno schermo). · Visualizzazione di menu · Invocazione dell'opportuno metodo di un gadget BOOPSI · Nessuna azione visibile (es.: click all'interno di una finestra, ma non su un gadget) A ciascuna di queste azioni può essere associato l'invio di un particolare messaggio, rappresentato da una struttura IntuiMessage, all'applicativo "proprietario" della finestra correntemente attiva (normalmente il task che l'ha aperta). Gli IntuiMessage hanno spesso una corrispondenza stretta con gli InputEvent da cui derivano. Al termine di queste azioni gli eventi che non possono essere utili agli handler successivi vengono rimossi dalla lista, altri (generalmente utili a console.device) vengono aggiunti, e la funzione Intuition() termina restituendo all'handler il puntatore alla nuova lista. Infine l'handler di Intuition restituisce a sua volta il puntatore all'input.device che può quindi passarlo all'handler successivo, solitamente quello di console.device. _ _ _ _ _ _ | \ \ \ \ \ | |Applicativo| |_\_\_\_\_\_| InputEvent stream /|\ .····················. _ _ _|_ _ __ : : | | _ _ _ _ _ _ _ _ _ _ _: _ _ _ _ __ _ _ V _ _ __ _ |Messaggio ad| | | | | | | |applicativo | |keyboard.device|-. | |==>|Input handler (CX) | |__ _ _ _ _ _| |_ _ _ _ _ _ _ _| \ | | |_ _ _ _ _ _ _ _ _ _| /\ _ _ _ _ _ _ _ _ \ | | _ __ _ _ V _ _ __ _ _ ||_ _ _ _ | | \ |input.device| | | | | |gameport.device|----->| task |==>|Input handler (I) |==>|Intuition()| |_ _ _ _ _ _ _ _| / | | |_ _ _ _ _ _ _ _ _ _| |_ _ _ _ _ _| _ _ _ _ _ _ _ _ / | | _ __ _ _ V _ _ __ _ || | | / | | | | _ _ \/_ _ | timer.device |-' | |==>|Input handler (c.d)| | | |_ _ _ _ _ _ _ _| |__ _ _ _ _ _| |_ _ _ _ _ _ _ _ _ _| |Refresh | : |della GUI| _: |_ _ _ _ _| / \_/ || : _ _ _ _ \/_ _ _ _ : | | V |Esecuzione metodo| ///// |_ _ _ _ _ _ _ _ _| Questo meccanismo comporta che l'unico codice eseguito nel contesto di un applicativo che faccia uso di Intuition è quello che si occupa di rispondere agli IntuiMessage ed intraprendere eventuali azioni in base al loro contenuto (generalmente finalizzate a svolgere il compito richiesto dall'utente più che a gestire l'interfaccia; tuttavia nel caso di GadTools alcune operazioni di gestione della GUI vengono affidate al task dell'applicativo mediante le funzioni GT_GetIMsg() e GT_ReplyIMsg()). In particolare, nel caso dei gadget BOOPSI, la risposta della GUI risulta sempre immediata e "in tempo reale", indipendentemente dalle operazioni che l'applicativo sta svolgendo nello stesso momento, poiché di fatto se ne occupa asincronamente un altro task (quello dell'input.device). Come si comporta MUI -------------------- La differenza fondamentale tra MUI ed Intuition è che i suoi gadget, pur essendo oggetti BOOPSI, sono sottoclassi di "rootclass" piuttosto che di "gadgetclass". Di conseguenza non sono riconosciuti da Intuition come dei normali gadget e non vengono quindi gestiti automaticamente dalla funzione Intuition(). Tutto ciò che quest'ultima rileva quando l'utente interagisce con i gadget MUI è una serie di eventi IDCMP_MOUSEBUTTONS e IDCMP_MOUSEMOVE che essa trasmette, invariati, al task proprietario della finestra. Quest'ultimo tipicamente si trova in uno stato di attesa degli eventi. Per ogni evento ricevuto chiama una funzione MUI di gestione dell'input (per l'esattezza invoca un metodo di una particolare classe) la quale è poi in grado di determinare a quale gadget MUI va passato, mediante l'invocazione di un suo opportuno metodo, l'evento appena letto. _ _ _ _ _ _ _ _ _ __ | \ \ \ \ \ \ \ \ \ \| |Operazioni programma| |_\_\_\_\_\_\_\_\_\_\| _ _ _ _ _ _ _ _ __ /\ _ _ _ _ _ _ | | _ _ _ _ _ _ _ _ _ _|| _ _ _ _ | | |Semplice messaggio| | \ \ \ \ \ | | \ \ \ \ \ \ \ \ | |Intuition()|==>| all'applicativo |---->|Applicativo| |Refresh della GUI| |_ _ _ _ _ _| | (IDCMP_MOUSE#?) | |_\_\_\_\_\_| |_\_\_\_\_\_\_\_\_| |__ _ _ _ _ _ _ _ _| || /\ _ _ _ \/_ _ __ _ _ _ _|| _ _ _ _ | \ \ \ \ \ \ \| | \ \ \ \ \ \ \ \ | |Gestione input|==>|Esecuzione metodo| |_\_\_\_\_\_\_\| |_\_\_\_\_\_\_\_\_| Con MUI, di conseguenza, la risposta della GUI (almeno con le classi di gadget standard fornite con il pacchetto) risulta sincrona alle operazioni del task dell'applicativo, in quanto avviene nel suo stesso contesto. PROBLEMI Problema n. 1 (input.device bloccato; Intuition) ------------------------------------------------ La gestione dell'input secondo il modello di Intuition, cioè tramite un handler, ha il vantaggio di garantire pressoché sempre una risposta immediata da parte della GUI, anche nel caso in cui l'applicativo non fosse pronto a reagire all'input ricevuto. Tuttavia, poiché l'handler di Intuition opera sempre, come già illustrato, nel contesto dell'input.device, qualsiasi trasmissione di eventi di input nel sistema risulta completamente bloccata fino alla conclusione delle sue operazioni. Il problema si manifesta in modo evidente soprattutto con i gadget BOOPSI; infatti l'handler invoca opportuni metodi di tali gadget quando l'input dell'utente è diretto a loro o comporta una modifica del loro stato. Nel caso di metodi particolarmente complessi, come quelli dei gadget associati ai DataType, il tempo di esecuzione può essere elevato, e di conseguenza la trasmissione dell'input nell'intero sistema può subire una sospensione di durata non trascurabile. Il sintomo più tipico è il blocco del puntatore del mouse, ma anche altre attività del sistema operativo che si basino su una regolare ricezione di eventi di input (ad esempio quelli generati dal timer.device) rischiano di venire ostacolate con conseguenze imprevedibili. Problema n. 2 (refresh della GUI bloccato; MUI) ----------------------------------------------- Il sistema MUI presenta un problema per certi versi opposto, ma ugualmente fastidioso per l'utente. Con i gadget di MUI le operazioni svolte nel contesto del task dell'input.device sono sempre molto limitate e di breve durata; si tratta per lo più di comunicare una serie di click dei pulsanti del mouse (e spostamenti di quest'ultimo) all'applicativo associato al canale IDCMP della finestra attiva. Ogni operazione relativa alla GUI viene poi effettuata nel contesto del task che riceve i messaggi in questione. Nel caso esso sia occupato in qualche elaborazione e quindi non si trovi in attesa di segnali dalla porta IDCMP, come è facile immaginare, nessun tipo di aggiornamento della GUI verrà attuato fino alla conclusione delle operazioni. L'utente, in questo caso, non osservando alcuna risposta dai gadget con cui tenta di interagire, può avere l'impressione che l'intero programma sia bloccato e non semplicemente impegnato in altre attività. Nel caso migliore l'utente si fa una cattiva opinione del programma; inoltre l'incertezza sul da farsi può portare l'utente a danneggiare inavvertitamente il lavoro che sta svolgendo mediante l'applicativo. Ad esempio, un tentativo di selezione ripetuta dello stesso gadget (nella speranza di una ripresa del funzionamento del programma) può provocare effetti collaterali indesiderati nell'istante in cui l'applicativo ricomincia a gestire l'input e si occupa di quello nel frattempo ricevuto. IPOTESI DI SOLUZIONI Possibile soluzione per il problema n. 1 (sotto-task IDCMP in parallelo) ------------------------------------------------------------------------ Una possibile soluzione al primo problema, attuabile al livello di Intuition, è la gestione multithreaded degli eventi di input trasmessi al suo handler dall'input.device, che in tal modo si libererebbe molto rapidamente dopo la chiamata alla funzione Intuition(). Come realizzare questo nella pratica? Un'idea potrebbe essere associare ad ogni schermo e finestra un task dedicato, creato all'apertura ed eliminato alla chiusura. Ciascuno di questi task riceverebbe solo gli eventi che lo riguardano e potrebbe gestirli del tutto asincronamente al resto del sistema e in particolare all'input.device. Per rendere possibile ciò sarebbe necessario apportare alcune modifiche alla funzione Intuition(): 1. Essa dovrebbe, preliminarmente, esaminare la lista di InputEvent ricevuta dall'input.device e in base ad essa costruire una seconda lista privata copiando tutti gli eventi che riguardano la GUI. 2. Fatto ciò, tutti gli eventi che non devono essere rilevati dagli altri handler dovrebbero essere rimossi dalla lista principale. 3. La lista privata di eventi dovrebbe poi essere separata in sottoliste, ognuna indirizzata all'opportuna finestra (o all'opportuno schermo). 4. Ogni sottolista dovrebbe essere spedita, tramite un opportuno messaggio, al task associato alla finestra (o schermo) destinazione. 5. A questo punto Intuition() potrebbe terminare subito la sua esecuzione, senza aspettare alcuna risposta dai task a cui ha spedito i messaggi; in questo modo l'input.device sarebbe subito libero di proseguire la sua attività. Una possibile variante è il passaggio (subito dopo il punto 2) della lista privata ad un task "intermedio" che si occupi di eseguire le operazioni rimanenti; in questo caso Intuition() potrebbe terminare prima del punto 3. Questo ipotetico task intermedio potrebbe ad esempio venire creato in modo automatico all'apertura della intuition.library. Occorre prestare molta attenzione all'implementazione del punto 2, in quanto è necessario stabilire delle regole precise in base alle quali si possa determinare IN ANTICIPO e senza ambiguità se un evento riguarda o no la GUI e se esso debba venire trasmesso o no ai successivi handler. Questo potrebbe, oggettivamente, non essere un compito facile. In particolare, se un evento deve essere modificato da Intuition e poi trasmesso al resto degli handler, bisogna che: - Si sappia già come modificarlo PRIMA di passarlo al task destinatario, per non dover aspettare che questo termini fornendo informazioni sulla modifica da effettuare (soluzione non sempre applicabile), oppure - Il task destinatario, dopo avere modificato personalmente l'evento, si occupi di REINSERIRLO nella catena di InputEvent a monte dell'handler di Intuition. Questo si può realizzare ad esempio aggiungendolo ad una coda di eventi globale periodicamente letta dall'handler, oppure sfruttando la commodities.library. Non basta chiamare direttamente Intuition() con l'evento in questione poiché si rimarrebbe nel contesto del task. Le regole per realizzare ciò potrebbero risultare abbastanza complicate. Ammettendo di risolvere questi problemi, restano da esaminare i compiti dei singoli task destinatari. Quelli associati alle finestre svolgerebbero esattamente gli stessi compiti che attualmente sono svolti dalla funzione Intuition(), cioè aggiornare lo stato della GUI, invocare opportuni metodi di eventuali gadget BOOPSI selezionati e spedire IntuiMessage all'applicativo che "possiede" la finestra (con l'unica avvertenza, ovvia del resto, di assicurarsi che il task sia completamente rientrante ed esegua una corretta arbitrazione sui dati globali di IntuitionBase). I task associati agli schermi non dovrebbero fare altro che gestire la selezione degli unici due possibili gadget, quello di trascinamento e quello di profondità, nonché la disattivazione di tutte le finestre in caso di click del mouse su una zona libera dello schermo, l'autoscrolling e lo screen dragging tramite Amiga sinistro + mouse. Si potrebbe anche pensare ad un ulteriore task indipendente che gestisca semplicemente il movimento del puntatore, ma questo è un compito talmente banale che potrebbe essere svolto direttamente (e più rapidamente) dalla funzione Intuition(). _ _ _ _ _ _ | \ \ \ \ \ | |Applicativo| |_\_\_\_\_\_| InputEvent stream /|\ .····················. | : : :::::::::::::::: _ _ _: _ _ _ _ __ _ _ V _ _ __ _ ::Messaggio ad:: | | | | ::applicativo::: | |==>|Input handler (CX) | :::::::::::::::: | | |_ _ _ _ _ _ _ _ _ _| /\ | | _ __ _ _ V _ _ __ _ _ _ _ _ _ _ || |input.device| | | | | ::::::::::::::::: | task |==>|Input handler (I) |==>|Intuition()|-->::Task finestra:: | | |_ _ _ _ _ _ _ _ _ _| |_ _ _ _ _ _| ::::::::::::::::: | | _ __ _ _ V _ _ __ _ || | | | | \/ | |==>|Input handler (c.d)| ::::::::::::: |__ _ _ _ _ _| |_ _ _ _ _ _ _ _ _ _| ::Refresh:::: : ::della GUI:: _: ::::::::::::: / \_/ || : \/ : ::::::::::::::::::::: V ::Esecuzione metodo:: ///// ::::::::::::::::::::: Per concludere, si può osservare che in realtà sarebbe abbastanza raro che la stessa lista contenga eventi indirizzati a finestre diverse; l'utente, in circostanze normali, non dovrebbe essere più veloce dell'elaborazione dell'input da parte del sistema. Un'eccezione sono gli eventi di timer (che non sono generati dall'utente e sono sempre diretti a tutte le finestre). Alla luce di questa considerazione si potrebbe pensare di lasciare al programmatore (o addirittura all'utente) la facoltà di decidere quali finestre debbano essere dotate di un task IDCMP dedicato, e quali invece possano semplicemente appoggiarsi ad un task IDCMP globale. Possibile soluzione per il problema n. 2 (classe MUI con task asincrono) ------------------------------------------------------------------------ Il problema di MUI potrebbe risolversi molto facilmente con una riscrittura delle classi di base del sistema. L'idea è che il dispatcher di un gadget MUI non dovrebbe eseguire in sequenza (e nel contesto dell'applicativo) il refresh della GUI e poi la chiamata alla funzione di callback associata al gadget. Ogni istanza di una classe di gadget MUI dovrebbe avere un proprio task privato a cui affidare la chiamata alla funzione di callback, rendendola così asincrona rispetto al refresh grafico. Tale task potrebbe essere creato dal metodo OM_NEW della classe e distrutto in seguito da OM_DISPOSE. Eventuali valori di ritorno diretti all'applicativo potrebbero essere comunicati mediante messaggi (gestiti automaticamente dal task del gadget). Il refresh grafico dei gadget, invece, essendo generalmente un'operazione abbastanza rapida, potrebbe essere affidato ad un unico task globale; una possibilità sarebbe quella di creare questo task all'apertura della libreria MUIMaster. :::::::::::::::::::::::: ::::::::::::::::::: ::Operazioni programma::<==::Task del gadget:: :::::::::::::::::::::::: ::::::::::::::::::: _ _ _ _ _ _ _ _ __ /|\ _ _ _ _ _ _ | | _ _ _ _ _ __ _ _ _ _ | _ _ _ _ | | |Semplice messaggio| | \ \ \ \ \ \ \| | \ \ \ \ \ \ \ \ | |Intuition()|==>| all'applicativo |-+ |Gestione input|==>|Esecuzione metodo| |_ _ _ _ _ _| | (IDCMP_MOUSE#?) | | |_\_\_\_\_\_\_\| |_\_\_\_\_\_\_\_\_| |__ _ _ _ _ _ _ _ _| | /\ | | _ _ ||_ _ _ \|/ | | \ \ \ \ \ | ;;;;;;;;;;;;;;;;;;;;; +-->|Applicativo| ;;Refresh della GUI;; |_\_\_\_\_\_| ;;;;;;;;;;;;;;;;;;;;; Se le operazioni di refresh non necessitano di restituire alcun valore al dispatcher dell'oggetto (oppure alla funzione di MUI che gestisce l'input) quest'ultimo verrebbe disimpegnato immediatamente; in caso contrario sarebbe sufficiente che il task preposto al refresh svolgesse tutte le sue operazioni prima di rispondere al dispatcher con ReplyMsg(), e copiasse il valore di ritorno in un apposito campo del messaggio "restituito" al mittente. Questo ovviamente terrebbe impegnato il task dell'applicativo per un tempo leggermente superiore, ma le operazioni di refresh grafico puro e semplice non dovrebbero, nella maggior parte dei casi, richiedere più di qualche millisecondo (come del resto accade per Intuition nel caso di gadget non troppo complicati). Chiaramente se tale comportamento fosse richiesto per TUTTI i gadget sarebbe più conveniente evitare del tutto l'uso di un task separato per il refresh, mantenendo però quello dedicato al callback. Sarebbero possibili diverse variazioni sul tema: ad esempio, l'ordine in cui vengono "richiamati" i due task potrebbe influenzare, sia pure di poco, la prontezza del refresh e quindi della risposta all'utente da parte della GUI; oppure in certi casi potrebbe essere conveniente creare "al volo" il task preposto al callback in modo che l'applicativo possa eseguire più volte contemporaneamente la stessa funzione (se la sua natura lo consente). In ogni caso questa soluzione eliminerebbe alla radice il problema del "blocco" apparente della risposta della GUI durante un'intensa attività dell'applicativo, senza per questo tornare al modello "mono-threaded" adottato attualmente da Intuition. L'alternativa proposta per quest'ultimo (vedi paragrafo precedente) risolverebbe in teoria anche il problema di MUI, ma solo se i gadget MUI fossero istanze di "gadgetclass", cosa che al momento, in pratica, non accade. CONSIDERAZIONI FINALI Funzionamento seriale dell'input.device --------------------------------------- Come già detto, l'input.device propaga lo stream di eventi di input attraverso i vari handler in cascata. Gli handler non sono altro che funzioni chiamate, una dopo l'altra, dal task dell'input.device; ogni handler riceve in ingresso il valore di uscita del precedente (e cioè il puntatore ad una particolare lista di InputEvent). Questo è un meccanismo intrinsecamente seriale; inoltre esso implica che gli handler di priorità più alta (come quello di Intuition) debbano esaminare, tra gli altri, molti eventi che non li riguardano direttamente e che vanno semplicemente trasmessi agli handler successivi. Come aumentare il parallelismo nelle operazioni dell'input.device? Ingenuamente si potrebbe pensare di avere diverse code, ognuna gestita da un task indipendente, tra cui suddividere gli eventi in base al tipo degli handler che tali code alimentano; ovviamente occorrerebbe che gli handler di una coda non abbiano mai la necessità di trasmettere eventi a quelli di un'altra coda. Purtroppo in pratica questo non è una soluzione, dato che porterebbe a ricreare la situazione corrente. Infatti normalmente gli handler esistenti nel sistema sono pochi (per lo più Commodities, Intuition e console.device) ed è difficile individuare tipi di eventi che non interessino, anche solo potenzialmente, almeno due di essi. In particolare, la quasi totalità degli eventi di input generati dall'utente interessa in qualche modo Intuition, che viene ad essere un vero e proprio "collo di bottiglia". Più vantaggioso risulterebbe applicare questa soluzione al livello dei singoli handler; ciascuno di essi, a meno che il suo funzionamento sia molto semplice, potrebbe gestire l'input in arrivo ripartendolo in modo opportuno tra diversi task paralleli (come illustrato riguardo al problema di Intuition). In questo modo sorgerebbe però il problema della trasmissione del flusso di input lungo la catena di handler. Ognuno di essi potrebbe trasmettere al successivo solo gli eventi che può scartare immediatamente come "non rilevanti" per le sue attività, ma gli sarebbe preclusa la possibilità di modificare gli eventi utilizzati, o crearne di nuovi in base ai risultati della loro elaborazione, e reinserirli nella posizione originale: questa operazione generalmente richiederebbe la conoscenza di dati non disponibili a priori e, d'altra parte, una sincronizzazione con i suoi task per ottenere da essi tali dati annullerebbe ovviamente tutti i vantaggi del parallelismo. E` dunque necessario, volendo impiegare un simile modello: · Stabilire delle regole estremamente precise per decidere quando l'ordine relativo di due eventi vada mantenuto oppure sia ininfluente; · Limitare al massimo la necessità di trasmettere informazioni tra un handler e il successivo (nel caso di entità strettamente connesse, come Intuition e console.device, questo potrebbe rivelarsi un problema serio); · Assicurarsi, ad esempio mediante semafori, che venga sempre mantenuta la consistenza interna dei valori che definiscono lo stato di un handler (e quindi dell'entità software che si appoggia ad esso) anche in presenza di numerosi sotto-task che possono accedere a tali valori. Ad esempio, se l'utente attiva una finestra di Shell e poi preme un tasto sulla tastiera, è necessario che il console.device riceva l'evento "finestra attiva" PRIMA di quello "tasto premuto", nonostante il fatto che il secondo potrebbe venire trasmesso immediatamente mentre il primo richiederebbe una più lunga elaborazione da parte di Intuition. Ancora, quando l'utente trascina un gadget proporzionale sarebbe auspicabile che la posizione relativa di knob e puntatore del mouse rimanesse costante, anche se gli spostamenti dei due oggetti vengono gestiti da due diversi task. La trasmissione di eventi agli handler successivi potrebbe ad esempio essere implementata mediante una coda ausiliaria globale svuotata periodicamente, accessibile a tutti i sotto-task di un handler, purché si presti la massima attenzione a mantenerla sempre perfettamente ordinata e ad inserire in essa anche quegli eventi (e solo quelli) che, pur non dovendo essere elaborati dall'handler corrente, possono risentire dell'ordine in cui vengono trasmessi rispetto a certi altri eventi. Queste considerazioni non pretendono certamente di costituire una soluzione completa, preferibile ad altre o facilmente realizzabile; si tratta solo di riflessioni su alcuni aspetti del problema di cui probabilmente converrebbe tenere conto. Fattibilità di un patch per Intuition ------------------------------------- E` possibile, tramite un patch, applicare all'attuale versione di Intuition i criteri appena esposti? Probabilmente no. L'idea sarebbe di applicare un patch alla funzione Intuition() per forzare il passaggio dell'input ad un task separato che se ne occupi, permettendo all'handler di Intuition di terminare subito la sua esecuzione. Ma anche immaginando di risolvere quasi tutti i problemi prima descritti, resta sempre l'impossibilità di garantire la consistenza dei dati PRIVATI contenuti nella struttura IntuitionBase, a cui sarebbe facile, in questo modo, effettuare un accesso asincrono. Non è escluso che si possa trovare una soluzione anche a questo problema, ma con ogni probabilità a questo punto conviene aspettare che sia Amiga Inc. ad implementare nel sistema operativo una gestione dell'input più efficiente.