多点触控输入是一种输入类型,它依赖于触摸屏输入概念,还可能依赖多种触控及其被解释为单元(有时也称为帧)的特征。多点触控输入需要有对触控敏感的硬件,以及支持将触控事件向各应用程序公开所需基础结构的环境。本主题讨论 Silverlight 中对多点触控的支持,并介绍几个关键概念。
多点触控硬件
多点触控这一概念需要能够记录表面上所产生触压的硬件。该表面可以直接是屏幕(如 Tablet PC 设备),也可以是单独的专用输入设备(如绘图板)。其中,Tablet PC 设备或类似的显示屏直接对触控敏感的设备通常与 Silverlight 关联最大。
平台要求
多点触控需要有能够将触摸屏输入传播到某一个应用程序(如基于 Silverlight 的应用程序)的环境(平台和操作系统、诸如浏览器等的宿主应用程序)。
在操作系统级别上,Windows 7 支持多点触控输入。一部分是通过消息 WM_TOUCH 来支持的。该操作系统已在此级别将多点触控消息提升为鼠标消息,由此使多点触控用户在与可能不具触控识别能力,而是通过鼠标事件/消息执行其所有空间输入处理的应用程序进行交互时,可以使用触控和笔势来代替鼠标移动或鼠标单击。Windows 7 还可在适当时合并这些消息。
Internet Explorer 版本 8 作为宿主也是能识别多点触控的,它转发平台多点触控消息的方式为:插件(如 Silverlight)可以与宿主中的多点触控交互。
Silverlight 的多点触控输入
注册多点触控
作为操作系统的多点触控设计的一部分,每个希望独立接收多点触控消息的应用程序必须注册其 HWND(为此,Windows 7 的触控 API 包含 RegisterTouchWindow)。对于整个 Silverlight 和所有将 Silverlight 用作运行时的应用程序,Silverlight 编程环境负责此注册步骤。因此,通常不需要直接与平台代码交互来处理多点触控输入。但是,由 Silverlight 为自身注册多点触控的方式所声明的多点触控交互的特有特征是相当具有特定性的:
- Silverlight 注册原始触控输入,而不注册笔势。如果需要包含笔势,您必须在 Silverlight 的上下文中使用自己的应用程序代码将触摸屏输入处理为笔势。此外,还需要进行更大规模的互操作设计,以便您可以在其中包含一个单独的 HWND,它将从平台进行笔势的多点触控注册,并且与 Silverlight 内容区域进行互操作。
- 通常,Silverlight 将原始触摸屏输入提升至鼠标事件。(但是,可以基于每个触控帧禁用提升,在本主题的下面几节中将会说明。)
提升至鼠标事件
鼠标事件提升使多点触控用户在与可能不具触控识别能力,而是通过鼠标事件/消息执行其所有空间输入处理的应用程序进行交互时,可以使用触控和笔势来代替鼠标移动或鼠标单击。从概念上说这是默认的,因为先前的应用程序或不考虑多点触控的应用程序不知道要调用哪个 API 来执行该提升,所以在大多数情况下由平台来执行鼠标提升。出于大部分都相同的原因,Silverlight 保留了鼠标事件提升的一般概念。任何给定的现有 Silverlight 控件都可能具有鼠标事件的处理程序,但不是专门用于多点触控事件的。例如,当用户使用多点触控设备与按钮交互时,按钮的预期行为与鼠标单击时的相同。
如果有专门用于多点触控帧及其触控点的处理,鼠标事件提升的确可能实现双重事件。在 Silverlight 的多点触控事件处理程序正文中,可以在主向下触控操作期间挂起鼠标事件提升。例如,如果要创建一个可识别触摸的按钮,该按钮根据触摸特征执行不同的操作,则您可以挂起提升,以使该按钮不提升至通常的"单击"行为,而是根据处理输入的方式进入不同的代码路径。为此,请调用 SuspendMousePromotionUntilTouchUp 作为处理程序最初的操作之一。
鼠标提升的具体特性不在此讨论,因为这是平台特征。一般说来,该机制是消息到消息的提升。
将触控处理为笔势
Silverlight 在原始消息级别上处理多点触控消息,类似于平台 WM_TOUCH,它还在该原始级别上处理对可捕获触控点特征的其他 API 的访问,并将这些 API 作为 Silverlight API 公开。Silverlight 本身不会将触控处理为笔势,请使用平台功能实现该效果,或者处理 WM_GESTURE。(处理 WM_GESTURE 需要处于平台注册状态,而 Silverlight 不会自动选择该状态。)
如果要使用笔势比喻处理多点触控,代码中必须处理触控事件并使用 Silverlight 下公开的 API 将其处理为笔势,可以使用也可以不使用笔势的平台 API。这一点无关紧要。
触控 API
多点触控输入与 Silverlight 中支持的其他输入方法(鼠标、键盘、触笔)之间的一个主要差异在于,注册多点触控事件是基于应用程序范围的,而不是向特定输入元素(UIElement 对象)添加处理程序。这与 Silverlight 整体上是向平台注册的"应用程序"这一比喻一致的。
- 指定多点触控事件处理程序的方法是为静态事件 Touch..::..FrameReported 指定一个处理程序。System.Windows.Input..::..Touch 是一个只出于目的而存在的静态服务类,Touch..::..FrameReported 是其仅有的 API。
- 为 Touch..::..FrameReported 编写的处理程序基于 TouchFrameEventHandler 委托。
- 在典型的 UI 设计中,可能会有一个要在其中支持特定多点触控操作的 UI 区域,还会有最好在其中使用鼠标提升而不一定要将输入处理为多点触控的其他区域。若要确定主触控点的位置,必须针对可识别多点触控的元素的位置及其边界计算整个坐标。有关更多信息及代码示例,请参见 GetPrimaryTouchPoint。
- 如上所述,作为 TouchFrameEventHandler 逻辑的一部分,您可能需要挂起鼠标事件提升。为此,请调用 SuspendMousePromotionUntilTouchUp 作为最初的操作之一。
- 向 Silverlight 报告的触控消息通常组合为帧,这些帧以主"向下"触控点开始。有时候您可能只对第一个触控点和第一个"向上"操作感兴趣,但帧可能包含其他触控点和"移动"操作。若要在处理程序中访问帧中各点的完整集合,请调用 GetTouchPoints。对于给定的触控点,最重要的信息可能是其 Position。
- 在平台 API 中公开信息的其他 API 可在 TOUCHINPUT 结构中找到。这些 API 的示例有:TouchFrameEventArgs..::..Timestamp;TouchDevice..::..DirectlyOver;TouchPoint..::..Size;TouchPoint..::..TouchDevice。随方案不同,可能不会始终需要此级别的信息。
1: public MainPage()
2: {
3: InitializeComponent();
4: Touch.FrameReported += new TouchFrameEventHandler(Touch_FrameReported);
5: }
6:
7: void Touch_FrameReported(object sender, TouchFrameEventArgs e)
8: {
9: foreach (TouchPoint tp in e.GetTouchPoints(this.Positions))
10: {
11: if (tp.Action == TouchAction.Down)
12: {
13: // do something
14: }
15: }
16: }