惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Application and Cybersecurity Blog
Application and Cybersecurity Blog
A
About on SuperTechFans
S
SegmentFault 最新的问题
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Help Net Security
Help Net Security
有赞技术团队
有赞技术团队
博客园 - 【当耐特】
O
OpenAI News
美团技术团队
月光博客
月光博客
Apple Machine Learning Research
Apple Machine Learning Research
Schneier on Security
Schneier on Security
Webroot Blog
Webroot Blog
Cyberwarzone
Cyberwarzone
Hacker News - Newest:
Hacker News - Newest: "LLM"
Google Online Security Blog
Google Online Security Blog
T
Tenable Blog
S
Security Affairs
博客园_首页
S
Schneier on Security
Security Latest
Security Latest
T
Threat Research - Cisco Blogs
T
Tailwind CSS Blog
大猫的无限游戏
大猫的无限游戏
Spread Privacy
Spread Privacy
量子位
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
K
Kaspersky official blog
Hugging Face - Blog
Hugging Face - Blog
TaoSecurity Blog
TaoSecurity Blog
博客园 - 聂微东
Vercel News
Vercel News
M
MIT News - Artificial intelligence
T
Troy Hunt's Blog
B
Blog
MongoDB | Blog
MongoDB | Blog
Martin Fowler
Martin Fowler
Attack and Defense Labs
Attack and Defense Labs
L
LINUX DO - 最新话题
D
DataBreaches.Net
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Stack Overflow Blog
Stack Overflow Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
博客园 - Franky
W
WeLiveSecurity
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
F
Fortinet All Blogs
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
Check Point Blog
H
Hacker News: Front Page

暗无天日

