KEY_RESIZE not returned from getch() when xterm is resized

末鹿安然 提交于 2019-12-11 09:38:10

问题


I am using Python 3.7 on a Debian Linux 9 box with the standard readline and curses modules. The following code should output 'True' when run inside an xterm and the xterm is resized:

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)

However, the output is 'False', indicating that the call to getch() is not returning KEY_RESIZE. Indeed, it is returning -1 instead.

Note that the code works as expected if I don't import the readline module.

In Googling for solutions to this problem, I encountered a post from 2016 indicating that there's a conflict when importing both the readline and curses modules. Basically, the readline module sets the 'LINES' and 'COLUMNS' environment variables and this interferes with the built-in SIGWINCH signal handler of ncurses which is what is ultimately responsible for getch() returning KEY_RESIZE when the terminal is resized. This is the reason why I have those calls to unsetenv() in there.

However, those unsetenv() calls apparently have no effect in 2019. Indeed, when I try to print out all of the environment variables after importing readline I see no reference to 'LINES' or 'COLUMNS' in the output. I put those calls to unsetenv() in there anyway, though, to see if it would do anything useful.

Does anybody know how to get the curses getch() method to return KEY_RESIZE like it is supposed to when the readline module is also imported in Python 3.7?


回答1:


In a quick check with strace, I can see that something resets the SIGWINCH handler back to SIG_DFL (no action) after ncurses sets its handler for SIGWINCH. The symbol table of readline has these relevant entrypoints:

_rl_block_sigwinch
_rl_redisplay_after_sigwinch
_rl_release_sigwinch
_rl_sigwinch_resize_terminal
rl_catch_sigwinch

The documentation for readline notes

    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;

However, reading the source for libpython3.5, it appears that the developer did not take that into account:

/* 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 appears to be related to the problem you're seeing (offhand, it looks like a new problem was introduced without solving the old one). If the signal-handler added for readline doesn't chain over to the one in ncurses, then the latter's no longer used and ncurses cannot return KEY_RESIZE. Also—if readline sets up its handler first, ncurses won't set up its handler.

The latter seems to be the case: the import readline calls the module initialization which sets up a signal handler. The ncurses signal handler is initialized when the Python curses wrapper calls initscr. That's not done in PyInit__curses (the function called on import curses) because that would clear the screen. Alternatively, ncurses would initialize its signal handler if newterm was called (which would not clear the screen), but Python doesn't do that.

You could work around this by loading the ncurses (or ncursesw!) library and calling newterm followed by endwin, doing that before the import statements. That seems like a lot of work. I'd recommend opening a bug report.

For reference:

  • #23735 - Readline not adjusting width after resize with 6.3
  • Signal Handlers, in ncurses documentation.


来源:https://stackoverflow.com/questions/54520435/key-resize-not-returned-from-getch-when-xterm-is-resized

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!