我想在 OSX 上获得高分辨率和高帧率的鼠标移动。
“高帧率”= 60 fps 或更高(最好 > 120)
“高分辨率”= 子像素值
问题
我有一个以显示器刷新率运行的opengl 视图,所以它是~60 fps。我用鼠标环顾四周,所以我隐藏了鼠标光标,我依赖于鼠标增量值。
问题是鼠标事件的帧率太低,并且值被捕捉到整数(整个像素)。这会导致“断断续续”的观看体验。这是鼠标增量值随时间变化的可视化:
mouse delta X
^ xx
2 | x x x x xx
| x x x x xx x x x
0 |x-x-x--xx-x-x-xx--x-x----x-xx-x-----> frame
|
-2 |
v
这是一条典型的(缩短的)曲线,用户将鼠标向右移动一点。每个 x 代表每一帧的 deltaX 值,并且由于 deltaX 值四舍五入为整数,因此该图实际上非常准确。正如我们所看到的,deltaX 值将在一帧为 0.000,下一帧为 1.000,但随后又为 0.000,然后是 2.000,然后又是 0.000,然后是 3.000、0.000,以此类推。
这意味着视图将在一帧旋转 2.000 个单位,然后在下一帧旋转 0.000 个单位,然后再旋转 3.000 个单位。当鼠标以或多或少的恒定速度拖动时会发生这种情况。不用说,这看起来像废话。
那么,我怎样才能 1)增加鼠标的事件帧率?和 2) 获得亚像素值?
到目前为止
,我已经尝试了以下方法:
- (void)mouseMoved:(NSEvent *)theEvent {
CGFloat dx, dy;
dx = [theEvent deltaX];
dy = [theEvent deltaY];
// ...
actOnMouse(dx,dy);
}
嗯,这个很明显。dx
这是浮点数,但值总是四舍五入(0.000、1.000 等)。这将创建上面的图表。
所以下一步是在鼠标事件进入 WindowServer 之前尝试点击鼠标事件,我想。所以我创建了一个 CGEventTrap:
eventMask = (1 << kCGEventMouseMoved);
eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap,
0, eventMask, myCGEventCallback, NULL);
//...
myCGEventCallback(...){
double dx = CGEventGetDoubleValueField(event, kCGMouseEventDeltaX);
double dy = CGEventGetDoubleValueField(event, kCGMouseEventDeltaY);
}
仍然值是n.000
,尽管我相信事件触发率要高一些。但它仍然不是60 fps。我仍然得到上面的图表。
我还尝试将鼠标灵敏度设置得非常高,然后在我这边按比例缩小值。但似乎 OSX 增加了某种加速或其他东西——这些值变得非常“不稳定”,因此无法使用,而且射速仍然太低。
没有运气,我开始跟踪兔子洞的鼠标事件,我已经到达了 IOKit。这对我来说很可怕。这是疯帽子。Apple 文档变得很奇怪,似乎在说“如果你如此深入,那么你真正需要的只是头文件”。
所以我一直在阅读头文件。我发现了一些有趣的花絮。
在<IOKit/hidsystem/IOLLEvent.h>
第 377 行有这个结构:
struct { /* For mouse-down and mouse-up events */
UInt8 subx; /* sub-pixel position for x */
UInt8 suby; /* sub-pixel position for y */
// ...
} mouse;
看,它说的是亚像素位置!好的。然后在第 73 行<IOKit/hidsystem/IOLLParameter.h>
#define kIOHIDPointerResolutionKey "HIDPointerResolution"
唔。
总而言之,我感觉 OSX 深知亚像素鼠标坐标,并且必须有一种方法可以读取每一帧的原始鼠标移动,但我只是不知道如何获得这些值。
问题
呃,那么,我在问什么?
- 有没有办法在 OSX 中获得高帧率鼠标事件?(示例代码?)
- 有没有办法在 OSX 中获取亚像素鼠标坐标?(示例代码?)
- 有没有办法每帧读取“原始”鼠标增量?(即不依赖事件。)
- 或者,我如何获取 NXEvents 或设置 HIDParameters?示例代码?(所以我可以自己更深入地研究这个......)
(抱歉发了这么长的帖子)