Mouse Input
电脑鼠标接口
当前的pc通常使用PS2鼠标,或模拟PS2鼠标的类似格式。 串行鼠标是一种更古老的技术,不再常见。
USB鼠标
USB鼠标通常模拟PS2鼠标,除了它从USB总线而不是IRQ 12生成IRQ。 建议使用复选框 “启用鼠标捕获”。 开启“鼠标切换方法” 使您可以从列表热键中进行选择,以在启用或禁用鼠标捕获之间进行切换。
Bochs模拟器
如果您使用bochs,并且希望您的鼠标模拟PS2鼠标,则需要编辑键盘和鼠标设置并将鼠标类型设置为 “ps2” (这是没有鼠标滚轮按钮的鼠标) 或 “imps2” (这是带有鼠标滚轮按钮的鼠标)。
PS2鼠标-基本操作 (符合微软标准)
一旦鼠标被初始化 (见下文),鼠标发送3或4个字节的数据包来传达鼠标移动和鼠标按钮按下/释放事件。 这些数据包异步显示为IO端口0x60上的数据。 即使数据显示在端口0x60 (键盘端口) 上,它也 不 触发irq1。 您将知道鼠标数据已到达的唯一方法是,如果您处理适当的IRQ (通常为IRQ12),或者如果您偶尔轮询端口0x64的位数0 (值 = 1),以查看端口0x60上是否可用的数据。 不必处理驱动程序内部的所有以下内容,但是这样做可以使事情更快地工作。
键盘/辅助数据位
由于键盘和鼠标数据都显示要在端口0x60上读取,因此必须能够分辨出哪个是哪个。 要判断端口0x60上是否有任何可用数据,有必要从端口0x64读取一个字节。 在端口0x64的那个字节中,位数0 (值 = 1) 表示可以在端口0x60上读取一个字节。 如果设置了该位,则额外的位编号5 (值 = 0x20) 表示该下一个字节来自鼠标。 如果你看 RBIL,它说这个 “鼠标位” 是特定的MCA,但这不再是真的。 所有支持PS2鼠标的pc都使用该位表示传入字节是由辅助PS2输入端口生成的。
PS2鼠标子类型
有几种类型的鼠标,但它们可以分为两组,具体取决于它们是否具有滚轮。 带有滚轮的鼠标可以在每个鼠标数据包中发送一个额外的字节,指示鼠标滚轮和额外按钮的状态。
没有滚轮的鼠标专门使用3字节数据包。 带有滚轮和最多5个按钮的鼠标 (当前) 可以发送4个字节的数据包,如果它们已正确初始化。
鼠标数据包信息
有关Microsoft兼容PS2鼠标数据包的更多详细信息,请参阅下面的链接,或搜索Adam Chapweske文章。 对于不符合MS标准的鼠标,请参见Linux文章。
鼠标数据包的定时/生成
通常会初始化鼠标以特定速率生成移动数据包。 如果鼠标正在移动,默认速率是每秒100个数据包。 如果按下或释放按钮,鼠标还会生成数据包。 如果鼠标没有移动并且没有单击任何按钮,则鼠标将不会生成任何自动数据包。
前3个数据包字节的格式
即使您的鼠标正在发送4个字节的数据包,前3个字节始终具有相同的格式。 第一个字节有一堆位标志。 第二个字节是 “delta X” 值-也就是说,它测量水平鼠标移动,左为负。 第三个字节是 “delta Y”,向下 (朝向用户) 为负。 deltaX和deltaY的典型值是慢速运动的一两个,非常快的运动的可能是20个。 最大可能值255为-256 (它们是9位数量,二补码)。
byte 1:
Y overflow | X overflow | Y sign bit | X sign bit | Always 1 | Middle Btn | Right Btn | Left Btn |
---|
byte 2:
X movement |
---|
byte 3:
Y movement |
---|
第一个字节的前两位 (值0x80和0x40) 应该分别显示Y和X溢出。 它们没有用。 如果设置了它们,您可能应该丢弃整个数据包。
第一个字节 (值0x20) 的位数5表示delta Y (第三个字节) 是负数 (如果已设置)。 这意味着你应该或0xFFFFFF00到delta Y的值,作为符号扩展 (如果使用32位)。
第一个字节 (值0X10) 的位数4表示delta X (第二个字节) 是负数 (如果已设置)。 这意味着你应该或0xFFFFFF00到delta X的值,作为符号扩展 (如果使用32位)。
应该始终设置第一个字节 (值0x8) 的位数3。 这有助于维护和验证数据包对齐。 不幸的是,一些老旧的鼠标 (如10多年的微速2按钮轨迹球) 没有设置这个位。 RBIL 声称这个位应该是0,但它是错误的。
如果设置了相应的位,则第一个字节的底部3位指示当前是否按住鼠标中间,右侧或左侧按钮。 Middle = bit 2 (value=4), right = bit 1 (value=2), left = bit 0 (value=1).
可选的第4个数据包字节的格式
如果鼠标已被初始化,以使其mouseID为3或4,则它将在每个数据包中发送第4个字节。 在所有当前的鼠标上,应该忽略前两位。 在某些鼠标上,基于滚动轮运动,位将在0到1之间翻转。 如果鼠标具有第4和第5鼠标按钮,则它们的状态分别由位4 (值 = 0x10) 和位5 (值 = 0x20) 指示。 注意: 如果 不存在 按钮,则这些位可能会根据滚轮的移动而翻转!(即。 请注意,这不会为不存在的按钮生成虚假的 “鼠标按钮单击” 事件。)
第4个字节的底部半字节 (4位) 将是以下值之一:
- 0 -- 无滚轮运动
- 1 -- 垂直向上滚动一键
- 0xF -- 垂直向下滚动一键
- 2 -- 水平滚动右一键式
- 0xE -- 水平滚动左一键式
当只有垂直滚动轮存在或已被激活时,第4个数据包字节仅包含:
byte 4:
Z movement |
---|
但是,如果鼠标具有额外的按钮并正确初始化,则看起来像这样:
byte 4:
Mostly 0 | Mostly 0 | 5th btn down (pressed) | 4th btn down (pressed) | Z3 | Z2 | Z1 | Z0 |
---|
其中Z0虽然Z3是Z机芯 (scrollwheel) 的4位带符号值,具有上面提到的值 (0,1,2,0xe,0xF) 和上面列出的含义。
非线性运动
当用户试图指向屏幕上的某个东西时,他们会迅速将鼠标朝目标的大致方向移动,然后放慢速度以准确指向它。 鼠标数据包中的deltaX/Y值可以直接使用,但是这样做会迫使用户将鼠标移动得很远,以将光标从屏幕的一个区域移到另一个区域。
一个更好的答案可能是根据鼠标移动的速度,按额外的倍数缩放鼠标移动。 如果鼠标移动缓慢,则比例因子可以为1-以允许最高的灵敏度。 当鼠标正在 (或已经) 快速移动时,比例因子可以是5或10,以允许光标在屏幕上快速移动较大距离。
显然,有很多方法可以进行这种缩放。 如果要在汇编程序中对驱动程序进行编码,则建议是使用BSR命令生成deltaX plus deltaY的近似日志base2,并将其用作缩放因子。
双击
如果您打算实现doubleclick,则需要以高精度记录mousedown事件的时间戳。 知道是否发生了双击的唯一方法是知道上次单击鼠标按钮发生了多久。 如果两次点击之间的延迟小于某个阈值,则是双击。 这里的问题是,你需要能够测量非常短的延迟,点击之间可能会有非常长的延迟 (天,也许) -- 足够长,您的时间戳测量可能会溢出。 这需要谨慎处理。
超时/鼠标断开
如果鼠标运行正常,但没有被移动或单击,则不会发送任何数据包。 如果已拔下鼠标,它也不会发送任何数据包。 如果您想支持PS2鼠标的 “热插拔”,那么您需要知道鼠标何时断开连接,因为您将需要重新初始化它。 如果您有一段时间没有看到来自鼠标的任何数据包,您可以查询鼠标以查看它是否还活着。 一种方便的方法是发送单个鼠标数据包的特殊请求 (鼠标命令0xEB)。 您将从鼠标返回一个ACK (0xFA),然后是一个鼠标数据包 (可能将所有内容设置为0)。 请注意,您需要确保0xFA不会导致输入鼠标数据包未对齐。 另外请注意,如果鼠标数据包的内容 不是 0,则意味着您的鼠标数据包已被禁用。
总的来说,最好在系统等待鼠标响应的任何地方都有超时,因为它可能永远不会出现。
PS2鼠标命令
启用PS2辅助端口后,您可以向鼠标发送命令。 建议在 “重新编程” 鼠标的同时禁用自动数据包流模式。 您可以通过将命令0xF5发送到鼠标来执行此操作,或者通过设置Compaq状态字节的位5来禁用 “主鼠标时钟” (请参见下文)。
等待将字节发送到端口0x60和0x64
所有输出到端口0x60或0x64之前必须等待端口0x64的位1 (值 = 2) 变为清除。 同样,在设置端口0x64的位0 (值 = 1) 之前,无法从端口0x60读取字节。 有关更多详细信息,请参见 PS2键盘。
0xD4字节,命令字节,数据字节
向鼠标发送命令或数据字节 (到端口0x60) 之前必须先向端口0x64发送0xD4字节 (在发送每个输出字节之前,在端口0x64 (位1) 上进行适当的等待)。 注意: 此0xD4字节不会从键盘或鼠标生成任何ACK。
等待鼠标ACK确认
需要等到鼠标在每个命令或数据字节之后发回0xFA确认字节,然后再发送下一个字节 (注意: 重置命令可能不会被ACK'ed-重置后等待0xAA)。 少数命令需要额外的数据字节,两个字节都会生成一个ACK。
有用的鼠标命令集
- 注意: 请记住,鼠标使用ACK (0xFA) 响应所有命令字节和数据字节。
- 注2: 表中给出的命令发送到端口0x60。如果命令需要额外的字节 (如采样率),则该字节也将转到端口0x60。
十六进制值 | 含义 | 描述 |
---|---|---|
0xFF | Reset | 鼠标可能发送ACK (0xFA) 加几个字节,然后重置自己,并总是发送0xAA。 |
0xFE | 重新发送 | 此命令使鼠标再次将其最新数据包发送到主机。 |
0xF6 | Set Defaults | 禁用流式传输,将数据包速率设置为每秒100,并将分辨率设置为每毫米4像素。 |
0xF5 | Disable Packet Streaming | 鼠标停止发送自动数据包。 |
0xF4 | Enable Packet Streaming | 当鼠标移动或被点击时,鼠标开始发送自动数据包。 |
0xF3 | Set Sample Rate | 需要额外的数据字节: 每秒自动数据包 (法律值见下文)。 |
0xF2 | Get MouseID | 鼠标发送发送它的当前 “ID”,它可能会随着鼠标初始化而改变。 |
0xEB | Request Single Packet | 鼠标发送ACK,然后是包含当前数据的完整鼠标数据包。 |
0xE9 | Status Request | 鼠标发送ACK,然后发送3个状态字节。有关状态字节格式,请参见下文。 |
0xE8 | Set Resolution | 需要额外的数据字节: 像素每毫米分辨率 (值0到3) |
附加无用的鼠标命令
十六进制值 | 含义 | 描述 |
---|---|---|
0xF0 | Set Remote Mode | 鼠标发送ACK (0xFA),然后重置其移动计数器,并进入远程模式 |
0xEE | Set Wrap Mode | 鼠标发送ACK (0xFA),然后重置其移动计数器,并进入换行模式 |
0xEC | Reset Wrap Mode | 鼠标发送ACK,然后进入最后一个模式,在进入换行模式之前,它还会重置其移动计数器 |
0xEA | Set Stream Mode | 鼠标发送ACK (0xFA),然后重置其移动计数器,并进入报告模式 |
0xE7 | Set Scaling 2:1 | 鼠标发送ACK并设置非线性缩放 “2:1” |
0xE6 | Set Scaling 1:1 | 鼠标发送确认并设置正常线性缩放 “1:1” |
状态字节看起来像这样:
Byte 1:
Always 0 | mode | enable | scaling | Always 0 | left btn | middle | right btn |
---|
Byte 2:
resolution |
---|
Byte 3:
sample rate |
---|
Mode: if it is 1, the current mode is remote mode; if 0 then it is stream mode
Enable: if it is 1, then data reporting is enabled; if 0 then data reporting is disabled
Scaling: if it is 1, scaling 2:1 is enabled; if 0 then scaling 1:1 is enabled.
分辨率、缩放比例和采样率
定义:
- 分辨率: 每毫米鼠标移动的DeltaX或DeltaY。
- 缩放: 将简单的非线性失真应用于鼠标移动 (请参见上面的非线性移动)。
- 采样率: 鼠标每秒可以发送的数据包。
分辨率:
value | resolution |
---|---|
0x00 | 1 count /mm |
0x01 | 2 count /mm |
0x02 | 4 count /mm |
0x03 | 8 count /mm |
缩放可以是 “1:1” (线性 = 无缩放) 或 “2:1” (非线性)。 这是非线性缩放:
Movement Counter | Reported Movement |
---|---|
0 | 0 |
1 | 1 |
2 | 1 |
3 | 3 |
4 | 6 |
5 | 9 |
more than 5 | 2 * Movement Counter |
采样率可以有以下值 :( 所有值都是十进制的,而不是十六进制的)
value | Samples pr second |
---|---|
10 | 10 |
20 | 20 |
40 | 40 |
60 | 60 |
80 | 80 |
100 | 100 |
200 | 200 |
- 注意: 人眼的运动速度不会超过每秒30个样本,并且人的手指也无法单击如此快的按钮。 低于30的采样率将导致明显的生涩鼠标运动,并可能错过mousedown事件。
明显高于30的采样率将浪费宝贵的I/O总线带宽。 您可以自己测试这些东西,但是通常不建议使用10、20、100或200的采样率。
Initializing a PS2 Mouse
PC上的PS2鼠标端口连接到PS2键盘控制器的辅助输入。 该输入可能在启动时被禁用,需要启用。 当鼠标通过键盘控制器向IO端口0x60发送字节时,通常还希望鼠标生成IRQ12中断。此外,有必要告诉鼠标启用数据包的传输。 可选地,您可能还希望启用其他鼠标功能,例如滚轮、更快的响应时间、更高的分辨率或其他鼠标按钮。
PS/2 Device Unplugging/Hot Plugging
创建PS/2设备规格的人没有指定在计算机保持打开状态 (“热插拔”) 时可以拔下PS/2设备并重新插入。很久以前,其他一些人实际上设计了如果发生PS2热插拔会稍微损坏的主板。 但是,鼠标和键盘的电源线被绊倒了,有时在不关闭两个系统的情况下,暂时尝试将鼠标从一台机器移动到另一台机器是非常合乎逻辑的。 因此,实际上,过去15年中制造的所有计算机都应支持PS2设备的热插拔。 当鼠标插入正在运行的系统时,它可能会发送0xAA,然后发送0x00字节,然后进入默认状态 (请参见下文)。
设置Compaq状态/启用IRQ12
在某些系统上,PS2辅助端口在启动时被禁用。 来自aux端口的数据不会产生任何中断。 要知道数据已经到达,您需要启用aux端口以生成irq12。 只有一种方法可以做到这一点,这涉及获取/修改 “compaq status” 字节。 您需要将命令字节0x20 (“获取Compaq状态字节”) 发送到端口0x64上的PS2控制器。 如果你看 RBIL,它说这个命令是康柏特有的,但这不再是真的。 此命令不会生成0xFA ACK字节。 返回的下一个字节应该是状态字节。 (注意: 在某些版本的Bochs上,由于某种原因,发送此命令后,您将获得一个 second 字节,其值为0xD8。) 获得状态字节后,需要设置位数1 (值 = 2,启用IRQ12),并清除位数5 (值 = 0x20,禁用鼠标时钟)。 然后将命令字节0x60 (“设置康柏状态”) 发送到端口0x64,然后将修改后的状态字节发送到端口0x60。 这可能会从键盘生成0xFA ACK字节。
Aux 输入启用命令
将启用辅助设备命令 (0xA8) 发送到端口0x64。这将从 键盘 生成ACK响应,您必须等待接收。 请注意,如果设置Compaq状态字节成功,则不需要使用此命令-但也不会造成伤害。
开机时的鼠标状态
重置鼠标时,无论是通过加电还是使用重置命令 (0xFF),它总是进入以下默认状态:
- packets disabled
- emulate 3 button mouse (buttons 4, 5, and scroll wheels disabled)
- 3 byte packets
- 4 pixel/mm resolution
- 100 packets per second sample rate
MouseID Byte
在初始化期间,鼠标通过响应初始化命令更改其mouseID来指示其具有各种功能 (滚轮,第4和第5鼠标按钮)。 因此,您发送一组鼠标命令,然后使用Get mouseID命令 (0xF2) 请求MouseID字节。如果mouseID从以前的值更改,则鼠标已更改模式。 mouseID字节始终是读取MouseID命令的ACK之后发送的下一个字节。 在初始化时,mouseID始终为0。其他当前的法律价值是3和4。
Init/Detection Command Sequences
如果您想要的不仅仅是3个按钮,则必须使用以下顺序。 如果接受第一个序列: 鼠标数据包中的字节数更改为4,则鼠标上的滚轮将被激活,并且mouseID从0更改为3。
第一个魔法序列是这样的:
- set sample rate to 200
- set sample rate to 100
- set sample rate to 80
- get the new id to verify acceptance
使用上述顺序激活滚轮后 ,可以通过以下附加魔术顺序激活第4和第5个鼠标按钮:
- set sample rate to 200
- set sample rate to 200
- set sample rate to 80
- get the new id to verify acceptance
如果接受这第二个序列,则返回的鼠标ID值从3变为4。
Enable Packets
将鼠标初始化为所需的mouseID值后,其采样率可能为每秒80个样本,其分辨率可能为4像素/mm,并且仍禁用数据包。 您可能希望修改采样率和分辨率,然后向鼠标发送0xF4命令,以使鼠标自动生成移动数据包。
Streaming Advantages and Disadvantages
代替启用自动流式数据包模式,可以一次请求一个鼠标数据包。 与流式数据包模式相比,这样做具有一些优势。 您可能会看到,您需要通过I/O总线发送或接收至少4个额外的字节,以便将每个0xEB命令发送到鼠标,并且I/O总线非常慢。 另一方面,典型的流式传输模式可能每秒通过I/O总线发送的鼠标数据包字节比您需要的多数百个-因此,如果存在缺点,则可能很小。
流模式的最大问题之一是 “对齐”-从未将数据包定义为具有明显的边界。 这意味着很容易忘记哪个鼠标字节应该是下一个数据包的第一个字节。 如果您专门请求单个数据包 (而不是使用流式传输模式),则完全避免了此问题,因为每个数据包都以ACK (0xFA) 开头,该ACK易于识别。
PC Serial Mouse
For info on running a serial mouse on an RS232 port, see this document from the freedos documentation.
Mac鼠标接口