Command key shortcut not working.

786 views
Skip to first unread message

Christopher Herrmann

unread,
Jun 10, 2016, 7:12:29 PM6/10/16
to MIDI2LR

Did this issue ever get resolved? Having the same issue with command key based shortcuts. But I can get others like Shift to work properly...  

rsjaffe

unread,
Jun 10, 2016, 11:01:24 PM6/10/16
to mid...@googlegroups.com
No. It's still a problem.

 I need help on that issue. Someone with a mac is going to have to do a cycle of test/code/test to see how to get LR to accept the command key. For some reason, LR won't accept the command key input like the other keys. This is not a problem with windows, and I don't have a mac with LR.

Christopher Herrmann

unread,
Jun 10, 2016, 11:49:40 PM6/10/16
to MIDI2LR
I can help you out. Just let me know what you need. I have some experience in Xcode but i am by no means a programmer. 
On a side note I tried modifying the shortcut key i wanted (Command-U) to Shift-U but didn't work. Apparently Lightroom won't allow keyboard shortcut changes natively. Still digging around into other plugins... 

Christopher Herrmann

unread,
Jun 11, 2016, 2:53:20 PM6/11/16
to MIDI2LR
In the meantime I found a clever way to work around the issue. For me I wanted Auto Tone as a button (Command-U) but I realized there's also an Auto Tone Preset and so I just assigned that to Preset 1 then mapped to the button of choice. Works like a charm. 

rsjaffe

unread,
Jun 11, 2016, 7:20:03 PM6/11/16
to MIDI2LR
If you could help it'd be great. Lines 281-335 of SendKeys.cpp send the keystrokes to Lightroom. The actual key sending occurs from lines 318 to 328. You'll see that I have two if statements at the beginning and end of that block. Originally, the send key code didn't have the if statements, it was just lines 322-324: send key down with modifiers, wait 30 msec, send key up with modifiers. That works with other OS X applications, but for some reason LR doesn't recognize the command modifier when sent that way. I suspect LR is doing some special scanning for the command key, as it is used for non-key purposes (e.g., holding command down while adjusting sharpening). So I tried sending an extra "command down" in the first if statement and an extra "command up" in the second if statement to see if that would help. No effect. 

So now, someone has to experiment with the sequence and timing of events, doing it several different ways until LR responds correctly. For example, the delays could be lengthened. Or, the command flag could be omitted from the d and u CGEventRefs, to see if just having d and u without a command modifier bracketed by a command down and a command up gives the right signal. Also, if you could figure out the sequence of keyboard events emitted by OS X for something like Command-U could help enormously, as we could just emulate that and see if it works.

Since I don't have OS X LR, I can't do this sort of experimentation.

Many thanks.


  const CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
  CGEventRef d;
  CGEventRef u;

  uint64_t flags = 0;
  if (SendKeys::key_map_.count(lower_string)) {
    auto vk = SendKeys::key_map_.at(lower_string);
    d = CGEventCreateKeyboardEvent(source, vk, true);
    u = CGEventCreateKeyboardEvent(source, vk, false);
    if (control) flags |= kCGEventFlagMaskCommand;
    if (alt) flags |= kCGEventFlagMaskAlternate;
    if (shift) flags |= kCGEventFlagMaskShift;
    if (flags != UINT64_C(0)) {
      CGEventSetFlags(d, static_cast<CGEventFlags>(flags));
      CGEventSetFlags(u, static_cast<CGEventFlags>(flags));
    }
  }
  else {
    const std::wstring utf16str{utf8_to_utf16(key)};
    const UniChar key_character = utf16str[0];
    d = CGEventCreateKeyboardEvent(source, 0, true);
    u = CGEventCreateKeyboardEvent(source, 0, false);
    CGEventKeyboardSetUnicodeString(d, 1, &key_character);
    CGEventKeyboardSetUnicodeString(u, 1, &key_character);
    flags = CGEventGetFlags(d); //in case KeyCode has associated flag
    if (control) flags |= kCGEventFlagMaskCommand;
    if (alt) flags |= kCGEventFlagMaskAlternate;
    if (shift) flags |= kCGEventFlagMaskShift;
    if (flags != UINT64_C(0)) {
      CGEventSetFlags(d, static_cast<CGEventFlags>(flags));
      CGEventSetFlags(u, static_cast<CGEventFlags>(flags));
    }
  }
  CGEventRef cmdd = CGEventCreateKeyboardEvent(source, 0x37, true);
  CGEventRef cmdu = CGEventCreateKeyboardEvent(source, 0x37, false);
  {   //restrict scope for mutex lock
    std::lock_guard< decltype(mutex_sending_) > lock(mutex_sending_);
    if (flags & kCGEventFlagMaskCommand) {
      CGEventPost(kCGHIDEventTap, cmdd);
      std::this_thread::sleep_for(std::chrono::milliseconds(30));
    }
    CGEventPost(kCGHIDEventTap, d);
    std::this_thread::sleep_for(std::chrono::milliseconds(30));
    CGEventPost(kCGHIDEventTap, u);
    if (flags & kCGEventFlagMaskCommand) {
      std::this_thread::sleep_for(std::chrono::milliseconds(30));
      CGEventPost(kCGHIDEventTap, cmdu);
    }
  }

  CFRelease(d);
  CFRelease(u);
  CFRelease(cmdd);
  CFRelease(cmdu);
  CFRelease(source);



