关于Linux控制台与鼠标交互的若干事项
至少在x86架构的PC上,Linux的文本控制台(即“TTY”控制台或“虚拟控制台”)支持一些令人意外的功能。其中一项是通过额外守护进程实现鼠标交互功能,例如运行gpm或更现代的consolation。该功能同时支持帧缓冲控制台和传统’VGA’文本控制台。操作体验相当直观:安装并激活相应守护进程后,即可实现鼠标移动、文本选取粘贴等功能。其工作原理与具体效果尚不明确,鉴于我近期因某些原因深入研究了该领域相关原因, 我决定趁记忆犹新时记录所知内容(重点阐述consolation的工作原理)。
简而言之,控制台TTY对鼠标的支持本质上类似终端模拟器。当鼠标守护进程运行时,TTY会自动执行“复制粘贴”等选取操作。支持鼠标的文本模式程序可将控制台切换至特殊模式,此时鼠标按键操作会直接传递至程序——这与xterm等终端模拟器的行为完全一致。
最简单的TTY模式是当非鼠标感知程序或shell处于活动状态时,即指在常规终端窗口运行时不会自行拦截鼠标操作、并将鼠标相关事务交由终端仿真器处理的程序。在此模式下,鼠标守护进程会读取鼠标输入事件,然后使用 TIOCLINUX ioctl命令的子选项向TTY注入操作,例如指示其“选取”文本片段,再要求将选定内容粘贴至某个文件描述符(通常是控制台本身,由其转发给当前接收终端输入的前台程序)。
(理论上可通过鼠标滚动文本,但实际中该功能已在2020年移除,涉及帧缓冲控制台 以及 VGA控制台。若我理解正确,VGA控制台仍可能具备少量滚动回溯支持——这取决于您为VGA控制台预留的VGA内存大小。不过您现在应该不再使用VGA控制台了。
控制台 TTY 的另一种模式是:某个程序使用标准 xterm 衍生转义序列请求 xterm 兼容的“鼠标跟踪”功能,这与终端模拟器自行处理鼠标时请求的功能相同。在内核TTY控制台驱动中,此机制会设置一个标志位,鼠标守护进程可通过TIOCL_GETMOUSEREPORTING查询该标志;但内核TTY驱动仍不会直接处理或监听鼠标事件。取而代之的是,控制台管理程序(或gpm)读取该标志位,当标志位设置时,通过TIOCLINUX的TIOCL_SETSEL子选项下的TIOCL_SELMOUSEREPORT子子选项,将鼠标位置和按键操作报告给内核(而非自行处理鼠标活动)。内核随即按程序要求向TTY发送鼠标报告转义码。
(据我发现,今年曾出现过与此相关的CVE漏洞,当时内核允许过多用户触发向程序发送’mouse’事件的行为。详情参见稳定版内核提交信息。)
类似于 consolation 的鼠标守护进程无需关注内核的 TTY ‘鼠标报告’ 标志。根据我对当前 Linux 内核代码的理解,若鼠标守护进程忽略该标志,它仍可正常执行所有常规的复制粘贴选区操作及鼠标按钮处理。但需注意:只有当程序主动请求时,系统才会发送鼠标报告;若在错误时机请求发送,内核将返回错误。
(据我观察,内核不会主动通知鼠标守护进程有人更改了’鼠标报告’标志。守护进程必须主动轮询该标志——consolation似乎在处理任何鼠标事件前,都会通过事件循环进行此轮询。)
附注:关于控制台鼠标报告机制的文档曾以2020年内核文档补丁形式编写 (替代版本),但似乎尚未合并到代码库中。根据多方资料(例如),鼠标守护进程相关功能仅限实际鼠标守护进程使用,程序无法调用——尽管程序有时会使用TIOCLINUX鼠标模块的其他组件。
PPS:即使你永远不打算使用文本终端(TTY),在台式机或笔记本上安装鼠标守护进程也是很有用的。万一因某种原因(比如常规显示环境崩溃)被迫进入文本终端时,拥有鼠标剪切粘贴功能会比没有它方便得多。
本文文字及图片出自 Some stuff on how Linux consoles interact with the mouse