读:AI Agent 安全日志——从可见性与隐私的两难说起 - 暗无天日 读:AI Agent 生产化——一份从原型到上线的速查清单 - 暗无天日 AI写作的语言指纹——如何让文字不那么像机器 - 暗无天日 读:50 条 Claude Code 技巧——一个工程经理的六个月使用心得 读:AI 辅助开发为什么让 E2E 测试更有价值 - 暗无天日 读:在Emacs中使用Claude Code(Spacemacs适配版) - 暗无天日 Claude Code 背后的工程哲学——读 Agent Harness Engineering 读:Agent Harness Engineering——AI 智能体不只是模型,还有套件 - 暗无天日 browser-harness:让 AI 直接接管你的浏览器 - 暗无天日 读:Security-First CI/CD —— DevSecOps 自动化实践指南 TIL: 数字小键盘的小数点陷阱与行内算术求值 - 暗无天日 读:Immutability 不是万能药,它是一种权衡 - 暗无天日 Conducty:给 Claude Code 加上项目记忆和并行执行能力 - 暗无天日 读 — GitHub Trending 里的 Claude Code 技能包 读 — Prompt Caching 省钱指南 TIL: Emacs 中那些跟鼠标配合的冷门快捷键 - 暗无天日 读:Anvil——把 Emacs 变成 AI 的工具服务器 读:Emacs 代码折叠终极指南 - 暗无天日 读:Clojure 搭车客指南 - 暗无天日 git推送失败后恢复仓库损坏的完整记录 - 暗无天日 多智能体系统的两个有效模式——以及对 Claude Code 用户的启示 - 暗无天日 用 Org Babel 写 Literate 博文:扩展执行 + 定制导出 proced:Emacs 内置的进程查看器 - 暗无天日 从 proced 定制中学到的 Elisp 模式 读:让 Emacs proced 在 macOS 上显示 CPU 和内存 异步编程的函数着色税 - 暗无天日 链式调用的代价:JavaScript 和 Clojure 的共同教训 - 暗无天日 hyperfine:命令行基准测试工具 - 暗无天日 管道中的变量去哪了?——子 shell 作用域陷阱 - 暗无天日 开源包装器的信任陷阱:四个危险信号 - 暗无天日 程序员愿意为 AI 写文档,却不愿为同事写 - 暗无天日 mktemp: Shell 脚本中临时文件的安全陷阱与最佳实践 - 暗无天日 WSL9x —— 在 Windows 9x 里跑 Linux 内核 6.19 用 ox.el 做你想做的事 —— org-export 高级编程指南 读:Hot-wiring the Lisp Machine —— 用纯 Elisp 构建零依赖的 Org 静态站点生成器 Elisp 性能优化的六个实战教训 - 暗无天日 fcitx5 下 Emacs 无法切换输入法的排查 - 暗无天日 ERT 测试交互命令的三种方式 - 暗无天日 SEM Assistant: 当 Elisp 守护进程遇上 LLM 用 dmsg 给 Elisp 加上结构化调试日志 用 org-habit 追踪非每日习惯 - 暗无天日 Clojure X-Men:当编程语言特性变成超能力 - 暗无天日 TIL: 用 diff-hl 在 fringe 中显示 git 变更 读:llm-test —— 用 LLM agent 驱动 Emacs 测试 TIL: AI 时代的橡皮鸭调试 - 暗无天日 fcitx 启动后键盘输入卡顿的排查 - 暗无天日 TIL: 早期网页的图片热区导航 - 暗无天日 读 Seeing the Whole System 用 Emacs 自动生成每周链接推荐 - 暗无天日 读:ASCII control characters in my terminal 读 What to learn - 暗无天日 Lisp 的括号之痛——一个愚人节玩笑揭开的老伤疤 - 暗无天日 一本书该"线性读"还是"并行读" - 暗无天日 读 How to Monetize a Blog:一篇伪装成变现指南的讽刺文 Python Mock 第三方依赖的四种策略 - 暗无天日 Emacs Lisp 热重载实用指南 - 暗无天日 Prot 的 Emacs 配置哲学 - 暗无天日 TIL: 从直播对谈中学到的三个 Emacs 技巧 - 暗无天日 TIL: 自动使用项目虚拟环境的 Python - 暗无天日 TIL: 让 Help buffer 自动获得焦点 一条命令让本地开发用上 HTTPS —— slim 工具介绍 用 fsck 检查和修复 Linux 文件系统 排查Linux进程"卡死"实战:从strace到gdb全流程 - 暗无天日 PostgreSQL 索引:从基础到你可能不知道的高级用法 - 暗无天日 用 .pdbrc 自定义 Python 调试器 ANSI 转义码的标准化现状 - 暗无天日 终端程序的潜规则 - 暗无天日 PARA Org-mode 测试配置 - 暗无天日 AI越强越辣鸡?控制论说这是必然的 - 暗无天日 AI 越强越需要你盯着——反馈循环实操指南 - 暗无天日 你的AI代理正在偷你的密钥——四种你没想到的泄露通道 - 暗无天日 LLM 在 DevOps 中的三种角色 - 暗无天日 写作风格的反建议 - 暗无天日 反驳本质复杂性——Dan Luu 论为什么《没有银弹》错了 - 暗无天日 文件充满了危险——Dan Luu 谈文件系统的可靠性陷阱 - 暗无天日 AI 时代的 PARA 方法:用 Org-mode 和 AI 打造个人知识管理系统 Linux 数据去重学习笔记 - 暗无天日 创建跨平台 ZIP 文件的隐藏陷阱:Extra Field - 暗无天日 X11 Forwarding 排障指南 - 暗无天日 IP欺骗端口扫描:当别人冒充你去扫描别人 - 暗无天日 Unix 系统中那些被埋没的配置开关——以 FontConfig 为例 - 暗无天日 在Linux上限制儿童使用电脑 - 暗无天日 GIF不仅仅是一种图片格式——用GIF流做些奇怪的事 - 暗无天日 Leiningen 学习笔记:Clojure 项目构建与管理从入门到实战配置 - 暗无天日 Google SRE Book 读书笔记 - 暗无天日 yes 管道 head 发生了什么 - 暗无天日 为什么 nohup 在 crontab 中不起作用 Bash中的Indirection与Nameref - 暗无天日 Linux PAM 简介 - 暗无天日 从Linux ISO文件启动计算机 - 暗无天日 用 Bash 打造一个Screen Locker 用GitHub Actions自动构建EGO博客 - 暗无天日 blocking I/O 的作用 - 暗无天日 mobileog 手机端同步提示Error:2 No such file 的解决方法 回收 WSL2 VHDX 文件占用空间 使用 org-mode columnview 生成任务列表 - 暗无天日 Emacs 作为 MPD 客户端 - 暗无天日 移动文件路径却不破坏org file link的方法 - 暗无天日 如何合理的导出help link 成HTML - 暗无天日 笑话理解之Biology - 暗无天日
Linux 输入栈全景解析:从硬件按键到屏幕响应 - 暗无天日
2026-04-14 · via 暗无天日

前言

本文整理自 The Input Stack on Linux — An End-To-End Architecture Overview(作者:Patrick Louis),是对 Linux 输入设备栈的一次系统性学习(很多内容不是很懂,依赖AI补充知识点,不确定正确率)。