Christopher Herrmann

unread,
Jun 13, 2016, 10:06:24 PM6/13/16
to MIDI2LR
Thanks for the explanation. I'll see what I can do, hopefully have something figured out this weekend or next.

Christopher Herrmann

unread,
Jun 19, 2016, 11:19:17 PM6/19/16
to MIDI2LR
Just a heads up I've been trying different delays today (60, 90, 120, 900) and haven't seen any changes except one time at 900 there was an error or message sent to the logs but I couldn't get it to repeat... Just to confirm I should be copying the Xcode build into the plugin folder every time? Then I reload the plugin via Lightroom...

Do you know of an easy way to confirm the command key is being sent via Xcode debugger? 

Christopher Herrmann

unread,
Jun 19, 2016, 11:50:53 PM6/19/16
to MIDI2LR
I was able to get the error in Xcode again, it only shows up when I run from Xcode and the MIDI2LR window is in foreground. When Lightroom is in foreground (active) it doesn't give me the error...

2016-06-19 20:43:59.132 MIDI2LR[12819:12321419] Failed to get CharCodes from EventRef (-9870)

2016-06-19 20:43:59.135 MIDI2LR[12819:12321419] (

0   CoreFoundation                      0x00007fff8d18e4f2 __exceptionPreprocess + 178

1   libobjc.A.dylib                     0x00007fff89f9773c objc_exception_throw + 48

2   CoreFoundation                      0x00007fff8d1f54bd +[NSException raise:format:] + 205

3   AppKit                              0x00007fff8374a01f -[NSEvent _matchesKeyEquivalent:modifierMask:] + 315

4   AppKit                              0x00007fff83798545 -[NSWindow _cancelActionIfCmdDot:] + 35

5   AppKit                              0x00007fff837982df -[NSWindow _processKeyboardUIKey:] + 80

6   AppKit                              0x00007fff8368664c -[NSWindow _handleKeyDownEvent:] + 325

7   AppKit                              0x00007fff83cb0b15 -[NSWindow _reallySendEvent:isDelayedEvent:] + 2108

8   AppKit                              0x00007fff836ef539 -[NSWindow sendEvent:] + 517

9   AppKit                              0x00007fff8367016a -[NSApplication sendEvent:] + 4382

10  AppKit                              0x00007fff834d6df2 -[NSApplication run] + 796

11  MIDI2LR                             0x0000000100065cfc _ZN4juce19JUCEApplicationBase4mainEv + 188

12  MIDI2LR                             0x0000000100065c23 _ZN4juce19JUCEApplicationBase4mainEiPPKc + 83

13  libdyld.dylib                       0x00007fff882a55ad start + 1

14  ???                                 0x0000000000000003 0x0 + 3

)

rsjaffe

unread,
Jun 20, 2016, 1:35:54 PM6/20/16
to MIDI2LR
In Windows, MIDI2LR sends the keystrokes to LR. In OS X, MIDI2LR sends keystrokes to the foreground application, which is why you're seeing that error.

I'd have to add some code in Objective-C++ to the application to select the Lightroom application in OS X, and haven't learned enough about that language to try.

