Guarda, io di Linux non ne capisco niente (e più passa il tempo e più lo odio)....
Questa affermazione è solo dipendente dalla non conoscenza dello strumento. Secondo me non puoi affermare ciò, in quanto le possiblità non sono nemmeno paragonabili ad altri sistemi chiusi, e dico "chiusi" (con lucchetti e serrature).
Ad ogni modo, come ho scritto, non conosco nè l'ahrdware che stai utilizzando, nè il processore. Questa mia non conoscenza non mi permette di formulare suggerimenti idonei.
L'unche cose che posso fornirti sono prelevate dalla mia vecchia esperienza con quel tipo di programmazione, a basso livello, e direttamente dell'hardware.
Questa cosa non è più possibile con windoz, in quanto il controllo diretto c'è l'ha lui, e tu puoi solo accedervi tramite librerie, che però sono condizionate dalle logiche interne del sistema operativo.
Su linux, volendo, hai la possibilità di crearti i tuoi driver personali e personalizzati, anche se la cosa può risultare difficoltosa di primo acchitto.
Comunque, nel tuo caso, stiamo affrontando due logiche alquanto contrastanti. Da una parte hai un hardware che, per quanto limitato sia, fornisce delle caratteristiche di un certo tipo, che sono accessibili costruendoci sopra dei driver a basso livello. Dall'altra hai un linguaggio ad alto livello, che si appoggia tra le altre cose a librerie di medio livello esterne, le quali poi vanno a chiamare funzioni del sistema operativo.
Cercare di pilotare direttamente l'hardware, partendo da questa situazione, credo sia alquanto complicato.
Riguardo invece ai sistemi con cui gestire quello che vuoi fare, tralasciando per il momento tutta la parte sopra, e in base alle mie esperienze, penso che i due esempi che ti ho fatto siano una base di partenza su cui sperimentare.
Sò bene che ci sono particolari condizioni, probabilmente complicate da gestire, ma da qualche parte penso devi partire.
Ricordo che lo Z80 gestiva un solo interrupt per tutto (mi pare sul registro 80 o 8, non ricordo). Il processore scatenava (tramite il software di base che alzava l'int) l'int e si posizionava su un indirizzo preciso. Da qui partiva l'analisi di cosa aveva attivato l'int e, tramite una serie di if, andavi ad eseguire le relative operazioni.
Parlando di timer o di polling, lo stesso processore deve lavorare in polling, analizzando in loop tutte le porte di accesso, scatenando di conseguenza (sempre dipendente dal sistema operativo) il relativo codice.
Dato che tu stai operando su un livello di software molto alto, e non avendo a disposizione altro, l'unica alternativa che vedo valida è quella del timer, magari anche tarato al millisecondo.
Sul discorso dei rimbalzi, è normale che ci siano, in quanto si opera tramite un mezzo meccanico, e per cui soggetto a questo. In questo caso viene un sistema di anti-rimbalzo e di analisi dei falsi positivi, un pò come funziona la logica di controllo dei pulsanti del mouse (click o doppio click). In java, per esempio, non esiste un evento double-click, ma l'oggetto mouse ti fornisce un contatore di click che puoi analizzare per sapere se l'utente ha fatto click o doppio click, e anche quale dei tasti ha premuto.
Se, invece, scopri che il processore fornisce un qualche sistema di interrupt o altro, allora puoi intraprendere un'altra logica.