2009-06-27 7 views
4

Chaque fois que j'utilise la recette au http://code.activestate.com/recipes/134892/, je n'arrive pas à la faire fonctionner. Il jette toujours l'erreur suivante:La lecture d'un seul caractère (style getch) en Python ne fonctionne pas sous Unix

Traceback (most recent call last): 
    ... 
    old_settings = termios.tcgetattr(fd) 
termios.error: (22, 'Invalid argument) 

Ma meilleure pensée est qu'il est parce que je suis en train de courir dans Eclipse si termios est de lancer un ajustement sur le descripteur de fichier.

Répondre

9

Cela fonctionne sur Ubuntu 8.04.1, Python 2.5.2, je ne reçois pas une telle erreur. Peut-être que vous devriez l'essayer à partir de la ligne de commande, eclipse peut utiliser son propre stdin, je reçois exactement la même erreur si je l'exécute à partir de Wing IDE, mais à partir de la ligne de commande cela fonctionne très bien. Raison est que IDE par exemple Wing utilise sa propre classe netserver.CDbgInputStream comme sys.stdin alors sys.stdin.fileno est zéro, c'est pourquoi l'erreur. Fondamentalement IDE stdin n'est pas un téléscripteur (impression sys.stdin.isatty() est faux)

class _GetchUnix: 
    def __init__(self): 
     import tty, sys 

    def __call__(self): 
     import sys, tty, termios 
     fd = sys.stdin.fileno() 
     old_settings = termios.tcgetattr(fd) 
     try: 
      tty.setraw(sys.stdin.fileno()) 
      ch = sys.stdin.read(1) 
     finally: 
      termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) 
     return ch 


getch = _GetchUnix() 

print getch() 
+0

L'exécution à partir de la ligne de commande a permis de résoudre le problème. –

+0

+100 IMPRESSIONNANT! Merci! – hasen

+0

Ne fonctionne pas avec les touches fléchées - laisse des caractères supplémentaires dans le tampon. –

3

Mettre la borne en mode brut n'est pas toujours une bonne idée. En fait, il suffit d'effacer bit ICANON. Voici une autre version de getch() avec prise en charge du délai d'attente:

import tty, sys, termios 
import select 

def setup_term(fd, when=termios.TCSAFLUSH): 
    mode = termios.tcgetattr(fd) 
    mode[tty.LFLAG] = mode[tty.LFLAG] & ~(termios.ECHO | termios.ICANON) 
    termios.tcsetattr(fd, when, mode) 

def getch(timeout=None): 
    fd = sys.stdin.fileno() 
    old_settings = termios.tcgetattr(fd) 
    try: 
     setup_term(fd) 
     try: 
      rw, wl, xl = select.select([fd], [], [], timeout) 
     except select.error: 
      return 
     if rw: 
      return sys.stdin.read(1) 
    finally: 
     termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) 

if __name__ == "__main__": 
    print getch() 
Questions connexes