Setting the keyboard focus initially

Hello. I begin plugin development with JUCE and at the moment I encounter a minor annoyance which I’m unable to solve. It occurs on Linux which is my current development OS.

I want a component to have the keyboard focus immediately when I start the editor, but it does not happen despite that the said component has WantsKeyboardFocus. grabKeyBoardFocus() has no effect.

I have experimented to understand what happens, and I have discovered some details.
In the early lifetime of the editor, grabKeyboardFocus() does nothing, ie. the currently focused component remains null. This is observable in the editor’s ctor, and also after the superclass’s method addToDesktop().
However, i observed grabKeyboardFocus() becomes usable sometime after the first call to paint(), neither before nor during that call.

void MyAudioProcessorEditor::paint(juce::Graphics &g) {
  if (!P->focus_initialized) {
    juce::Component *tofocus = P->uikb;
    tofocus->grabKeyboardFocus();
    if (tofocus == juce::Component::getCurrentlyFocusedComponent())
      P->focus_initialized = true;
  }
  g.fillAll(juce::Colours::white);
}

The code above is awful but is able to work around my problem.
Does this problem have an appropriate solution?

Well, until a component and all its parents are actually visible inside a window which itself can take focus, then nothing can happen. Even after addToDesktop call, then OS may not immediately allow the window to grab focus so that could be the problem.

A better way to do this kind of thing is to set up the focus order and other component focus flags so that the component you want will be the one that gets focus by default when the window actually appears.

Or perhaps a neater way to do the hack above would be to start a timer for a few milliseconds, and then in the callback, check your component’s isShowing() method - when it becomes true, you can stop the timer and grab focus

1 Like

A better way to do this kind of thing is to set up the focus order and other component focus flags so that the component you want will be the one that gets focus by default when the window actually appears.

When the window is shown, no component seems to take the keyboard focus, whether or not I give explicit z-order and the component requests the keyboard focus.
A timer based solution works however and I will keep using that. Thanks :+1:

  this->setEnabled(false);
  FunctionalTimer *timer = new FunctionalTimer;
  timer->setCallback([this, timer]() {
      if (this->isShowing()) {
        this->setEnabled(true);
        this->grabKeyboardFocus();
        delete timer;
      }
    });
 timer->startTimer(100);
1 Like

Could you elaborate on “set up the focus order and other component focus flags” ? When I launch my app, default focus component is of class StandaloneFilterWindow and has the name “vmpc” (name of my app). How can I make a given component receive focus instead, also after:

  1. Changing audio settings, switching to another application’s window, etc. in standalone mode
  2. Closing and opening the editor window when in plugin mode

I have just 1 component that I’d like to always receive all keyboard input (including keymodifier changes) whenever the JUCE’s app/plugin has focus. Or is there a way to relay it from StandaloneFilterWindow (and its plugin counterparts) ?

In standalone mode (haven’t tried it as a plugin yet), I can get my component to grab the focus by making MainComponent inherit from Timer, starting the timer during the constructor, using the timer callback to check to see if my desired child component is visible, and invoking grabFocus if it is visible.

Here’s an example:

MainComponent::MainComponent()
{    	
	addAndMakeVisible(&tabbedComponent);
	startTimer(3);
}

void MainComponent::timerCallback()
{
	if (tabbedComponent.isShowing() == true)
	{
		stopTimer();
		tabbedComponent.grabKeyboardFocus();
	}
}
2 Likes