keyboard event not being caught

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
zapcity
Earned a small fee
Earned a small fee
Posts: 17
Joined: Thu Oct 22, 2020 12:42 pm

keyboard event not being caught

Post by zapcity » Wed Aug 04, 2021 6:24 am

Hi, I'm having a few problems understanding why some keyboard events are not being triggered in my code. My original project uses a wxGLCanvas within a wxFrame, but I noticed that keyboard events are also not being caught when using a wxPanel (instead of wxGLCanvas). So I reduced the code to one which uses a wxPanel instead to simplify things. In specific, there seem to be issues with firing the wxEVT_KEY_DOWN event. With the code in the current state below, the wxEVT_KEY_DOWN event is not caught for some reason. If I instead replace wxEVT_KEY_DOWN with wxEVT_KEY_UP, it is caught.

However when I do either of the following:

1. comment out the two lines with [#1] related to the scrollbar, or
2. comment out the single line containing [#2] related to binding the mouse event wxEVT_LEFT_DOWN

... then the wxEVT_KEY_DOWN event is caught. So I don't quite know what's going on

Code: Select all

#include <wx/wx.h>

class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};

class MyFrame : public wxFrame
{
public:
    MyFrame();
private:
    void OnKeyPress(wxKeyEvent& event);
    void OnMousePress(wxMouseEvent& event);
};

wxIMPLEMENT_APP(MyApp);

bool MyApp::OnInit()
{
    MyFrame* frame = new MyFrame();
    frame->Show(true);
    return true;
}

MyFrame::MyFrame() : wxFrame(NULL, wxID_ANY, "")
{
    wxScrollBar * scrollbar = new wxScrollBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL); // #1
    wxPanel* panel = new wxPanel(this, wxID_ANY);
    
    wxBoxSizer* hbox = new wxBoxSizer(wxHORIZONTAL);
    hbox->Add(panel, 1, wxEXPAND, 0);
    hbox->Add(scrollbar, 0, wxEXPAND, 0); // #1
    SetSizer(hbox);

    panel->Bind(wxEVT_KEY_DOWN, &MyFrame::OnKeyPress, this); // this doesn't work. Only works if I replace it with wxEVT_KEY_UP
    panel->Bind(wxEVT_LEFT_DOWN, &MyFrame::OnMousePress, this); // #2
}


void MyFrame::OnKeyPress(wxKeyEvent& event)
{
    wxLogMessage("Key press event captured!");
}

void MyFrame::OnMousePress(wxMouseEvent& event)
{
    wxLogMessage("Mouse press event captured!");
}
Thanks for any help.
Last edited by zapcity on Fri Aug 06, 2021 5:06 am, edited 5 times in total.

User avatar
doublemax@work
Earned some good credits
Earned some good credits
Posts: 131
Joined: Wed Jul 29, 2020 6:06 pm

Re: keyboard event not being caught

Post by doublemax@work » Wed Aug 04, 2021 7:23 am

Which platform are you using?

Keyboard events are sent to the window that has keyboard focus. At least under Windows wxLogMessage opens a new window and i suspect that this steals the keyboard focus. Try something less intrusive like wxLogDebug for debug information. If you're under Windows, you needs an IDE that catches these messages or DebugView https://docs.microsoft.com/en-us/sysint ... /debugview

zapcity
Earned a small fee
Earned a small fee
Posts: 17
Joined: Thu Oct 22, 2020 12:42 pm

Re: keyboard event not being caught

Post by zapcity » Wed Aug 04, 2021 10:04 am

Thanks. I'm on windows 10 using visual studio 2019. My original code doesn't use wxLogMessage() and still suffers from this behavior. If I replace wxEVT_KEY_DOWN with wxEVT_KEY_UP, then it works. I'll try the wxLogDebug / DebugView and see where that gets me. If by chance someone can verify my code on their end, that would be great.

User avatar
doublemax@work
Earned some good credits
Earned some good credits
Posts: 131
Joined: Wed Jul 29, 2020 6:06 pm

Re: keyboard event not being caught

Post by doublemax@work » Wed Aug 04, 2021 11:56 am

Call event.Skip(); in the event handlers. If you don't do that, you "consume" the event.

