windows鼠标,物理位移与屏幕位移的计算方法(鼠标加速度)

1、背景
在Windows系统中,有3种获取鼠标位移信息的方法:WM_MOUSEMOVE, WM_INPUT 和DirectInput。这3种方法中,WM_MOUSEMOVE获取的是鼠标当前在窗口上的绝对位置,通过它可以获取鼠标的屏幕位移;WM_INPUT和DirectInput获取的则是鼠标相对于上一个位置的相对位移,它们就是鼠标实际上的物理位移。事实上,WM_INPUT与DirectInput在获取鼠标位移信息上是等价的,这与他们的实现有关,本文不作讨论。下面的讨论中,我只会提及WM_INPUT。

物理位移与屏幕位移之间有一个转换公式,但是这个公式微软没有公开(或者是我没有找到)。本文第二、三节分别讨论物理位移和屏幕位移的一些细节,第四节要讨论这两者之间的转换关系以及我的一些研究结果。第五节是结论。

2、物理位移
物理位移就是鼠标实际上移动了多少个点,这里首先要介绍一下鼠标的一些概念。首先是鼠标的分辨率,鼠标分辨率单位是dpi,即每个英寸可以分辨多少个点。以400dpi的鼠标为例(以下都会使用这个参数的鼠标),理想情况下,用户每移动鼠标1/400英寸,鼠标硬件就可以检测到一个点的位移。第二是鼠标的扫描率,这个参数会影响鼠标的跳帧问题,不过这与我的讨论没有太大关系。在下面讨论中,我假设不存在跳帧问题。最后一个参数是数据更新频率,这是与鼠标接口和鼠标本身都有关的一个参数。例如USB1.1鼠标,数据更新频率是125Hz,PS/2的鼠标为100Hz,而USB2.0的鼠标频率更高。

鼠标数据每一次更新时包含一个数据包,这个包中包含了此次更新间隔中鼠标的每一个轴的位移,这个位移值为一个8bit整数,即每一个轴位移可以在-128到+127之间。

根据以上数据,我们可以计算出鼠标某个轴向的速度。

                                                                                              数据更新频率   
鼠标某个轴向速度Vmouse(单位 inch per second)=  ---------------------× 此轴位移    (1)
                                                                                                鼠标分辨率

对于400dpi的USB1.1鼠标,如果某一帧鼠标x轴变化3的话,则Vmouse=0.9375,大约是1英寸每秒

3、屏幕位移
我们实际看到屏幕上的鼠标指针移动为屏幕位移。对于一个在1280*1024显示模式下的19英寸4:3显示器,其长边约为15.2英寸,其分辨率(这里指的是dpi)大约为84dpi。此时我们可以计算屏幕指针在某个轴向的速度。

                                                                                                        屏幕刷新率
屏幕指针某个轴向速度Vpointer(单位inch per second)=------------------------ ×此轴位移  (2)
                                                                                                        屏幕分辨率

如果在上面的屏幕上,屏幕刷新频率为75Hz,则某一帧鼠标指针在x轴移动3的话,Vpointer= 2.67,大约2.67英寸每秒。从这个数据和上面物理鼠标位移速度比较可以看出,如果屏幕位移与物理位移比率是1:1的话,指针在屏幕上移动的速度大约是鼠标实际移动速度的3倍。此处写屏幕刷新率是因为windows设计者将屏幕指针刷新频率与屏幕刷新频率挂钩了。

4、鼠标加速度
实际上,由于以上谈到的参数都不是固定的,因此不同情况下这些Vpointer和Vmouse都不一样。如果只有一个固定的物理位移到屏幕位移的比率会给用户带来不适。因而Windows系统要设计一个鼠标加速度函数。

Windows XP设计鼠标加速度函数的目的有以下几点:

为了在不同分辨率的屏幕上能够有效的移动鼠标的同时,保证鼠标能够移动到每个像素上。
平滑鼠标移动
保证加速是基于鼠标整体移动而不是基于单独的轴的移动。
减少选择对象时的鼠标移动,并且可以一个个像素的选择(?这不是和1一个意思吗)
移除鼠标设置中的“高级”按钮。这是由于原来大多数用户不知道如何使用这些设置。
在这种情况下,Windows需要建立起一个物理位移与屏幕位移的转换函数,而且这个函数必须不是纯线性的,为了降低计算复杂度,使用一个基于查表的分段函数比较合适。假设F(Vmouse)=Vpointer / Vmouse。则在鼠标速度比较小的情况下,F(x)<1,这样可以做到使鼠标能够移动到屏幕上的每个像素上。而在鼠标速度比较大的情况下,F(x)>1,这样保证在高分辨率屏幕上鼠标仍然能够高速移动,否则如果如第三节中分析,屏幕位移与物理位移比率是1:1的话,在高分辨率屏幕上人会感觉到鼠标移动的特别慢。

微软的研究人员经过可用性研究后得出了一个用户最希望的Vmouse-Vpointer曲线,见下图

 Vmouse-Vpointer曲线

 可以看出这个曲线是分段的,在Vmouse较小的时候,曲线斜率较小。在Vmouse较大的时候,曲线斜率较大。由于屏幕坐标为整数,因此每次计算的小数部分都会使用一个变量记录下来,以累积到下一次的计算中。Windows会根据当前的屏幕参数和鼠标参数来调整F(x),设得到的新曲线为F1(x)

总的计算公式如下:
Vpointer=interger(F1(Vmouse)×(Vmouse+Rn-1)×M)                         (3)
Rn=remainder(F1(Vmouse)×(Vmouse+Rn-1)×M)                             (4)
这里的interger表示取整数部分,remainder表示取小数部分,M为windows中固定的放大倍数,为控制面板-〉鼠标-〉指针选项中的鼠标移动速度设定。在这个计算公式中,有一个原则就是在M可取得范围中,如果Vmouse<1,则F1(Vmouse)×M<=1

在实际的Windows系统中,F1(x)是通过查表和插值的到的,如果控制面板-〉鼠标-〉指针选项中的“提高指针精确度”被关闭,则上述计算是通过会被跳过,此时的计算公式是将公式(3)(4)中的F1(Vmouse)去掉而成。

而F(x)中几个分段点为(0,0.43,1.25,3.86,40),这几个分段点在Windows XP Sp2以及Windows 2003 Sp1中都是正确的。下面是控制面板-〉鼠标-〉指针选项中的鼠标移动速度设定中拖动条从左到右各个值所对应的M

公式中M实际大小 拖动条值 1            2          3      4    5      6    7    8    9    10    11
MouseSensitivity           1             2          4      6    8     10  12   14  16   18   20
M值大小                          0.03125 0.0625 0.25 0.5 0.75 1   1.5   2    2.5  3     3.5

 

5、结论
虽然我没有将微软将F(x)转换到F1(x)的实际公式推导出来,也没有得到F(x)的每一段的具体斜率,但是通过以上的说明,我相信耐心的读者可以通过实验将这些具体数据得到的。

参考材料:
[1] "Pointer Ballistics for Windows XP" http://www.microsoft.com/whdc/device/input/pointer-bal.mspx
[2] MSDN Library April 2005

未经作者同意,请勿将此文用于商业用途。转载本文时,请保留作者信息以及原始链接。


本文来自CSDN博客,转载自:http://blog.csdn.net/liuweili_lwl/archive/2006/04/12/660868.aspx

阅读更多
想对作者说点什么? 我来说一句

鼠标加速算法 c 源码

2012年01月31日 2KB 下载

位移、速度、加速度信号互转

2016年12月07日 23KB 下载

加速度计计算位移

2014年08月14日 3KB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