A leitura de um único caractere (estilo getch) em Python não está funcionando em Unix

StackOverflow https://stackoverflow.com/questions/1052107

  •  20-08-2019
  •  | 
  •  

Pergunta

Toda vez que eu usar a receita em http://code.activestate.com/recipes/134892 / eu não consigo fazê-lo funcionar. É sempre lança o seguinte erro:

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

O meu melhor pensamento é que é porque eu estou correndo em Eclipse para termios está jogando um ajuste sobre o descritor de arquivo.

Foi útil?

Solução

Este está trabalhando em Ubuntu 8.04.1, Python 2.5.2, recebo nenhum tal erro. Pode ser que você deve experimentá-lo a partir da linha de comando, eclipse pode estar usando seu próprio stdin, eu recebo exatamente o mesmo erro se eu executá-lo a partir Ala IDE, mas a partir de linha de comando que funciona muito bem. A razão é que IDE por exemplo Ala está usando lá própria classe netserver.CDbgInputStream como sys.stdin assim sys.stdin.fileno é zero, é por isso que o erro. Basicamente IDE stdin não é um tty (sys.stdin.isatty print () é False)

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()

Outras dicas

Colocando o terminal em modo RAW não é sempre uma boa idéia. Na verdade, é o suficiente para pouco ICANON clara. Aqui está outra versão do getch () com o apoio timeout:

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()
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top