当我们按下键盘上的一个键,到屏幕上出现对应的字符,中间经历了怎样的旅程?这篇文章试图回答这个问题。

Linux 的输入处理大致分为三层:

  • **内核层**:硬件、总线、输入核心子系统(input core)
  • **暴露层**:evdev 事件抽象、devtmpfs 设备节点、sysfs 属性、procfs 调试接口
  • **用户空间层**:udev 设备管理、libinput 事件处理库、XKB 键盘映射、X11/Wayland 图形栈

让我们逐层深入。

内核的 Input Core

input core 是什么

input core 是内核中负责管理输入设备及其事件的核心子系统,代码位于 drivers/input/input.c 。它提供了:

  • 设备的分配与注册( input_allocate_device, input_register_device
  • 事件的分发机制:驱动通过 input_event 推送事件,input core 以扇出(fan-out)方式转发给所有注册的 handler
  • 默认的 evdev handler 会将事件标准化后暴露到用户空间的 /dev/input/eventX

简单来说,input core 充当了硬件驱动和用户空间之间的中间层,实现了一种发布-订阅模式。

事件分发流程

驱动
  → input_event()
    → input core (遍历 input_handler_list)
      → handler.events() (如 evdev)
        → handler 遍历其 input_handle 链表
          → 通过字符设备 /dev/input/eventX 暴露给用户空间

[注] handler 和 handle 的命名很容易混淆:

  • input_handler=:事件处理模块(如 evdev、kbd、joydev),注册在 input core 上,实现 =events 回调
  • input_handle=:内核中的一个绑定结构,连接一个 =input_dev 和一个 =input_handler=,表示"这个设备被这个 handler 处理"。一个 handler 可以有多个 handle(对应多个设备)

用户空间的程序通过打开 handler 创建的字符设备文件来读取事件。

关键数据结构

  • struct input_dev: 代表一个输入设备,包含设备名称、能力位图(支持哪些事件类型)等信息
  • struct input_handler: 事件处理接口,核心是 events 回调函数,负责接收并转发事件
  • struct input_handle: 连接一个 input_dev 和一个 input_handler 的桥梁,每个 handle 代表一组设备-处理器的绑定关系

设备拓扑路径

一个 USB 键盘在内核中的路径可能像这样:

/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/0003:046D:C31C.0003/input/input6/event3

从左到右解读:

  1. pci0000:00/0000:00:14.0 — PCI 总线上的 USB 主控制器
  2. usb1/1-1/1-1:1.0 — USB 总线和端口层级
  3. 0003:046D:C31C.0003 — HID 设备节点(总线 0003=USB HID,厂商 046D=Logitech)
  4. input/input6 — input 子系统设备
  5. event3 — evdev 接口,对应的字符设备 /dev/input/event3

内核对象层级

内核通过以下对象类型来管理系统中的设备:

对象 说明
bus 总线,设备连接的基础
device 物理或逻辑设备
driver 与设备关联的驱动程序
class 按功能分类的设备类别(如 input、disk)
subsystem 系统结构视图,我们关心的是 input 子系统

MODALIAS 与热插拔

内核通过 MODALIAS 机制实现驱动自动加载:

  1. 设备接入时,内核构造 MODALIAS 字符串(包含厂商 ID、产品 ID 等)
  2. 通过 uevent(基于 netlink)发送到用户空间
  3. udev 收到后调用 modprobe 加载对应模块

查看设备的 MODALIAS:

cat /sys/class/input/event3/device/id/modalias
udevadm info --query=property /dev/input/event3 | grep MODALIAS

sysfs 文件系统

sysfs 是内核对象在用户空间的文件系统映射,通常挂载在 =/sys/=。

对于输入设备,重要的目录包括:

目录 说明
/sys/devices/ 设备的层级结构,反映真实的硬件拓扑
/sys/class/input/ 所有 input 类设备的符号链接
/sys/bus/ 按总线类型组织的设备视图
/sys/module/ 已加载的内核模块信息

实用命令:

udevadm info --tree

cat /sys/class/input/event3/device/capabilities/ev

cat /proc/bus/input/devices

cat /proc/bus/input/devices 是非常有用的调试命令,它会列出所有输入设备及其绑定的 handler(如 event3、kbd 等)。

HID — 人机接口设备

HID(Human Interface Device)是当今最重要的输入/输出标准协议。大多数新设备(鼠标、键盘、麦克风等)都通过 USB、I2C、Bluetooth 等传输层使用 HID 协议。

HID 的核心思想:设备先通过 Report Descriptor 描述自己的能力(有哪些按钮、轴等),然后按照约定的 Report 格式发送/接收数据。这意味着不需要为每种新设备写专门的驱动。

HID Report Descriptor 示例

一个鼠标的 Report Descriptor 可能描述:

Usage Page (Button)     ; 按钮页面
  Usage Minimum (1)     ; 按钮 1
  Usage Maximum (5)     ; 按钮 5
  Logical Minimum (0)
  Logical Maximum (1)
  Report Count (5)      ; 5 个按钮
  Report Size (1)       ; 每个按钮 1 bit
  Input (Data, Variable, Absolute)  ; 绝对值

  Report Count (1)      ; 填充
  Report Size (3)
  Input (Constant)      ; 常量,被忽略

Usage Page (Generic Desktop)
  Usage (X)
  Usage (Y)
  Logical Minimum (-127)
  Logical Maximum (127)
  Report Size (8)
  Report Count (2)
  Input (Data, Variable, Relative)  ; 相对值

HID 调试工具

hid-decode /sys/bus/hid/devices/0003:046D:C31C.0003/report_descriptor

cat /dev/hidraw0 | hexdump -C

HID Core 子系统

HID Core 管理设备的生命周期,解析 Report Descriptor,然后将 Report 分发给注册在 HID 总线上的驱动。最重要的是 =hid-input=,它会将 HID Report 翻译为 evdev 事件,并注册 input 设备。

evdev — 事件设备

evdev 是 input core 的默认 handler,它将各种输入设备的事件标准化后暴露给用户空间。

evdev 事件格式

struct input_event {
    struct timeval time;      __u16 type;               __u16 code;               __s32 value;          };

常见事件类型:

类型 说明
EV_KEY 按键和按钮
EV_REL 相对事件(鼠标移动、滚轮)
EV_ABS 绝对事件(触摸屏坐标)
EV_SYN 同步事件,标记一帧事件的结束

一个触摸板的 evdev 帧示例:

type: EV_ABS  code: ABS_X         value: 1234
type: EV_ABS  code: ABS_Y         value: 5678
type: EV_ABS  code: ABS_PRESSURE  value: 50
type: EV_SYN  code: SYN_REPORT    value: 0

设备能力

每个输入设备在注册时会声明自己的能力(capabilities),可通过 sysfs 查看:

ls /sys/class/input/input6/capabilities/

更方便的方式是使用 =libinput record=,它会以人类可读的格式展示设备的所有信息。

evdev 调试工具

sudo evtest /dev/input/event3

sudo libinput record /dev/input/event3

sudo evemu-record /dev/input/event3
sudo evemu-play /dev/input/event3 < recording.txt

udev 与 hwdb

udev 的职责

udev(systemd-udevd)是用户空间的动态设备管理器,它监听内核的 uevent 并执行相应操作:

  • 根据 MODALIAS 加载内核模块
  • 设置设备节点的访问权限
  • 为设备附加属性
  • 创建符号链接,使设备名称更可预测
  • 通过规则系统在设备插拔时执行自定义操作

udev 规则基础

规则文件存放在:

  • /usr/lib/udev/rules.d/ (系统默认)
  • /etc/udev/rules.d/ (管理员自定义,优先级最高)

一个简单的规则示例:当特定键盘插入或拔出时执行脚本:

ACTION=="add|remove", SUBSYSTEM=="input", ATTRS{idVendor}=="1234", ATTRS{idProduct}=="5678", RUN+="/path/to/script.sh"

常用的匹配键:=KERNEL=, SUBSYSTEM, ACTION, ATTR{...}, ENV{...}

常用的赋值键:=SYMLINK=, ENV{...}, RUN+, MODE, OWNER, GROUP

udevadm 常用命令

udevadm info -a /dev/input/event3

udevadm monitor

udevadm test /dev/input/event3

systemd-analyze cat-config udev/rules.d

hwdb — 硬件数据库

hwdb 是 udev 的硬件属性查找表,以 .hwdb 文件定义,编译为 hwdb.bin 用于快速检索。

更新 hwdb:

sudo systemd-hwdb update
sudo udevadm trigger

libinput

libinput 是现代 Linux 图形环境的统一输入处理库,被 Xorg(通过驱动)和 Wayland 合成器广泛使用。它封装了 udev 和 evdev,提供设备检测、事件处理、以及各种输入处理的抽象。

为什么需要 libinput

  1. **统一性**:避免 X11 各个 xf86 输入驱动中的重复逻辑
  2. **处理硬件缺陷**:许多设备的固件报告错误的 HID 描述符,libinput 通过 quirks 机制修正
  3. **复杂输入处理**:触摸板多点触控追踪、按钮防抖、手势识别等

libinput 的主要功能

  • 按钮防抖(debouncing)
  • 触摸板软件按钮(clickpad)
  • 触摸板压力检测
  • 手掌和拇指检测
  • 滚动(两指滚动、边缘滚动)
  • 点击行为(tap-to-click)
  • 手势(滑动、捏合)
  • 指针加速度

Seat 的概念

Seat 是与用户会话关联的输入设备集合。大多数机器只有一个 seat,但在多座位场景下一个机器可以有多个用户同时使用不同的输入设备。

seat 通过 udev 的 ENV{ID_SEAT} 属性分配,可通过 loginctl 管理。

libinput 调试工具

libinput list-devices

libinput debug-events

libinput debug-gui

libinput record /dev/input/event3
libinput replay recording.yaml

键盘处理细节

扫描码到键码

键盘处理涉及三层映射:

Scancode (硬件原始码) → Keycode (内核事件码) → Keysym (用户空间符号)
  • Scancode=:硬件产生的原始值,如 =0x1E
  • =Keycode=:内核映射后的事件码,如 =KEY_A=(定义在 =input-event-codes.h=)
  • =Keysym=:用户空间的符号,如 "a" 或 "A"

键码映射可通过 hwdb 在运行时修改:

# /etc/udev/hwdb.d/61-custom-keyboard.hwdb
evdev:input:b0003v046DpC31C*
 KEYBOARD_KEY_70039=leftalt   # 将 CapsLock 映射为左 Alt

控制台键盘

在文本控制台中,kbd handler(=drivers/tty/vt/keyboard.c=)负责处理键盘输入,它通过 TTY 和 line discipline 机制工作。相关工具:

showkey --scancodes

loadkeys us

kbd_mode

kbdrate

XKB — 键盘布局系统

XKB(X Keyboard)是处理 keycode 到 keysym 映射的用户空间库和配置系统。虽然名字中有 "X",但它也被 Wayland 和各种图形工具包使用。

XKB 的核心概念:

概念 说明
RMLVO Rules-Model-Layout-Variant-Options,用户友好的配置
KcCGST Keycodes-Compat-Geometry-Symbols-Types,内部组件
Levels 按键的不同层级(如按 Shift 时切换到 Level 2)
Groups 完全切换键盘布局(如切换到日语布局)
Modifiers 修饰键状态(Shift、Ctrl、Alt 等)

[注] XKB 的 keycode = evdev keycode + 8,这是一个历史遗留的偏移量。

RMLVO 到 KcCGST 的解析过程

用户选择 RMLVO(如 layout=us, variant=dvorak),XKB 通过 rules 文件将其解析为 KcCGST 组件,编译成完整的 keymap。

xkbcli compile-keymap --layout us --variant dvorak

xkbcli list

xkbcli interactive-evdev

xkbcli how-to-type --keysym "eacute"

Compose 键

XKB 的 Compose 功能允许通过组合键输入特殊字符,配置文件位于:

/usr/share/X11/locale/*/Compose

~/.XCompose

示例:=AltGr+'= + eé

指针设备细节

触摸板类型

类型 说明
Clickpad 整个触摸板可按下,无独立按钮(INPUT_PROP_BUTTONPAD)
Forcepad 类似 clickpad,通过压力检测代替物理按钮
Trackpoint ThinkPad 中间的小红帽摇杆

多点触控(MT)

支持多点触控的触摸板通过 evdev 的 slot 和 tracking ID 机制追踪每个手指:

slot 0: tracking_id=1  ABS_MT_POSITION_X=100  ABS_MT_POSITION_Y=200
slot 1: tracking_id=2  ABS_MT_POSITION_X=300  ABS_MT_POSITION_Y=400
slot 0: tracking_id=-1  (手指抬起)

指针加速

libinput 支持三种加速配置:

  • =adaptive=(默认):根据速度动态调整
  • =flat=:1:1 线性映射
  • 自定义配置

游戏手柄

游戏手柄不经过 evdev 和 libinput,而是使用 joydev handler,通过 /dev/input/jsN 暴露 js_event 格式的事件。

jstest /dev/input/js0

jscal /dev/input/js0

上层图形栈:X11 与 Wayland

X11 输入栈

在 X11 中:

  1. X Server 通过 xf86-input-libinput 驱动使用 libinput
  2. 配置通过 /usr/share/X11/xorg.conf.d/ 中的配置片段
  3. 客户端通过 X 协议接收 XInput 事件
  4. 键盘映射由 X Server 内部维护,通过 XKB 配置
xinput --list

xinput --list-props <device_id>

xev

setxkbmap -layout us -variant dvorak

Wayland 输入栈

在 Wayland 中:

  1. 合成器直接使用 libinput,无中间驱动层
  2. 客户端必须显式注册监听器来接收事件(更安全)
  3. 事件只转发给当前获得焦点的客户端
  4. 输入设备列表在协议中不暴露(合成器内部管理)
  5. 配置方式因合成器而异
gsettings get org.gnome.desktop.input-sources xkb-options
gsettings set org.gnome.desktop.peripherals.touchpad tap-to-click true

export XKB_DEFAULT_LAYOUT=us
export XKB_DEFAULT_VARIANT=dvorak

Wayland 与 X11 的关键差异

方面 X11 Wayland
事件广播 全局广播(任何客户端可监听) 只发给焦点客户端
输入注入 XTEST 扩展可直接注入事件 需要 libei + portal 权限控制
键盘配置 X Server 统一管理 各合成器自行实现
设备列举 xinput 可列出 协议不暴露,需 libinput list-devices

虚拟输入与自动化

uinput — 用户空间输入模拟

uinput 模块允许在用户空间创建虚拟输入设备:

#include <linux/uinput.h>

int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
ioctl(fd, UI_SET_EVBIT, EV_KEY);
ioctl(fd, UI_SET_KEYBIT, KEY_A);

struct uinput_setup setup = {.id.bustype = BUS_USB, .name = "virtual"};
ioctl(fd, UI_DEV_SETUP, &setup);
ioctl(fd, UI_DEV_CREATE, 0);

struct input_event ev = {.type = EV_KEY, .code = KEY_A, .value = 1};
write(fd, &ev, sizeof(ev));

XTEST — X11 测试扩展

XTEST 允许在 X11 中直接注入键盘和鼠标事件,无需 root 权限:

xdotool key a
xdotool mousemove 100 100 click 1

libei — Wayland 的模拟输入

Wayland 通过 libei(Emulated Input)库来处理虚拟输入,架构如下:

客户端(libei) → xdg-desktop-portal(dbus) → 合成器(EIS侧) → 内部虚拟设备

这种方式下,合成器可以控制哪些客户端被允许模拟输入,提供更好的安全性。

相关工具:=ydotool=(基于 uinput)、=wtype=(基于 Wayland 虚拟键盘协议)

输入法框架

输入法(Input Method)用于输入键盘上没有的字符(如中文、日文等)。

IMF 与 IME

  • **IMF**(Input Method Framework):输入法框架,负责管理输入法切换、与工具包集成
  • **IME**(Input Method Engine):具体的输入法引擎,负责将按键序列转换为文字

当今两大主流 IMF:

  • **IBus**(GNOME/GTK 默认)
  • **Fcitx5**(KDE/Qt 默认)

切换输入法框架的环境变量:

export GTK_IM_MODULE=ibus    
export QT_IM_MODULE=ibus     
export XMODIFIERS=@im=ibus   

输入法的处理流程:

按键事件 → XKB(keycode→keysym) → 工具包 IM 模块 → IMF → IME(候选词) → 提交文本

总结

从按下键盘到屏幕响应,事件经过了这样的旅程:

硬件 → 总线驱动 → HID 驱动 → Input Core → evdev handler → /dev/input/eventX
  → udev(权限/属性) → libinput(事件处理) → 合成器/X Server
  → XKB(键盘映射) → 工具包 → 应用程序

每一层都有自己的职责,也都有相应的调试工具。理解这个栈对于排查输入相关问题、自定义输入行为都非常有帮助。

调试工具速查表

层级 工具
硬件/总线 lsusb -v, lspci -vn, hwinfo --short
HID hid-decode, usbhid-dump, hid-tools
evdev evtest, evemu-record, libinput record
sysfs cat /proc/bus/input/devices, udevadm info
udev udevadm monitor, udevadm test, udevadm info
libinput libinput list-devices, libinput debug-events, libinput debug-gui
XKB xkbcli list, xkbcli interactive-evdev, xkbcli how-to-type
X11 xinput, xev, setxkbmap, xdotool
Wayland wev, gsettings, loginctl seat-status
游戏手柄 jstest, jscal