将鼠标限制在 Mac 上的一台显示器上(可能使用 Cocoa)

发布于 2024-12-16 17:14:11 字数 2030 浏览 3 评论 0原文

我一直在热切地寻找一种方法,在 Mac 上的多显示器设置中将用户的鼠标限制在一个显示器上。

我偶然发现了这个问题:Cocoa:限制鼠标到屏幕,我保证我没有重复这个问题。

然而,这个问题确实在我脑海中激发了一个想法,即可以使用 Cocoa 编写一个简单的应用程序,将鼠标限制在一个屏幕上,在后台运行该应用程序,并且仍然使用我在 AS3 中开发的游戏/Adobe AIR/Flash。

该游戏是全屏游戏,并且在同一台显示器上始终保持相同的分辨率。另一台显示器也始终具有相同的分辨率,但只是非交互式信息显示。我需要用户能够与游戏交互,但不会意外地将鼠标移离游戏屏幕。

问题摘要: 我可以使用 Cocoa/Objective C 创建一个适用于 Mac OS X (Lion) 的基本应用程序,该应用程序将鼠标限制在一台可以在后台运行的显示器上,并防止用户将鼠标移到具有完整功能的显示器之外。屏幕上运行游戏吗?


[编辑:] 我找到了运行 Quartz 事件过滤器循环所需的基本代码,由以下答案提供: 修改 NSEvent 以发送与按下的键不同的键

我将使用它我编写了用于测试目的的代码,并且我对其进行了一些修改以检测鼠标事件,如下所示:

CGEventRef mouse_filter(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {

    NSPoint point = CGEventGetLocation(event);
    NSPoint target = NSMakePoint(100,100);
    if (point.x >= 500){
        CGEventSetLocation(event,target);

    }
    return event;
}

int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    CFRunLoopSourceRef runLoopSource;

    CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, kCGEventMouseMoved, mouse_filter, NULL);

    if (!eventTap) {
        NSLog(@"Couldn't create event tap!");
        exit(1);
    }

    runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);

    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);

    CGEventTapEnable(eventTap, true);

    CFRunLoopRun();

    CFRelease(eventTap);
    CFRelease(runLoopSource);
    [pool release];

    exit(0);
}

但是,这似乎不太正确。它确实可以正确检测鼠标事件,并且也可以正确移动事件。例如,如果我将窗口拖动到距离屏幕左侧超过 500 像素,则窗口拖动事件将移动到 100,100。但是,当鼠标只是在屏幕上移动而不执行其他操作时,鼠标本身不会移动到新位置。 IE:您仍然可以在屏幕周围移动鼠标,而不是仅在左侧 500 像素列上移动。

有什么想法吗?

I've been feverishly searching for a method by which to limit the user's mouse to one display in a multi-display setup on a Mac.

I've stumbled upon this question: Cocoa: Limit mouse to screen, I promise I have not duplicated this question.

The question did, however, spark an idea in my mind that it might be possible to write a simple application using Cocoa to restrict the mouse to one screen, run this application in the background, and still use my game which has been developed in AS3/Adobe AIR/Flash.

The game is a full-screen game, and will always be at the same resolution on the same monitor. The other monitor will also always have the same resolution, but is to be just a non-interactive display of information. I need the user to be able to interact with the game, but not accidentally move the mouse off of the game's screen.

Question Summary:
Can I create a basic application for Mac OS X (Lion) using Cocoa/Objective C that will restrict the mouse to one monitor that can be run IN THE BACKGROUND and prevent users from moving the mouse outside of the monitor that will have a full-screen game running on it?


[EDIT:]
I found the basic code necessary to run a loop for the Quartz Event Filter, courtesy of this answer: Modify NSEvent to send a different key than the one that was pressed

I am going to use that code for testing purposes, and I have modified it a bit to detect mouse events like so:

CGEventRef mouse_filter(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {

    NSPoint point = CGEventGetLocation(event);
    NSPoint target = NSMakePoint(100,100);
    if (point.x >= 500){
        CGEventSetLocation(event,target);

    }
    return event;
}

int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    CFRunLoopSourceRef runLoopSource;

    CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, kCGEventMouseMoved, mouse_filter, NULL);

    if (!eventTap) {
        NSLog(@"Couldn't create event tap!");
        exit(1);
    }

    runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);

    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);

    CGEventTapEnable(eventTap, true);

    CFRunLoopRun();

    CFRelease(eventTap);
    CFRelease(runLoopSource);
    [pool release];

    exit(0);
}

This, however, doesn't seem to work quite right. It is certainly detecting mouse events properly, and it moves the events properly as well. For instance, if I drag a window past 500 pixels from the left of the screen, the window drag event gets moved to 100,100. However, the mouse itself doesn't get moved to the new location when it is simply being moved around the screen, performing no other actions. IE: You can still move the mouse all around the screen, instead of just on the left 500 pixel column.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

神也荒唐 2024-12-23 17:14:11

使用 Quartz Event Tap 过滤鼠标移动和鼠标拖动事件。在点击回调中,使用 CGEventSetLocation 修改鼠标事件的位置,否则这些事件会移出主屏幕。

您可能需要以 root 身份运行该程序,或者在系统偏好设置中启用辅助设备访问。

Quartz 事件服务参考

Use a Quartz Event Tap to filter mouse moved and mouse dragged events. In the tap callback, use CGEventSetLocation to modify the location of mouse events that would otherwise move off the main screen.

You may need to run the program as root, or have assistive device access enabled in System Preferences.

Quartz Event Services Reference

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文