Чтение одного символа (стиль getch) в Python не работает в Unix

Каждый раз, когда я использую рецепт на http://code.activestate.com/recipes/134892/ Кажется, я не могу заставить его работать. Всегда выдает следующую ошибку:

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

Моя лучшая мысль заключается в том, что это потому, что я запускаю его в Eclipse, поэтому termios закатывает истерику по поводу файлового дескриптора.


person Evan Fosmark    schedule 27.06.2009    source источник


Ответы (2)


Это работает на Ubuntu 8.04.1, Python 2.5.2, я не получаю такой ошибки. Возможно, вам следует попробовать это из командной строки, eclipse может использовать свой собственный стандартный ввод, я получаю точно такую ​​​​же ошибку, если запускаю его из Wing IDE, но из командной строки он отлично работает. Причина в том, что IDE, например, Wing, использует собственный класс netserver.CDbgInputStream как sys.stdin, поэтому sys.stdin.fileno равен нулю, поэтому возникает ошибка. В основном IDE stdin не является tty (print sys.stdin.isatty() имеет значение 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()
person Anurag Uniyal    schedule 27.06.2009
comment
Не работает со стрелками - оставляет лишние символы в буфере. - person anatoly techtonik; 01.05.2011

Перевод терминала в необработанный режим не всегда является хорошей идеей. На самом деле достаточно сбросить бит ICANON. Вот еще одна версия getch() с поддержкой тайм-аута:

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()
person Vitja Makarov    schedule 30.07.2013