【问题标题】:Simulating mouse input programmatically in OS X在 OS X 中以编程方式模拟鼠标输入
【发布时间】:2011-02-13 14:46:45
【问题描述】:

是否可以从 OS X 中的程序模拟鼠标的动作?具体来说,简短的版本是我正在尝试使用两个网络摄像头来模拟触摸屏。因此,假设我可以获得 X、Y 位置,我可以通过鼠标移动或单击将信息发送到操作系统吗?

编辑-或者如果在另一个操作系统中特别容易,我愿意考虑。

【问题讨论】:

  • 根据您的用例,有一个名为“UI Recorder”的工具可以记录您对程序 UI 所做的任何事情,并在您需要时重放。
  • 谢谢,但我真正想做的是将任意鼠标输入发送到操作系统。
  • 我之前通过运行一个 vnc 服务器并编写一个小型 vnc 客户端来将鼠标事件发送到服务器来做到这一点。有开源的 vnc 服务器可以做到这一点,所以一个不错的最后手段是阅读一个的源代码。
  • 好主意,汤姆,我会考虑的。
  • 你们是救生员。我通过将 PowerMac 连接到 6 个投影仪显示器制作了一个显示墙,这些投影仪显示器以 2x3 网格排列,包括一个巨大的桌面。这很好用,但有一个错误:操作系统不会让我以编程方式调整窗口的大小高于一行。我可以用鼠标将它调整大,但不能用 AppleScript。使用此代码,我可以首先使用 AppleScript 创建和定位窗口,然后使用命令行单击拖动程序将窗口拉伸到我想要的大小。我注意到不需要特殊的拖动事件,只需订购这四个事件的调度以便

标签: macos input mouse touchscreen


【解决方案1】:

是的,这是可能的。您可以使用Quartz Event Services 来模拟输入事件。

假设 C,我写了这个简单的例子:

#include <ApplicationServices/ApplicationServices.h>
#include <unistd.h>

int main() {
    // Move to 200x200
    CGEventRef move1 = CGEventCreateMouseEvent(
        NULL, kCGEventMouseMoved,
        CGPointMake(200, 200),
        kCGMouseButtonLeft // ignored
    );
    // Move to 250x250
    CGEventRef move2 = CGEventCreateMouseEvent(
        NULL, kCGEventMouseMoved,
        CGPointMake(250, 250),
        kCGMouseButtonLeft // ignored
    );
    // Left button down at 250x250
    CGEventRef click1_down = CGEventCreateMouseEvent(
        NULL, kCGEventLeftMouseDown,
        CGPointMake(250, 250),
        kCGMouseButtonLeft
    );
    // Left button up at 250x250
    CGEventRef click1_up = CGEventCreateMouseEvent(
        NULL, kCGEventLeftMouseUp,
        CGPointMake(250, 250),
        kCGMouseButtonLeft
    );
    // Now, execute these events with an interval to make them noticeable
    CGEventPost(kCGHIDEventTap, move1);
    sleep(1);
    CGEventPost(kCGHIDEventTap, move2);
    sleep(1);
    CGEventPost(kCGHIDEventTap, click1_down);
    CGEventPost(kCGHIDEventTap, click1_up);
    // Release the events
    CFRelease(click1_up);
    CFRelease(click1_down);
    CFRelease(move2);
    CFRelease(move1);
        return 0;
}

假设 GCC,编译:

gcc -o program program.c -Wall -framework ApplicationServices

享受魔法。

【讨论】:

  • @Rob:不客气。我希望答案没有来得太晚。
  • 答案很好,但现在引用的文档指出These functions are still supported, but they are not recommended for new development,他们忘了提及推荐什么,有人知道吗?
  • 根据文档,these functions 严格指在文件CGRemoteOperation.h 中声明的旧的事件相关函数集 - 这里没有使用。
  • CGEventCreateMouseEvent 方法似乎在最近的 OSX 10.10 和 10.11 SKD 中不存在。从 QT IDE 编译时出现错误:“没有匹配函数调用 'CGEventCreateMouseEvent' CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, CGPointMake(x, y), 0 /*ignored*/);"
  • @YiannisMpourkelis:该方法自 OS X 10.4 (see my output on 10.10.5) 以来就存在。如果你使用(d) Homebrew 安装Qt,问题seems to be in the Qt5 formula.
【解决方案2】:

如果您不想编译东西并正在寻找基于 shell 的工具,Cliclick 可能是解决方案。

【讨论】:

    【解决方案3】:

    这是一个基于 jweyrick 回答的工作 C 程序:

    // Compile instructions:
    //
    // gcc -o click click.c -Wall -framework ApplicationServices
    
    #include <ApplicationServices/ApplicationServices.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[]) {
      int x = 0, y = 0, n = 1;
      float duration = 0.1;
    
      if (argc < 3) {
        printf("USAGE: click X Y [N] [DURATION]\n");
        exit(1);
      }
    
      x = atoi(argv[1]);
      y = atoi(argv[2]);
    
      if (argc >= 4) {
        n = atoi(argv[3]);
      }
    
      if (argc >= 5) {
        duration = atof(argv[4]);
      }
    
      CGEventRef click_down = CGEventCreateMouseEvent(
        NULL, kCGEventLeftMouseDown,
        CGPointMake(x, y),
        kCGMouseButtonLeft
      );
    
      CGEventRef click_up = CGEventCreateMouseEvent(
        NULL, kCGEventLeftMouseUp,
        CGPointMake(x, y),
        kCGMouseButtonLeft
      );
    
      // Now, execute these events with an interval to make them noticeable
      for (int i = 0; i < n; i++) {
        CGEventPost(kCGHIDEventTap, click_down);
        sleep(duration);
        CGEventPost(kCGHIDEventTap, click_up);
        sleep(duration);
      }
    
      // Release the events
      CFRelease(click_down);
      CFRelease(click_up);
    
      return 0;
    }
    

    托管在https://gist.github.com/Dorian/5ae010cd70f02adf2107

    【讨论】:

    • 我会使用usleep(duration*1000000)。否则你只会睡整数秒!
    • 投了反对票,因为它没有超时并且我的 mac 崩溃了 :)
    【解决方案4】:

    Swift鼠标移动点击示例:

    func mouseMoveAndClick(onPoint point: CGPoint) { 
        guard let moveEvent = CGEvent(mouseEventSource: nil, mouseType: .mouseMoved, mouseCursorPosition: point, mouseButton: .left) else {
            return
        }
        guard let downEvent = CGEvent(mouseEventSource: nil, mouseType: .leftMouseDown, mouseCursorPosition: point, mouseButton: .left) else {
            return
        }
        guard let upEvent = CGEvent(mouseEventSource: nil, mouseType: .leftMouseUp, mouseCursorPosition: point, mouseButton: .left) else {
            return
        }
        moveEvent.post(tap: CGEventTapLocation.cghidEventTap)
        downEvent.post(tap: CGEventTapLocation.cghidEventTap)
        upEvent.post(tap: CGEventTapLocation.cghidEventTap)
    }
    

    【讨论】:

      猜你喜欢
      • 2012-10-25
      • 2017-09-22
      • 2014-05-18
      • 2011-03-25
      • 2012-08-20
      • 1970-01-01
      • 1970-01-01
      • 2015-03-05
      • 1970-01-01
      相关资源
      最近更新 更多