execve_hook/TERMINAL_EVENTS.md

5.4 KiB
Raw Blame History

终端交互事件捕获功能

概述

现在socket通信系统已支持捕获和传输所有终端交互事件包括

  • 键盘输入
  • 鼠标点击、移动、滚轮
  • 终端窗口大小变化

新增消息类型

typedef enum {
    MSG_TYPE_INIT = 1,              // 初始化连接
    MSG_TYPE_WINDOW_SIZE_UPDATE = 2, // 窗口大小更新
    MSG_TYPE_SERVER_RESPONSE = 3,    // 服务器响应
    MSG_TYPE_CLOSE = 4,              // 关闭连接
    MSG_TYPE_TERMINAL_INPUT = 5,     // 终端输入(原始数据)
    MSG_TYPE_TERMINAL_OUTPUT = 6,    // 终端输出
    MSG_TYPE_MOUSE_EVENT = 7,        // 鼠标事件(结构化)
    MSG_TYPE_KEY_EVENT = 8           // 键盘事件(结构化)
} MessageType;

鼠标事件结构

typedef struct {
    uint32_t event_type;  // 1=按下, 2=释放
    uint32_t button;      // 鼠标按钮1=左键2=中键3=右键)
    uint32_t x;           // X坐标
    uint32_t y;           // Y坐标
    uint32_t modifiers;   // 修饰键Shift, Ctrl, Alt等
} MouseEvent;

工作原理

1. 鼠标跟踪启用

客户端通过ANSI转义序列启用终端的鼠标跟踪

// 启用X11鼠标报告 + SGR扩展模式
const char* enable_seq = "\033[?1000h\033[?1002h\033[?1006h";
write(STDOUT_FILENO, enable_seq, strlen(enable_seq));

2. 事件解析

客户端监听标准输入的ANSI转义序列

鼠标事件格式:\033[<b;x;yM 或 \033[<b;x;ym
- b: 按钮编码 + 修饰键
- x: 列坐标
- y: 行坐标  
- M: 按下
- m: 释放

3. 独立输入线程

专门的线程持续监听stdin

static void* terminal_input_thread(void* arg) {
    while (!g_should_exit) {
        // 使用poll等待输入
        poll(&pfd, 1, 100);
        
        // 读取数据
        read(STDIN_FILENO, buf, sizeof(buf));
        
        // 解析鼠标事件或发送原始输入
        if (is_mouse_event(buf)) {
            parse_and_send_mouse_event();
        } else {
            send_terminal_input();
        }
    }
}

4. Go服务端处理

服务端接收并记录所有交互事件:

switch msgType {
case MsgTypeTerminalInput:
    logging.Debug("收到终端输入: %d bytes", len(payload))
    
case MsgTypeMouseEvent:
    event := parseMouseEvent(payload)
    logging.Info("鼠标事件 - 类型:%d, 按钮:%d, 位置:(%d,%d)", 
        event.EventType, event.Button, event.X, event.Y)
}

线程架构

客户端现在运行4个线程

  1. 主线程:发送初始化消息,等待其他线程
  2. 响应监听线程:接收服务器响应
  3. 窗口监控线程:监听 SIGWINCH 信号(使用条件变量驱动,零 CPU 占用等待)
  4. 输入监听线程监听stdin捕获键盘和鼠标

使用示例

编译

cd execve_hook
make clean
make

测试

  1. 启动服务端:
cd go_service  
sudo ./build/bash_go_service-amd64 daemon
  1. 运行测试程序:
cd execve_hook
./build/test_window_resize
  1. 在程序运行时:

    • 调整终端窗口大小
    • 点击鼠标
    • 输入键盘字符
  2. 观察服务端日志输出所有事件

支持的鼠标模式

X11鼠标报告模式 (\033[?1000h)

  • 捕获鼠标按键按下/释放
  • 基本的鼠标位置报告

单元格运动跟踪 (\033[?1002h)

  • 捕获鼠标移动(按下按钮时)
  • 拖拽操作支持

SGR扩展模式 (\033[?1006h)

  • 更好的大坐标支持超过223列/行)
  • 更清晰的按下/释放区分

应用场景

1. 用户行为分析

记录用户在终端中的所有操作,用于:

  • 问题诊断
  • 使用习惯分析
  • 操作回放

2. 交互式帮助

根据用户的鼠标位置提供上下文帮助

3. 终端UI增强

捕获鼠标点击实现:

  • 可点击的链接
  • 交互式菜单
  • 拖放操作

4. 会话记录

完整记录终端会话,包括:

  • 所有输入输出
  • 鼠标操作
  • 窗口调整

性能考虑

  • 窗口监听:使用条件变量事件驱动,零 CPU 占用,即时响应
  • 输入延迟: < 10mspoll超时100ms
  • CPU使用: 每个线程休眠或等待条件变量不占用CPU
  • 内存: 每个连接 < 100KB
  • 带宽: 鼠标事件20字节键盘事件按实际输入

兼容性

终端支持

支持以下现代终端:

  • ✓ xterm
  • ✓ gnome-terminal
  • ✓ konsole
  • ✓ iTerm2
  • ✓ Windows Terminal
  • ✓ alacritty
  • ✓ kitty
  • ⚠ screen部分支持
  • ⚠ tmux需要配置

禁用鼠标跟踪

如果不需要鼠标功能,可以注释掉:

// enable_mouse_tracking(STDOUT_FILENO);

调试

开启DEBUG模式查看所有事件

make DEBUG=1
./build/test_window_resize

输出示例:

Mouse event: type=1, button=1, pos=(25,10)
Mouse event: type=2, button=1, pos=(25,10)
Terminal input: 5 bytes
Window size update sent to server

注意事项

  1. 非TTY环境如果stdin不是TTY鼠标跟踪会自动禁用
  2. 信号处理正确处理SIGINT/SIGTERM以清理终端状态
  3. 原始模式如需完全控制可启用raw模式
  4. 终端恢复:程序退出时应恢复终端原始设置

扩展建议

  1. 触摸事件:支持触摸屏输入
  2. 手势识别:识别常见鼠标手势
  3. 快捷键绑定:自定义快捷键处理
  4. 剪贴板集成:捕获复制粘贴操作
  5. 焦点事件:终端获得/失去焦点通知