在 ncurses 繪製的 UI 中嵌入一個「真正的終端」區域:用戶輸入命令 → 轉發給 Shell → 捕獲輸出 → 顯示在 UI 區域。
普通管道 popen("ls") 無法支援交互式命令(如 vim、top、Tab 補全)。必須使用 PTY (Pseudo-Terminal),它模擬一個真實終端設備,擁有主從兩端:
#include
#include
#include
int master_fd, slave_fd;
pid_t child_pid;
// 1. 打開 PTY 對
if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) != 0) {
perror("openpty");
exit(1);
}
// 2. Fork 子進程運行 Shell
child_pid = forkpty(&master_fd, NULL, NULL, NULL);
if (child_pid == 0) {
// 子進程:執行 Shell
execl("/bin/bash", "bash", "-i", NULL); // -i 交互模式
_exit(1);
}
// 3. 父進程:設置非阻塞,接入事件循環
fcntl(master_fd, F_SETFL, O_NONBLOCK);
// 4. ncurses 主循環中
while (running) {
// 處理鍵盤輸入
int ch = getch();
if (ch != ERR) write(master_fd, &ch, 1);
// 讀取 Shell 輸出
char buf[1024];
int n = read(master_fd, buf, sizeof(buf));
if (n > 0) {
// 將 buf 解析為 ANSI 轉義序列,渲染到 ncurses 窗口
render_terminal_output(buf, n);
}
// ... 其他 UI 邏輯
}
| 難點 | 方案 |
|---|---|
| ANSI 轉義序列解析 | 使用 libvterm 或 libtsm 庫,將字節流轉為網格字符+屬性 |
| 窗口大小同步 | ncurses SIGWINCH 處理器中 ioctl(master_fd, TIOCSWINSZ, &winsize) |
| 信號傳遞 | 父進程捕獲 SIGINT/SIGTSTP 等,kill(child_pid, sig) 轉發 |
| UTF-8 寬字符 | ncursesw (libncursesw) + 設置 locale setlocale(LC_ALL, "") |
純 C 手寫 PTY 解析器工作量極大,強烈建議直接集成 libvterm 或改用 Web 技術棧。