1

I am trying to automate a left mouse click in iTunes from Objective-C. I am doing the following.

  1. first I am listening to iTunes events

    [[NSDistributedNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(allDistributedNotifications:)
                                                     name:nil
                                                     object:nil];
    
  2. when the allDistributedNotifications is called I do the following:

    - (void) allDistributedNotifications:(NSNotification *)note {
        NSString *object = [note object];
        NSString *name = [note name];
        NSDictionary *userInfo = [note userInfo];
        NSLog(@"object: %@ name: %@ userInfo: %@",object, name, userInfo);
    
        if([object isEqualToString:@"com.apple.iTunes.dialog"]&& [userInfo objectForKey:@"Showing Dialog"] == 0){
            NSLog(@"*** ended iTunes Dialogue");
        }
    
        if([name isEqualToString:@"com.apple.iTunes.sourceSaved"]){
            NSLog(@"*** iTunes saved to file");
            currentURLIndex +=1;
            [self loadWithData:[itmsURLs objectAtIndex:currentURLIndex] fromBot:YES];
        }
    }
    
  3. LoadWithData looks like this

    -(void) loadWithData:(NSURL*) url fromBot:(BOOL)aBot
    {
        BOOL success;
    
        success = [[NSWorkspace sharedWorkspace] openURLs:[NSArray arrayWithObject:url]
                  withAppBundleIdentifier:@"com.apple.itunes"
                  options:NSWorkspaceLaunchDefault
                  additionalEventParamDescriptor:nil
                  launchIdentifiers:nil];
        if(success){
            [numAppsDownloaded setStringValue:[NSString stringWithFormat:   @"%lu",currentURLIndex+1]];
        }
        if(success && aBot){
            [self performSelector:@selector(clickDownload) withObject:nil afterDelay:0.5];
        }
     }
    
  4. clickdownload in turn looks like this

    -(void) clickDownload
    {
        NSPoint mouseLoc;
    
        mouseLoc                = [NSEvent mouseLocation]; //get current mouse position
        CGPoint point           = CGPointMake(mouseLoc.x, mouseLoc.y);
    
        CGEventRef theEvent;
        CGEventType type;
    
        CGMouseButton button    = kCGMouseButtonLeft;
    
        type                    = kCGEventLeftMouseDown; // kCGEventLeftMouseDown = NX_LMOUSEDOWN,
        theEvent                = CGEventCreateMouseEvent(NULL,type, point, button);
    
        NSEvent* downEvent      = [NSEvent eventWithCGEvent:theEvent];
        [self forwardEvent:downEvent];
    
        [NSThread sleepForTimeInterval:0.2];
    
        type                    = kCGEventLeftMouseUp;
        theEvent                = CGEventCreateMouseEvent(NULL,type, point, button);
        NSEvent* upEvent        = [NSEvent eventWithCGEvent:theEvent];
        [self forwardEvent:upEvent];
    }
    

    5.Finally, forwardEvent looks like this

    - (void)forwardEvent: (NSEvent *)event
    {
        NSLog(@"event: %@",event);
    
        pid_t PID;
        NSInteger WID;
    
        // get the iTunes Window ID
    
        NSArray* windows    =  (NSArray*)CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);
    
        NSEnumerator* windowEnumerator = [windows objectEnumerator];
    
        while( (window = [windowEnumerator nextObject] ) )
        {
            if([[(NSDictionary*) window objectForKey:@"kCGWindowName"]  isEqualToString:@"iTunes"])
                WID = (NSInteger)[(NSDictionary*) window objectForKey:@"kCGWindowNumber"];
        }
    
        ProcessSerialNumber psn;
        CGEventRef CGEvent;
        NSEvent *customEvent;
    
        NSPoint mouseLoc        = [NSEvent mouseLocation]; //get current mouse position
        NSPoint clickpoint      = CGPointMake(mouseLoc.x, mouseLoc.y);
    
        customEvent = [NSEvent mouseEventWithType: [event type]
                                   location: clickpoint
                              modifierFlags: [event modifierFlags] | NSCommandKeyMask
                                  timestamp: [event timestamp]
                               windowNumber: WID
                                    context: nil
                                eventNumber: 0
                                 clickCount: 1
                                   pressure: 0];
    
        CGEvent = [customEvent CGEvent];
    
        // get the iTunes PID
    
        NSRunningApplication* app;
    
        NSArray* runningApps = [[NSWorkspace sharedWorkspace] runningApplications];
    
        NSEnumerator* appEnumerator = [runningApps objectEnumerator];
    
        while ((app = [appEnumerator nextObject]))
        {
            if ([[app bundleIdentifier] isEqualToString:@"com.apple.iTunes"])
    
                PID = [app processIdentifier];
        }
        NSLog(@"found iTunes: %d %@",(int)PID,WID);
    
        NSAssert(GetProcessForPID(PID, &psn) == noErr, @"GetProcessForPID failed!");
    
        CGEventPostToPSN(&psn, CGEvent);
    }
    

The problem is that I cannot see the mouse click being performed.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Peyman
  • 1,058
  • 1
  • 14
  • 27
  • 2
    Why are you signing up for all distributed notifications? There are many that have nothing to do with iTunes; your code will be much simpler and your application will run more efficiently if you sign up for the specific iTunes notifications you're interested in by name. Second, your forwardEvent: method appears to ignore the event passed into it, instead creating a new one. Third, you're assuming that the mouse cursor is within the iTunes window, which may be unlikely. – Peter Hosey Jun 26 '11 at 06:04
  • 2
    What's up with the title of this question? – Chris Frederick Jul 14 '11 at 22:58

1 Answers1

0

You are sending left mouse button events with NSCommandKeyMask. For right click equivalent (i.e. control-click) you would want to use NSControlKeyMask. Alternatively you could just use right mouse button events without a modifier mask.

Nick Moore
  • 15,547
  • 6
  • 61
  • 83
  • Hi Nick. I am sending left down and up events ([self forwardEvent:NSLeftMouseDown];[NSThread sleepForTimeInterval:0.2];[self forwardEvent:NSLeftMouseUp];) Am I doing something wrong here? I had tried setting modifierFlags to 0 but it didn't work. – Peyman Jun 29 '11 at 03:08
  • There are two ways to "right click": (1) press right mouse button, or (2) press left mouse button while holding the **control (⌃)** key. Your code does neither of these, you are pressing the left button while holding the **command (⌘)** key. – Nick Moore Jul 04 '11 at 07:33
  • NSCommandKeyMask was wrong. agreed. but i am not trying to right click. I am trying to left click down and then up on a button in itunes. i want to simulate a left button click. thanks Nick – Peyman Jul 05 '11 at 04:52
  • OK, but your opening sentence is "I am trying to automate a right mouse click" – Nick Moore Jul 06 '11 at 12:17
  • oh my bad. Sorry. any suggestions why the code is not working? – Peyman Jul 06 '11 at 20:00