This is explained by this part from the docs:
If a key down (EVT_KEY_DOWN) event is caught and the event handler does not call event.Skip() then the corresponding char event (EVT_CHAR) will not happen. This is by design and enables the programs that handle both types of events to avoid processing the same key twice. As a consequence, if you do not want to suppress the wxEVT_CHAR events for the keys you handle, always call event.Skip() in your wxEVT_KEY_DOWN handler. Not doing may also prevent accelerators defined using this key from working.
https://docs.wxwidgets.org/trunk/classwx_key_event.html

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 5308
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: keyboard event not being caught

Post by ONEEYEMAN » Wed Aug 04, 2021 12:18 pm

Hi,
You should also call it for mouse events (in fact all non-wxCommandEvent's) to let OS processing do its thing.
Unless you are really know what you're doing.

Thank you.

zapcity
Earned a small fee
Earned a small fee
Posts: 17
Joined: Thu Oct 22, 2020 12:42 pm

Re: keyboard event not being caught

Post by zapcity » Fri Aug 06, 2021 5:02 am

Thanks for that. When I placed event.Skip() in the mouse event handler, the wxEVT_KEY_DOWN event was caught; but not if I place it in the key event handler.

Code: Select all

void MyFrame::OnKeyPress(wxKeyEvent& event)
{
    // event.Skip() // doesn't work
    wxLogMessage("Key press event captured!");
}

void MyFrame::OnMousePress(wxMouseEvent& event)
{
    event.Skip(); // works i.e. wxEVT_KEY_DOWN caught
    wxLogMessage("Mouse press event captured!");
}
I am still trying to wrap my head around this event stuff. The documentations "If a key down (EVT_KEY_DOWN) event is caught and the event handler does not call event.Skip()..." suggests it needs to be placed in the key event handler, which is not the case in my code.

I will need to dig into the documentation to fully understand events in wxwidgets. Thanks!

User avatar
doublemax
Moderator
Moderator
Posts: 16381
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: keyboard event not being caught

Post by doublemax » Fri Aug 06, 2021 6:11 am

When you start the app, the frame has keyboard focus and will receive keyboard events. But you're catching the key events at the panel, so you don't receive them.

Only when you click into the panel, it will get keyboard focus. But: As you catch the mouse event and "consume" it, the doesn't get processed any further, and as a consequence, the panel doesn't get focus.

The name of the method event.Skip() is not very clear, think of it as "ContinueProcessing()". By calling it, the event gets processed by wxWidgets internally, the panel gets focus and receives the key events.

E.g. if you put "panel->SetFocus()" at the end of the MyFrame ctor, it will get key events right away without the need to click into it first.
Use the source, Luke!

zapcity
Earned a small fee
Earned a small fee
Posts: 17
Joined: Thu Oct 22, 2020 12:42 pm

Re: keyboard event not being caught

Post by zapcity » Sat Aug 07, 2021 9:42 am

Thanks so much for that detailed explanation, it really helped frame things together. So the event.Skip() allows the event to be passed up the event chain hierarchy to some code that eventually sets focus on the panel.

I have replaced wxLogMessage() with debug printing and can observe when the panel is in focus. There are a few other odd behaviors I am seeing i.e. if i bind wxEvt_Motion to the panel and move the mouse across the panel, it is being caught even if the panel is not in focus (via clicking in it), which i am observing via panel->HasFocus(). I guess there are certain oddities here and there that require deeper understanding. But that's ok for now. Thanks again doublemax!

User avatar
doublemax
Moderator
Moderator
Posts: 16381
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: keyboard event not being caught

Post by doublemax » Sat Aug 07, 2021 10:38 am

So the event.Skip() allows the event to be passed up the event chain hierarchy to some code that eventually sets focus on the panel.
Correct.
if i bind wxEvt_Motion to the panel and move the mouse across the panel, it is being caught even if the panel is not in focus (via clicking in it)
wxEVT_MOTION is independent of the focus, it goes to the topmost window under the mouse.
Use the source, Luke!

zapcity
Earned a small fee
Earned a small fee
Posts: 17
Joined: Thu Oct 22, 2020 12:42 pm

Re: keyboard event not being caught

Post by zapcity » Wed Aug 11, 2021 3:29 am

Thanks for all the help. It all makes better sense now :)

Post Reply