在您的应用程序中处理增强型鼠标滚轮






4.91/5 (23投票s)
如何为用户提供高分辨率鼠标滚轮的平滑滚动体验
- 下载 HiResDibSample 源代码 - 1.67 MB
- 下载 HiResScrollWheelEmulator 源代码 - 26.29 KB
- 下载 Emulator EXE - 165.28 KB
引言
增强型鼠标滚轮在相同滚轮旋转量下会比标准鼠标滚轮生成更多的滚动事件。如今,许多应用程序在使用增强型滚轮鼠标时,要么无法正常工作,要么没有针对充分利用滚轮移动精度的高分辨率功能进行编写。本文将介绍如何使您的应用程序对增强型鼠标滚轮友好。它为应用程序开发人员提供了技巧,以帮助他们创建能够利用 Windows Vista(及更高版本)中增强型滚轮支持的应用程序。
我们首先介绍标准和增强型鼠标滚轮的一些背景信息。然后探讨在应用程序中添加增强型鼠标滚轮支持的好处。接着,我们将考察那些不了解增强型滚轮的应用程序中常见的问 题,并提供改进用户体验的技巧。
我们还将介绍如何使用具有增强型滚轮的真实硬件来测试应用程序,以确保您的应用程序与增强型滚轮兼容。如果无法获得具有增强型滚轮的硬件,您还可以使用我编写并随本文一起提供的模拟器来测试您的应用程序。
最后,我们将通过一个现有的示例应用程序来说明这些改进。这将有助于开发人员创建能够识别增强型滚轮并能够处理精细滚动事件以实现更流畅滚动体验的应用程序。
鼠标滚轮
鼠标滚轮结合了滚轮和鼠标按钮的功能。滚轮具有离散的、等距的刻度。当您旋转滚轮时,每遇到一个刻度,就会向您的应用程序发送一个滚轮消息。
应用程序通过 WM_MOUSEWHEEL
消息接收鼠标滚轮滚动事件的通知。当鼠标滚轮旋转时,该消息将被发送到焦点窗口。DefWindowProc
函数会将该消息传播给窗口的父窗口。不应进行内部转发,因为 DefWindowProc
会沿着父窗口链向上传播该消息,直到找到处理它的窗口为止。
该消息包含有关滚轮旋转距离以及鼠标指针的水平和垂直位置的信息。滚轮旋转的距离以 WHEEL_DELTA
(值为 120
)的倍数或分数表示。正值表示滚轮向前旋转(远离用户);负值表示滚轮向后旋转(朝向用户)。
背景
WM_MOUSEWHEEL
消息是在 Windows 98 和 Windows NT 4.0 中引入的。该消息将滚轮旋转的距离定义为任意值 120
,即 WHEEL_DELTA
。这是采取行动的阈值,每次 delta 应该发生一次行动(例如,滚动一个增量)。delta 设置为 120
是为了允许 Microsoft 或其他供应商将来构建更高分辨率的滚轮,甚至可能是带有刻度的自由旋转滚轮。预期是这样的设备将每旋转一次发送更多的消息,但每条消息的值会更小。基本上,Microsoft 为将来实现更流畅的鼠标滚轮留下了空间。未来已至。
随着 Vista 的推出,Microsoft 提供了对增强型鼠标滚轮的支持,这些滚轮在相同滚轮旋转量下会比标准鼠标滚轮生成更多的滚动事件。您的标准鼠标滚轮(有时称为低分辨率滚轮)会生成垂直滚动滚轮事件,其 delta 为 +/- WHEEL_DELTA
(在 winuser.h 中定义为 120
)。具有增强型滚轮的鼠标通常设计为在相同的滚动滚轮旋转距离内发送多个事件,这些事件的 delta 之和加起来等于 120
或 -120
。
有关 Microsoft 增强型滚轮设计的更多信息,请访问此链接。
应用程序中增强型鼠标滚轮支持的好处
增强型鼠标滚轮可用于支持用户界面中的平滑动画。当应用程序以增强型鼠标滚轮支持进行编写时,用户可以获得更流畅的滚动体验。这不仅会让用户感到满意,而且多项研究表明这种方法具有可衡量的益处。研究表明,使用平滑的动画过渡有助于理解呈现内容的变更,从而减轻用户的认知负担 [Chang, 1993]。在各种应用程序场景中的研究都证实了这种好处,无论是在性能还是主观用户满意度方面。Klein [Klein, 2005] 在需要用户滚动的阅读任务中证明了这些好处。动画过渡的好处也在各种界面中得到证明,包括缩放 [Shanmugasundaram, 2008]、平移 [Bederson, 1999] 以及对不同版本信息和文档的审阅 [Bezerianos, 2006; Chevalier, 2010]。
增强型鼠标滚轮的典型应用程序问题
Windows Vista(及更高版本)会自动为支持它的任何设备启用平滑滚动。如今,许多应用程序在使用增强型滚轮鼠标时,要么无法正常工作,要么没有针对充分利用滚轮移动精度的高分辨率功能进行编写。
以下是许多应用程序中常见的问 题以及纠正它们的技巧
- 应用程序根本不滚动。这可能是因为消息 delta 值不够大,无法使应用程序可见地滚动。技巧:只需添加一个变量来累积 delta,直到达到可见滚动的最小量。
- 应用程序滚动太快。这可能是因为应用程序忽略了
WM_MOUSEWHEEL
消息收到的 delta 值。技巧:不要假设滚轮 delta 总是120
。选择您的滚动粒度并累积 delta,直到达到它。 - 如果滚动方向反转,用户可能需要滚动滚轮更多次才能使内容滚动。技巧:确保在滚动滚轮方向改变时重置累积的 delta。
- 滚动体验并不比标准鼠标更顺畅。这发生的原因是应用程序所做的最多就是为用户提供与低分辨率(标准鼠标)相同的体验。通常,此类应用程序会累积 delta,直到达到
120
的绝对值。然后,它会执行标准滚动事件的操作。技巧:使用最小累积 delta 进行滚动。 - 按住 Ctrl 键和鼠标滚轮进行缩放会导致应用程序缩放过快。技巧:当 Ctrl 键按下时(它包含在
WM_MOUSEWHEEL
消息中),只需累积 delta,直到达到 120 的绝对值,然后相应地进行缩放。或者,应用程序可以按比例缩放一个较小的量,以适应消息中包含的 delta 大小。
如何测试您的应用程序与增强型鼠标滚轮的兼容性
注意:由于 XP 上不支持增强型滚轮,请使用 Windows Vista 及更高版本。
- 如何使用具有增强型鼠标滚轮的真实硬件测试您的应用程序
- 如何使用本文提供的模拟器测试您的应用程序?
如果您没有增强型滚轮鼠标,请使用随附的增强型滚动滚轮模拟器。此应用程序通过向您的应用程序发送更小的滚轮 delta 来模拟增强型滚轮。因此,您仍然可以通过运行模拟器应用程序(HiResScrollWheel.exe)来测试您的应用程序,并创建自己的高分辨率
WM_MOUSEWHEEL
消息。启动 HiResScrollWheel.exe 并设置以下参数,可以模拟一个高分辨率鼠标,每单击产生 8 个事件,delta 为 15。
在应用程序处于前台运行时,检查您的鼠标是否具有增强型滚轮功能。
为此,您需要一个具有增强型滚动滚轮功能的鼠标以及相应的驱动程序。您可能需要联系制造商以获取驱动程序或有关如何开启此功能的说明。要查看它是否已开启,您需要运行 Spy++ 或类似的 Message Snooping 软件来捕获 WM_MOUSEWHEEL
消息。您应该看到鼠标滚轮小幅度转动时有多条消息,并且每条消息的绝对 delta 值都小于 120
。(在示例中,我们看到 zDelta
为 -15
)。
如果您的应用程序运行良好,那么使用增强型鼠标滚轮时,滚动行为将更加顺畅。在滚轮旋转相同距离的情况下,它会滚动相同的距离,但会更顺畅、更不生涩。您还应该测试应用程序在按下 Ctrl 键并转动滚轮时的行为。如果您的应用程序在按下 Ctrl 键并转动滚轮时通常会缩放,那么使用增强型滚动滚轮时应该获得相同的行为。您的应用程序不应该在滚轮滚动相同距离的情况下缩放更多。理想情况下,您的应用程序会更平滑地缩放。
如何使您的应用程序对增强型滚轮友好
为了支持增强型滚轮功能,您应该累加传入的 delta 值,直到达到 WHEEL_DELTA
(这样对于给定的 delta 旋转,您会得到相同的响应),或者根据更频繁的消息部分滚动。您也可以选择您的滚动粒度并累积 delta,直到达到它。有关 Microsoft 推荐的鼠标和键盘(包括鼠标滚轮)软件支持的最佳实践,请访问此链接。
为了说明这些技巧,我将改进 Microsoft MFC 示例应用程序 Diblook
。该程序随 Microsoft Visual Studio 2008 一起提供。我在机器上找到以下 zip 文件中的应用程序源代码
Program Files\Microsoft Visual Studio9.0\Samples \1033\AllVCLanguageSamples.zip
zip 文件中的子目录是 C++\MFC\general\diblook。
示例应用程序执行并加载 dib 文件后的外观如下
我使用了增强型滚动滚轮模拟器(HiResScrolLWheel.exe)来识别并帮助修复我在 Diblook
中发现的许多问 题。
为了让示例应用程序实现增强型滚动而进行的更改是在 DoMouseWheel()
中完成的,如下所示。每当移动鼠标滚轮时,都会调用 DoMouseWheel()
,该函数应执行在鼠标滚轮事件上应该发生的所有操作。
应用程序根本不滚动
技巧:累积您的滚轮 Delta
当我使用模拟器将滚轮 Delta 设置为 1 时,我发现的第一个问题是图片拒绝滚动。处理导致用户无法可见滚动的微小 delta 值的最佳方法是累积 delta,直到滚轮旋转足够以执行某个操作。
BOOL CDibView::DoMouseWheel(UINT fFlags, short zDelta, CPoint point) { ... // we keep a member variable m_nAccumulatedDelta // which may be non-zero in the event the method // is called with a delta too small to cause a // visible scroll. If this occurs we accumulate the // deltas until a visible scroll occurs. m_nAccumulatedDelta += zDelta ; ... ... ... return bResult; }如果滚动方向反转,用户可能需要滚动滚轮更多次才能使内容滚动。
技巧:在滚动方向改变时重置您的累积 Delta。
但是,如果滚动滚轮方向发生改变,请确保重置累积的 delta。我将上述两个修改合并到以下代码块中。
BOOL CDibView::DoMouseWheel(UINT fFlags, short zDelta, CPoint point) { ... // we keep a member variable m_nAccumulatedDelta // which may be non-zero in the event the method // is called with a delta too small to cause a // visible scroll. If this occurs we accumulate the // deltas until a visible scroll occurs. if ((m_nAccumulatedDelta*zDelta) > 0 ) { // we're scrolling in the same direction and // there is a non-zero value in m_nAccumulatedDelta m_nAccumulatedDelta += zDelta ; } else { // we've changed direction or // m_nAccumulatedDelta is zero // So reset accumulated delta // variable to the current new // delta. m_nAccumulatedDelta = zDelta ; } ... ... ... return bResult; }滚动体验并不比标准鼠标更顺畅。
技巧:使用最小累积 Delta 进行滚动。
我对该应用程序做的另一项改进是使最小滚动量为一个像素。在示例代码中,程序可以滚动的最小量是应用程序字体定义的字符像素高度。
我用以下内容替换了
nScroll
的计算…... int nDisplacement; ... ... int nToScroll = ::MulDiv(-zDelta, uWheelScrollLines, WHEEL_DELTA); ... ... nDisplacement = nToScroll * m_lineDev.cy; ...用以下内容…
... int nDisplacement; ... ... int nToScroll = ::MulDiv(-m_nAccumulatedDelta, (uWheelScrollLines*m_lineDev.cy), WHEEL_DELTA); ... ... nDisplacement = nToScroll * m_lineDev.cy; ...如果您在开发领域无法控制像素级别,请查看您是否可以控制行级别。如果是这样,那么您的应用程序滚动所需的最小 delta 将是
WHEEL_DELTA (120)
除以用户在控制面板中为鼠标选择的滚动行数。使用以下系统调用,可以通过非托管 C++ 获得此值。::SystemParmetersInfo(SPI_GETWHEELSCROLLLINES, 0, &nWheelScrollLines, 0) ;最后,如果您无法选择滚动粒度,那么您只需继续累积传入的 delta 值,直到达到
WHEEL_DELTA
(这样对于给定的 delta 旋转,您会得到与标准滚轮鼠标相同的响应)。
结论
通过少量修改,您可以创建在与增强型滚动滚轮配合使用时为用户提供更流畅滚动体验的应用程序。
参考文献
- B. Bederson 和 A. Boltman。动画有助于用户构建空间信息的心理地图吗?在 Proc. INFOVIS'99, Washington, DC, USA, 1999。
- A. Bezerianos、P. Dragicevic 和 R. Balakrishnan。Mnemonic rendering:一种基于图像的方法,用于暴露动态显示中的隐藏更改。在 Proc. UIST'06, 159–168, 2006。
- B.W. Chang 和 D. Ungar。动画:从卡通到用户界面。在 Proc. UIST'93, 45–55, 1993。
- F. Chevalier、P. Dragicevic、A. Bezerianos 和 JD. Fekete。2010。使用文本动画过渡来支持文档历史记录中的导航。在第 28 届国际人因计算系统会议(CHI '10)的论文集中。
- C. Klein 和 B. B. Bederson。动画滚动的益处。在 Proc. CHI'05, 1965–1968, 2005。
- M. Shanmugasundaram 和 P. Irani。动画过渡在缩放界面中的效果。在 Proc. AVI'08, 396–399, 2008
修订历史
- 2011 年 2 月 8 日:初始帖子