调整xterm的大小时,getch()不返回KEY_RESIZE

时间:2019-02-04 16:32:15

标签: python python-3.x readline curses

我在带有标准readline和curses模块的Debian Linux 9机器上使用Python 3.7。在xterm中运行并调整xterm的大小时,以下代码应输出“ True”:

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)

但是,输出为'False',表明对getch()的调用未返回KEY_RESIZE。实际上,它返回的是-1。

请注意,如果我不导入readline模块,则代码将按预期工作。

在谷歌搜索这个问题的解决方案中,我遇到了2016年的一篇文章,指出导入readline和curses模块时存在冲突。基本上,readline模块会设置“ LINES”和“ COLUMNS”环境变量,这会干扰ncurses的内置SIGWINCH信号处理程序,这最终会导致getch()在调整终端大小时最终返回KEY_RESIZE。这就是为什么我在那里调用unsetenv()的原因。

但是,那些unsetenv()调用显然在2019年无效。确实,当我尝试在导入readline之后打印出所有环境变量时,在输出中没有看到对“ LINES”或“ COLUMNS”的引用。无论如何,我还是将那些调用放在了unsetenv()上,以查看它是否有帮助。

有人知道如何获得curses getch()方法以返回KEY_RESIZE,就像在python 3.7中也导入readline模块时那样吗?

1 个答案:

答案 0 :(得分:1)

通过strace进行的快速检查,我可以看到在ncurses将其SIGWINCH的处理程序设置为SIG_DFL之后,将SIGWINCH处理程序重置为_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;

readline注释文档

/* 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

但是,在阅读libpython3.5的源代码时,开发人员似乎没有考虑到这一点:

KEY_RESIZE

This change in 2016似乎与您遇到的问题有关(顺便说一句,看起来好像是在没有解决旧问题的情况下引入了新问题)。如果为readline添加的信号处理程序未在ncurses中链接到一个信号处理程序,则后者不再使用,并且ncurses无法返回import readline。另外,如果readline首先设置 处理程序,则ncurses不会设置其处理程序。

似乎是后者: initscr 调用模块初始化,该初始化设置了信号处理程序。当Python curses包装器调用 PyInit__curses 时,将初始化ncurses信号处理程序。在 import curses (在newterm上调用的函数)中不会这样做,因为那样会清除屏幕。另外,如果调用 newterm (不会清除屏幕),ncurses将初始化其信号处理程序,但是Python不会这样做。

可以 通过加载ncurses(或ncursesw!)库并调用 endwin ,然后调用 > import ,然后在 canvas.js 语句之前执行此操作。这似乎是很多工作。我建议打开一个错误报告。

供参考:

相关问题