按键触发硬件中断,内核驱动解码为扫描码,输入子系统转换为统一事件格式,经用户空间服务(如X/Wayland)传递给应用程序。
硬件层:信号生成
- 键盘硬件
- 机械键盘通过金属触点闭合产生电流信号;薄膜键盘通过电路板矩阵扫描定位按键位置。
- 每个按键对应唯一扫描码(Scan Code)(如
KEY_A
的扫描码为0x1E
),由键盘控制器转换为数字信号。
- 接口传输
- 通过USB/PS2接口将信号发送至计算机,USB键盘使用HID协议(Human Interface Device)封装数据。
内核层:信号处理
中断触发(Interrupt)
- 键盘控制器通过IRQ(中断请求)通知CPU(如IRQ1对应PS2键盘)。
- CPU暂停当前任务,调用预设的中断处理程序。
驱动层解码
- 键盘驱动(如
drivers/hid/hid-generic.ko
)解析扫描码,转换为Linux输入事件类型:struct input_event { struct timeval time; // 时间戳 __u16 type; // 事件类型(如EV_KEY) __u16 code; // 键码(如KEY_ENTER) __s32 value; // 状态(0=释放, 1=按下, 2=长按) };
- 键码定义在
linux/input-event-codes.h
(如KEY_A=30
)。
输入子系统(Input Subsystem)
- 驱动将事件传递至输入核心层(
input core
),统一管理所有输入设备。 - 事件被写入设备节点(如
/dev/input/event0
),供用户空间读取。
终端处理(TTY场景)
- 在终端环境中(如Ctrl+C):
- 行规则(Line Discipline) 转换原始键码:
Ctrl+C
→SIGINT
信号。 - 终端驱动(如
n_tty
)处理回显、缓冲等逻辑。
- 行规则(Line Discipline) 转换原始键码:
用户空间:事件分发
显示服务器(图形界面)
- Xorg/Wayland 通过
libinput
读取/dev/input/event*
:- 将键码映射为XKB键符号(如
KEY_A
→ 字母a
或A
)。 - 分发给当前焦点窗口(如Firefox浏览器)。
- 将键码映射为XKB键符号(如
- 组合键处理:
Shift+A
→ 由XKB转换为大写A
。
应用程序响应
- GUI应用(如文本编辑器)通过Xlib/GTK/Qt接收键符。
- 终端应用(如Vim)通过PTY(伪终端) 接收转义序列(如方向键→
^[[A
)。
特殊场景
- Fn功能键
由键盘固件直接处理(如调节亮度),不发送扫描码。
- 虚拟键盘
- 通过
uinput
内核模块模拟输入事件(如Android模拟器)。
- 通过
- 按键映射修改
- 使用
xmodmap
或setkeycodes
重定义键码(如交换Ctrl/CapsLock)。
- 使用
总结流程
graph LR A[按键按下] --> B[键盘生成扫描码] B --> C[中断触发CPU] C --> D[驱动解码为输入事件] D --> E[输入子系统写入/dev/input/event*] E --> F[显示服务器/Xorg/Wayland] F --> G[应用程序响应]
Linux输入系统的模块化设计(驱动→输入核心→用户接口)确保了灵活性和扩展性,无论是实体键盘、触摸屏还是手势输入,均可通过统一框架处理。
引用说明:
- Linux内核文档:Documentation/input/input.rst
- USB HID协议规范:usb.org/hid
- XKB键映射标准:X Keyboard Extension
- 内核源码参考:drivers/hid/, drivers/tty/, include/linux/input.h
- 权威指南:Linux Device Drivers, 3rd Edition (O’Reilly)
原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/4672.html