Command manager does not react to default keypresses

Hi all! After a long absence I started playing around with JUCE again, and now I’m posting again on this forum… but this time as a clueless JUCE user, not as a juce developer :slight_smile:

I have an app (macOS) with some commands like Open, Save, and so on. I added a command manager and some command IDs and all that boilerplate, and I also added some default keypresses like this:

void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result) override
    {
        switch (commandID)
        {
            case CommandIDs::open:
                result.setInfo ("Open...", "Opens an existing document", CommandCategories::application, 0);
                result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0));
                break;
                // ...

Unfortunately however, the keypresses do not work. The option does show ⌘O next to it, and the main app menu flashes blue if I hit the key combination, but the action is not performed. It is only performed if I select “Open” with the mouse.

After an hour of digging and failing to understand why it doesn’t work, I thought it might be faster to post the question here. What did I miss?

Thanks,
Timur

Have you added CommandID::open to the array of commands in getAllCommands()? And have you added an action for the open command in your implementation of ApplicationCommandTarget::perform()?

It might be worth looking at KeyMappingsDemo.h in JUCE/examples/GUI as it’s a stripped-down example of getting some key mappings working.

Thanks much, Ed! Turns out I forgot this one line of code in my top-level component:

addKeyListener (commandManager.getKeyMappings());

Everything works now :slight_smile:

2 Likes

New problem: It only works as long as the command target is the application class itself.

I now introduced an additional command target, which is one of my subcomponents. I repeated all the boilerplate in there (inherit from ApplicationCommandTarget, call registerAllCommandsForTarget(this) in the constructor, and override getAllCommands/getCommandInfo/perform. Unfortunately, this time it did not work. The commands in question appear in the app menu, but they are greyed out. I cannot work out why. It seems like the CommandManager somehow cannot find the target for those commands, but it’s weird because the component in question does all the required things afaik…

I have compared it with the way Projucer is set up (both the App and several subcomponents are command targets there, too) and I cannot find any difference…

I must have overlooked something :frowning:

After another hour of digging, it turned out that it works if the MainWindow that owns the component in question is itself also an ApplicationCommandTarget, and if the component in question has focus.

At least the second part makes sense.

Hey @timur,

did you ever find a proper solution. I’m facing exactly the same problem.

Johannes

Hi @johannesk,

No, I didn’t, sorry.

Ok, wow, I think I just found it. That took some time.

class MyWindowComponent : public Component, public ApplicationCommandTarget
{
...
}

ApplicationCommandTarget needs to inherit publicly, otherwise and internal JUCE dynamic_cast in ApplicationCommandManager::findTargetForComponent fails to recognize it.

2 Likes