在OS X中以编程方式模拟鼠标输入


68

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

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


根据您的用例,有一个称为“ UI记录器”的工具可以记录您对程序的用户界面所做的任何操作,并在需要时重放它。
zneak

谢谢,但是我真正想做的是将任意鼠标输入发送到操作系统。
罗伯·劳伦斯

3
之前,我是通过运行vnc服务器并编写一个小型vnc客户端将鼠标事件发送到服务器来完成此操作的。有开放源代码的vnc服务器可以执行此操作,因此最好的办法是读取其中一个的源代码。

好主意汤姆,我会考虑的。
罗伯·劳伦斯

3
你们是救命的人。我将PowerMac连接到6个投影仪显示器上,形成了显示墙,这些投影仪显示器以2x3网格排列,包括一个巨型桌面。这很好用,但是有一个错误:操作系统不允许我以编程方式调整大于一排的窗口的大小。我可以使用鼠标将其调整为较大的尺寸,但不能使用AppleScript调整其尺寸。通过此代码,我可以首先使用AppleScript创建和定位窗口,然后使用命令行的clicky-drag程序将窗口拉伸到所需的大小。我注意到,不需要特殊的拖动事件,只需订购这四个事件的调度即可,以便

Answers:


96

对的,这是可能的。您可以使用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:不客气。我希望答案不会太晚。
jweyrich 2010年

4
答案很好,但是现在引用的文档指出These functions are still supported, but they are not recommended for new development,他们忘了提出什么建议,有人知道吗?
2014年

4
根据文档,these functions严格指的是文件中声明的较旧的事件相关函数集CGRemoteOperation.h-此处未使用。
jweyrich 2014年

1
在最近的OSX 10.10和10.11 SKD中似乎不存在CGEventCreateMouseEvent方法。从QT IDE进行编译,我得到一个错误:“没有匹配的函数来调用'CGEventCreateMouseEvent'CGEventRef event = CGEventCreateMouseEvent(NULL,kCGEventMouseMoved,CGPointMake(x,y),0 / *忽略* /);”
Yiannis Mpourkelis,2015年

1
@YiannisMpourkelis:该方法自OS X 10.4起存在(请参阅我在10.10.5上的输出)。如果您使用(d)Homebrew安装Qt,则问题似乎出在Qt5公式中
jweyrich,2015年

14

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)
}

8

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


2

这是一个基于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


3
我会用usleep(duration*1000000)。否则,您将只睡整数秒!
nneonneo '02

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.