【问题标题】:KEY_RESIZE not returned from getch() when xterm is resized调整 xterm 大小时,不会从 getch() 返回 KEY_RESIZE
【发布时间】:2019-06-28 10:43:46
【问题描述】:

我在带有标准 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() 的原因。

但是,这些 un​​setenv() 调用显然在 2019 年无效。确实,当我尝试在导入 readline 后打印出所有环境变量时,我在输出中看不到对“LINES”或“COLUMNS”的引用。不过,我还是把这些对 unsetenv() 的调用放在那里,看看它是否会做任何有用的事情。

有谁知道如何让 curses getch() 方法返回 KEY_RESIZE,就像在 Python 3.7 中导入 readline 模块时应该返回的那样?

【问题讨论】:

    标签: python python-3.x readline curses


    【解决方案1】:

    在使用 strace 进行快速检查时,我可以看到在 ncurses 将其处理程序设置为 SIGWINCH 之后,某些东西将 SIGWINCH 处理程序重置回 SIG_DFL(无操作)。 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
    

    This change in 2016 似乎与您所看到的问题有关(顺便说一下,似乎引入了一个新问题而没有解决旧问题)。如果为 readline 添加的信号处理程序没有链接到 ncurses 中的信号处理程序,则后者不再使用并且 ncurses 无法返回 KEY_RESIZE。另外——如果 readline 先设置 its 处理程序,ncurses 将不会设置它的处理程序。

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

    可以通过加载 ncurses(或 ncursesw!)库并调用 newterm 然后调用 @ 来解决此问题987654338@,在 import 语句之前执行此操作。这似乎是很多工作。我建议打开一个错误报告。

    供参考:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-20
      • 1970-01-01
      • 1970-01-01
      • 2012-03-22
      • 2019-06-17
      相关资源
      最近更新 更多