Christopher Herrmann

unread,
Jun 20, 2016, 11:35:40 PM6/20/16
to MIDI2LR
Ah that makes total sense now because one of my shortcuts is Shift L and when I tap that button on the MIDI controller in a text editor it actually types L. So as an experiment I tried setting a button to Command-R which is the shortcut Reply in Mail sadly it didn't work. However I have this other app called CheatSheet (https://www.mediaatelier.com/CheatSheet/) that when you hold down the command key long enough it brings up a window of shortcuts. When I set the time long enough in Xcode the MIDI button actually brings up this shortcut window.

Actually I just tapped the MIDI button while typing this message and it selected the underline format button (which is also command-u).
All this to say that I think it's sending the right signal unless the OS requires a special signal for Menu shortcuts, I'm still reading through OS X documentation... 

Sorry if none of this is new to you or useful, just wanted to share my findings. Feel free to delete so I don't clutter the thread. :)  

rsjaffe

unread,
Jun 21, 2016, 10:09:10 AM6/21/16
to MIDI2LR
Your experience mirrors mine, which helps confirm the problem. Lightroom somehow looks at keystrokes it receives differently from normal OS X applications, and MIDI2LR's key sending works with most OS X applications.

Now we need to figure out what LR is looking for when looking for a Cmd shortcut. 

And I think I have an idea. LR has probably tapped into the keyboard event stream higher up for monitoring Cmd key state.

Try the following. First, change the sleep times back to 30 milliseconds, then, line 281 has the code 
   
const CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);

change to
 const CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);

that will move the insertion point for keystroke events from MIDI2LR higher in the system. See if that successfully sends keystrokes to LR. 

If that doesn't work, change line 281 to:

  const CGEventSourceRef source = nullptr;

and try again. In short, I think we need to find the right event source to use for inserting events.

Christopher Herrmann

unread,
Jun 21, 2016, 9:00:40 PM6/21/16
to MIDI2LR
First change had no effect. Second one crashes MIDI2LR....

rsjaffe

unread,
Jun 21, 2016, 11:41:28 PM6/21/16
to mid...@googlegroups.com
Could you try

const CGEventSourceRef source = 0;

If that doesn't work, change CGEventSourceRef back to its original setting then try the following:


Search and replace:
kCGHIDEventTap replace with kCGAnnotatedSessionEventTap



If that doesn't work, replace kCGAnnotatedSessionEventTap with kCGSessionEventTap


And if that doesn't work, I'm going to have to think about this some more.

Christopher Herrmann

unread,
Jun 21, 2016, 11:53:09 PM6/21/16
to MIDI2LR
sure nothing changed, but no crash this time. 


On Tuesday, June 21, 2016 at 8:41:28 PM UTC-7, rsjaffe wrote:
Could you try

const CGEventSourceRef source = 0;



On Tuesday, June 21, 2016 at 6:00:40 PM UTC-7, Christopher Herrmann wrote:
First change had no effect. Second one crashes MIDI2LR....

Christopher Herrmann

unread,
Jun 22, 2016, 12:03:51 AM6/22/16
to MIDI2LR

Not sure if it helps but I built this sample app that is a button that successfully sends a command-m (minimize). The only thing i see different is the block 45-49 but that might have to do with the button or because it's obj-c... I copied a lot of the code from this page: http://stackoverflow.com/questions/10734349/simulate-keypress-for-system-wide-hotkeys

rsjaffe

unread,
Jun 22, 2016, 10:19:58 AM6/22/16
to MIDI2LR
Can you use that sample app to send a command to Lightroom emulating one of the shortcut keys? The code segment you show is exactly how I send the codes, with two small differences: 

  1. the virtual key code you're using for Command (0x38) is different from what I used (0x37)
  2. the source is kCGEventSourceStateHIDSystemState instead of kCGEventSourceStateCombinedSessionState.

I've pulled Events.h to find the definitions--there command is 0x37 (see http://stackoverflow.com/questions/3202629/where-can-i-find-a-list-of-mac-virtual-key-codes), but, maybe it is wrong!

