KEY_RESIZE не возвращается из getch () при изменении размера xterm - PullRequest
0 голосов
/ 04 февраля 2019

Я использую Python 3.7 на Debian Linux 9 box со стандартными модулями readline и curses.Следующий код должен вывести «True» при запуске внутри xterm и при изменении размера xterm:

import readline
import os
import curses

terminal_resized = False

def main(stdscr):
    global terminal_resized
    ch = stdscr.getch()
    if ch == curses.KEY_RESIZE:
        terminal_resized = True

os.unsetenv('LINES')
os.unsetenv('COLUMNS')

curses.wrapper(main)
print(terminal_resized)

Однако вывод - «Ложь», указывая, что вызов getch () не возвращает KEY_RESIZE.Действительно, вместо этого возвращается -1.

Обратите внимание, что код работает должным образом, если я не импортирую модуль readline.

В Googling для решения этой проблемы я обнаружил сообщениес 2016 года указывает на наличие конфликта при импорте модулей readline и curses.По сути, модуль readline устанавливает переменные окружения 'LINES' и 'COLUMNS', и это мешает встроенному обработчику сигналов SIGWINCH для ncurses, который в конечном счете отвечает за getch (), возвращая KEY_RESIZE при изменении размера терминала.Это причина, по которой у меня есть эти вызовы unsetenv ().

Однако эти вызовы unsetenv () явно не действуют в 2019 году. Действительно, когда я пытаюсь распечатать все переменные окружения послеимпортируя readline, я не вижу ссылки на 'LINES' или 'COLUMNS' в выводе.Тем не менее я в любом случае помещаю эти вызовы в unsetenv (), чтобы посмотреть, будет ли он полезен.

Кто-нибудь знает, как заставить метод curches getch () возвращать KEY_RESIZE, как это должно быть, когдамодуль readline также импортируется в Python 3.7?

1 Ответ

0 голосов
/ 05 февраля 2019

При быстрой проверке с помощью strace я вижу, что что-то сбрасывает обработчик SIGWINCH обратно в SIG_DFL (без действий) после того, как ncurses устанавливает его обработчик для SIGWINCH.Таблица символов readline имеет следующие соответствующие точки входа:

_rl_block_sigwinch
_rl_redisplay_after_sigwinch
_rl_release_sigwinch
_rl_sigwinch_resize_terminal
rl_catch_sigwinch

Документация для заметок readline

    o A new variable, rl_catch_sigwinch, is available to application
      writers to indicate to readline whether or not it should install its
      own signal handler for SIGWINCH, which will chain to the calling
      applications's SIGWINCH handler, if one is installed;

Однако, читая исходный код libpython3.5 , онПохоже, что разработчик не учел это:

/* Helper to initialize GNU readline properly. */

static void
setup_readline(readlinestate *mod_state)
{
...
    rl_readline_name = "python";
    /* Force rebind of TAB to insert-tab */
    rl_bind_key('\t', rl_insert);
    /* Bind both ESC-TAB and ESC-ESC to the completion function */
    rl_bind_key_in_map ('\t', rl_complete, emacs_meta_keymap);
    rl_bind_key_in_map ('\033', rl_complete, emacs_meta_keymap);
#ifdef HAVE_RL_RESIZE_TERMINAL
    /* Set up signal handler for window resize */
    sigwinch_ohandler = PyOS_setsig(SIGWINCH, readline_sigwinch_handler);
#endif

Это изменение в 2016 , по-видимому, связано с проблемой, с которой вы столкнулись (случайно, это выглядит как новая проблема)был введен без решения старого).Если обработчик сигнала, добавленный для readline, не соединяется с обработчиком в ncurses, то последний больше не используется и ncurses не может вернуть KEY_RESIZE.Кроме того, если readline устанавливает сначала свой обработчик , ncurses не будет устанавливать его обработчик.

Последний вариант выглядит так: import readline вызывает инициализацию модуля, которая устанавливает обработчик сигнала.Обработчик сигнала ncurses инициализируется, когда оболочка проклятий Python вызывает initscr.Это не сделано в PyInit__curses (функция вызывается import curses), потому что это очистит экран.В качестве альтернативы, ncurses инициализирует свой обработчик сигнала, если будет вызван newterm (что не очистит экран), но Python этого не сделает.

You может обойти эту проблему, загрузив библиотеку ncurses (или ncursesw!) и вызвав newterm, а затем endwin, выполнив это до import заявлений.Это похоже на большую работу.Я бы рекомендовал открыть отчет об ошибке.

Для справки:

...