ApplicationCommandManager & command targets

I’m puzzled with the behavior of the CommandManager and looking for the appropriate command target in this case:

  • Application has a main window, and two separate modeless windows that can be created with commands. The commands that open these other windows are handled in the Application object, which is an ApplicationCommandTarget. When the application window has focus, those commands are dispatched as expected.

  • If either of the other windows have the focus, the key commands to open the other window are never dispatched.

Looking at the docs for the ApplicationCommandManager, we see this:

When a command is invoked, the ApplicationCommandManager will try to choose the best ApplicationCommandTarget to receive the specified command. To do this it will use the current keyboard focus to see which component might be interested, and will search the component hierarchy for those that also implement the ApplicationCommandTarget interface. If an ApplicationCommandTarget isn’t interested in the command that is being invoked, then the next one in line will be tried (see the ApplicationCommandTarget::getNextCommandTarget() method), and so on until ApplicationCommandTarget::getNextCommandTarget() returns nullptr. At this point if the command still hasn’t been performed, it will be passed to the current JUCEApplication object (which is itself an ApplicationCommandTarget).

I’m not clear why the commands, when issued while the subsidiary windows have the focus, don’t end up being routed to the JUCEApplication object as a handler of last resort.

Am I missing something obvious here?

(answering my own question after some time in the debugger).

It looks like the main disconnect for me was here:

If you want key-presses to trigger your commands, use the ApplicationCommandManager::getKeyMappings() method to access the key-mapper object, which you will need to register as a key-listener in whatever top-level component you’re using.

JUCE has a different concept of “top-level” than I have in the mental model of my application – those modeless windows are each instances of DocumentWindow, which means that they have a PeerComponent that makes them “top level” from that point-of-view.

Adding a key listener to the CommandManager’s Key Mappings in my classes that derive from DocumentWindow was enough to get those windows connected to that bit of infrastructure.