数位板指针协议¶
在 0.50.0 版本加入.
笔和手指包含远超鼠标协议表达能力的信息:压力、倾斜、笔杆旋转、正在使用笔的哪一端、悬停、多个同时接触的手指,以及手指在玻璃上的形状。数位板在笔之外还有按键、触控环和旋钮。数位板指针协议是报告所有这些信息的开放终端扩展,支持绘图数位板、数位屏、触摸屏和触控板,并为设备测量的其他信息预留扩展空间。它不专属于任何终端:silkie(本 kitty 分支)实现了它,本页是其规范。目标与其他扩展相同:小巧、低干扰、易于实现,不改变 TTY 的本质。
消息封装¶
帧使用带有 tablet-pointer 选择器的 OSC 777::
<OSC> 777 ; tablet-pointer ; v=1 : op=query : id=42 <ST>
封装遵循 OSC 777 扩展封装,其中也说明了全部扩展共有的单位、t 的时钟、可合并的报告及模式拒绝规则。协议版本 v 为 1,op 为 query、cap、mode、device、label 或 event。
协议可在不升级版本的情况下扩展。除了各扩展共用的忽略规则外,程序还应忽略不认识 kind 的报告和不认识的 valid 位,将未知 tool 值视为 0。新增报告种类只有在程序通过独立模式位请求后才发送,确保程序不会收到其设计时无法处理的种类。
能力探测¶
程序询问终端是否支持本协议::
<OSC> 777 ; tablet-pointer ; v=1 : op=query : id=42 <ST>
id 是程序自行选择的非负 31 位整数,回复原样返回,以便匹配查询。支持协议的终端回答::
<OSC> 777 ; tablet-pointer ; v=1 : op=cap : id=42 : caps=101 : mode=0 : w=1200 : h=800 : cw=12 : ch=24 <ST>
caps 是终端可报告能力的位集合:
|
工具 |
|
触摸屏上的手指 |
|
触控板上的手指 |
|
手指接触形状 |
|
控制板 |
|
工具动作 |
|
工具和控制板的硬件标识 |
|
估算与预测采样 |
|
系统判定为意外接触的手指 |
能力位描述终端在所运行系统上能报告什么,而非当前连接了什么硬件。只有终端确定能报告的能力才设置相应位。如果系统不预先说明是否提供接触形状,则位 8 在实际出现带形状的接触前保持清除;程序不应等待该位,只要报告的 valid 声明存在,就应使用形状信息。超出工具和手指范围的能力(16 及以上的位)只有通过模式请求后才发送。mode 为下述模式的当前状态。w,h 是字符单元区域的像素尺寸(1 至 65535),cw,ch 为字符单元尺寸(1 至 4096)。此处及报告中的像素均为终端帧缓冲区的物理像素,而非窗口系统缩放后的逻辑单位,因此位置精度与显示器一致。调整窗口大小后程序应重新查询。不支持本协议的终端会忽略查询,程序必须设置超时并回退到鼠标报告。查询不改变模式。
模式¶
报告默认关闭,按终端窗口开启::
<OSC> 777 ; tablet-pointer ; v=1 : op=mode : mode=3 <ST>
mode 是程序请求的能力位集合,0 关闭全部报告:
|
工具报告 |
|
手指报告 |
|
控制板报告,见 控制板 |
|
工具和控制板的硬件标识,见 设备 |
|
工具动作报告,见 工具动作 |
|
估算与预测采样,见 估算与预测 |
|
系统判定为意外接触的手指,见 手指 |
开启位 1 或 2 时,窗口内对应输入通过本协议报告,不再作为鼠标事件。因此 mode=1 可用笔绘图,手指仍作为鼠标点击和滚动;mode=3 下,轻点不再点击,拖动不再选择。物理鼠标,以及触控板自行产生的鼠标和滚动事件,仍使用程序请求的鼠标报告方式。只希望笔作为鼠标使用的程序无须使用本协议。位 4 不会剥夺既有功能:系统对控制板控件的操作,例如用户绑定到某个按键的快捷键,仍会执行。
模式仅作用于当前窗口,由 RIS 重置;改变模式会取消所有活动接触,并释放控制板上所有按住的按键。程序必须在退出、挂起或失败时关闭,恢复时重新开启。多路复用器与其他状态一起保存它,重连时恢复,脱离连接时关闭。终端可允许用户针对全部或部分程序拒绝模式或某些位;被拒绝的位读回为关闭,不发送其本应启用的报告。kitty 默认拒绝硬件标识位 8,除非用户通过 tablet_hardware_ids 允许,因为序列号可识别笔的所有者,查询程序可能运行在远程机器上。拒绝体现在模式中,而非 caps;后者描述终端在该系统上具有的报告能力。
不带 mode 字段的 mode 请求读取状态而不修改,回复为::
<OSC> 777 ; tablet-pointer ; v=1 : op=mode : mode=3 <ST>
终端仅保留其支持且用户未拒绝的位,因此请求超出获准范围的程序可通过读回模式获知。程序重连后恢复时,应读回模式确认是否保留,而非假定状态仍在。
设备¶
每次工具进入一个已启用工具报告的窗口感应范围时,终端在第一条工具报告之前描述该工具::
<OSC> 777 ; tablet-pointer ; v=1 : op=device : device=3 : kind=1 : tool=1 : axes=7 : name=V2Fjb20gSW50dW9zIFBybyBN <ST>
device 是该工具报告所携带的 ID,kind 为 1,tool 为工具类型,取值与事件报告相同。系统提供时还携带下列字段:
|
该工具可测量的项目,位集合与 |
|
工具所在数位板或工具本身的名称,最多 127 字节 UTF-8,使用带填充的 base64 编码 |
|
工具序列号,无符号 64 位整数 |
|
工具硬件 ID,无符号 64 位整数;在 Wacom 数位板上表示笔型号 |
|
数位板的厂商和产品 ID,无符号 32 位整数 |
|
工具电池电量, |
|
工具位于哪块已连接数位板上,从 |
|
该数位板有效表面尺寸,以 1/256 毫米为单位 |
|
该表面为显示器时为 |
|
工具自身存储的颜色、线宽和线条样式 |
|
参阅 笔内存储的设置 |
|
serial、hwid、vid 和 pid 属于硬件标识,仅在模式位 8 开启时发送。序列号让每个开启报告的程序识别同一支物理笔及其所有者,包括 SSH 会话另一端远程主机上的程序。按笔保存设置的程序可请求它们;只绘图的程序无需知道笔属于谁。
工具离开感应范围后再次进入、移到另一窗口,或仍在感应范围时程序更改模式,都会重新发送描述。使用期间,描述内容变化时也重新发送,例如电量下降、用户在笔上选择另一种颜色,或系统获得更多工具信息。新描述整体替换旧描述,省略字段表示该属性不再已知,不影响已开始笔划。程序不得依赖一定收到描述:如果终端只知道事件报告包含的信息,就不必单独描述工具。控制板以类似方式描述,kind=3 并使用自身字段,见 控制板。手指报告中的设备不发送描述。
数位板¶
可以同时连接多块数位板,笔也可在不同板之间移动。tablet 表示工具当前所在数位板:终端为每块板分配从 1 起的编号,在该板连接期间保持稳定,板上的每个工具和所属控制板都携带相同编号,程序因此知道这些按键和那支笔属于同一设备。系统未提供归属关系时省略或为 0。它是计数编号,不是硬件标识,断开连接后不再具有识别意义,因此不需要额外模式位。
w 和 h 是数位板跟踪工具的有效表面宽高,要么同时出现,要么都省略。direct 表示该表面是否为显示器。屏幕上,工具直接指向所绘内容,程序只需 x,y。非屏幕数位板上,手在一处移动,笔迹出现在另一处,其指针位置经过系统映射;希望自行将板映射到画布,或获知手实际移动距离的程序,需要数位板上的位置。这是工具报告的 rx、ry,由 valid 位 256 声明:从有效表面左上角起,水平和竖直范围均为 0 至 65535。结合 w 和 h 可换算成毫米。x,y 仍照常报告,表示系统放置指针的位置。
Windows 指针输入提供上述全部信息:每个指针指明来源设备,设备说明它是显示器内置笔还是独立数位板上的笔、表面矩形尺寸(百分之一毫米)及笔在板上的位置。Linux 内核也提供位置范围、分辨率及是否为显示器。终端实际能得到什么,取决于中间层。Wayland tablet-v2 只说明工具和控制板所属数位板,但提供数位板设备节点,同机终端可据此向内核查询尺寸及是否为显示器。X11 提供位置和范围,驱动声明时也提供分辨率,但不提供工具所属数位板关系。AppKit 为数位板编号,并提供数位板单位的位置,却不告知其取值范围。
笔内存储的设置¶
某些笔将颜色、线宽和线条样式保存在笔自身,可用开关设置或由程序写入,因此换到另一设备时仍按原来的设置绘制。这些是数字化仪 HID 用途表中的 Preferred Color、Preferred Line Width 和 Preferred Line Style,Universal Stylus Initiative 的笔实现了它们。获得这些信息的终端应将其放入工具描述:
|
颜色,sRGB 中的六位十六进制 |
|
线宽,以 1/256 毫米为单位; |
|
|
HID 用两种形式表示颜色。24 位值依次为各八位的红、绿、蓝,原样转发;用途表未指定色彩空间,此处按另一种形式所用的 sRGB 解释。8 位值是按字母顺序排列的 CSS 命名颜色索引,gray 仅保留一种拼写:从 0 AliceBlue 到 140 YellowGreen,见 HID Usage Tables 1.7 附录 A。终端发送名称对应的实际颜色,因此索引 7 Black 为 pcolor=000000,索引 9 Blue 为 pcolor=0000ff。附录保留的索引 255,以及 24 位值旁的 No Preferred Color 标志,均表示笔没有首选颜色,省略 pcolor。
宽度使用笔声明的单位。用途表建议十分之一毫米的步长,但允许笔声明其他单位,因此终端按报告描述符中的物理范围和单位换算;描述符未提供时省略 pwidth。线条样式 Ink、Pencil、Highlighter、Chisel Marker 和 Brush 对应 1 至 5;No Preference 表示未指定样式,省略 pstyle。
这些是笔的偏好而非命令,程序可采用其他绘制方式。HID 还说明笔是否允许修改各项设置,但这只与写入笔设置的程序有关,不向终端程序转发。笔在使用中改变设置时会重新发送描述。只有笔自身报告携带这些设置,因此终端直接读取数字化仪时才能获得;Windows、macOS、Wayland 和 X11 的数位板接口均不转发它们。
报告¶
每个事件对应一帧报告::
<OSC> 777 ; tablet-pointer ; v=1 : op=event : kind=1 : phase=1 : device=3 : t=408211 : contact=0 : x=25600 : y=51200 : buttons=1 : mods=0 : tool=1 : valid=3 : p=32000 : tx=-1200 : ty=600 <ST>
工具和手指报告必须包含 kind、phase、device、t、contact、x 和 y。表中其他字段默认零,只有 tool 默认 1:
|
|
|
|
|
工具或触摸设备在感应范围内期间的标识,为非负 31 位整数;系统不区分设备时为 |
|
事件时间,以终端全部扩展共用时钟的毫秒表示,见 OSC 777 扩展封装:系统认定发生的时刻;系统未提供时刻时,使用终端获知事件的时刻 |
|
|
|
标识某设备的一次接触,在该接触生命周期中保持稳定。笔通常为接触 |
|
位置以物理像素 1/256 为单位,有符号、从零开始,相对于字符单元区域左上角,范围 ±1073741823;对于触控板上的手指( |
|
按住的按钮:笔尖或左键 |
|
Shift |
|
|
|
报告携带哪些测量值的位集合,见下文 |
|
手指位于触控板而非屏幕上时为 |
|
能测量力度的触控板上的手指,其按压力度,见 手指 |
|
对于手指,系统认为接触是有意操作时为 |
|
对于触控板上的手指,系统已知时提供触控板尺寸,单位 1/256 毫米,使程序能将位置转换为距离,或按正确宽高比将触控板映射到画布 |
|
工具 |
仅在 valid 对应位被设置时,该测量值才存在。位清除表示设备不测量该项,绝不表示值为零;终端不得捏造测量值。各测量值及其 valid 位如下:
|
1 |
压力,0 至 65535 |
|
2 |
倾斜角,单位百分之一度,−9000 至 9000,朝屏幕右侧和下方为正 |
|
4 |
工具绕自身轴线旋转的角度,单位百分之一度,顺时针,0 至 35999 |
|
8 |
切向压力,即喷枪滚轮,−65535 至 65535 |
|
16 |
高度,设备单位,−1000000 至 1000000 |
|
32 |
距数位板的距离,0 至 65535 |
|
64 |
工具滚轮自上次报告以来的转动,分别以百分之一度和格数表示。鼠标或镜头工具具有此项,其他工具也可能具有 |
|
128 |
屏幕上手指或图腾的接触形状: |
|
接触椭圆的轴长,单位物理像素 1/256;方向以百分之一度表示,从竖直方向顺时针计算 |
|
|
256 |
工具在其数位板有效表面上的位置,从左上角起 0 至 65535,见 数位板 |
|
512 |
握持工具笔杆的力度,0 至 65535 |
任何具有滚轮的工具都可报告滚轮,不只限于始终带滚轮的两类:tablet-v2 和 libinput 将它视为工具能力,而非工具类型限定。AppKit 和 XInput 的工具报告不提供滚轮。
grip 是支持测量的笔所感知的手握笔杆力度,对应 HID 用途表的 Barrel Pressure。它与 p 一样属于测量值,随每条工具报告发送,可随握持力度连续增加线宽或打开喷嘴。工具动作 中的挤压是另一种信息:系统在力度跨过阈值时识别出的动作,只发生一次,没有量值。笔可提供其中任一、两者或都不提供。与笔内设置一样,只有笔自身报告携带 grip;Windows、macOS、Wayland 和 X11 的数位板接口均不转发。
手指¶
手指报告为 kind=2、tool=0,落下期间 buttons=1,每个手指使用独立 contact,通常除形状外没有其他测量值。触摸系统会先交付一组同时移动的手指,再处理它们;终端保留分组:每组报告后发送帧报告,仅含 kind=2、phase=6、device 和 t,若报告有 tu 也一并包含::
<OSC> 777 ; tablet-pointer ; v=1 : op=event : kind=2 : phase=1 : device=0 : t=408211 : contact=0 : x=25600 : y=51200 : buttons=1 : mods=0 : tool=0 : valid=0 <ST>
<OSC> 777 ; tablet-pointer ; v=1 : op=event : kind=2 : phase=1 : device=0 : t=408211 : contact=1 : x=38400 : y=51200 : buttons=1 : mods=0 : tool=0 : valid=0 <ST>
<OSC> 777 ; tablet-pointer ; v=1 : op=event : kind=2 : phase=6 : device=0 : t=408211 <ST>
关心手指间关系的程序(如捏合识别器)应收集到帧报告后一起处理;按手指分别绘制笔划的程序可逐条处理。帧报告只用于手指,工具一次只报告一个接触点。
支持按压力度的触控板通过 p 和 stage 报告。力度属于整块触控板,不属于单个手指,因此板上每个手指携带相同的两个值;仅力度变化时,也会重新报告手指为位置未变的 move。stage 为 0 表示未达到点击力度,1 为点击,2 为更用力的点击;p 在各阶段内取 0 至 65535,所以阶段升高时压力值会回落。
接触屏幕或触控板的不一定都是有意操作。放在玻璃上的手掌、握笔手的侧面、停在触控板边缘的拇指也都是接触,一些系统会根据大小、形状和笔位置判断。手指报告通过 conf 传达系统判断:1 为有意,0 为意外。系统未说明时省略 conf,不代表任一结论。有些系统完全不判断;另一些只标记意外接触,对其他接触不作说明,此类未标记接触没有 conf,不能当作已确认有意,因为系统漏判的手掌也一样。只有系统明确说明有意时才给出 conf=1。接触期间判断可能变化,例如手掌先以侧边接触,短暂像手指,或静止拇指开始移动。
意外接触仍然是接触,如何处理由程序决定:有的程序忽略,有的允许手掌涂抹。但不认识 conf 的程序会把手掌当成手指,因此系统判定为意外的接触仅在模式位 64 开启时报告。未开启时,只要系统仍认为是意外,就不向程序显示:
起初被判为意外的接触不报告。如果在抬起前系统不再认为是意外,则从那时以
down开始报告;若先抬起,则始终不报告。正在报告的接触若被系统改判为意外,则发送
phase=4、conf=0取消;程序与其他取消一样撤销该接触造成的效果。即使接触以意外状态抬起,最后一条也是cancel而非up。取消后不再报告,除非抬起前系统不再视其为意外,此时以新的down重新开始。只有组内实际报告过内容时,才在该组后发送帧报告。
开启位 64 后,所有接触按发生情况报告,并携带系统提供的 conf,不会因为意外接触而自动取消。程序应逐条检查 conf,若已绘制的接触后来被判为意外,应自行撤销。系统不执行判断时,该位不改变行为。支持报告这些接触的终端会设置 caps 位 256。
Windows 通过指针的 confidence 标志提供判断;HID 用途表在接触报告中使用 Touch Valid,直接读取数字化仪的终端可获得。Android 也会判断,但较晚说明:把某个手指判为手掌后取消它,映射为该接触的 cancel、conf=0。AppKit 能标记触控板上静止搁置的接触,但不说明其他接触,实际观察中尚未见到该标记被设置,见 实现情况。Wayland 和 X11 不提供此信息。
工具动作¶
有些工具操作不是持续按住按钮:双击笔杆、挤压笔杆,或点击笔尾按钮。模式位 16 开启时,以 kind=4 报告::
<OSC> 777 ; tablet-pointer ; v=1 : op=event : kind=4 : device=3 : t=408211 : action=1 : x=25600 : y=51200 : mods=0 <ST>
|
工具标识,与工具报告相同;系统未说明是哪支工具时为 |
|
动作时刻,与其他报告相同 |
|
|
|
持续动作(如挤压)开始时为 |
|
|
|
指针位置,与工具报告相同 |
|
与工具报告相同 |
始终含有 device、t、action、x、y 和 mods。动作没有 phase 或 contact,不属于笔划。若某窗口捕获了该工具的笔划,则发送给该窗口,否则发给指针下的窗口。动作的用途由程序决定;双击通常在笔和橡皮之间切换。程序应忽略未知 action。
如果设备有笔槽或可充电磁吸收纳位,笔会在放入和取出时告知系统,适合用来隐藏或显示调色板。Windows 向应用通知这两种动作。它们都没有持续状态,x,y 只是当前指针位置。
带无线连接和运动传感器的笔,可像魔杖一样挥动:远离屏幕并按住按钮时报告运动,例如部分通过蓝牙配对的 Samsung S Pen。这就是动作 8:按钮按下时 state=1,随后任意数量 state=2 报告携带 dx、dy,松开时 state=0。这些量是笔内传感器对运动的解释,没有单位,只有符号和比例有意义;终端收到小数时应始终用同一系数转换为整数。程序可累加来移动光标,或从序列识别挥动。此时笔不在数位板上方,因此没有工具报告,x,y 保持原指针位置。
控制板¶
控制板是数位板本体或独立遥控器上的按键、触控环、触控条和旋钮。模式位 4 开启时,以 kind=3 报告,每条对应一个控件::
<OSC> 777 ; tablet-pointer ; v=1 : op=event : kind=3 : device=5 : t=408211 : mods=0 : ring=0 : angle=9000 : src=1 <ST>
device、t 和 mods 始终存在,与其他报告含义相同,tu 也相同。控制板报告没有 phase、contact 或位置,其余字段为下列形式之一:
|
按键按下 |
|
手指在触控环上的位置,单位百分之一度, |
|
手指在触控条上的位置,顶端或左端为 |
|
手指离开触控环或触控条时,用此形式替代位置报告 |
|
替代 |
|
旋钮自上次报告以来的转动量,有符号,每个卡点为 |
|
一组控件切换到了另一模式 |
button、ring、strip 和 dial 的值是控件编号,各种类型按系统列举顺序在整块控制板上从零编号。系统说明触控环或触控条由手指操作时,报告添加 src=1。
控制板控件划分为组,每组有一个从零开始编号的模式,用户可在控制板上切换,通常用系统保留的按键,并可能由指示灯显示。模式只是一个数字,用于让相同控件在不同模式中执行不同功能,具体功能由程序决定。group 报告给出分组编号和当前模式。控制板进入窗口时,终端也会为每个分组发送一次,因此程序不必等用户切换才知道状态。
控制板报告发送到获得键盘焦点的窗口,而非指针下的窗口。每次控制板进入启用报告的窗口,在首条报告前,终端描述该控制板::
<OSC> 777 ; tablet-pointer ; v=1 : op=device : device=5 : kind=3 : buttons=9 : rings=1 : strips=0 : dials=0 : groups=1 : modes=4 : name=V2Fjb20gSW50dW9zNSB0b3VjaCBNIFBlbg== <ST>
|
控制板上按键、触控环、触控条和旋钮的数量 |
|
|
|
|
|
|
|
控件分组的数量 |
|
按分组顺序,以逗号分隔的各组模式数量 |
|
各组当前模式,形式相同,终端在当时已知时才提供 |
|
各按键、触控环、触控条和旋钮所属的分组,见下文 |
|
|
|
|
|
|
|
控制板所属数位板的编号,与该板上的工具相同,见 数位板 |
|
控制板所属数位板的名称,与工具相同 |
|
该数位板的硬件 ID,仅在模式位 |
模式属于分组,因此显示控件当前功能的程序必须知道控件所属组。bgroups 用于按键,rgroups 用于触控环,sgroups 用于触控条,dgroups 用于旋钮:按各类控件编号顺序,以逗号分隔给出所属组号;不属于任何组的控件(如系统保留用于切换模式的按键)用 -。bgroups=0,0,0,-,1,1 表示三个键属于组 0,一个不属于组,两个属于组 1。列表为该类型每个控件提供一项;没有该类控件或系统未说明时省略,只有一个组的控制板不会有归属疑问。系统可能在使用期间为自身用途将按键移出组或归还,此时重新描述控制板,与工具属性变化时一样。分组来自 libinput,Wayland 合成器通过 tablet-v2 转发:各组列出按键并公布触控环、触控条和旋钮。silkie 读取的其他接口均不提供分组。
控制板只有按键具有持续按住状态。模式改变、终端重置、键盘焦点转到其他窗口或控制板消失时,终端为每个按住的键报告 state=0,时间 t 使用原按下时刻;控制板稍后实际产生的释放不再报告。开始报告前已经按住的键,之后释放时也不报告。程序必须容忍释放一个自己并未记录为按下的键。
程序可以声明控件当前的功能,供系统在可用界面(如控制板布局蒙层)中展示给用户::
<OSC> 777 ; tablet-pointer ; v=1 : op=label : device=5 : button=2 : text=VW5kbw== <ST>
device 指定控制板,并在 button、ring、strip、dial 中恰选一个,以 0 至 255 编号指定控件。text 为不含控制字符的 UTF-8,使用带填充的 base64 编码;text 为空或省略时表示移除标签。窗口系统可能限制标签长度:Wayland 请求最多容纳 4075 字节,kitty 会在字符边界截断更长标签。标签属于控件所在组的当前模式,因此程序应在收到控制板描述后,以及每次 group 报告后重新设置。仅接受来自正在接收该控制板报告的程序的标签,不回复;没有标签显示位置的终端忽略请求。
图腾工具¶
图腾 tool=8 是放在屏幕上、由屏幕跟踪的旋钮或游标装置。它按工具报告:x,y 是中心,twist 为旋转量,valid 位 128 声明的接触形状为其覆盖的屏幕区域。按下对应按钮 1,因此按住并转动图腾是一个 twist 变化的笔划。
估算与预测¶
某些系统会在全部数据测量完成前交付采样:笔尖位置可能先到,压力随后经无线连接到达,期间系统先填入估算值。有些系统还提供工具即将到达位置的预测采样,程序可先绘制以掩盖显示延迟,再替换。能转发此类信息的终端,仅在模式位 32 开启时发送,并在工具和手指报告中增加三个字段:
|
设备采样计数,无符号 32 位整数,可回绕;后续报告据此引用先前采样 |
|
本报告中仍为估算的测量项目,使用与 |
|
预测采样为 |
估算值通过修正报告更新:phase=7,携带被修正报告的 seq,重复该报告并使用实际测量值,不是笔划的新点。修正自身的 est 标明哪些项目仍为估算;没有估算项时省略。修正可能在笔划 up 后到达,也可能永远不来,此时保留估算值。
预测采样不属于实际笔划。绘制预测的程序,在收到同一接触点下一条非预测报告时,应移除该接触点的全部预测采样。预测采样不带 seq,也不会被修正。
未启用位 32 时,终端把估算值作为普通值发送,不发送修正和预测,因此不认识这些机制的程序直接绘制收到的内容。
生命周期¶
笔划以 down 开始,以 up 或 cancel 结束,期间该接触点每条报告都是 move。工具或手指离开窗口后,笔划仍由起始窗口捕获,因此坐标可为负或超出字符单元区域,不得钳制到另一个窗口。一次手指序列从首个手指落下到最后一个抬起,全部发送给首指下方的窗口;触控板则使用首指落下时指针所在窗口。被判为意外的接触不会保持序列活动,否则留在触控板上的拇指会让之后所有手指锁定同一窗口:若当前按下的接触全为意外,此时新手指落下或某接触不再被判为意外,将以当时该接触(或指针)下方窗口开始新序列。如果换了窗口,原窗口会取消已有接触,新窗口中每个接触都以 down 开始。hover 跟随感应范围内未接触的工具,不被捕获。工具离开感应范围时取消其未结束笔划,系统提供离开事件时再发送阶段 5。它发给最后获知该工具的窗口,无论工具离开时在哪里;即使笔划曾拖出窗口并在外结束,程序也仍需要知道笔已离开。
模式改变、终端重置、窗口字符行列数变化、系统为自身手势接管手指,或设备消失时,终端以 buttons=0、p=0 取消接触。取消后不再报告该笔划的任何后续内容,包括 up。因意外接触取消的手指若重新报告(见 手指),视为以 down 开始的新笔划。程序必须容忍丢失的 hover、重复取消,以及对仍被记录为活动的接触收到新 down,后者替换旧笔划。
终端或中继无法跟上时,可按 OSC 777 扩展封装 合并部分报告。本协议仅允许合并 move 和 hover:同一接触点连续出现,期间没有该接触点的其他报告,且 buttons 相同。合并后绝对值取最后一条,wheel、wclicks 分别求和,并合并它们所在组的帧报告。其他报告(包括控制板、设备、动作和修正)全部原样到达。
多路复用器按窗格原点(含边框)和滚动偏移转换屏幕接触的 x,y,其余字段不变;笔划和手指序列只交给起始窗格,窗格移动或调整大小时取消接触。保存各窗格模式,并向终端请求其并集。为感应范围内每个工具保存最近描述,在窗格收到首条工具报告前先发送描述;除非窗格请求硬件标识,否则去掉这些标识。终端重新描述设备时,保存新描述替换旧描述,并转发给当前接收该设备报告的窗格。rx、ry、grip 和 conf 不表示屏幕位置,原样转发。不同窗格的模式位 64 可不同;任一窗格启用时向终端请求,对未启用的窗格则按终端规则过滤:隐藏意外接触、取消后来被判为意外的接触、不再意外时以 down 开始,仅在实际发送过组内内容后发送帧报告。tablet 沿用终端编号;汇集多终端数位板的中继应重新编号,确保板间不冲突,且控制板与所属数位板工具编号相同。工具动作发给捕获该工具笔划的窗格,否则发给指针下方窗格,x,y 像接触位置一样转换,dx,dy 不变。修正跟随原报告进入同一窗格,seq 不变。控制板先发送描述,再原样发送给获得焦点的窗格;焦点离开时,向原窗格报告全部按住键已释放。标签仅从接收控制板报告的窗格转发。多路复用器或中继在有活动接触时脱离或断连,必须向程序为各接触发送 cancel,避免保留失效接触;重连后不补造没见过的事件,当前已落下的手指只从下次 down 开始报告。
实现情况¶
silkie(本 kitty 分支):macOS、Wayland 和 X11 支持工具;macOS 支持触控板手指,Wayland 支持带接触形状的触摸屏手指,X11 支持无形状的触摸屏手指;Wayland 支持控制板及控件分组,X11 支持控制板按键;macOS 支持工具动作;macOS 和 Wayland 提供数位板编号;Wayland 和 X11 提供数位板尺寸及是否为显示器;X11 提供工具在数位板上的位置。
kitty --debug-input记录收到的数位板、控制板和触摸事件。Inkline、Goblin Skiff 和 GoblinView 包含较早草案的编解码器,正在更新至本规范。
silkie 实现说明¶
silkie 通过窗口系统读取数位板和触摸设备,因此程序得到系统所报告的内容。接受模式位 1、2、4、8、16 和 64,caps 说明当前系统实际能提供哪些能力。现有运行平台均不提供估算或预测,因此不接受位 32,也不报告图腾或电量。仅 macOS 发送 tu;Wayland 和 X11 的数位板/触摸事件使用整毫秒时间戳。
silkie 转发窗口系统提供的设备信息,具体见下文:macOS 和 Wayland 的 tablet,Wayland 的控制板控件分组,Wayland 与 X11 从内核或驱动读取的 w、h、direct,以及 X11 的 rx、ry。实现能生成本页每个字段,测试也覆盖它们,但实际读取接口均不提供 grip、pcolor、pwidth、pstyle 或动作 6 至 8,因此不会发送;conf 来自 AppKit 的标记,但尚未观察到任何实际接触携带它,因此任何平台均不声明 caps 位 256。描述内容变化时重新描述工具或控制板,目前只有 Wayland 控制板会出现此情况。
本规范将倾斜定义在屏幕坐标轴上。系统为左手使用或旋转数位屏而旋转数位板时,会同时变换位置,却不一定变换设备自身坐标轴上的倾斜。系统说明数位板朝向时,silkie 转换倾斜;未说明时原样转发:
libinput 仅为左手模式旋转半圈,此时会同时变换位置、倾斜和笔杆旋转。
Wayland
tablet-v2给出数位板轴上的倾斜;合成器把板映射到旋转显示器或自行校准时,不告知终端,因此原样转发。数位屏旋转四分之一圈时,倾斜仍在面板轴上,而非屏幕轴上。X11 wacom 驱动的
Wacom Rotation及服务器的Coordinate Transformation Matrix会转换位置,但将倾斜保留在数位板轴上。silkie 读取两者,并在变化后重新读取;矩阵保持轴线正交时(四分之一圈、半圈、镜像或映射到屏幕局部),相应转换倾斜。矩阵旋转其他角度或将其压平时,省略倾斜。笔杆旋转不做变换。AppKit 提供驱动按用户设置的朝向处理后的倾斜值。
上述行为尚未使用旋转的数位板实测。
macOS 的数位板数据随驱动的鼠标事件到达。倾斜从驱动给出的最大倾斜比例,按 Wacom 报告的 60 度假定换算;
z为驱动的绝对 Z。程序接收工具报告期间,禁用 AppKit 的数位板采样合并,以便上报每个采样。AppKit 区分笔、橡皮和游标;Wacom 喷枪和镜头光标通过驱动工具代码识别。设备描述中没有已知名称。tablet为 AppKit 在已连接数位板中的索引加一。AppKit 还提供数位板单位下的工具位置,但不提供范围或板尺寸,因此没有rx、ry、w、h。唯一工具动作是与 iPad 配对的 Apple Pencil 双击,前提是 Mac 将 iPad 用作显示器;系统不说明来源工具,因此除非只有一个工具处于感应范围内,否则device为0。手指来自 AppKit 向内容视图报告的触控板间接触摸;板尺寸取 AppKit 的设备尺寸,按每英寸 72 点解释。触控板手指报告与系统生成的鼠标、滚动事件同时存在。支持力度的触控板首次被按压后提供p和stage。AppKit 对静止搁置的触摸有一个标记,文档描述为拇指或其他静止接触;silkie 也请求它们:有标记的触摸为conf=0,开始或停止静止时即使没移动也会报告。对无标记触摸,AppKit 不作判断,因此没有conf。在 macOS 26 的 16 英寸 MacBook Pro 触控板上从未观察到该标记:手掌压在板上、拇指停在边缘而另一手指移动时,都作为普通触摸到达。因此 silkie 在 macOS 不声明caps位256,程序得不到conf,需自行判断手掌,其他 AppKit 接口也不提供分类。相关代码仍保留,以支持实际会设置标记的设备:无论能力位是否声明,程序开启模式位64就会收到带conf=0的该类触摸;未开启时将其过滤,类似 AppKit 对未请求视图的过滤,但有一项刻意差异:手指变为静止时以cancel结束,而非 AppKit 的up,因为停止移动不等于点击。kitty --debug-input会在带标记的触摸后输出accidental。Wacom 工具类型、双击和力度依据 AppKit 文档实现,尚未经相应硬件实测。没有控制板报告:AppKit 不提供这些控件事件,应用只能通过 Wacom 驱动自己的请求接口读取。Wayland 工具通过
tablet-v2提供,该协议报告上述测量、工具标识和数位板名称;手指通过wl_touch提供,seat 为版本 6 或以上且合成器发送时,可带shape和orientation。撰写时 sway 和 GNOME 尚未发送,caps在实际收到带形状接触后才声明形状能力。仅支持cursor-shape-v1的合成器会让指针光标跟随工具。GNOME 先应用自身笔按钮映射(默认下方按钮为中键),sway 原样转发。对 silkie 而言,工具不移动鼠标指针:合成器可为数位板提供独立光标,所以滚动等按指针位置报告的事件仍位于原鼠标指针处。控制板也通过tablet-v2提供:第一版有按键、触控环、触控条和模式,第二版新增旋钮,需要合成器公布相应版本;标签作为控件反馈传给合成器。控制板的name和硬件 ID 取自其所属数位板。合成器支持协议时,caps才声明工具和控制板。tablet按合成器公布 seat 数位板的顺序编号:工具使用进入感应范围的板号,控制板使用获得焦点时关联的板号。按键属于列出它的组,触控环/触控条/旋钮属于公布它们的组;控制板有焦点时,若合成器重新列出某组按键,就重新发送控制板描述。协议不提供数位板尺寸、是否为显示器或工具在板上的位置,尽管合成器知道三者。但它提供设备节点,系统可向查询者公开前两项,而无须访问设备本身。udev 根据设备位置范围和分辨率计算尺寸,在数据库中以向下取整的毫米保存为ID_INPUT_WIDTH_MM和ID_INPUT_HEIGHT_MM。内核在 sysfs 提供设备属性,INPUT_PROP_DIRECT表示显示器,INPUT_PROP_POINTER表示非显示器数位板。silkie 在数位板给出节点时加载 libudev,读取两者并发送w、h、direct;没有节点时不使用它。只读取笔对应的节点,不读取控制板或板上手指节点。节点属于合成器所在机器,因此只有内核中的厂商/产品 ID 与合成器提供值匹配,或未提供 ID 时名称匹配,读取结果才有效;终端与合成器位于不同机器时不报告这些信息。内核没提供的属性会省略,例如设备未声明分辨率时不提供尺寸。无法通过此方式获得rx、ry。已用模拟 libudev 检查两块数位板的内核/udev 应答,并在没有数位板的机器上检查实际设备读取,未有真实数位板可用。控制板也只用按 wlroots 行为发送事件的模拟合成器测试,未使用硬件。X11 工具来自 XInput 2 设备,名称按 libinput 或 wacom 驱动惯例包含工具类型;设备描述的
name使用此名称,数位板硬件 ID 未知。tangent携带设备滚轮轴,twist为旋转 Z 轴。工具位置从其自身设备报告生成,并像服务器一样缩放到屏幕,因为服务器把事件发生前的指针位置放入事件,实际落后工具一条报告。rx、ry也源于该位置。服务器会应用用户将板映射到屏幕或某显示器的矩阵,因此 silkie 读取矩阵并在变化时重读,再反向变换;矩阵不可逆时省略rx、ry。libinput 的区域宽高比也会导致省略,因为它按 silkie 无法精确获知的因子拉伸一轴并截断超出部分。w、h是位置范围除以驱动声明的分辨率;没有可用的、声明分辨率的驱动硬件,因此尺寸尚未实测。libinput 不声明分辨率;两个驱动均通过Device Node属性提供工具节点,通过Device Product ID提供厂商和产品 ID。驱动未声明分辨率时,silkie 与 Wayland 一样从内核读取节点的尺寸和direct,尺寸按毫米向下取整;仅当连接 X 服务器使用本地套接字,且内核设备 ID 匹配时才信任,因为节点属于服务器所在机器。已通过带这些属性的 X 服务器测试驱动设备和模拟 libudev 检查,未使用数位板硬件。X 没有工具所属数位板的概念,每个工具都是独立设备,因此不提供tablet。X 服务器不报告工具离开感应范围,故仅设备消失时发送阶段5。也识别 Xwayland 数位板设备,但 GNOME 下测试未收到移动事件,那里应使用 Wayland 后端。此类设备不报告数位板信息:位置是桌面位置,分辨率为虚构。触摸屏手指通过 XInput 2.2 触摸事件提供,服务器具备该版本时caps声明支持。X 将每个手指作为独立事件,因此各手指报告后各跟一个帧报告,同时移动的手指不分组。没有接触形状;系统接管触摸时以普通up结束,因为服务器不说明接管;触控板手指也不上报。服务器会将鼠标指针移到首指落点,但不会将此变化作为鼠标报告转发。已通过 Xwayland 将合成器触摸转换为事件来测试,未使用触摸屏。控制板来自 libinput 和 wacom 驱动,它们为控制板提供类型PAD的独立设备,服务器具备这些驱动之一时caps声明支持。X 只提供控制板按键,作为设备按钮:键 0 至 2 对应按钮 1 至 3,其余从按钮 8 起;按钮 4 至 7 是驱动默认从触控环和触控条生成的滚动,不转发。描述的buttons为设备按钮数减四,在 libinput 下等于实际按键数;wacom 可能提供比实际按键更多的按钮。触控环、触控条均不报告,描述也不列出:libinput 不论实际硬件都给出两个环和两个条的相同轴,无法得知数量;wacom 则提供未说明方向和单位的原始值。没有分组和模式,libinput 只通过 silkie 未读取的私有属性发布它们;标签也没有显示位置。控制板应向键盘焦点窗口报告,但服务器只把按键交给指针下的窗口,因此指针位于其他应用时按控制板键,不会报告。已通过 X 服务器测试驱动设备,使用 wacom 的Wacom Tool Type属性将其标为控制板来检查,未使用实际控制板。