[Python] Gestione tastiera in un loop
Manlio Perillo
manlio_perillo a libero.it
Gio 26 Giu 2008 13:39:09 CEST
farolfo a hotmail.com ha scritto:
> --------------------------------------------------
> From: "Manlio Perillo" <manlio_perillo a libero.it>
> Sent: Thursday, June 26, 2008 12:28 PM
> To: "Discussioni generali sul linguaggio Python" <python a lists.python.it>
> Subject: Re: [Python] Gestione tastiera in un loop
>
>> manlio_perillo a libero.it ha scritto:
>>
>> Ma stai usando .NET?
>> In questo caso non posso aiutarti, non lo conosco.
>
> non uso .net e non lo o neanche usare :) Uso python 2.5 e PyScripter per
> l'edit in Windows e ScrIDE in MacOS
>
PhoneProfile.SerialPort sembra provenire da .NET.
Che package stai usando per comunicare con la seriale?
>> Ti consiglio di cominciare a leggere un tutorial su Python.
>> Questo codice intercetta un interrupt da tastiera (quando premi CTRL-C)
>> non la pressione di un tasto qualsiasi.
>
> Ho letto "Pensare da informatico" di Allen B. Downey, Jeffrey Elkner e Chris
> Meyers, pensavo intercettare la pressione dei tasti fosse una cosa più
> semplice da fare, cmq seguiro i vostri consigli e mi documenterò meglio.
E' abbastanza semplice, se hai un pò di esperienza.
Il problema è che l'unica cosa che è possibile fare in modo portabile è
leggere una riga completa dalla console.
Ossia, se fai:
sys.stdin.read()
questa funziona ritorna solo dopo che l'utente preme il tasto [invio].
Per gestire un singolo tasto devi usare codice che dipende dalla
piattaforma.
Eccoti due funzioni, per sistemi POSIX (Linux, OS X) e Windows.
Le due funzioni non sono equivalenti al 100%:
def posix_getch():
"Si protrebbe usare direttamente tty.setcbreak() ma non c'è una
funzione per ripristinare la modalità normale.
"""
import termios, sys
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
new = termios.tcgetattr(fd)
new[3] = new[3] & ~(termios.ECHO | termios.ICANON) # lflags
try:
termios.tcsetattr(fd, termios.TCSAFLUSH, new)
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, old)
return ch
def win_getch():
import msvcrt
return getch()
Queste due funzioni non ti bastano.
Quando fai:
PhoneProfile.SerialPort.readline()
la funzione non ritorna fino a quando non ha letto una riga completa
dalla seriale.
Invece tu hai bisogno di monitorare sia la seriale che lo stdin allo
stesso tempo.
Questo è un esempio di programmazione concorrente, non proprio banale.
Ci sono diverse soluzioni, la più elegante ed efficiente è usare l'IO
multiplexing e non bloccante, ma avresti problemi ad implementarlo in
modo semplice su Windows.
Quindi ti consiglio di usare un thread separato in cui fai:
def thread_main():
# blocca fino a quanto non viene premuto un tasto
getch()
# lancia un KeybordInterrupt nel thread principale
thread.interrupt_main()
In questo modo non devi modificare la struttura nel tuo codice
principale, anche se questa soluzione è abbastanza limitata.
> Visto che cmq dovrei dotare il programma anche di un interfaccia grafica
> vedro se le gui disponibili hanno queste funzioni.
>
Con una GUI le cose si complicano, cerca di fare un passo alla volta.
> grazie
>
> Luca
>
Manlio Perillo
Maggiori informazioni sulla lista
Python