开发者

Strange behaviour when posting CGEvent to PSN

EDIT - not getting much input on this so here's the skinny. I'm posting keyboard events to a PSN. I then switch to another window, post some more events (this time tat session level) and switch back to the first window. When I start posting to the PSN again, nothing happens. Until I move the mouse or scroll wheel. Why would this be the case and how can I work around it (if not fix it)?

ORIGINAL - If I set up a loop that posts some keyboard events to a PSN, I find that it works fine except for when first launched. Th开发者_如何学Pythone event only seems to post when i do something with the mouse manually - even just moving it slightly. Here's the details, if they help.

An external application has a list box of text lines, which I am reading by posting copy commands (and checking the pasteboard). Unfortunately this is my only way to get this text.

Sometimes, the application pulls focus away from the list, which I can detect. When this happens, the most reliable way to return focus is by sending a mouse event to click on a text field directly above the list, then send a 'tab' keyboard event to shift the focus onto the list.

So at launch, the loop runs fine, scrolling down the list and copying the text. When focus is shifted away, its is detected fine, and the events are sent to move focus back to the list. But nothing seems to happen. The loop continues detecting that focus has changed, but the events only work once I move the mouse. Or even just use the scroll wheel. Strange.

Once this has happened the first time, it works fine - each time focus moves, the PSN events switch it back without me having to do anything at all.

Here's the code that runs in the loop - verified as working:

    //copy to pasteboard - CMD-V
e3 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)8, true);
CGEventSetFlags(e3, kCGEventFlagMaskCommand);
CGEventPostToPSN(&psn, e3);
CFRelease(e3);
e4 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)8, false);
CGEventPostToPSN(&psn, e4);
CFRelease(e4);

//move cursor down
e1 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)125, true);
CGEventPostToPSN(&psn, e1);
CFRelease(e1);
e2 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)125, false);
CGEventPostToPSN(&psn, e2);
CFRelease(e2);

And here's where I switch focus, also working (except when first required):

    //click in text input box - point is derived earlier
e6 = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, point, 0);
CGEventPostToPSN(&psn, e6);
CFRelease(e6);
e7 = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseUp, point, 0);
CGEventPostToPSN(&psn, e7);
CFRelease(e7);

//press tab key to move to chat log table
CGEventRef e = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)48, true);
//CGEventPost(kCGSessionEventTap, e);
CGEventPostToPSN(&psn, e);
CFRelease(e);
CGEventRef e11 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)48, false);
CGEventPostToPSN(&psn, e11);
CFRelease(e11); 


Hey, i know it's not what you want to hear but applescript works much better for this kind of thing - reading textfields by posting copy commands, setting focused by sending click events to nearby items then sending tab events - it really isn't the best way to do it.

The problem with simulating events is that generating them isn't the whole story. They only become 'Events' if the target app interprets them correctly. Do you know if the target app is even a cocoa app?

For example, in your second bit of code you create 4 events. The target app needs to run it's event processing loop, which you don't have much control over, and check for queued events. If it did this it would find a simultaneous mouse down, mouse up, key down, key up. You want it to interpret these simultaenious events as a mouse click and THEN a keypress.. but who is to say it will?

You may be able to get this to work by adding into the mix a combination of flushing event queues, getting the target app to run it's runloop, throw in some pauses between the simulated events, and fiddling with event timestamps - but it probably won't be that reliable.

In Applescript you could get the text of row 3 of a table in another app by

tell application "System Events"
  tell process targetAppName
    set frontmost to true
    tell window named windowTitle
      tell table 1
        set value of attribute "AXFocused" to true
        set txtField to first text field of row 3
        return value of txtField
      end tell
    end tell
  end tell
end tell

From a cocoa App you can execute a String as an Applescript, you can call functions in different scripts, pass variables, return values, etc.


Instead of creating the event with a null CGEventSourceRef try creating an input source this way:

CGEventSourceRef eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);

Based on this mailing list message, this seems to be the secret for success in posting events with CGEventCreateXXXEvent. A Google search shows that lots of devs are having problems with this, but this is the one success post I've found, and a proper CGEventSourceRef (instead of NULL) seems to be the one difference in this example vs. all the others I've found. It solved my problems with posting keyboard events.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