Home > cocoa, PandoraBoy > PandoraBoy 0.8.2 – Fixes Flash

PandoraBoy 0.8.2 – Fixes Flash

For those of you having trouble with Flash 10.1, I’ve fixed PB to handle it. This moves from the hackish “dig around in the NetscapePlugin objects and call undocumented methods” approach to a standard CGEvent based keyboard injection. You can’t use NSApp’s sendEvent: to talk to Flash (probably because Flash is not in Cocoa). But the following code is a good general purpose “send me a virtual keystroke.”

- (void)sendKeyPress:(int)keycode withModifier:(int)modifier
{
    ProcessSerialNumber psn;
    GetCurrentProcess(&psn);
    CGEventRef modifierEvent;
    if (modifier != 0)
    {
        modifierEvent = CGEventCreateKeyboardEvent(NULL, modifier, YES);
        CGEventPostToPSN(&psn, modifierEvent);
    }

    CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, keycode, YES);
    CGEventPostToPSN(&psn, keyEvent);
    CGEventSetType(keyEvent, kCGEventKeyUp);
    CGEventPostToPSN(&psn, keyEvent);
    CFRelease(keyEvent);

    if (modifier != 0)
    {
        CGEventSetType(modifierEvent, kCGEventKeyUp);
        CGEventPostToPSN(&psn, modifierEvent);
        CFRelease(modifierEvent);
    }
}

First note the use of CGEventPostToPSN(). I originally made the mistake of using CGEventPost(). The problem is that this will send the keystroke to the currently active application, not PandoraBoy. For keyboard shortcuts and applescript where PB will certainly be in the background, CGEventPostToPSN() is a must here.

Note that this uses virtual keycodes. That’s fine for PB, since (for now) we only send things that are universal (like spacebar). But it will be a problem when I implement sending “z” to snooze a song. The problem is that “z” means “the location of ‘z’ on an ANSI keyboard.” If you have a different keyboard layout, it’s still going to act like you pressed that lower left-hand key beside the shift, not “z”. If people have trouble with this, I’ll look into UCKeyboardLayout, but it was too much for tonight, and I don’t need it myself.

The modifiers are tricky because if you want to send “Z” that really means “shift down, z down, z up, shift up.” This method takes care of all that for you. You would send “Z” like this:

[self sendKeyPress:kVK_ANSI_Z withModifier:kVK_Shift];
Categories: cocoa, PandoraBoy Tags:
  1. Alex Wayne
    July 21st, 2010 at 13:02 | #1

    You are my hero. The broken keyboard hotkeys were driving me crazy. THank you so much for your work on this app!

  2. August 17th, 2010 at 13:49 | #2

    I seem to recall trying this approach, and if I remember correctly it doesn’t work if the window is hidden or minimized. Is that right? I’ll have to try it again and see—big headsmack if I’m wrong.

    In case I’m not: I just posted the code I’m using in Musicality over on StackOverflow…it calls right into the plugin directly (as it sounds like you were doing before), and works even with hidden windows.

    http://stackoverflow.com/questions/2128235/how-do-i-send-key-events-to-a-flash-movie-in-webkit

    For the life of me I can’t seem to make it accept modifier keys though (Command in particular, needed to advance the song on Grooveshark).

  3. August 17th, 2010 at 14:15 | #3

    Interesting. This is extremely similar to the old technique that PB used (and that didn’t work if the window was minimized, but did if it was hidden). I was using Carbon events rather than CGEvents as I recall, but the rest looks the same. Let me compare this code to my old code and see if I can find something even better.

  4. August 17th, 2010 at 16:33 | #4

    I think I got pointed to sendEvent: by the response to a question you asked somewhere, perhaps on the cocoa-dev mailing list? Saved my butt too—the initial (WebHostedNetscapePluginView) clause is the one that works on my machine; I was baffled when my testers told me it didn’t work on theirs.

  1. No trackbacks yet.