Keyboard Focus

Hi, I have the following problem:


I have a Viewport component, which contains some content component containing varying number of my custom components that can grab focus (setWantsKeyboardFocus(true)). Now there are 2 major problems:


1) I would expect the keyPressed() method to be called for the focused component. What really happens is that it is called for all the components in the reverse order in which they had been added. It is called by this method:


bool ComponentPeer::handleKeyPress (const int keyCode, const juce_wchar textCharacter)


As I understand it, first it should be the focused component to be tried whether it can process the keypress. Now I need to manually check in the keyPressed() method, whether it is the focused one or return false so that all the other components could be checked.

When there was no viewport (there was no need to scroll) it worked just fine I think. What is the problem? Is it somehow related to the Viewport component?


2) When the viewed component gets large enough (so that the scrollbar appears), the cursor keys get cought by the viewport and are not sent to the components. They are used to scroll the view. I dont want that. I have set the viewport not to grab the focus (viewport->setWantsKeyboardFocus(false)) but that does'nt help. What am I missing? Thanks.


Huh? The key event definitely gets offered to the focused component first. Presumably the component that you think has the focus doesn't really have it.

That is what I thought, but: In draw(Graphics) method , I render the focused component (determined by hasKeyboardFocus() - hope that this is correct) with diferrent color so I can see which component has focus (supposing the focus is not changed by the very same keystroke I want to capture, but this should not be the case as I want to capture the cursor keys). Second, if this is the case, how come, that I can solve the problem like this:


bool TrackComponent::keyPressed(const KeyPress &key, Component *originatingComponent){
    if (!hasKeyboardFocus(false))
        return false;
    if (key.getKeyCode() == KeyPress::upKey){   


I mean, if the component I think has the focus did not have the focus, why would hasKeyboardFocus() return true for the component that I think has the focus (sounds awkward, when I put it like this, but I think You see the point).


And how would You solve the second problem I have? I think these two are related. Maybe if I solve the second problem I will also progress on the first one.

Does the fact that the component is in the viewport somehow affect the focus? And how would I prevent the viewport form capturing the cursor keys?

No, there's nothing special about it. And the best way to stop the keys is either to have a subcomponent catch them and not pass them on, or maybe use its setWantsKeyboardFocus method.

By "its setWantsKeyboardFocus" you mean the viewport, or the "subcomponent"? Because I did set the setWantsKeyboardFocus(false) for the Viewport and it didn't help (see the second point in the first post).


//edit: I tried to set false for the viewedComponent as well and this doesn't help either. Well, there's nothing strange about that, because there's no reason for it to be true in the first place. It's just Component instance...

When i put a breakpoint in Viewport::keyPressed() and press any key, I still end up hitting the breakpoint even though I set viewport->setWantsKeyboardFocus(false). The stack looks like this:


>    exampleJUCE.exe!juce::Viewport::keyPressed(const juce::KeyPress & key) Line 424    C++
     exampleJUCE.exe!juce::ComponentPeer::handleKeyPress(int keyCode, unsigned int textCharacter) Line 206    C++
     exampleJUCE.exe!juce::HWNDComponentPeer::doKeyChar(int key, const long flags) Line 2052    C++
     exampleJUCE.exe!juce::HWNDComponentPeer::peerWindowProc(HWND__ * h, unsigned int message, unsigned int wParam, long lParam) Line 2392    C++
     exampleJUCE.exe!juce::HWNDComponentPeer::windowProc(HWND__ * h, unsigned int message, unsigned int wParam, long lParam) Line 2256    C++


I can't really see how would wantKeyboardFocus affect this behaviour but I can see, the keyPressed method is called from ComponentPeer::handleKeyPress and it is this line:


keyWasUsed = target->keyPressed (keyInfo);

Well there's this cycle prior to the line above:

for (int i = keyListeners->size(); --i >= 0;)

And I can see that keyListeners are empty and therefore it is not called for anything else. I also do not see any if (wantsKeyboardFocus) ... there. What I also don't understand is the way how the focused component recieves the event before anything else... There should be some pointer indicating the focused component, right? Where is it called from?



OK, I think have the first problem solved. I mixed two things together. I misunderstood the way key presses works for components. My custom component inherited keyListener, which was completly unnecessary as Components already have their way of catching the key presses and overloaded the keyPress method that takes 2 arguments and not the one that takes just the keyCode. The result was of course the other method being called. It worked without viewport because the parrent component forwarded the keyPresses now it would not work for the focusedComponent... And that solves the second problem as well because if the event is processed by the focused component, it does not continue to the others (including the Viewport).


Thanks for being unwavering, it forced me to try harder :-D