8

I'm writing an application for Mac OS X 10.6 and later in C++. One part of the application needs to simulate mouse movement and mouse clicks. I do this currently by posting CGEvent objects using CGEventPost(kCGHIDEventTap, event);.

This works, for the most part - I can simulate mouse movement and clicks just fine, but it seems to fail in some areas. For example:

  • In Mozilla Firefox and Safari, I can click on all the menus, but cannot click on a link within a website. When I try, the link is highlighted, but the browser never follows the link. However, I can right-click on a link, select "open link in new tab", and everything works as expected. Solved - creating the mouse event using CGEventCreateMouseEvent(...) makes the event work within web browser.
  • I can click on the "Dashboard" icon to brink up the dashboard, but I cannot click on the "i" button on any of the dashboard widgets. Similarly, clicking on any of the search results from the spotlight search widget doesn't work either.

This inconsistency is along application boundaries. What might be the cause?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Thomi
  • 11,647
  • 13
  • 72
  • 110

4 Answers4

8

What you need to do to convince these applications that you have in fact generated a click is to explicitly set the value of the "click state" field on the mouse up event to 1 (it defaults to 0). The following code will do it:

CGEventSetIntegerValueField(event, kCGMouseEventClickState, 1);

It also has to be set to 1 for the mouse down, but by using CGEventCreateMouseEvent() rather than CGEventCreate() that gets done for you.

I have tested this and it works in the 'i' buttons in the dashboard and the Spotlight search results.

(As an aside, if you were simulating a double click you would need to set the click state to 2 for both the mouse down and mouse up events of the second click.)

Nick Moore
  • 15,547
  • 6
  • 61
  • 83
1

Most menus are activated with the mouseDown event. Hyperlinks are followed after the mouseUp event. The "i" button only works when the mouse has been clicked but not a long time. All this seem to show that you have a timing problem, try several pressed timing.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
elou
  • 1,242
  • 15
  • 21
  • This sounds like a promising lead. I have just timed the gap between sending the mouse down and mouse up events - a typical click takes 42 mS, which seems to me should be short enough to generate a click event rather than a click-and-hold or whatever... – Thomi Mar 09 '10 at 14:52
  • Indeed, it's not a timing issue. As long as you set the click count, any reasonable timing will do. – Nick Moore Mar 11 '10 at 07:26
0

Use OSXVnc. I see they use CGPostMouseEvent() instead of CGPostEvent().

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Taybin
  • 31
  • 3
  • 1
    CGPostMouseEvent has been deprecated in 10.6. Thanks fro the suggestion, but I'd rather not use deprecated functions. – Thomi Mar 08 '10 at 08:36
  • 2
    CGPostMouseEvent() has been replaced with CGEventCreateMouseEvent(). Why not use that? http://developer.apple.com/mac/library/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple_ref/c/func/CGEventCreateMouseEvent – Taybin Mar 08 '10 at 16:36
  • Changing from CGEventCreate() to CGEventCreateMouseEvent() has fixed the firefox issue - whcih is odd, I'm setting the same parameters after all, but not the dashboard issue. – Thomi Mar 09 '10 at 15:12
  • ... no matter which function you use to create the event, you still need to post it with CGPostEvent()... – Thomi Mar 09 '10 at 15:12
  • 1
    The reason this worked is that CGEventCreate() sets the click state to 0 *always*, whereas CGEventCreateMouseEvent() sets it to 1 for mouse down and 0 for mouse up. So it fixed part of the problem. – Nick Moore Mar 10 '10 at 20:49
0

I have written how to do it in the blog post Python Mouse Click and Move Mouse on Apple Mac OS X Snow Leopard 10.6.x.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Quack
  • 9
  • 1