You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从curses进程fork交互式程序引发键盘输入干扰问题排查

Curses界面与feh进程的按键冲突问题

问题描述

在curses界面中,用户通过fork启动feh实例查看图片,curses本身支持hjkl导航,要求查看图片时不阻断curses的操作。现有实现代码如下:

void display_file(void) {
    def_prog_mode();
    endwin();

    pid_t pid = fork();
    if (!pid) {
        execl("/usr/bin/feh", "feh", "/home/abc/main/violet.jpg", NULL);
    }

    reset_prog_mode();
    wrefresh(state_of_curses.a_win);
    wrefresh(state_of_curses.b_win);
}

当前出现异常:当feh是活动窗口时,hjkl仅控制feh(符合预期);但切换回curses终端窗口时,输入的按键会随机发送给curses或feh,比如hjkl本该控制curses导航,却可能触发feh里的图片翻页。

备注:若通过bash将feh后台运行(执行execl("/bin/bash", "bash", "-c", "feh /home/abc/main/violet.jpg &", NULL);),程序可达到预期效果。

问题原因

  • 父子进程共享终端资源:fork操作后,父进程(curses程序)和子进程(feh)会共享同一个终端的标准输入、输出流。当终端处于激活状态时,内核会将输入的按键随机分配给其中一个进程,导致按键事件被两个进程争抢,出现混乱。
  • 终端控制权未彻底分离:调用endwin()只是让curses暂时释放终端的显示控制权,但父进程仍在监听终端输入;子进程feh同样在监听同一个终端的输入,两者的输入监听逻辑产生冲突。

正确实现方式

方式一:通过bash将feh放入后台运行

这是备注中提到的有效方式,通过bash的后台执行符号&让feh脱离当前终端的输入连接,不再与父进程的curses争抢按键事件。修改后的代码:

void display_file(void) {
    def_prog_mode();
    endwin();

    pid_t pid = fork();
    if (!pid) {
        // 通过bash启动feh并放入后台
        execl("/bin/bash", "bash", "-c", "feh /home/abc/main/violet.jpg &", NULL);
        _exit(1); // 确保execl失败后子进程退出
    }

    reset_prog_mode();
    wrefresh(state_of_curses.a_win);
    wrefresh(state_of_curses.b_win);
}

方式二:子进程调用setsid()脱离原终端

在子进程中调用setsid()创建新的会话,让子进程成为会话首进程,彻底脱离原终端的控制,不再共享终端输入资源。代码示例:

void display_file(void) {
    def_prog_mode();
    endwin();

    pid_t pid = fork();
    if (!pid) {
        // 创建新会话,脱离原终端的控制
        setsid();
        execl("/usr/bin/feh", "feh", "/home/abc/main/violet.jpg", NULL);
        _exit(1);
    }

    reset_prog_mode();
    wrefresh(state_of_curses.a_win);
    wrefresh(state_of_curses.b_win);
}

方式三:父进程等待feh退出后再恢复curses

如果不需要在feh运行时操作curses,可以让父进程等待feh进程退出后,再恢复curses界面。这种方式下,feh运行期间终端输入只会发送给feh,不会产生冲突:

void display_file(void) {
    def_prog_mode();
    endwin();

    pid_t pid = fork();
    if (!pid) {
        execl("/usr/bin/feh", "feh", "/home/abc/main/violet.jpg", NULL);
        _exit(1);
    } else {
        // 等待feh进程执行完毕
        waitpid(pid, NULL, 0);
    }

    reset_prog_mode();
    wrefresh(state_of_curses.a_win);
    wrefresh(state_of_curses.b_win);
}

内容的提问来源于stack exchange,提问作者user1121974

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 02:50:08