ncurses中fork后WINDOW内箭头键码异常问题咨询
问题:ncurses中fork+execl启动vim后,WINDOW的箭头键码异常
在ncurses的自定义WINDOW中执行fork+execl启动vim后,按下上箭头键原本返回259(KEY_UP),但返回变为65(ASCII 'A');若直接用stdscr运行相同程序,上箭头键从一开始就返回65。仅fork执行简单循环则无此问题,怀疑与execl有关。
#include <curses.h> #include <sys/ioctl.h> #include <sys/wait.h> #include <unistd.h> #include <stdlib.h> void openVim() { pid_t pid = fork(); if (pid < 0) {} else if (pid == 0) { execl("/usr/bin/vim", "/usr/bin/vim", NULL); exit(0); } else { wait(NULL); } } int main() { initscr(); noecho(); int ch = 0; WINDOW* mainWin = newwin(10,10,0,0); keypad(mainWin, TRUE); while ((ch = wgetch(mainWin)) != 'q') { wclear(mainWin); if (ch == 'V') openVim(); else mvwprintw(mainWin, 0, 0, "%i - %c", ch, ch); wrefresh(mainWin); } delwin(mainWin); endwin(); return 0; }
原因分析
- 终端模式被外部程序修改未恢复:ncurses初始化时会将终端切换到
cbreak模式,并通过keypad(win, TRUE)开启特殊键码解析(如箭头键返回KEY_UP=259)。但vim运行时会将终端改回默认的canonical模式,此时箭头键会被解析为转义序列(上箭头对应^[[A,第一个字符就是ASCII 65)。 - 父进程等待vim退出后,终端模式已经被修改,但ncurses并未自动恢复原有的程序模式,导致后续
wgetch只能读到转义序列的单个字符,而非ncurses定义的特殊键码。 - 仅fork不执行execl时,子进程未修改终端模式,因此父进程的键码解析正常;使用stdscr时默认未开启
keypad(stdscr, TRUE),所以从一开始就只能读到转义序列的字符。
解决方法
在vim退出后,手动恢复ncurses的终端模式并重新激活窗口的键码解析:
修改后的代码示例
#include <curses.h> #include <sys/ioctl.h> #include <sys/wait.h> #include <unistd.h> #include <stdlib.h> void openVim() { pid_t pid = fork(); if (pid < 0) {} else if (pid == 0) { execl("/usr/bin/vim", "/usr/bin/vim", NULL); exit(0); } else { wait(NULL); // 恢复ncurses的程序终端模式 reset_prog_mode(); // 刷新全局屏幕确保模式生效 refresh(); } } int main() { initscr(); noecho(); int ch = 0; WINDOW* mainWin = newwin(10,10,0,0); keypad(mainWin, TRUE); while ((ch = wgetch(mainWin)) != 'q') { wclear(mainWin); if (ch == 'V') { openVim(); // 重新启用窗口的键码解析 keypad(mainWin, TRUE); } else { mvwprintw(mainWin, 0, 0, "%i - %c", ch, ch); } wrefresh(mainWin); } delwin(mainWin); endwin(); return 0; }
关键步骤说明
reset_prog_mode():将终端恢复到ncurses初始化时设置的程序模式,覆盖vim修改的默认模式。refresh():触发ncurses重新输出终端控制序列,确保模式变更生效。- 重新调用
keypad(mainWin, TRUE):确保自定义窗口的特殊键码解析功能重新激活。
内容的提问来源于stack exchange,提问作者Iugin74
相关产品推荐
相关产品推荐

