部分窗口系统支持响应用户触摸屏幕以及在触摸屏幕时移动手指的输入设备。 这些输入设备被称为触摸屏,Emacs 将它们产生的事件报告为 触摸屏事件(touchscreen events)。
触摸屏产生的大多数单个事件只有作为其他事件组成的更大序列的一部分才有意义: 例如,轻触触摸屏的简单操作涉及用户将手指放在触摸屏上并抬起, 而滑动屏幕以滚动则涉及放置手指、多次向上或向下移动手指,然后抬起手指。
对于轻触和滚动来说,由单根手指构成的简单模型已经足够, 但更复杂的手势需要支持跟踪多根手指, 其中每根手指的位置由一个 触摸点(touch point) 表示。 例如,“捏合缩放”手势可能由用户放置两根手指并分别向相反方向移动构成, 它们各自点位置之间的距离决定显示画面的缩放幅度, 而这些位置之间假想线的中心点决定缩放后显示画面的平移位置。
下面描述的底层触摸屏事件可用于实现上述所有触摸序列。 在这些事件中,每个点由一个标识该点的任意数字和一个鼠标位置列表(see 点击事件) 组成的 cons 单元表示,该列表指定事件发生时手指的位置。
(touchscreen-begin point) ¶当用户将手指按在触摸屏上创建 point 时,发送该事件。
当这些事件发生在框架或窗口的特殊部分上方时,
虚拟前缀键也会附加到这些事件与 read-key-sequence 上。
See 读取按键序列。
(touchscreen-update points) ¶当触摸屏上的某个点改变位置时,发送该事件。 points 是一个触摸点列表,包含当前触摸屏上每个触摸点的最新位置。
(touchscreen-end point canceled) ¶当 point 不再出现在显示屏上时发送该事件, 原因可能是其他程序接管了捕获,或是用户将手指从触摸屏上抬起。
如果触摸序列被其他程序(如窗口管理器)拦截,
canceled 为非 nil,此时 Emacs 应撤销或避免执行
原本由该触摸序列触发的任何编辑命令。
当这些事件发生在框架或窗口的特殊部分上方时,
虚拟前缀键也会附加到这些事件与 read-key-sequence 上。
如果触摸点按在菜单栏上,Emacs 不会生成任何对应的
touchscreen-begin 或 touchscreen-end 事件;
相反,菜单栏可能会在原本应发送 touchscreen-end 事件之后显示。
当没有命令绑定到 touchscreen-begin、
touchscreen-end 或 touchscreen-update 时,
Emacs 会调用“按键转换函数”(see 事件序列翻译键盘映射)
将包含触摸屏事件的按键序列转换为普通鼠标事件(see 鼠标事件)。
由于 Emacs 不支持区分来自不同鼠标设备的事件,
它假设在转换过程中最多有两个触摸点处于活动状态,
当超出该限制时,不保证事件转换的结果。
Emacs 采用两种不同策略将触摸事件转换为鼠标事件,
具体取决于在 touchscreen-begin 事件所在位置
处于活动状态的按键映射所绑定的命令等因素。
如果该位置有命令绑定到 down-mouse-1,
初始转换会生成一个 down-mouse-1 事件,
后续的 touchscreen-update 事件转换为鼠标移动事件(see 移动事件),
最终的 touchscreen-end 事件转换为 mouse-1
或 drag-mouse-1 事件(除非 touchscreen-end 事件
表明触摸序列已被其他程序拦截)。这被称为“简单转换”,
在触摸点移动与鼠标移动之间建立简单对应关系。
但是,某些绑定到 down-mouse-1 的命令——例如 mouse-drag-region——
要么与已定义的触摸屏手势(如“长按拖拽”)冲突,
要么不符合用户对触摸输入的预期,
不应对触摸序列进行简单转换。
如果遇到名称包含属性(see 符号属性)
ignored-mouse-command 的命令,
或者 down-mouse-1 没有绑定任何命令,
则会进行一种更特殊的转换:
此时 Emacs 会先处理触摸屏手势(see Touchscreens in The GNU Emacs Manual),
如果在结束 touchscreen-end 事件(与简单转换一样,其 canceled 参数为 nil)
之前未检测到任何手势,
且该事件位置有命令绑定到 mouse-1,
最后才尝试将触摸屏事件转换为鼠标事件。
在生成 mouse-1 事件之前,
点会被设置为 touchscreen-end 事件的位置,
并且包含该事件位置的窗口会被选中,
这是对那些假定 mouse-drag-region
已经将点设置为任意鼠标点击位置并选中发生点击窗口的包的兼容方案。
为了避免在鼠标菜单关闭后(see 菜单与鼠标)出现多余的 mouse-1 事件,
如果 down-mouse-1 绑定到一个按键映射使其成为前缀键,
Emacs 也会避免简单转换。
作为简单转换的替代,它会将结束的 touchscreen-end
转换为带有触摸序列起始位置的 down-mouse-1 事件,
从而显示鼠标菜单。
由于某些命令也绑定到 down-mouse-1 用于显示弹出菜单,
如果 down-mouse-1 绑定到名称具有 mouse-1-menu-command 属性的命令,
Emacs 会按照上一段所述的方式额外处理。
当一个触摸点已经在转换过程中,又注册了第二个触摸点时,
手势转换会终止,并测量第二个触摸点(辅助工具)
到第一个触摸点的距离。
随后这两个触摸点中任意一个的移动都会产生
touchscreen-pinch 事件,
其中包含它们新位置之间的距离与最初测量距离形成的比例,
如下表所示。
如果在转换过程中检测到触摸手势, 可能会生成以下输入事件之一:
(touchscreen-scroll window dx dy) ¶如果在转换过程中检测到 “滚动(scrolling)” 手势,
每个后续的 touchscreen-update 事件会被转换为
touchscreen-scroll 事件,
其中 dx 和 dy 以像素为单位指定
触摸点相对于启动序列的 touchscreen-begin 事件位置
或上一个 touchscreen-scroll 事件位置的相对移动,
以较晚者为准。
(touchscreen-hold posn) ¶如果在生成 touchscreen-begin 事件后,
单个活动触摸点保持静止超过 touch-screen-delay 秒,
转换过程中会检测到 “长按(long-press)” 手势,
并发送 touchscreen-hold 事件,
其中 posn 设置为包含 touchscreen-begin 事件位置的鼠标位置列表。
(touchscreen-drag posn) ¶如果在转换当前触摸序列时检测到 “长按(long-press)” 手势,
或者由于 touch-screen-extend-selection 用户选项
恢复 “拖拽选择(drag-to-select)”,
则在每个后续的 touchscreen-update 事件时发送
touchscreen-drag 事件,
其中 posn 设置为触摸点的新位置。
(touchscreen-restart-drag posn) ¶该事件在触摸序列开始时发送,
表示继续 “拖拽选择(drag-to-select)” 手势(取决于上述用户选项),
其中 posn 设置为该触摸序列中初始
touchscreen-begin 事件的位置列表。
(touchscreen-pinch posn ratio pan-x pan-y ratio-diff) ¶当辅助工具处于活动状态时, 任一活动触摸点的位置发生显著变化时发送该事件。
posn 是从辅助工具到另一个被观察触摸点连线中点的鼠标位置列表。
ratio 是被观察的两个触摸点之间的距离 除以辅助点最初注册时的距离; 也就是 “捏合(pinch)” 手势的缩放比例。
pan-x 和 pan-y 是 posn 的像素位置 与属于该系列触摸事件的上一个事件中此位置之间的差值, 如果不存在这样的事件,则为辅助工具最初注册时 两个触摸点之间的中心点。
ratio-diff 是当前事件的比例与上一个事件中 ratio 的差值; 如果不存在这样的事件,则为 ratio。
当这些事件所表示的变化幅度会导致 ratio 与上一个事件中的值相差超过 0.2 时, 或者 pan-x 与 pan-y 之和超过框架字符宽度(以像素为单位)的一半时(see Frame Font), 会发送此类事件。
为处理触摸屏事件的 Lisp 程序提供了多个函数。
下面描述的前两个函数旨在用于直接绑定到
touchscreen-begin 事件的命令;
它们允许独立于鼠标事件转换响应常用的触摸屏手势。
该函数用于跟踪源自 touchscreen-begin 事件 event 的单个 “轻触(tap)” 手势,
通常用于设置点或激活按钮。
它等待具有相同触摸标识符的 touchscreen-end 事件到达,
此时返回 t,表示手势结束。
如果在此期间到达 touchscreen-update 事件,
并且包含至少一个与 event 中标识符相同的触摸点,
则使用两个参数调用函数 update:
该 touchscreen-update 事件中的触摸点列表和 data。
如果 threshold 为非 nil,
并且此类事件表明 event 所代表的触摸点
已经超出 threshold 阈值(如果不是数字则为 10 像素)
相对于 event 位置的移动,
则返回 nil 并为该触摸点恢复鼠标事件转换,
以免妨碍识别来自其序列的任何后续触摸屏手势。
如果在此期间到达任何其他事件,返回 nil。
在这种情况下,调用者不应执行任何操作。
该函数用于跟踪源自 touchscreen-begin 事件 event 的单个“拖拽”手势。
其行为类似于 touch-screen-track-tap,
不同之处在于,如果 event 中的触摸点
没有移动足够距离(默认情况下,相对于其在 event 中的位置移动 5 像素)
以符合实际拖拽的条件,
则返回 no-drag 并避免调用 update。
除这两个函数外,还提供了一个函数, 用于绑定到通过鼠标事件转换生成的某些类型事件的命令, 以防止在调用后生成多余事件。
调用该函数后,在转换当前触摸序列期间,
会禁止在鼠标事件转换过程中生成 touchscreen-drag 事件。
它必须从绑定到 touchscreen-hold
或 touchscreen-drag 事件的命令中调用,
否则会发出错误信号。
由于该函数只能在鼠标事件转换过程中 已经识别出手势后调用, 调用后,构成前述触摸序列的触摸事件将不会生成任何鼠标事件。