Are you using an English keyboard? If so, try anoother idea--rip out everything in Sendkeys::SendKeyDownUp , and replace it with the code you have in your app. Change the virtual key code to one that sends a command to lightroom, such as 0 (which is a on an ansi keyboard). Assign that to a keyboard shortcut--what you set up in the MIDI2LR app is irrelevant, it'll always send command-a (select all). That way we simplify what we're debugging.

Christopher Herrmann

unread,
Jun 22, 2016, 8:17:10 PM6/22/16
to MIDI2LR
I'll give it a shot. I did see that difference between 0x37 & 0x38 but actually just tried & they both work in my mini test app... strange.
Yes, english keyboard. 

Christopher Herrmann

unread,
Jun 22, 2016, 8:31:29 PM6/22/16
to MIDI2LR
I tried your second idea first and it worked! MIDI2LR successfully sent a Command-A.

rsjaffe

unread,
Jun 22, 2016, 10:41:40 PM6/22/16
to MIDI2LR
Did it send Command-a to Lightroom successfully? Could you do two things:
1. copy and paste the code you're successfully using in a reply here.
2. try removing the cmmd and cmmu events, and see if Lightroom still responds.

Great progress!
Message has been deleted

Christopher Herrmann

unread,
Jun 23, 2016, 5:40:32 PM6/23/16
to MIDI2LR

When I comment out the cmdd and cmdu events Lightroom fails to respond. Uncommented though works as planned. 


here is the function, NOTE Sendkeys.cpp still has existing code above line 172 that I didn't touch.


