getch() возвращает неправильные символы

У меня возникли проблемы с функцией getch() библиотеки curses. Предположим, у нас есть следующая программа:

import curses

def main(stdscr):
    while 1:
        c = stdscr.getch()
        stdscr.addstr(chr(c) + ": " + str(c) + "\n")
curses.wrapper(main)

Давайте запустим это и введем следующие символы: a, <backspace>, œ

Тогда вывод:

a: 97
ć: 263
Å: 197

Как видите, символ a взят правильно. Однако другие нет. Я просто хочу получить backspace '\b' и символ юникода œ, но мы получаем кое-что еще.

Почему getch() ведет себя таким образом и как добиться желаемого поведения?

ИЗМЕНИТЬ:

Позвольте мне подчеркнуть, что проблема не в печати символов, а в чтении символов. А именно, запуск stdscr.addstr('œ') действительно печатает œ.


person Chiel ten Brinke    schedule 03.03.2014    source источник
comment
Какая версия питона?   -  person hivert    schedule 04.03.2014
comment
Версия питона 3.3   -  person Chiel ten Brinke    schedule 04.03.2014
comment
Похоже на плохое взаимодействие между кодировками - какие переменные для вашей локали установлены, и выполняете ли вы какие-либо настройки для локали в своем коде Python?   -  person twalberg    schedule 04.03.2014
comment
Я не делаю никаких настроек кодирования. Запуск locale.getpreferredencoding() дает 'UTF-8'.   -  person Chiel ten Brinke    schedule 04.03.2014
comment
Следовали ли вы примечанию на странице docs.python.org/3.3/library/curses.html< /а> ?   -  person Mike C    schedule 04.03.2014
comment
Вызов locale.setlocale(locale.LC_ALL, '') в начале не меняет вывод.   -  person Chiel ten Brinke    schedule 04.03.2014
comment
Отредактировал вопрос, чтобы подчеркнуть, что проблема связана с чтением символов, а не с записью.   -  person Chiel ten Brinke    schedule 04.03.2014


Ответы (1)


В Python 3.3 была добавлена ​​функция window.get_wch. Он правильно обрабатывает все эти символы.

Если вы прочтете документацию по window.getch, вы обратите внимание, что он не претендует на поддержку печатных символов, отличных от ASCII. Он просто документирует, что может обрабатывать нажатия клавиш, отличных от ASCII, таких как функциональные клавиши или клавиши клавиатуры.

ИЗМЕНИТЬ:

При использовании window.get_wch символы (например, 'a', 'ă', '好', '\n' или '\t') возвращаются в виде строк. Функциональные клавиши возвращаются как целые числа (например, 265 или 274). Вот новый пример для запуска. Попробуйте поиграть с разными ключами, которые вы хотите распознать, чтобы увидеть, как возвращаются их значения. Формат печатаемых данных: [repr]: [type].

def main(stdscr):
    while 1:
        c = stdscr.get_wch()
        stdscr.addstr("%s: %s\n" % (repr(c), type(c)))

Вот что я получаю, когда ввожу a, œ, <enter>, <backspace> и <F1>:

'a': <class 'str'>
'œ': <class 'str'>
'\n': <class 'str'>
'\x7f': <class 'str'>
265: <class 'int'>

Если возвращается целое число, вы можете узнать имя нажатой клавиши через curses.keyname:

>>> curses.keyname(265)
b'KEY_F(1)'
person tsroten    schedule 04.03.2014
comment
Это действительно работает для œ, но символы <backspace><delete>, <F1>, <F2>,... и т. д.) по-прежнему обрабатываются неправильно. - person Chiel ten Brinke; 04.03.2014
comment
Я добавил в ответ информацию о возвращаемых значениях. - person tsroten; 04.03.2014
comment
Для меня ваш скрипт возвращает '\n': <class 'str'>, 330: <class 'int'> и 265: <class 'int'> при вводе <enter>, <delete> и <F1>. Так что <delete> все равно трактуется неправильно, а у вас видимо работает. - person Chiel ten Brinke; 04.03.2014
comment
Вы получили 330 при вводе <delete>. curses.keyname(330) возвращает 'KEY_DC'. - person tsroten; 05.03.2014
comment
Backspace/Delete работают по-разному на разных компьютерах. Я использую Mac OS X, где мой Backspace (с надписью Delete) возвращает '\x7f' -- значение ASCII для Delete. Ваш ключ удаления вернул 330, что соответствует имени ключа 'KEY_DC'. Константа KEY_DC относится к символу удаления. Что вы получаете, когда нажимаете <backspace>? - person tsroten; 05.03.2014
comment
Это также зависит от настроек терминала. Здесь может помочь curses.erasechar. erasechar возвращает b'\x7f' для меня. - person tsroten; 05.03.2014
comment
Да, действительно curses.keyname возвращает правильные имена для <delete> и <backspace>. Тем не менее, я ожидаю (и должен) получить b'\x7f' в первую очередь при нажатии кнопки удаления вместо получения какого-либо другого числа. Точно так же при нажатии backspace мне нужен символ '\b'. - person Chiel ten Brinke; 05.03.2014
comment
Для меня curses.erasechar() также возвращает b'\x7f'. - person Chiel ten Brinke; 05.03.2014
comment
В первую очередь извиняюсь, что ранее сделал опечатку, когда сказал, что нажал удалить и получил '\x7f'. Я должен был сказать «возврат». Во-вторых, ключ <delete> не возвращает и не должен возвращать '\x7f'. '\x7f' — это символ ASCII, а не имя ключа. Клавиша удаления не соответствует символу ASCII, поэтому не следует этого ожидать. Вы должны ожидать, что он вернет curses.KEY_DC. В-третьих, способ обработки возврата — это не ожидать '\b' (или '\x08'), а ожидать того, что возвращает curses.erasechar(). Надеюсь, это поможет прояснить ситуацию. - person tsroten; 05.03.2014
comment
Если вы должны иметь '\b', тогда да, вам нужно будет обработать этот случай вручную. На некоторых компьютерах и терминалах '\b' может возвращаться <backspace>, поэтому лучше проверить curses.erasechar(). Клавишу <delete>, вероятно, не следует рассматривать как '\x7f' (см. Википедию о символе удаления). -- не key), но вы можете справиться с этим, если вам нужно. - person tsroten; 05.03.2014