怎么让css鼠标手势点到input上有显示手势

WGestures鼠标手势 | YingDev
WGestures全局鼠标手势
一个更简单、更现代的鼠标手势。免费 & 开源。
当前版本: 1.8.3.0&() &&系统要求: Windows 7+
&&"360卫士"用户请注意: 您可能需要禁用其“驱动防护”功能,已知该功能可能导致WGestures“右键失效”问题
停止浪费时间在琐碎操作上!WGestures让用户跳过琐碎细节,专注于重要的事物。
WGestures包含大量预设手势
精心设计的"快速入门"教程
不言自明的设置界面
&"搜" Easy!
搜索引擎是每个用户必不可少的工具,WGestures专门设计了"Web搜索"操作来简化搜索信息的流程。
随时随地,一个手势就能搜索选中的文字。
支持Google、百度和必应,以及自定义的搜索引擎。
随着手势数量的增加,用户要记忆越来越多的手势,这是个头疼的问题。WGestures从用户角度出发,设计出了更符合直觉的方案。
修饰键:让一个手势变为多个
手势名提示:手势名称实时反馈到屏幕上,消除误操作
&触发角&&&摩擦边
有了“触发角”功能,您只需将鼠标移到屏幕角落即可触发相应操作,快如闪电。
“摩擦边”允许您用鼠标摩擦屏幕边缘来执行一些例行性的操作,比如锁屏、关机等。
1.8.3.0 # 修正鼠标交换左右键情况下无法弹出菜单的问题# 修正托盘菜单显示暂停快捷键不同步问题# 避免意外失效+ 为cmd增加预设的“标记”、“复制”和“粘贴”手势* 低调恢复隐藏图标功能(只通过 Shift+左键+中键)1.8.2.0 # 修正空快捷键导致启动时崩溃问题1.8.1.0 * Win键触发变为可选1.8.0.0 + 增加 “摩擦边” 功能+ 增加 X键 触发和修饰功能+ 增加 Win键 触发功能+ 自定义暂停快捷键(默认 Ctrl-Alt-Shift + W)+ 按键序列延迟支持: {sleep 100} (毫秒)* 增加预设手势:缩放(↑▲/▼/●),切换虚拟桌面(x1→/←)* 更细腻的轨迹显示,手势执行时标签颜色匹配系统主题色* “命令行”自动提取首行注释(::/rem)为描述信息* 显示标签:修饰符置于手势名称之后# 修正当命令行代码包含注释符时不正常运行的问题- 删除“隐藏托盘图标”功能- 删除“左键+中键”暂停,避免与其他软件冲突1.7.4.0 + 触发角支持执行命令行操作# 修正Win10上自启动后以低权限运行问题(表现为无法作用于“以管理员权限运行”的程序)1.7.3.0 # 修正命令行“隐藏窗口”仍出现cmd窗口闪过# 修正Web搜索设置在某些系统上出错1.7.2.0 + 增加窗口置顶操作+ 增加2个预设手势: 窗口置顶(↑→↑), 强制退出(↓←?)* “输出文本”改为“按键序列”, 比如 hello{enter}* Cmd支持相关的环境变量 (WG_PROCID, WG_WINID等), Lua加入Context对象* 更新的快速入门* 优化轨迹显示效果# 修正使用默认浏览器搜索被360阻止问题# 修正win7显示Web搜索设置报错# 修正添加ModernApp识别错误问题# 修正1.7.1引入的多屏轨迹未显示Bug# 修正添加/编辑手势错误地提示“已存在”问题1.7.1.0 * Web搜索内置引擎使用 支持选择浏览器* 允许无聊人士画更长的轨迹 ( ^ω^)* 设置界面细节调整* 细粒度的音量调整* 性能优化# 修正一些小bug1.7.0.0 + Lua脚本支持+ 自定义触发角+ 恢复默认手势* 触发角支持多显示器# 修正编辑手势保存按钮不可点击问题# 修正高dpi屏幕上设置界面显示问题1.6.4.0 # 修正Web搜索可能无法打开浏览器# 图标隐藏提示信息修正* 如果已经在运行,再次运行将打开设置1.6.3.0 # 修正手势无效时仍激活窗口问题# 修正exe路径大小写引起的识别错误1.6.2.0 # 修正“总是作用于指针下方窗口”相关的bug# 修正在“全屏自动禁用”时,触发角在全屏下依然被触发的问题1.6.1.0 + 增加选项"总是作用于指针下方窗口"1.6.0
+ 触发角+ 增加 允许使用斜线 选项# 修正64位系统上可能无法正常工作问题# 修正应用程序安装在RamDisk的情况下获取进程信息错误的问题1.5.2
# 修正导入1.4版本wgb文件错误(1.5.2.2) * 优化手势存储格式* 手势列表允许拖拽排序* 轨迹更平滑* 统一暂停/继续、托盘显示/隐藏控制方式# 修正多显示器路径显示问题1.5.1
+ 隐藏/显示托盘图标(左键+右键)+ 手势名称支持显示执行状态反馈(目前 音量控制 能反馈音量+/-)# 修正添加/修改手势无法录入纯修饰键手势问题1.5.0
(春节快乐!)+ 增加手势触发键选项(右键/中键/右+中)+ 编辑手势* Win10兼容* 性能优化,降低内存占用* 启动速度提升# 修正长期以来的“右键点击卡死”Bug1.4.1# 修正shift+delete删除不会强制删除的问题(以及相似问题)* 改善容错能力,减少在与其他软件冲突时崩溃的几率 并尽可能 恢复键盘状态1.4.0
# 修正“起始超时”和“停留超时”冲突的问题# 修正偶然崩溃的问题# 修正禁用手势程序上,修饰键被拦截的问题(比如SublimeText上的右键+滚轮切换tab)+ 支持中键手势+ 支持 [左键+中键] 在任何地方暂停/继续WGestures(左手习惯用户为 右键+中键)+ "继承全局手势"选项,允许应用程序不使用全局手势* 设置界面Tweak* 右键拖拽的准确性1.3.1
# 修正被禁用手势的程序上“修饰键”被拦截的问题# 修正由于第三方库引起的可能使ALT键处于“按下”状态的问题(表现为点击桌面图标,显示“属性”)+ 增加手势修饰键,并允许使用修饰键“立即执行”+ 支持多显示器+ 支持右键拖拽(起始超时)+ “全屏模式禁用”选项+ “执行命令行代码”支持“自动设置工作目录”(比如当前打开的文件夹)+ 音量控制操作+ 支持左手使用习惯+ 导入/导出* 改善“禁用手势”应用程序上鼠标操作延迟的问题* 程序列表和手势列表允许拖拽排序* 设置界面改进* 改善与部分国产软件的兼容问题(搜狗浏览器等)* 优化响应速度* 安装程序简化1.2.0.0
新增: “执行命令行”和“输出文本”操作修正: 解决UIPI限制,并支持Metro应用程序,支持Alt+Tab切换程序(默认手势:右下右)修正: 使用注册表自启动,不再需要管理员权限改进: 使用独立线程执行命令,提高性能减少崩溃卡顿1.1.1.0
修正: 某些情况下在迅雷上不能正常显示轨迹的问题; 提高优先级,减少了系统繁忙时手势卡顿的几率1.1.0.0
新增: 现在可以使用8个基本方向。预设↗最大化,↙最小化,↘显示桌面1.0.0.1
改进: 减少内存占用。以及其他小问题。1.0.0.0
第一个正式版。提问者:匿名 & 时间:
>> >> >> >> >> >> >> >> >> >>
asp.net中当鼠标点击文本框时如何让TextBox1或者HTML中Input(Text)控件里默认的字符自动清除?
先让TextBox1的Text的值是一个字符串,或者让HTML中Input(Text)的Value的值为一串字符串,运行网页后呈现出来的文本框里就会有预先打好的值,当鼠标点到该文本框的时候,该框的字符串自动清除的效果,谢谢赐教【尽量详细点,新手】问题补充:
&td style="width: 100px"&
&td style="width: 100px"&
&input id="HTML_Name" type="text" value="请输入您的名字" onfocus="if(value=='请输入您的名字'){value="}"onblur="if(value=="){value='请输入您的名字'}"/&&/td&
&td style="width: 100px"&
HTML中的INPUT(TEXT)这种效果:&html&&head&&title&&/title&&/head&&body&&input type="text" value="testValue" onfocus="if(value=='testValue') {value=''}" onblur="if(value=='') {value='testValue'}"&&/body&&&#4沪揣高废薨肚胳莎供极7;html&把上面的代码作成html文件,运行就有效果shijiaokun
asp.net中textbox控件如何正常显示html文本
asp.net中当鼠标移动到文本框时如何让TextBo...
如何让asp.net的textbox控件和html的i...
Asp.Net中HTML控件Input(Text)和T...
asp.net的TextBox控件问题:这个控件如果输...更多相关问题&&
鼠标点击文本框内文字就消失 Input属性怎么写
鼠标点击桌面没反应
当鼠标点击一个链接
鼠标点击左键一次,怎么会默认为双击?
鼠标点击文本框 后面显示文字手势是HoloLens三个首要输入形式之一。一旦你使用凝视定位了一个全息图像,手势允许你与它交互。手势输入允许你使用手或者点击器原生地与全息图像交互。
手势之外,你也可以在应用中使用语音输入来交互。
手势识别 Hand recognition
HoloLens通过追踪手来实现手势识别。HoloLens能够明白手什么时候准备好了(竖起食指手背面向脸)或者点击(手背向脸食指点下)。当手处于其他姿势时,HoloLens将会忽略它们。
HoloLens在设备前方的锥形范围内追踪手部运动,这片区域被称为手势框(gesture frame),这拓展了全息图像显示视图的上下左右边界。这允许你手势输入时,可以舒适地保持着手臂弯曲。当使用点击器时,就不必将手保持在手势框之中。
对于每个HoloLens识别的手,你能够得到它的位置(无方向)和他的点击状态。当手接近手势框边缘时,你能得到一个方向向量,你可以提醒用户将手移回HoloLens可识别的区域。
交互 Interactions
HoloLens的核心交互是点击(press)、松开(release)和绽开(bloom)手势。
点击和松开 Press and release
你选中和激活全息图像的首要方式是air-tap手势,它包含了一个点击和松开手势。
Air-tap手势,首先是指面向了脸点下,这是点击手势;随后食指向上松开,这是松开手势。Air-tap会实现对全息图像的选择,点击器或者语音命令也能做到。
绽开手势 Bloom
Bloom是很特别的系统手势,被用于从全息应用中唤起开始菜单。这和在键盘上点击Windows键或者Xbox手柄上点击Xbox按钮功能类似。
为了做Bloom手势,先攥紧拳头,手心向上,然后五指绽开。通过说:&Hey Cortanna,Go Home&也能唤起开始菜单。注意:你的应用无法刻意响应Bloom手势,因为它只能被系统响应。
手势 Gesture
你的应用可以识别简单点击和松开之外更多的手势。通过移动手或使用点击器,你可以做更多复杂的手势:
长按Hold:保持点击手势直到触发系统长按手势阈值
操作 Manipulation: 保持点击手势,在3D世界中绝对运动
导航 Navigation: 保持点击手势,在一个标准3D立方空间内相对运动
长按手势 Hold
Hold手势和触屏上长按手势类似,被用于执行二级行为,例如拿起一个对象而不是激活它或者显示上下文菜单。
操纵手势 Manipulation
当你想要全息图像1:1响应用户手部移动时,操纵手势能被用于移动、缩放或旋转全息图像。如此的一个用处是使得用户可以在世界中绘制图像或作画。
使用所有的手势时,操纵手势的初始目标应该通过凝视来选中。一旦点击手势开始,通过手部移动的任何对对象的操作都能够被处理,在用户操作全息图像时,从而使得用户得以自由地四处张望。
操纵行为只能使用手势来实现。
导航手势 Navigation
导航手势就像一个虚拟的操纵杆,能够用于UI控件导航,例如弧形菜单。通过点击开始手势,然后在以点击处为中心的标准立方空间中移动手部。你可以沿着X、Y、Z轴移动手部,这回带来数值-1到1的变化,初始位置的值为0.
导航手势可以用于构建基于速度持续滚动或缩放的手势,这和在2D UI上通过按住鼠标滚轮上下移动类似。
定向导航是指在特定轴上识别运动直到此轴上阈值的能力。当应用中开发者启用了多轴运动,这很有用,例如如果一个应用被设置为识别X、Y轴上的运动,但同时X轴被设为定向导航。在这种情况下,如果手也在Y轴上移动,只要他们保持在X轴假想导轨区间上,系统会识别到X轴上的手势移动。
在HoloLens 2D应用内,用户可以使用垂直导航手势来滚动、缩放或在应用内拖拽。为了模拟同样类型的触摸手势,导航手势为应用虚拟了手指触摸,实际体验和触屏上的相应手势类似。用户可以通过切换Holobar上的Scroll/Drag/Zoom工具来显示相应行为。
阅读(...) 评论()windows7多点触摸
您的位置: →
windows7多点触摸
第一篇:windows7多点触摸Windows 7 中的多点触控功能
本文是有关 Windows 7 的系列文章的第三篇文章。该系列文章主要介绍了新的用户体验,开发人员可以 深入研究这些体验,使其应用程序在 Windows 7 上发挥强大作用。第 1 部分介绍了库。第 2 部分介绍 了任务栏 API。3 部分介绍 Windows 7 中的多点触控功能。第 请立即下载 Windows 7 Release Candidate, 以帮助您充分理解本文。
Windows 7 多点触控简介
在 Windows 7 中,我们通过触控功能丰富了 Windows 体验,从而使触控成为继鼠标和键盘之后又一种 与 PC 进行交互的绝佳方式。近年来, 各种多点触控设备相继问世, 创造了极佳的用户体验。因此, Windows 理所当然地在 Windows 7 中引入了这种多点触控支持,并将其作为一项核心功能。通过 Windows 7 多点触控平台, 您可以随心所欲地直接与计算机进行交互。例如, 您可以直接从 Windows 资源管理器中访问和缓慢浏览图片,也可以通过点按操作快速浏览这些图片。有一点您必须清楚的是,我 们并未创建特殊的 Windows 7 多点触控外壳程序, 也未提供只能在多点触控设备上使用的特殊 Windows 资源管理器。Windows 7 任务栏跳转列表就是一个最简单的示例。使用鼠标右键单击任务栏上的任一图标 时,您将看到对应的跳转列表。例如,右键单击 Windows Live Messenger 图标可以显示 Live Messenger 的跳转列表。但如何使用多点触控实现右键单击的功能呢?只需用手指触摸 Live Messenger 图标并将其 拖出,如图 1 所示。
图 1:在 Live Messenger 的跳转列表上使用多点触控 执行该拖动手势可以显示 Live Messenger 的跳转列表。如图 2 所示,通过触控触发的跳转列表显示了与 标准右键单击跳转列表相同的内容。右侧的图像显示了使用触控触发的 Live Messenger 跳转列表。多点 触控启用的跳转列表中每个列表项之间的间距大于左图(默认的右键单击跳转列表)中每个列表项之间的 间距。
图 2:跳转列表的多点触控视图和标准视图 Windows Live Messenger 只是一个示例,它可以证明 Windows 7 没有专为触控方案创建一组新的 UI, 而是将其结合到现有基础结构中。任务栏也只是一个示例,它可以证明 Windows 7 提供的多点触控功能 可以带来诸多优化体验,例如 XPS 查看器、Windows 照片查看器和 IE8。
Windows 7 多点触控平台编程模型
为了提供适用于各种应用程序的全面 Windows 触控解决方案, Windows 触控平台提供了不同级别的支持。您可以通过多种方案来使用 Windows 触控平台功能增强应用程序。在采用某种特定方法之前,应该考虑 一下您究竟希望如何让应用程序支持触控。旧版支持 假定您已经有一个广泛安装使用的现有应用程序。您可能会问自己, 在启用多点触控的 Windows 7 计算机上运行该应用程序时,用户使用多点触控的体验将是怎样的呢?令人庆幸的是,对于那些无法识 别触控且不支持多点触控的应用程序,Windows 7 多点触控平台提供了现成的免费支持。具体来说,它为 一些基本手势提供了现成的免费支持。换而言之,您可以在应用程序中使用一些基本手势,并获得理想的 效果。基本手势包括在 Windows Vista 阶段引入的单指或双指平移手势、双指缩放手势以及光标手势。添加基本多点触控支持 在本部分, 我们的讨论重点是添加直接手势支持以及其他行为和用户界面更改, 以 使应用程序除了支持简单手势以外还可以更好地支持触控。在本文开头,我们已经了解一个触控优化的任务栏跳转列表示例。通过使用 getMessageExtraInfo 方法, 任务栏可以跟踪输入消息的来源,并确定该消息是否为触控消息,然后做出相应的响应。此外,您可以使用手势来增强应用程序,提供更好的多点触控支持。直接响应手势的应用程序可以完全控 制它们在用户触摸触控设备时的行为。例如,Windows 7 附带了 Windows 照片查看器。在照片查看器应 用程序中,查看器接收有关缩放手势起始位置的特定信息。也就是说,缩放手势包含有关缩放手势中心点
(特定的 X 和 Y 坐标)的信息,这使得照片查看器可以根据手势中心位置进行缩放。Windows 照片查 看器应用程序还使用平移和旋转手势来提供绝佳的图像查看体验,而且相对简单一些。利用手势,您还可以替代默认的平移行为。例如,默认的触控滚动适合在以文本为中心并通常垂直滚动的 窗口(例如网页或文档)中使用,而水平拖动则可以进行文本选择,而不是滚动。在大多数应用程序中, 这种触控方式可以正常工作。但如果您的应用程序实际上需要支持水平滚动,该怎么办?此外,对于某些 应用程序, 默认滚动可能显得不够灵活, 即速度过快或过慢。有了手势支持, 您可以替代默认的平移行为, 并根据应用程序的需要对其进行优化。多点触控优化体验 最好的情况是从头开始设计应用程序以支持多点触控。这些应用程序基于 Windows Messages 触控消息 WM_TOUCH 构建。此消息为应用程序提供原始触控数据,您可以利用这些消息并处 理多个接触点。我们之前提到的大多数手势都是双指手势, 您可以利用 WM_TOUCH 消息同时接收基础触 敏式硬件所支持的多个接触点。Windows 7 多点触控平台还提供操作和延时处理器,帮助您解释触控消息。可以将操作视作一个黑匣子, 用于以输入形式接收用户触摸的对象,以及所有相关的触控消息。结果是一个二维仿射转换矩阵,表示通 过手指移动产生的转换。例如,如果您要编写一个照片编辑应用程序,则可以使用一个或多个手指同时捕 捉两张照片,以对照片进行旋转、调整大小和转换操作,而操作过程将提供您需要在对象上反映的变化。延时为应用程序提供了一个非常基本的物理模型,并为您提供了一种简单的方法来继续平稳转换对象(即 使在您将手指从触敏式设备拿开以后也能平稳转换),并创建简单的转换效果,而不是立即停止对象。
默认情况下,每当用户触摸触敏式 Windows 7 设备时,Windows 7 多点触控平台都会向您的应用程序发 送手势消息 WM_GESTURE。这是现成的免费行为,如果您希望停止接收此类消息,则需要选择退出。手势被视为单指或双指触控输入,可以转换为用户执行的某种预定义操作(手势)。一旦检测到手势(操 作系统为您进行所有检测),操作系统就会向应用程序发送手势消息。此消息包含解码和进行操作所需的 全部信息。Windows 7 支持下列手势缩放 单指和双指平移 旋转 双指点击 按下并点击 处理 WM_Gesture 消息 要使用手势, 必须处理发送到应用程序的 WM_GESTURE 消息。如果您是 Win32 程序员,可以在应用程序的 WndProc 函数中检查 WM_GESTURE 消息。WM_GESTURE 是用于所有手势的通用消息。因此,要确定需要处理的手势,您首先需要对手势消息进行 解码。有关手势的信息可在 lParam 参数中找到,您需要使用一个特殊函数 GetGestureInfo 来解码手势 消息,如下面的代码片段中所示。GESTUREINFO ZeroMemory(&gi, sizeof(GESTUREINFO)); gi.cbSize = sizeof(gi); BOOL bResult = GetGestureInfo((HGESTUREINFO)lParam, &gi); 获取 GESTUREINFO 结构后,可以检查 dwID 以确定执行了哪个手势。GESTUREINFO 结构包含几个其他 重要成员bSize - 结构大小(以字节为单位)
ptsLocation - 一个 POINTS 结构,其中包含与手势相关的坐标。这些坐标始终都相对于屏幕的原点 dwFlags - 手势的状态,例如开始、延时和结束 ullArguments - 一个 64 位无符号整数,其中包含手势的参数,组合为八字节。这是额外信息,对于每个 手势类型都是唯一的 掌握了这些知识后, 我们可以继续操作并编写用于处理所有手势的完整 switch-case 方法, 如图 3 所示。
图 3:Switch-Case 方法
void CMTTestDlg::DecodeGesture(WPARAM wParam, LPARAM lParam) { GESTUREINFO ZeroMemory(&gi, sizeof(GESTUREINFO)); GetGestureInfo((HGESTUREINFO)lParam, &gi); switch (gi.dwID){ case GID_ZOOM// Code for zoo case GID_PAN case GID_ROTATE case GID_TWOFINGERTAP case GID_PRESSANDTAP default// You have encountered an u CloseGestureInfoHandle((HGESTUREINFO)lParam); } 请注意,在函数的末尾,我们调用了 CloseGestureInfoHandle 函数,用于关闭与手势信息处理程序相关联 的资源。如果处理 WM_GESTURE 消息,则您要确保使用此函数来关闭句柄。不这么做可能会导致内存泄 漏。处理手势消息具有一个固定流程,包括配置、解码手势消息以及根据应用程序的需要处理特定手势。正如 您在以上代码中看到的那样,执行这个流程并不很难。现在,让我们来详细了解缩放手势,通过这种手势,您也可以大致了解所有其他手势的工作原理。使用缩放手势缩放对象 缩放手势通常被用户视为两个接触点之间的“挤压”运动,您可以将手指相互靠近以缩小内容显示,或者将 手指分开以放大内容显示。使用缩放手势,您可以缩放对象的大小。图 4 说明了缩放手势的使用方式。
图 4:缩放手势 现在,我们将了解需要在 GID_ZOOM switch 中实现什么代码才能达到所需的缩放效果。手势信息结构包括 dwFlags 成员,该成员用于确定手势的状态,而且可以包括以下任何值GF_BEGIN - 指示手势即将开始,在第一个 WM_Gesture 消息中收到 GF_INERTIA - 指示手势已经触发了延时 GF_END - 指示手势已经完成 switch 的默认值 - 指示手势消息的剩余部分,通常称为变化量 我们将使用 GF_BEGIN 标志将接触点的初始开始坐标保存在变量中,并将其作为以下步骤的引用。我们将 ptsLocation 保存在 _ptFirst 变量中。对于缩放手势,ptsLocation 表示缩放的中心。收到的以下缩放消息由 default case 进行处理。我们将坐标保存在 _ptSecond 变量中。接下来,我们将计 算缩放中心点和缩放比例。最后,我们还将更新矩形(我们的图形对象)以反映缩放中心点和缩放比例。图 5 显示了这些参数。
图 5:GID_ZOOM Switch
case GID_ZOOMswitch(gi.dwFlags) { case GF_BEGIN_dwArguments = LODWORD(gi.ullArguments); _ptFirst.x = gi.ptsLocation.x; _ptFirst.y = gi.ptsLocation.y; ScreenToClient(hWnd,&_ptFirst); default// We read here the second point of the gesture. This is middle point between fingers. _ptSecond.x = gi.ptsLocation.x; _ptSecond.y = gi.ptsLocation.y; ScreenToClient(hWnd,&_ptSecond); // We have to calculate zoom center point
ptZoomCenter.x = (_ptFirst.x + _ptSecond.x)/2; ptZoomCenter.y = (_ptFirst.y + _ptSecond.y)/2;
// The zoom factor is the ratio between the new and the old distance. k = (double)(LODWORD(gi.ullArguments))/(double)(_dwArguments); // Now we process zooming in/out of the object ProcessZoom(k,ptZoomCenter.x,ptZoomCenter.y); InvalidateRect(hWnd,NULL,TRUE);
// Now we have to store new information as a starting information for the next step _ptFirst = _ptS _dwArguments = LODWORD(gi.ullArguments); } 在默认的 case 处理程序中,我们保存手势的位置,从两组点(表示当前接触点和前一个接触点)计算缩 放中心位置,并将其存储在 ptZoomCenter 中。我们还通过计算两个点之间的比例来计算出缩放系数。调 用 ProcessZoom 帮助函数可以更新新的坐标,以反映缩放系数和中心点。处理其他 Windows 7 默认手势与以上所述的特定缩放手势处理非常相似。所有手势都遵循相同的流程, 只是在每个使用案例场景中,每个手势的内部逻辑实现有所不同。接下来,我们将了解最佳模型,并深入 探讨让您能够接收和处理原始触控事件的 API。
处理 Windows 原始触控消息
要开始接收原始触控消息 WM_TOUCH,首先需要请求操作系统开始向应用程序发送触控消息,并停止发 送默认手势消息。若要执行此操作,则需要调用 RegisterTouchWindow(HWND hWnd, ULONG uFlags) 函 数。调用此函数可将单个 hWnd 元素(通常是一个窗口)注册为启用触控的。与手势相同,您在应用程序的 WndProc 函数中处理 WM_TOUCH 消息。单条 WM_TOUCH 消息可能包 含多条不同的“接触点消息”,需要将它们解包为一个触控输入结构数组。标准做法是将 WM_TOUCH 消息 解包为一个 TOUCHINPUT 结构数组,该数组中的每个结构表示来自单个接触点的数据。若要进行解包, 需要调用 GetTouchInputInfo(HTOUCHINPUT hTouchInput, UINT cInputs, PTOUCHINPUT pInputs, int cbSize) 函数,并向其传递 WM_TOUCH 消息的 lParam 以及一个新创建的接触点数组,如图 6 所示。
图 6:对 WM_TOUCH 进行解包
case WM_TOUCH{ unsigned int numInputs = (unsigned int) wP TOUCHINPUT* ti = new TOUCHINPUT[numInputs]; if(GetTouchInputInfo((HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT))) {
// Handle each contact point for(unsigned int i=0; i& numI ++i) { /* handle ti[i] */ } } CloseTouchInputHandle((HTOUCHINPUT)lParam); delete [] } defaultreturn DefWindowProc(hWnd, message, wParam, lParam);
在这里,您可以看到我们如何使用来自每个接触点的数据来填充 TOUCHPOINT ti 数组。接下来,我们将 遍历接触点数组,将逻辑应用于每个接触点 handle ti[i] 注释。最后,我们需要通过调用 CloseTouchInputHandle(HTOUCHINPUT hTouchInput) 清除触控句柄,传递原始 WinProc 的 lParam。不 这么做将会导致内存泄漏。以上代码表示处理 WM_TOUCH 消息的第一个步骤。单个触控输入结构 TOUCHINPUT 包含了有关您需要 使用的单个接触点的所有必需信息dwID - 接触点标识符,用于区分特定触控输入与其他输入 dwFlags - 一组位标志,用于指定接触点的状态 接触点的 X 和 Y 坐标(基本上是每个接触点的位置) dwTime - 事件的时间步长,以毫秒为单位 dwMask - 一组位标志,用于指定结构中的哪些可选字段包含有效值 请务必注意,X 和 Y 坐标的单位是实际屏幕坐标的像素的百分之一(即 centa-pixel)。对于可能需要高 分辨率的其他应用程序而言,这种超高分辨率有利于达到高精度,实现更加精确的手写识别。但在大多数 情况下,在开始使用这些坐标之前,请务必记住应将接触点的 X 和 Y 坐标除以一百,从而将接触点坐标 转换为可用的屏幕坐标。现在,您已经知道了如何处理触控消息, 并且掌握了为上述 WM_TOUCH 处理程序添加真实逻辑所需的全 部信息。接下来让我们利用这些知识来构建一个多点触控画图应用程序,也称为“草稿板”。跟踪接触点 ID 若要创建“草稿板”应用程序,需要跟踪每个接触点的运动及其形成的轨迹,然后沿着该轨 迹绘制线条。为了区分不同的接触点,确保真正正确地处理每个接触点,我们可以为每个接触点指定不同 的颜色。在将触控消息解包为触控输入结构数组 ti 之后, 需要检查每个接触点状态, 并针对每个接触点状态应用不 同的逻辑。在“草稿板”示例中,新接触点由向下状态 TOUCHEVENTF_DOWN 进行标识。您注册新的接触 点 ID, 并为其指定一种颜色。删除接触点 TOUCHEVENTF_UP 之后, 您完成最后的绘图, 并注销接触点 ID。在向上和向下事件之间,您很可能会收到大量移动消息 TOUCHEVENTF_MOVE。收到每条移动消息时,您 向现有线条添加一个新点,然后绘制新的线段。图 7 显示了“草稿板”应用程序支持多点触控所需的整个 WM_TOUCH 处理程序。
图 7:WM_TOUCH 处理程序
case WM_TOUCH:
{ unsigned int numInputs = (unsigned int) wP TOUCHINPUT* ti = new TOUCHINPUT[numInputs]; if(GetTouchInputInfo((HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT))) { // For each contact, dispatch the message to the appropriate message handler. for(unsigned int i=0; i& numI ++i) { if(ti[i].dwFlags & TOUCHEVENTF_DOWN) { OnTouchDownHandler(hWnd, ti[i]); } else if(ti[i].dwFlags & TOUCHEVENTF_MOVE) { OnTouchMoveHandler(hWnd, ti[i]); } else if(ti[i].dwFlags & TOUCHEVENTF_UP) { OnTouchUpHandler(hWnd, ti[i]); } } } CloseTouchInputHandle((HTOUCHINPUT)lParam); delete [] } 跟踪各个接触点的关键是使用 dwID,在特定触控笔划的整个过程中,它都保持不变。在 OnTouchDownHandler 帮助函数中,您将此 ID 指定给 CStroke 对象,该对象基本上是一个代表线条的 点数组。这个线条是您在触敏式设备上拖动手指时形成的轨迹。我们将不再介绍支持应用程序并在屏幕上 实际绘制线条的完整代码示例。在前面的代码示例中,您基本上可以找到支持多点触控所需的全部操作。在图 8 中,您可以查看“草稿板”应用程序的输出。
图 8:“草稿板”应用程序的输出 在默认的 case 处理程序中,我们保存手势的位置,从两组点(表示当前接触点和前一个接触点)计算缩 放中心位置,并将其存储在 ptZoomCenter 中。我们还通过计算两个点之间的比例来计算出缩放系数。调 用 ProcessZoom 帮助函数可以更新新的坐标,以反映缩放系数和中心点。处理其他 Windows 7 默认手势与以上所述的特定缩放手势处理非常相似。所有手势都遵循相同的流程, 只是在每个使用案例场景中,每个手势的内部逻辑实现有所不同。接下来,我们将了解最佳模型,并深入 探讨让您能够接收和处理原始触控事件的 API。
处理 Windows 原始触控消息
要开始接收原始触控消息 WM_TOUCH,首先需要请求操作系统开始向应用程序发送触控消息,并停止发 送默认手势消息。若要执行此操作,则需要调用 RegisterTouchWindow(HWND hWnd, ULONG uFlags) 函 数。调用此函数可将单个 hWnd 元素(通常是一个窗口)注册为启用触控的。与手势相同,您在应用程序的 WndProc 函数中处理 WM_TOUCH 消息。单条 WM_TOUCH 消息可能包 含多条不同的“接触点消息”,需要将它们解包为一个触控输入结构数组。标准做法是将 WM_TOUCH 消息 解包为一个 TOUCHINPUT 结构数组,该数组中的每个结构表示来自单个接触点的数据。若要进行解包, 需要调用 GetTouchInputInfo(HTOUCHINPUT hTouchInput, UINT cInputs, PTOUCHINPUT pInputs, int cbSize) 函数,并向其传递 WM_TOUCH 消息的 lParam 以及一个新创建的接触点数组,如图 6 所示。
摘要 Windows 7 多点触控平台是一个非常强大的开发平台。从实现默认手势支持到更高级的原始触 控消息,它为您提供了强大的功能,而且实现起来相对要简单一些。该平台还包括操作和延时处理器。操作在很多方面与手势相似,但却强大得多。使用操作可以 简化对任何给定数量的对象的转换操作。您可以同时对某个特定对象执行特定手势组合,例如 旋转、缩放和伸缩。操作处理器生成二维的“转换矩阵”,该矩阵用 X 和 Y 坐标来表示转换, 还表示由于执行接触点移动,对象随着时间推移发生的大小变化和旋转。最后一个接触点拉起 之后,您可能希望将简单的物理运动应用于对象,使其平滑停止,而不是突然停在点上。为了 支持这种平滑运动,Windows 7 多点触控平台提供了延时 API。
这些 API 将是我们下一篇 MSDN 文章的主题。
第一篇:windows7多点触摸基于 Visual C++ 2010 开发 Windows7 应用-开发多点触控 MFC 应 用程序
当下计算机变得越来越智能化,越来越无所不能,触摸屏的普及只是时间问题了。虽 然鼠标和键盘不会很快就离开人们的视野, 毕竟人们使用鼠标跟键盘已经成为一种习惯, 但 是处理信息或者说操作计算机的其他方法也层出不穷――比如触控技术。从硬件技术的角度 来讲,触控技术是可行的,随着最新一代的触摸屏技术,接触技术现在已经存在,如今 Web 开发人员可以利用 Silverlight 3 提供多点触摸功能。可惜的是,只有 Windows 7 同时支持 Silverlight 和多点触摸能力。这个因素大大制约了这部分功能的运用和推广,不过如果多点 触摸继续流行开来的话,情况会有所改变的,不过现在 Windows 7 为触摸屏技术提供了发 挥的软件空间,Windows 7 让屏幕触控技术成为可能。借助 Windows 7 和触摸感应屏幕,您只需使用手指即可在电脑上翻阅在线报纸,翻阅 相册,拖拽文件和文件夹。多年来在 Windows 中早已开始采用触控技术。Windows 7 进 一步将其扩展到电脑的每个角落。“开始”菜单和任务栏现在都采用了加大显示、易于手指 触摸的图标。常用的 Windows 7 程序也都可以执行触摸操作。您甚至可以在“画图”中使 用手指来画图! Windows 触控功能还可以识别多点触控(使用适当的监视器)。是否需要缩小图片将手指 捏在一起即可。是否要用鼠标右键单击某项内容?用一个手指触及该内容,并用第二个手指 点击屏幕即可。Windows 触控功能仅在 Windows 7 的家庭高级版、 专业版和旗舰版中提供。什么是触控操作呢?触控指 Windows 允许你使用手指直接与计算机进行交互的方式。与使用鼠标、键盘或手写笔相比,触摸更加方便、自然、具有吸引力。也更符合人们日常的 交流习惯。而 Windows 7 中引入了全新的多点触摸的概念。多点触摸又称多点触控,简而 言之可以理解为一个屏幕多点操作。多点触摸不但是两个点或者几个点同时应用到屏幕上这 么一点点便利,由于是多点触摸,所以他能感应到手指滑动的快慢以及力度(力度用触摸点 的多少转换来实现),从而操作系统应用起来更加人性化。传统的触控屏幕一次只能判断一 个触控点,若同时有两个以上的点被触碰,就不能做出正确反应,或者说反应混乱了。多重 触控的任务可以分解为两个方面的工作, 一是同时采集多点信号, 二是对每路信号的意义进 行判断,也就是所谓的手势识别。最早在 Apple 公司的 iPhone 上应用。多点触摸技术是一 项划时代的输入方式。可以设想随着全息投影的发展,完全有可能实现屏幕在空中投影,而 用户直接在投影中触控电脑,科幻电影中的场景将会变成现实。下面我们来看一段关于用手玩转 win7 触摸屏多点触摸屏电脑,现在您是不是被这种 绚丽界面所吸引,被这种便捷而有趣的操作所震撼? 我们自己打造的程序里面如何使用多点触摸技术呢, 就是让我们的程序也具有此种多 点触摸功能,用手就可以玩转我们的应用程序呢? 好了,不多说了,下面我用实例来讲解这些功能实现:
首先:我们基于 MFC 新建一个简单窗体工程,如下图所示:
单击&finish&完成工程创建
接下来我们向应用程序添加触控支持,表现以下两点1.我们正在构建的应用程序需要支持触控的硬件,因此我们需要在应用程序中查看这一点。2.在 Scratchpad.cpp 中,在 CScratchPadApp::InitInstance()后添加以下检查代码view plaincopy to clipboardprint? BYTE digitizerStatus = (BYTE) GetSystemMetrics(SM_DIGITIZER); if ((digitizerStatus & (0x80 + 0x40)) == 0) //堆栈就绪+多触点 { AfxMessageBox(L&No touch input is currently available.&); } BYTE nInputs = (BYTE) GetSystemMetrics(SM_MAXIMUMTOUCHES);
CS str.Format(L&Touch input available with %d touch points.&, nInputs); AfxMessageBox(str); BYTE digitizerStatus = (BYTE) GetSystemMetrics(SM_DIGITIZER); if ((digitizerStatus & (0x80 + 0x40)) == 0) //堆栈就绪+多触点 { AfxMessageBox(L&No touch input is currently available.&); } BYTE nInputs = (BYTE) GetSystemMetrics(SM_MAXIMUMTOUCHES); CS str.Format(L&Touch input available with %d touch points.&, nInputs); AfxMessageBox(str); 3. 您可以看到,除了查看触控可用性和就绪情况以外,我们还可以发现硬件支持的触控输 入数量。4. 编译并运行。5. 根据机器上触控输入的数量,您应该看到类似下图的输出:
6. 为 了 注 册 应 用 程 序 客 户 端 视 图 窗 口 来 接 收 触 控 消 息 , 我 们 需 要 调 用 MFC 函 数 CWnd::RegisterTouchWindow()。我们将在视图创建之后执行该操作,即在 OnCreate() 事件
处理程序中完成。切换到 Class View 并选择 CChildView 类。在 Properties 页面中,转到 Message 属性表并导航到 WM_CREATE,然后从下拉框中添加 OnCreate() 消息处理程序:
7. 在 CChildView::OnCreate() 处理程序中添加以下代码,注册视图窗口的触控输入view plaincopy to clipboardprint? if (!RegisterTouchWindow()) { ASSERT(FALSE); } if (!RegisterTouchWindow()) { ASSERT(FALSE); } 注意:调用 CWnd::RegisterTouchWindow() 注册(和注销)窗口,使其具有触控功能,允许 接收低级 WM_TOUCH 消息。8. 因为我们注册了视图来接收触控输入,我们必须重写接收每个触控消息的处理程序CWnd::OnTouchInput()。该处理程序接收来自 Windows Touch 的单个输入,并在应用程序处理该消息时返回 TRUE; 否则返回 FALSE。
9.在 ChildView.h 中添加该方法声明view plaincopy to clipboardprint? // 重写 protectedvirtual BOOL OnTouchInput(CPoint pt, int nInputNumber, int nInputsCount, PTOUCHINPUT pInput); // 重写 protectedvirtual BOOL OnTouchInput(CPoint pt, int nInputNumber, int nInputsCount, PTOUCHINPUT pInput); 10.在 ChildView.cpp 中提供相应的实现view plaincopy to clipboardprint? BOOL CChildView::OnTouchInput(CPoint pt, int nInputNumber, int nInputsCount, PTOUCHINPUT pInput) { // 在此处输入消息处理 T } BOOL CChildView::OnTouchInput(CPoint pt, int nInputNumber, int nInputsCount, PTOUCHINPUT pInput) { // 在此处输入消息处理 T } 然后我们向项目添加笔画源和头文件,并使用手指绘制线条 我们希望将手指作为多输入设备。我们希望为每个触摸屏幕的手指绘制一条线。为此,我们 将使用两个笔画集合。一个集合保存完成的笔画(线条) ,另一个集合保存正在绘制的线条。触摸屏幕的每个手指都指向 m_StrkColDrawing 集合中的笔画。当我们从屏幕拿开手指时, 我们将手指的笔画从 m_StrkColDrawing 移动到 m_StrkColFinished 集合。此外,如果用户在 多点触控监视器上使用两个以上的手指,我们希望笔画有不同的颜色。1. 在 Starter 文件夹中,您将找到两个文件:Stroke.h 和 Stroke.cpp。将它们复制到项目 文件夹下并使用“Add? Existing item…”将其添加到项目中。2. 类似地,向项目添加 StrokeCollection.h 和 StrokeCollection.cpp。3. 将 &Stroke.h& 和 &StrokeCollection.h& 放在 StdAfx.h 头文件结束处。#include &Stroke.h& #include &StrokeCollection.h& 4. 将这些私有成员变量定义添加到 ChildView.h 中:
view plaincopy to clipboardprint? privateint m_iCurrC // 当前笔触的颜色 CStrokeCollection m_StrkColF // 用户完成输入笔画,接触笔触焦点 CStrokeCollection m_StrkColD // 收集用户当前的绘图笔画 privateint m_iCurrC // 当前笔触的颜色 CStrokeCollection m_StrkColF // 用户完成输入笔画,接触笔触焦点 CStrokeCollection m_StrkColD // 收集用户当前的绘图笔画 5.重要:我们必须初始化当前颜色。我们将在 ChildView.cpp 的 CChildView 构造函数中完 成该操作view plaincopy to clipboardprint? CChildView::CChildView() :m_iCurrColor(0) { } CChildView::CChildView() :m_iCurrColor(0) { } 6. 要绘制完成的集合,我们将以下调用添加到 CChildView::OnPaint() 处理程序的末尾。它 将绘制所有已完成的笔画。m_StrkColFinished.Draw(&dc); 7. 我们需要处理所有接收到的触控输入消息, 因此我们处理感兴趣的所有事件:touch input down、move 和 up。8. 在 CChildView.h 中,声明以下方法,我们将用来处理不同的触控输入事件protectedview plaincopy to clipboardprint? // 不同触摸输入事件的处理程序 BOOL OnTouchInputDown(CPoint pt, PTOUCHINPUT pInput); BOOL OnTouchInputMove(CPoint pt, PTOUCHINPUT pInput); BOOL OnTouchInputUp(CPoint pt, PTOUCHINPUT pInput); // 不同触摸输入事件的处理程序 BOOL OnTouchInputDown(CPoint pt, PTOUCHINPUT pInput); BOOL OnTouchInputMove(CPoint pt, PTOUCHINPUT pInput); BOOL OnTouchInputUp(CPoint pt, PTOUCHINPUT pInput); 9.在 CChildView.cpp 中,添加每个触控输入处理程序的实现:
view plaincopy to clipboardprint? BOOL CChildView::OnTouchInputDown(CPoint pt, PTOUCHINPUT pInput) { // 创建新的画笔,并为他添加指针 COLORREF strokeColor = GetTouchColor((pInput-&dwFlags &
TOUCHEVENTF_PRIMARY) != 0); CStroke* pStrkNew = new CStroke(pInput-&dwID, strokeColor); pStrkNew-&Add(pt); // 添加新的笔触收集画板中的笔画 m_StrkColDrawing.Add(pStrkNew); } BOOL CChildView::OnTouchInputMove(CPoint pt, PTOUCHINPUT pInput) { // 在绘图查找笔画收集笔触。int strokeIndex = m_StrkColDrawing.FindStrokeById(pInput-&dwID); if (strokeIndex &= 0) { CStroke* pStrk = // 增加笔画触摸点 pStrk-&Add(pt); // 绘制最后的笔画 pStrk-&Draw(GetDC()); } } BOOL CChildView::OnTouchInputUp(CPoint pt, PTOUCHINPUT pInput) { // 在绘图查找笔画收集笔触. int strokeIndex = m_StrkColDrawing.FindStrokeById(pInput-&dwID); if (strokeIndex &= 0) { CStroke* pStrkCopy = m_StrkColDrawing[strokeIndex]; // 从绘图上移除笔画. m_StrkColDrawing.RemoveAt(strokeIndex); // 在已经完成的笔画中增加一画. m_StrkColFinished.Add(pStrkCopy); } } BOOL CChildView::OnTouchInputDown(CPoint pt, PTOUCHINPUT pInput) { m_StrkColDrawing[strokeIndex];
// 创建新的画笔,并为他添加指针 COLORREF strokeColor
GetTouchColor((pInput-&dwFlags
TOUCHEVENTF_PRIMARY) != 0); CStroke* pStrkNew = new CStroke(pInput-&dwID, strokeColor); pStrkNew-&Add(pt); // 添加新的笔触收集画板中的笔画 m_StrkColDrawing.Add(pStrkNew); } BOOL CChildView::OnTouchInputMove(CPoint pt, PTOUCHINPUT pInput) { // 在绘图查找笔画收集笔触。int strokeIndex = m_StrkColDrawing.FindStrokeById(pInput-&dwID); if (strokeIndex &= 0) { CStroke* pStrk = // 增加笔画触摸点 pStrk-&Add(pt); // 绘制最后的笔画 pStrk-&Draw(GetDC()); } } BOOL CChildView::OnTouchInputUp(CPoint pt, PTOUCHINPUT pInput) { // 在绘图查找笔画收集笔触. int strokeIndex = m_StrkColDrawing.FindStrokeById(pInput-&dwID); if (strokeIndex &= 0) { CStroke* pStrkCopy = m_StrkColDrawing[strokeIndex]; // 从绘图上移除笔画. m_StrkColDrawing.RemoveAt(strokeIndex); // 在已经完成的笔画中增加一画. m_StrkColFinished.Add(pStrkCopy); } } 10.在 CChildView.cpp 中,修改 CChildView::OnTouchInput() 的实现,以根据需要调用每个 触控输入处理程序view plaincopy to clipboardprint? BOOL CChildView::OnTouchInput(CPoint pt, int nInputNumber, int nInputsCount, PTOUCHINPUT pInput) m_StrkColDrawing[strokeIndex];
{ if ((pInput-&dwFlags & TOUCHEVENTF_DOWN) == TOUCHEVENTF_DOWN) // 触摸按下事件 { return OnTouchInputDown(pt, pInput); } else if ((pInput-&dwFlags TOUCHEVENTF_MOVE) // 触摸移动事件 { return OnTouchInputMove(pt, pInput); } else if ((pInput-&dwFlags & TOUCHEVENTF_UP) == TOUCHEVENTF_UP) // 触摸移动事件 { return OnTouchInputUp(pt, pInput); } } BOOL CChildView::OnTouchInput(CPoint pt, int nInputNumber, int nInputsCount, PTOUCHINPUT pInput) { if ((pInput-&dwFlags & TOUCHEVENTF_DOWN) == TOUCHEVENTF_DOWN) // 触摸按下事件 { return OnTouchInputDown(pt, pInput); } else if ((pInput-&dwFlags & TOUCHEVENTF_MOVE) == TOUCHEVENTF_MOVE) // 触摸移动事件 { return OnTouchInputMove(pt, pInput); } else if ((pInput-&dwFlags & TOUCHEVENTF_UP) == TOUCHEVENTF_UP) // 触 摸移动事件 { return OnTouchInputUp(pt, pInput); } } 11.注意,调用了 GetTouchColor() 方法,但它尚未实现。当用户移动应用程序窗口上的多个 手指时,该方法负责处理钢笔的颜色。在 CChildView.h 中添加该方法的声明privateCOLORREF GetTouchColor(bool bPrimaryContact); 12.以下是 CChildView.cpp 的实现& TOUCHEVENTF_MOVE) ==
view plaincopy to clipboardprint? COLORREF CChildView::GetTouchColor(bool bPrimaryContact) { static COLORREF c_arrColor[] = // 数组中的颜色 { RGB(255, 0, 0), RGB(0, 255, 0), RGB(0, 0, 255), RGB(0, 255, 255), RGB(255, 0, 255), RGB(255, 255, 0) }; COLORREF if (bPrimaryContact) { // 主要接触中绘制黑色. color = RGB(0,0,0); } else { // 保存当前的次要颜色. color = c_arrColor[m_iCurrColor]; // 移动到数组中的下一个颜色 m_iCurrColor = (m_iCurrColor + 1) % (sizeof(c_arrColor)/sizeof(c_arrColor[0])); } } COLORREF CChildView::GetTouchColor(bool bPrimaryContact) { static COLORREF c_arrColor[] = // 数组中的颜色 { RGB(255, 0, 0), // 红 RGB(0, 255, 0), RGB(0, 0, 255), RGB(0, 255, 255), RGB(255, 0, 255), RGB(255, 255, 0) }; COLORREF // 绿 // 蓝 // 青 // 品红 // 黄 // 黑 // 红 // 绿 // 蓝 // 青 // 品红 // 黄
if (bPrimaryContact) { // 主要接触中绘制黑色. color = RGB(0,0,0); } else { // 保存当前的次要颜色. color = c_arrColor[m_iCurrColor]; // 移动到数组中的下一个颜色 m_iCurrColor = (m_iCurrColor + 1) % (sizeof(c_arrColor)/sizeof(c_arrColor[0])); } } 13.最后,由于我们已经动态创建了许多笔画,我们需要确保每个笔画在应用程序退出之前 都被销毁,因此我们在 CChildView? 的析构函数中包含以下内容view plaincopy to clipboardprint? CChildView::~CChildView() { for (int i = 0; i & m_StrkColDrawing.GetCount(); ++i) { delete m_StrkColDrawing[i]; } for (int i = 0; i & m_StrkColFinished.GetCount(); ++i) { delete m_StrkColFinished[i]; } } CChildView::~CChildView() { for (int i = 0; i & m_StrkColDrawing.GetCount(); ++i) { delete m_StrkColDrawing[i]; } for (int i = 0; i & m_StrkColFinished.GetCount(); ++i) { // 黑
delete m_StrkColFinished[i]; } } 14.现在编码部分已经全部完成,可以开始实验刚才实现的应用程序了。15.编译并运行应用程序。它应该如下所示:
第一篇:windows7多点触摸Windows 7 中的多点触控功能
Yochay Kiriaty 本文是有关 Windows 7 的系列文章的第三篇文章.该系列文章主要介绍了新的用户体验,开发人员可以 深入研究这些体验,使其应用程序在 Windows 7 上发挥强大作用.第 1 部分介绍了库.第 2 部分介绍 了任务栏 API. 3 部分介绍 Windows 7 中的多点触控功能. 第 请立即下载 Windows 7 Release Candidate, 以帮助您充分理解本文.
Windows 7 多点触控简介
在 Windows 7 中,我们通过触控功能丰富了 Windows 体验,从而使触控成为继鼠标和键盘之后又一种 与 PC 进行交互的绝佳方式. 近年来, 各种多点触控设备相继问世, 创造了极佳的用户体验. 因此, Windows 理所当然地在 Windows 7 中引入了这种多点触控支持,并将其作为一项核心功能. 通过 Windows 7 多点触控平台, 您可以随心所欲地直接与计算机进行交互. 例如, 您可以直接从 Windows 资源管理器中访问和缓慢浏览图片,也可以通过点按操作快速浏览这些图片.有一点您必须清楚的是,我 们并未创建特殊的 Windows 7 多点触控外壳程序, 也未提供只能在多点触控设备上使用的特殊 Windows 资源管理器.Windows 7 任务栏跳转列表就是一个最简单的示例.使用鼠标右键单击任务栏上的任一图标 时,您将看到对应的跳转列表.例如,右键单击 Windows Live Messenger 图标可以显示 Live Messenger 的跳转列表.但如何使用多点触控实现右键单击的功能呢?只需用手指触摸 Live Messenger 图标并将其 拖出,如图 1 所示. 图
图 1:在 Live Messenger 的跳转列表上使用多点触控 在 执行该拖动手势可以显示 Live Messenger 的跳转列表.如图 2 所示,通过触控触发的跳转列表显示了与 图 标准右键单击跳转列表相同的内容.右侧的图像显示了使用触控触发的 Live Messenger 跳转列表.多点 触控启用的跳转列表中每个列表项之间的间距大于左图(默认的右键单击跳转列表)中每个列表项之间的 间距.
图 2:跳转列表的多点触控视图和标准视图 跳转列表的多点触控视图和标准视图 Windows Live Messenger 只是一个示例,它可以证明 Windows 7 没有专为触控方案创建一组新的 UI, 而是将其结合到现有基础结构中.任务栏也只是一个示例,它可以证明 Windows 7 提供的多点触控功能 可以带来诸多优化体验,例如 XPS 查看器,Windows 照片查看器和 IE8.
Windows 7 多点触控平台编程模型
为了提供适用于各种应用程序的全面 Windows 触控解决方案, Windows 触控平台提供了不同级别的支持. 您可以通过多种方案来使用 Windows 触控平台功能增强应用程序.在采用某种特定方法之前,应该考虑 一下您究竟希望如何让应用程序支持触控. 您可能会问自己, 在启用多点触控的 Windows 旧版支持 假定您已经有一个广泛安装使用的现有应用程序. 7 计算机上运行该应用程序时,用户使用多点触控的体验将是怎样的呢?令人庆幸的是,对于那些无法识 别触控且不支持多点触控的应用程序,Windows 7 多点触控平台提供了现成的免费支持.具体来说,它为 一些基本手势提供了现成的免费支持.换而言之,您可以在应用程序中使用一些基本手势,并获得理想的 效果.基本手势包括在 Windows Vista 阶段引入的单指或双指平移手势,双指缩放手势以及光标手势. 添加基本多点触控支持 在本部分,我们的讨论重点是添加直接手势支持以及其他行为和用户界面更改,以 使应用程序除了支持简单手势以外还可以更好地支持触控. 在本文开头,我们已经了解一个触控优化的任务栏跳转列表示例.通过使用 getMessageExtraInfo 方法, 任务栏可以跟踪输入消息的来源,并确定该消息是否为触控消息,然后做出相应的响应. 此外,您可以使用手势来增强应用程序,提供更好的多点触控支持.直接响应手势的应用程序可以完全控 制它们在用户触摸触控设备时的行为.例如,Windows 7 附带了 Windows 照片查看器.在照片查看器应 用程序中,查看器接收有关缩放手势起始位置的特定信息.也就是说,缩放手势包含有关缩放手势中心点
(特定的 X 和 Y 坐标)的信息,这使得照片查看器可以根据手势中心位置进行缩放.Windows 照片查 看器应用程序还使用平移和旋转手势来提供绝佳的图像查看体验,而且相对简单一些. 利用手势,您还可以替代默认的平移行为.例如,默认的触控滚动适合在以文本为中心并通常垂直滚动的 窗口(例如网页或文档)中使用,而水平拖动则可以进行文本选择,而不是滚动.在大多数应用程序中, 这种触控方式可以正常工作.但如果您的应用程序实际上需要支持水平滚动,该怎么办?此外,对于某些 应用程序, 默认滚动可能显得不够灵活, 即速度过快或过慢. 有了手势支持, 您可以替代默认的平移行为, 并根据应用程序的需要对其进行优化. 多点触控优化体验 最好的情况是从头开始设计应用程序以支持多点触控.这些应用程序基于 Windows Messages 触控消息 WM_TOUCH 构建.此消息为应用程序提供原始触控数据,您可以利用这些消息并处 理多个接触点.我们之前提到的大多数手势都是双指手势,您可以利用 WM_TOUCH 消息同时接收基础触 敏式硬件所支持的多个接触点. Windows 7 多点触控平台还提供操作和延时处理器,帮助您解释触控消息.可以将操作视作一个黑匣子, 用于以输入形式接收用户触摸的对象,以及所有相关的触控消息.结果是一个二维仿射转换矩阵,表示通 过手指移动产生的转换.例如,如果您要编写一个照片编辑应用程序,则可以使用一个或多个手指同时捕 捉两张照片,以对照片进行旋转,调整大小和转换操作,而操作过程将提供您需要在对象上反映的变化. 延时为应用程序提供了一个非常基本的物理模型,并为您提供了一种简单的方法来继续平稳转换对象(即 使在您将手指从触敏式设备拿开以后也能平稳转换),并创建简单的转换效果,而不是立即停止对象.
默认情况下,每当用户触摸触敏式 Windows 7 设备时,Windows 7 多点触控平台都会向您的应用程序发 送手势消息 WM_GESTURE.这是现成的免费行为,如果您希望停止接收此类消息,则需要选择退出. 手势被视为单指或双指触控输入,可以转换为用户执行的某种预定义操作(手势).一旦检测到手势(操 作系统为您进行所有检测),操作系统就会向应用程序发送手势消息.此消息包含解码和进行操作所需的 全部信息.Windows 7 支持下列手势缩放 单指和双指平移 旋转 双指点击 按下并点击 必须处理发送到应用程序的 WM_GESTURE 消息. 如果您是 Win32 处理 WM_Gesture 消息 要使用手势, 程序员,可以在应用程序的 WndProc 函数中检查 WM_GESTURE 消息. WM_GESTURE 是用于所有手势的通用消息.因此,要确定需要处理的手势,您首先需要对手势消息进行 解码.有关手势的信息可在 lParam 参数中找到,您需要使用一个特殊函数 GetGestureInfo 来解码手势 消息,如下面的代码片段中所示. GESTUREINFO ZeroMemory(&gi, sizeof(GESTUREINFO)); gi.cbSize = sizeof(gi); BOOL bResult = GetGestureInfo((HGESTUREINFO)lParam, &gi); 获取 GESTUREINFO 结构后,可以检查 dwID 以确定执行了哪个手势.GESTUREINFO 结构包含几个其他 重要成员bSize - 结构大小(以字节为单位)
ptsLocation - 一个 POINTS 结构,其中包含与手势相关的坐标.这些坐标始终都相对于屏幕的原点 dwFlags - 手势的状态,例如开始,延时和结束 ullArguments - 一个 64 位无符号整数,其中包含手势的参数,组合为八字节.这是额外信息,对于每个 手势类型都是唯一的 掌握了这些知识后, 我们可以继续操作并编写用于处理所有手势的完整 switch-case 方法, 图 3 所示. 如图
图 3:Switch-Case 方法
void CMTTestDlg::DecodeGesture(WPARAM wParam, LPARAM lParam) { GESTUREINFO ZeroMemory(&gi, sizeof(GESTUREINFO)); GetGestureInfo((HGESTUREINFO)lParam, &gi); switch (gi.dwID){ case GID_ZOOM// Code for zoo case GID_PAN case GID_ROTATE case GID_TWOFINGERTAP case GID_PRESSANDTAP default// You have encountered an u CloseGestureInfoHandle((HGESTUREINFO)lParam); } 请注意,在函数的末尾,我们调用了 CloseGestureInfoHandle 函数,用于关闭与手势信息处理程序相关联 的资源.如果处理 WM_GESTURE 消息,则您要确保使用此函数来关闭句柄.不这么做可能会导致内存泄 漏. 处理手势消息具有一个固定流程,包括配置,解码手势消息以及根据应用程序的需要处理特定手势.正如 您在以上代码中看到的那样,执行这个流程并不很难. 现在,让我们来详细了解缩放手势,通过这种手势,您也可以大致了解所有其他手势的工作原理. 使用缩放手势缩放对象 缩放手势通常被用户视为两个接触点之间的&挤压&运动,您可以将手指相互靠近以缩小内容显示,或者将 手指分开以放大内容显示.使用缩放手势,您可以缩放对象的大小.图 4 说明了缩放手势的使用方式. 图
图 4:缩放手势 缩放手势 现在,我们将了解需要在 GID_ZOOM switch 中实现什么代码才能达到所需的缩放效果. 手势信息结构包括 dwFlags 成员,该成员用于确定手势的状态,而且可以包括以下任何值GF_BEGIN - 指示手势即将开始,在第一个 WM_Gesture 消息中收到 GF_INERTIA - 指示手势已经触发了延时 GF_END - 指示手势已经完成 switch 的默认值 - 指示手势消息的剩余部分,通常称为变化量 默认值 我们将使用 GF_BEGIN 标志将接触点的初始开始坐标保存在变量中,并将其作为以下步骤的引用.我们将 ptsLocation 保存在 _ptFirst 变量中.对于缩放手势,ptsLocation 表示缩放的中心. 收到的以下缩放消息由 default case 进行处理.我们将坐标保存在 _ptSecond 变量中.接下来,我们将计 算缩放中心点和缩放比例.最后,我们还将更新矩形(我们的图形对象)以反映缩放中心点和缩放比例. 图 5 显示了这些参数.
图 5:GID_ZOOM Switch
case GID_ZOOMswitch(gi.dwFlags) { case GF_BEGIN_dwArguments = LODWORD(gi.ullArguments); _ptFirst.x = gi.ptsLocation.x; _ptFirst.y = gi.ptsLocation.y; ScreenToClient(hWnd,&_ptFirst); default// We read here the second point of the gesture. This is middle point between fingers. _ptSecond.x = gi.ptsLocation.x; _ptSecond.y = gi.ptsLocation.y; ScreenToClient(hWnd,&_ptSecond); // We have to calculate zoom center point
ptZoomCenter.x = (_ptFirst.x + _ptSecond.x)/2; ptZoomCenter.y = (_ptFirst.y + _ptSecond.y)/2;
// The zoom factor is the ratio between the new and the old distance. k = (double)(LODWORD(gi.ullArguments))/(double)(_dwArguments); // Now we process zooming in/out of the object ProcessZoom(k,ptZoomCenter.x,ptZoomCenter.y); InvalidateRect(hWnd,NULL,TRUE);
// Now we have to store new information as a starting information for the next step _ptFirst = _ptS _dwArguments = LODWORD(gi.ullArguments); } 在默认的 case 处理程序中,我们保存手势的位置,从两组点(表示当前接触点和前一个接触点)计算缩 放中心位置,并将其存储在 ptZoomCenter 中.我们还通过计算两个点之间的比例来计算出缩放系数.调 用 ProcessZoom 帮助函数可以更新新的坐标,以反映缩放系数和中心点. 处理其他 Windows 7 默认手势与以上所述的特定缩放手势处理非常相似.所有手势都遵循相同的流程, 只是在每个使用案例场景中,每个手势的内部逻辑实现有所不同.接下来,我们将了解最佳模型,并深入 探讨让您能够接收和处理原始触控事件的 API.
处理 Windows 原始触控消息
要开始接收原始触控消息 WM_TOUCH,首先需要请求操作系统开始向应用程序发送触控消息,并停止发 送默认手势消息.若要执行此操作,则需要调用 RegisterTouchWindow(HWND hWnd, ULONG uFlags) 函 数.调用此函数可将单个 hWnd 元素(通常是一个窗口)注册为启用触控的. 与手势相同,您在应用程序的 WndProc 函数中处理 WM_TOUCH 消息.单条 WM_TOUCH 消息可能包 含多条不同的&接触点消息&,需要将它们解包为一个触控输入结构数组.标准做法是将 WM_TOUCH 消息 解包为一个 TOUCHINPUT 结构数组,该数组中的每个结构表示来自单个接触点的数据.若要进行解包, 需要调用 GetTouchInputInfo(HTOUCHINPUT hTouchInput, UINT cInputs, PTOUCHINPUT pInputs, int cbSize) 函数,并向其传递 WM_TOUCH 消息的 lParam 以及一个新创建的接触点数组,如图 6 所示. 图
图 6:对 WM_TOUCH 进行解包
case WM_TOUCH{ unsigned int numInputs = (unsigned int) wP TOUCHINPUT* ti = new TOUCHINPUT[numInputs]; if(GetTouchInputInfo((HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT))) {
// Handle each contact point for(unsigned int i=0; i& numI ++i) { /* handle ti[i] */ } } CloseTouchInputHandle((HTOUCHINPUT)lParam); delete [] } defaultreturn DefWindowProc(hWnd, message, wParam, lParam);
在这里,您可以看到我们如何使用来自每个接触点的数据来填充 TOUCHPOINT ti 数组.接下来,我们将 遍历接触点数组,将逻辑应用于每个接触点 handle ti[i] 注释.最后,我们需要通过调用 CloseTouchInputHandle(HTOUCHINPUT hTouchInput) 清除触控句柄,传递原始 WinProc 的 lParam.不 这么做将会导致内存泄漏. 以上代码表示处理 WM_TOUCH 消息的第一个步骤. 单个触控输入结构 TOUCHINPUT 包含了有关您需要 使用的单个接触点的所有必需信息dwID - 接触点标识符,用于区分特定触控输入与其他输入 dwFlags - 一组位标志,用于指定接触点的状态 接触点的 X 和 Y 坐标(基本上是每个接触点的位置) dwTime - 事件的时间步长,以毫秒为单位 dwMask - 一组位标志,用于指定结构中的哪些可选字段包含有效值 请务必注意,X 和 Y 坐标的单位是实际屏幕坐标的像素的百分之一(即 centa-pixel).对于可能需要高 分辨率的其他应用程序而言,这种超高分辨率有利于达到高精度,实现更加精确的手写识别.但在大多数 情况下,在开始使用这些坐标之前,请务必记住应将接触点的 X 和 Y 坐标除以一百,从而将接触点坐标 转换为可用的屏幕坐标. 现在,您已经知道了如何处理触控消息,并且掌握了为上述 WM_TOUCH 处理程序添加真实逻辑所需的全 部信息.接下来让我们利用这些知识来构建一个多点触控画图应用程序,也称为&草稿板&. 跟踪接触点 ID 若要创建&草稿板&应用程序,需要跟踪每个接触点的运动及其形成的轨迹,然后沿着该轨 迹绘制线条.为了区分不同的接触点,确保真正正确地处理每个接触点,我们可以为每个接触点指定不同 的颜色. 在将触控消息解包为触控输入结构数组 ti 之后, 需要检查每个接触点状态, 并针对每个接触点状态应用不 同的逻辑.在&草稿板&示例中,新接触点由向下状态 TOUCHEVENTF_DOWN 进行标识.您注册新的接触 点 ID, 并为其指定一种颜色. 删除接触点 TOUCHEVENTF_UP 之后, 您完成最后的绘图, 并注销接触点 ID. 在向上和向下事件之间,您很可能会收到大量移动消息 TOUCHEVENTF_MOVE.收到每条移动消息时,您 向现有线条添加一个新点,然后绘制新的线段.图 7 显示了&草稿板&应用程序支持多点触控所需的整个 图 WM_TOUCH 处理程序.
图 7:WM_TOUCH 处理程序
case WM_TOUCH:
{ unsigned int numInputs = (unsigned int) wP TOUCHINPUT* ti = new TOUCHINPUT[numInputs]; if(GetTouchInputInfo((HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT))) { // For each contact, dispatch the message to the appropriate message handler. for(unsigned int i=0; i& numI ++i) { if(ti[i].dwFlags & TOUCHEVENTF_DOWN) { OnTouchDownHandler(hWnd, ti[i]); } else if(ti[i].dwFlags & TOUCHEVENTF_MOVE) { OnTouchMoveHandler(hWnd, ti[i]); } else if(ti[i].dwFlags & TOUCHEVENTF_UP) { OnTouchUpHandler(hWnd, ti[i]); } } } CloseTouchInputHandle((HTOUCHINPUT)lParam); delete [] } 跟踪各个接触点的关键是使用 dwID,在特定触控笔划的整个过程中,它都保持不变.在 OnTouchDownHandler 帮助函数中,您将此 ID 指定给 CStroke 对象,该对象基本上是一个代表线条的 点数组.这个线条是您在触敏式设备上拖动手指时形成的轨迹.我们将不再介绍支持应用程序并在屏幕上 实际绘制线条的完整代码示例.在前面的代码示例中,您基本上可以找到支持多点触控所需的全部操作. 在图 8 中,您可以查看&草稿板&应用程序的输出. 图
图 8:&草稿板 应用程序的输出 草稿板&应用程序的输出 草稿板 在默认的 case 处理程序中,我们保存手势的位置,从两组点(表示当前接触点和前一个接触点)计算缩 放中心位置,并将其存储在 ptZoomCenter 中.我们还通过计算两个点之间的比例来计算出缩放系数.调 用 ProcessZoom 帮助函数可以更新新的坐标,以反映缩放系数和中心点. 处理其他 Windows 7 默认手势与以上所述的特定缩放手势处理非常相似.所有手势都遵循相同的流程, 只是在每个使用案例场景中,每个手势的内部逻辑实现有所不同.接下来,我们将了解最佳模型,并深入 探讨让您能够接收和处理原始触控事件的 API.
处理 Windows 原始触控消息
要开始接收原始触控消息 WM_TOUCH,首先需要请求操作系统开始向应用程序发送触控消息,并停止发 送默认手势消息.若要执行此操作,则需要调用 RegisterTouchWindow(HWND hWnd, ULONG uFlags) 函 数.调用此函数可将单个 hWnd 元素(通常是一个窗口)注册为启用触控的. 与手势相同,您在应用程序的 WndProc 函数中处理 WM_TOUCH 消息.单条 WM_TOUCH 消息可能包 含多条不同的&接触点消息&,需要将它们解包为一个触控输入结构数组.标准做法是将 WM_TOUCH 消息 解包为一个 TOUCHINPUT 结构数组,该数组中的每个结构表示来自单个接触点的数据.若要进行解包, 需要调用 GetTouchInputInfo(HTOUCHINPUT hTouchInput, UINT cInputs, PTOUCHINPUT pInputs, int cbSize) 函数,并向其传递 WM_TOUCH 消息的 lParam 以及一个新创建的接触点数组,如图 6 所示. 图
摘要 Windows 7 多点触控平台是一个非常强大的开发平台. 多点触控平台是一个非常强大的开发平台. 从实现默认手势支持到更高级的原始触 从实现默认手势支持到更高级的原始触 控消息,它为您提供了强大的功能,而且实现起来相对要简单一些. 控消息,它为您提供了强大的功能,而且实现起来相对要简单一些. 该平台还包括操作和延时处理器.操作在很多方面与手势相似,但却强大得多. 该平台还包括操作和延时处理器.操作在很多方面与手势相似,但却强大得多.使用操作可以 简化对任何给定数量的对象的转换操作.您可以同时对某个特定对象执行特定手势组合, 简化对任何给定数量的对象的转换操作.您可以同时对某个特定对象执行特定手势组合,例如 旋转,缩放和伸缩.操作处理器生成二维的 转换矩阵 转换矩阵&, 坐标来表示转换, 旋转,缩放和伸缩.操作处理器生成二维的&转换矩阵 ,该矩阵用 X 和 Y 坐标来表示转换, 还表示由于执行接触点移动,对象随着时间推移发生的大小变化和旋转. 还表示由于执行接触点移动,对象随着时间推移发生的大小变化和旋转.最后一个接触点拉起 之后,您可能希望将简单的物理运动应用于对象,使其平滑停止,而不是突然停在点上. 之后,您可能希望将简单的物理运动应用于对象,使其平滑停止,而不是突然停在点上.为了 支持这种平滑运动,Windows 7 多点触控平台提供了延时 API. 持这种平滑运动, .
文章的主题. 这些 API 将是我们下一篇 MSDN 文章的主题.
windows7多点触摸相关文章
《》由(一起看范文网)整理提供,版权归原作者、原出处所有。
Copyright &
All Rights Reserved.

我要回帖

更多关于 input 鼠标放上去边框 的文章

 

随机推荐