在没有抖动的情况下将鼠标移动到OS X中的区域

时间:2016-12-01 07:26:51

标签: objective-c macos core-graphics osx-elcapitan hid

我想在OS X 10.11中将鼠标移动限制在屏幕的特定矩形区域。我修改了MouseTools(下面)中的一些代码来执行此操作,但是当您点击屏幕边缘时它会感到紧张。我怎样摆脱这种抖动?

// gcc -Wall constrain.cpp -framework ApplicationServices -o constrain

#include <ApplicationServices/ApplicationServices.h>

int main (int argc, const char * argv[]) {
    if(argc != 5) {
        printf("Usage: constrain left top right bottom\n");
        return 0;
    }
    int leftBound = strtol(argv[1], NULL, 10);
    int topBound = strtol(argv[2], NULL, 10);
    int rightBound = strtol(argv[3], NULL, 10);
    int bottomBound = strtol(argv[4], NULL, 10);
    CGEventTapLocation tapLocation = kCGHIDEventTap;
    CGEventSourceRef sourceRef = CGEventSourceCreate(kCGEventSourceStatePrivate);
    while(true) {
        CGEventRef mouseEvent = CGEventCreate(NULL);
        CGPoint mouseLoc = CGEventGetLocation(mouseEvent);
        int x = mouseLoc.x, y = mouseLoc.y;
        if(x < leftBound || x > rightBound || y < topBound || y > bottomBound) {
            if(x < leftBound) x = leftBound;
            if(x > rightBound) x = rightBound;
            if(y < topBound) y = topBound;
            if(y > bottomBound) y = bottomBound;
            CGEventRef moveMouse = CGEventCreateMouseEvent(sourceRef, kCGEventMouseMoved, CGPointMake(x, y), 0);
            CGEventPost(tapLocation, moveMouse);
            CFRelease(moveMouse);
        }
        CFRelease(mouseEvent);
        usleep(8*1000); // 8ms, ~120fps
    }
    CFRelease(sourceRef);
    return 0;
}

以下是我尝试的其他一些事项:Receiving, Filtering, and Modifying Mouse Events显示了如何使用CGEventTapCreate为鼠标移动创建回调。在代码中它说&#34;我们可以改变鼠标事件的各个方面。例如,我们可以使用CGEventSetLocation(event, newLocation)。&#34;不幸的是,这实际上并没有改变鼠标的位置(完整示例here)。我能够改变鼠标位置的唯一方法是CGEventPostCGWarpMouseCursorPosition。我还尝试使用 kCGHIDEventTap而不是kCGSessionEventTap,我检查了我为该应用启用了超级用户权限和辅助功能。它似乎应该工作,因为有另一个modifying key presses的例子可以正常工作。我没有使用CGEventSetLocation,而是尝试使用CGEventSetIntegerValueField(如键盘示例中所示)将x和y增量设置为0,但这并没有改变任何内容。

最后,我还尝试在CGEventPost内使用CGWarpMouseCursorPositionCGEventCallback,&#34;隐形边框&#34;仍然比上面的代码更加紧张。

1 个答案:

答案 0 :(得分:3)

我在Mac驱动程序中为Wine实现了这个功能。它有点复杂。

方法是通过调用CGAssociateMouseAndMouseCursorPosition(false)来基本禁用鼠标光标的移动。如果约束矩形是光标当前位置的1x1矩形,这里就可以实现你想要的效果。

最重要的是,然后我使用事件点击来观察鼠标移动事件。这些不会改变位置,但具有用户尝试做的增量。然后我使用CGWarpMouseCursorPosition()根据这些增量移动光标并在传递之前调整事件。

请注意,鼠标事件中的位置信息没有意义。这将是陈旧的。有些事件会在您最后一次扭曲之前排队,因此有一个旧位置。您需要跟踪光标本身的位置。它会从您将鼠标与鼠标取消关联的任何地方开始,并在您扭曲它时进行更改。您将增量添加到该(而不是事件位置),将其添加到约束矩形,并将其用作事件和扭曲的新位置。对于下一个活动,您将从这个新职位开始。等

还有一个令人遗憾的皱纹。 CGWarpMouseCursorPosition()会影响后续鼠标移动事件的增量值。基本上,您扭曲光标的距离将添加到在扭曲后排队的第一个鼠标移动事件。未经检查,这将有效地使用户的鼠标移动加倍,每次事件都会出现失控的反馈循环,光标会射到一个极端或另一个极端。

因此,您必须记录您执行的经线,执行时的扭曲以及它们改变位置的程度。然后,当事件通过水龙头时,您将它们的时间与经线时间进行比较。对于比当前事件更早的任何扭曲,您从事件的增量中减去它们的位置变化并将其从列表中删除。