void SendKeys::SendKeyDownUp(const std::string& key, bool alt, bool control, bool shift) const {

  

    CGEventSourceRef src =

    CGEventSourceCreate(kCGEventSourceStateHIDSystemState);

    

    //CGEventRef cmdd = CGEventCreateKeyboardEvent(src, 0x37, true);

    //CGEventRef cmdu = CGEventCreateKeyboardEvent(src, 0x37, false);

    CGEventRef akeyd = CGEventCreateKeyboardEvent(src, (CGKeyCode) 0, true);

    CGEventRef akeyu = CGEventCreateKeyboardEvent(src, (CGKeyCode) 0, false);

    

    CGEventSetFlags(akeyd, kCGEventFlagMaskCommand);

    CGEventSetFlags(akeyu, kCGEventFlagMaskCommand);

    

    CGEventTapLocation loc = kCGHIDEventTap; // kCGSessionEventTap also works

    //CGEventPost(loc, cmdd);

    CGEventPost(loc, akeyd);

    CGEventPost(loc, akeyu);

    //CGEventPost(loc, cmdu);

    

    //CFRelease(cmdd);

    //CFRelease(cmdu);

    CFRelease(akeyd);

    CFRelease(akeyu);

    CFRelease(src);

rsjaffe

unread,
Jun 25, 2016, 1:12:06 AM6/25/16
to mid...@googlegroups.com
Great! I'll work on getting this into the next release. Two things I'd like you to try:
1. does it work with 0x38 instead of 0x37? I suspect the documentation I was using regarding 0x38 being Command VK was wrong.
2. can you try the following code? First, check the BundleID for your version of Lightroom. One way is to run the following from the command line:
osascript -e 'id of app "Lightroom"'
then substitute it for "com.adobe.Lightroom6" (twice) in the following code, and use it for the sendkey app. Tell XCode to compile SendKeys.cpp as Objective-C++. If this works, you should be able to send the command-a to Lightroom even when it is not in the foreground. Also, please tell me what the bundleid was for your lightroom and which version (CC or 6) you're using. Thanks.
    CGEventSourceRef src = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
    CGEventRef cmdd = CGEventCreateKeyboardEvent(src, 0x37, true);
    CGEventRef cmdu = CGEventCreateKeyboardEvent(src, 0x37, false);
    CGEventRef akeyd = CGEventCreateKeyboardEvent(src, (CGKeyCode) 0, true);
    CGEventRef akeyu = CGEventCreateKeyboardEvent(src, (CGKeyCode) 0, false);

    CGEventSetFlags(akeyd, kCGEventFlagMaskCommand);
    CGEventSetFlags(akeyu, kCGEventFlagMaskCommand);

    CGEventTapLocation loc = kCGHIDEventTap; // kCGSessionEventTap also works
    
    OSStatus err{1};
    ProcessSerialNumber psn;
if ([[NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.adobe.Lightroom6"] count])
    {
        // get pid
        pid_t pid = [(NSRunningApplication*)[[NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.adobe.Lightroom6"] objectAtIndex:0] processIdentifier];


        // get PSN
        err = GetProcessForPID(pid, &psn);
}
if (err == noErr) {
    CGEventPostToPSN(&psn, cmdd);
    CGEventPostToPSN(&psn, akeyd);
    CGEventPostToPSN(&psn, akeyu);
    CGEventPostToPSN(&psn, cmdu);
}
else
{
    CGEventPost(loc, cmdd);
    CGEventPost(loc, akeyd);
    CGEventPost(loc, akeyu);
    CGEventPost(loc, cmdu);
}
    

    CFRelease(cmdd);
    CFRelease(cmdu);
    CFRelease(akeyd);
    CFRelease(akeyu);
    CFRelease(src);


Christopher Herrmann

unread,
Jun 27, 2016, 9:33:02 PM6/27/16
to MIDI2LR
Can do. Should I keep using the same SendKeys file or should I download & use the latest release (1.2.0.0) in my test? 

Rory Jaffe

unread,
Jun 27, 2016, 11:35:47 PM6/27/16
to MIDI2LR
probably best to use the latest release. Also, I'm getting reports that it isn't working for some others, so I'll look real carefully at the code you end up successfully testing to make sure I'm replicating it properly. thanks.

Christopher Herrmann

unread,
Jun 29, 2016, 1:50:43 AM6/29/16
to MIDI2LR
I had to go back to previous version: 1.2.0.0 wasn't connecting properly with Lightroom the dials/knobs would always jump to the left and increment one fraction at a time. I also recently updated LR too so not sure if that's causing trouble. 

Anyway I added the code above but got some errors and is there anything else I need to do to tell Xcode to compile Obj-C++ other than changing file type on the right? Attached screenshot. 

I couldn't get 0x38 to work.
My Lightroom is com.adobe.Lightroom6 — 

Adobe recently updated to version: CC 2015.6 [ 1078672 ]


Christopher Herrmann

unread,
Jul 25, 2016, 8:57:52 PM7/25/16
to MIDI2LR
Hey I'm still around too if you need more test done just let me know. Otherwise I've just been using the preset for auto-tone vs the command key....

Rory Jaffe

unread,
Jul 27, 2016, 9:22:40 AM7/27/16
to mid...@googlegroups.com
Could you do the following with version 1.4?
In SendKeys.cpp, change

CGEventPost(loc, cmdd);
CGEventPost(loc, d);
CGEventPost(loc, u);
CGEventPost(loc, cmdu);



to 

CGPostKeyboardEvent( (CGCharCode)0, (CGKeyCode)55, true );
CGEventPost(loc, d);
CGEventPost(loc, u);
CGPostKeyboardEvent( (CGCharCode)0, (CGKeyCode)55, false );

See if those changes make it work.

A second thing to try (and please try this even if the first one works, because the code above uses a deprecated function):

use the original 
CGEventPost(loc, cmdd);
CGEventPost(loc, d);
CGEventPost(loc, u);
CGEventPost(loc, cmdu);



and change:


CGEventRef cmdd = CGEventCreateKeyboardEvent(source, kVK_Command, true);
CGEventRef cmdu = CGEventCreateKeyboardEvent(source, kVK_Command, false);


to

CGEventRef cmdd = CGEventCreateKeyboardEvent(nullptr, kVK_Command, true);
CGEventRef cmdu = CGEventCreateKeyboardEvent(nullptr, kVK_Command, false);


Christopher Herrmann

unread,
Jul 29, 2016, 2:04:02 PM7/29/16
to MIDI2LR
I couldn't get either to work. Received this popup when I tried using Command-U set to a button/key. Dials and other keys like Shift-L work as expected when assigned to a button. Actually got the same pop up error when I went back to the 1.4 build from GitHub. In previous versions it just beeped at me or did nothing at all. 

Christopher Herrmann

unread,
Jul 29, 2016, 2:06:22 PM7/29/16
to MIDI2LR
I have a separate machine that I can try again over the weekend just to confirm. Just remembered The one that I tested with above is running beta macOS Sierra
Reply all
Reply to author
Forward
0 new messages