触摸事件的生命周期

本文档介绍了在 Fuchsia 平台上如何处理来自触摸设备(触摸屏或触控板)的事件。

概览

概括来讲,事件路径被划分为在不同级别的抽象和状态上运行的多个组件。

  • 驱动程序知道来自触摸设备的原始触摸事件,但不知道视图树。
  • 输入管道了解视图系统和设备详情,但不知道视图树中的特定视图客户端。
  • Views 拥有界面客户端(也称为 Flatland 客户端)和视图树数据结构,其中包括命中区域等关键详细信息。因此,Sensing 会执行点击测试来确定触摸事件的实际目的地。
  • 客户端知道它收到的事件,但不知道发送到其他客户端的事件。

这种划分方式支持可就触摸事件分派做出断言的特定全局属性。

  • 驱动程序的工作非常简单,不涉及任何界面客户端互动。
  • 通过 fuchsia.ui.pointerinjector 协议的输入流水线必须知道视图树层次结构。通过这种方式,它可以对一组特定的客户端强制执行触摸事件。它甚至可以保证特定界面客户端的机密性、完整性和可用性(通过独占模式注入)。
  • Schens 并不知道实体设备及其怪异。而是通过输入流水线创建的注入器协议在抽象设备上运行。

这些部分是剪切层,使平台或产品能够在不修改整个堆栈的情况下引入不同的行为。例如,您可以设置一个简单的触控板来模拟实体鼠标设备。可以在测试环境中设置模拟触摸屏。如果界面客户端尚无法使用新的模态抽象化(例如触控笔),则可以将新输入模态暂时设置为旧版设备。

界面客户端协议

界面客户端的核心协议(典型的 Fuchsia 应用会看到)是 fuchsia.ui.pointer.TouchSource 协议。它以缩放不变的 injector viewport 抽象将触摸事件传递给界面客户端,Flatland 会提供转换矩阵,将这些 injector viewport 坐标转换为特定于视图的坐标。通过这种方式,界面客户端可以在放大时识别物理缩放手势,但也允许手势直接操作它位于视图坐标系内的界面元素之一。

为提高效率,事件可以作为向量进行批处理。我们无法保证事件一定会(或一定不会)批量处理。

事件的时间戳在驱动程序中生成,并一直保留到此时间点。因此,在到达界面客户端之前,手势速度计算不会受到 FIDL 事件延迟的不利影响。

驱动程序

hid-input-report 会解析 USB Touch HID 输入报告,并将其转换为 FIDL sdk/fidl/fuchsia.input.report/touch

解析 HID 报告很麻烦,因此界面团队决定避免将 HID 导出到驱动程序实现之外。界面团队为触摸、鼠标和键盘等常见事件定义了一个简洁的 FIDL。这样,输入流水线和其他组件就可以轻松与驱动程序进行交互。

不常见的 HID 设备会怎么样?

Fuchsia 可能会直接将 HID 连接提供给实际上非常了解该 USB HID 设备的客户端,并让它直接进行处理。不过,驱动程序作者可以选择根据更易于使用的 FIDL 而不是 HID 来定义事件。

输入管道

Input Pipeline 可以处理 2 种类型的触摸设备,并将它们转换为不同的事件以将其转换为 scenic

触摸屏

输入管道通过设备坐标(来自设备描述符)获取联系位置,输入管道会将其标准化为显示坐标中的物理像素。输入流水线还会监视 scene_manager 的视口更新,以将界面客户端的 injector viewport 附加到事件。

在输入流水线中,injector viewport 通常采用物理像素和显示坐标。这样可以更轻松地与后续事件处理进行通信。

触控板

当设备报告 HID 集合(包括 Windows 精确触控板收集(一种广泛使用的触控板标准)时,输入流水线会将设备标识为触控板。

触控板事件会转换为鼠标事件,例如双指垂直或水平移动会被解释为鼠标滚动事件。本文档不会介绍触控板的其余部分。请参阅鼠标文档

注入器视口

injector viewport 抽象是将缩放不变的手势数据中继到界面客户端的关键部分,以便在放大等影响下正确解释指针移动。该结构定义了视口在视口坐标系中的最小和最大范围。

视口(矩形)的边界与视口坐标系对齐;不过,它可以在此区域内自由放置(“浮动”):可以平移和缩放,但不能旋转。浮动使注入器在如何传递坐标方面提供了一些选择,例如在 Vulkan NDC 中或屏幕像素坐标中。视口矩形定义了调度中使用的锁存区域。

界面客户端会接收指针在视口坐标系中的坐标,以及用于将视口坐标系中的坐标转换为界面客户端坐标系的矩阵。

命中区域

Flatland 协议定义了不可见的“命中区域”,用于描述在界面客户端的视图空间内用户可以进行互动的位置。通常情况下,整个视图都是交互式的,因此 Flatland 会提供完全覆盖整个视图的默认命中区域。

某些高级场景需要对命中区域进行更多设置。例如,如果父视图嵌入了子视图,并且父视图还想要“弹出”会部分遮挡子视图的叠加层,则父界面客户端必须将相应叠加层的大小描述为命中区域,即 Flatland。

关闭视图中的所有命中区域意味着界面客户端的图形内容将对用户可见,但用户的触摸操作不会被分派到此界面客户端。此外,无障碍功能无法将界面客户端的语义内容与用户手势相关联。

手势消除歧义

界面客户端通常会参与手势消除歧义协议,以确定每个手势的手势所有者。Flatland 将通知界面客户端是被授予还是拒绝该手势。GD 协议具有协作性,因此拒绝手势必须视为取消。如果界面客户端无法保证某个手势可被视为已取消,则权宜解决方法是直接缓冲触摸事件,直至获得所有权授予为止,否则舍弃这些事件。某些客户端(例如 Chrome)会使用这种悲观模型,以便 Fuchsia 的触摸事件实际上不会转换为 JavaScript 事件,除非通过 Flatland 的显式手势所有权保证。

无障碍功能的 LocalHit 协议升级

无障碍功能的界面客户端需要常规界面客户端不应接收的额外数据。这些额外的数据通过平台专用协议 fuchsia.ui.pointer.augment.LocalHit 提供,该协议可将客户端的 TouchSource 端点“升级”为包含更多数据字段的更精美版本。

这些数据字段描述了每个指针事件的命中测试结果,能够提供非常精细的数据,以了解每个触摸事件所在的视图和视图内部位置。

无障碍功能利用这些命中数据执行“探索模式”。