Keyboard event handled not always respected

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
pkl
Knows some wx things
Knows some wx things
Posts: 36
Joined: Mon Jan 30, 2017 11:46 pm

Keyboard event handled not always respected

Post by pkl »

Under wxWidgets 3.0 and Windows 10, I use Alt-I as a shortcut key. When I press the key-combination, my shortcut gets executed and I do remember to mark the event as handled. And yet, I hear an annoying "ping" from my OS, indicating that the system tries to handle the key-combination anyway. How do you prevent this from happening?

I tried to debug this a while ago (this is not easy!) and it seems that the system ignores my "Event handled" notification in certain situations. Is it a setup problem?

/Peter
Manolo
Can't get richer than this
Can't get richer than this
Posts: 827
Joined: Mon Apr 30, 2012 11:07 pm

Re: Keyboard event handled not always respected

Post by Manolo »

my shortcut gets executed and I do remember to mark the event as handled
Can you show your code doing this? It should use event.Skip(false)
pkl
Knows some wx things
Knows some wx things
Posts: 36
Joined: Mon Jan 30, 2017 11:46 pm

Re: Keyboard event handled not always respected

Post by pkl »

The code is as follows:

Code: Select all

void ui_ctrl_info::on_key_down(wxKeyEvent& kd_info)
{
    auto result = handle_keycode({kd_info.GetModifiers(),get_key_id(kd_info.GetKeyCode())});
    kd_info.Skip(!result.processed);
    if (result.processed)
    {
		//---
    }
}
ui_ctrl_info is basically a class extending a wxWidget (so my widget could be e.g. public wxTextCtrl, public ui_ctrl_info).
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7459
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Keyboard event handled not always respected

Post by ONEEYEMAN »

Hi,
Generally speaking you should always call event.Skip() in non-wxCommandEvent handlers in order for the OS to process those events.
If you will not do that for wxKeyEvent - you may find yourself without the caret or any other weird thing may start happening.

What is you intention when you are eating those events? Why you don't want the OS to process them?

Thank you.
pkl
Knows some wx things
Knows some wx things
Posts: 36
Joined: Mon Jan 30, 2017 11:46 pm

Re: Keyboard event handled not always respected

Post by pkl »

I am not sure I follow?
I call skip(false) if I do not want the system to process the event any further. In this case I handled the key combination, and I do not want a higher layer to process the key. Right now, I process the key but the Skip function is not honored so the system handles the key, finds no use for it and gives a warning sound. This is of course most annoying for the user. It would be equally or more annoying to the user if the key combination did have a meaning as that would cause the effect of that key combination to take effect.
Did I explain what I meant and did I understand your question?

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

Re: Keyboard event handled not always respected

Post by doublemax »

It's very unlikely that wxWidgets randomly handles the Skip() call incorrectly. Did you check that the result.processed flag always contains what you expect?

I'm afraid we'll need a sample to reproduce the issue here, too.
Use the source, Luke!
pkl
Knows some wx things
Knows some wx things
Posts: 36
Joined: Mon Jan 30, 2017 11:46 pm

Re: Keyboard event handled not always respected

Post by pkl »

So now I have had time to spend time on this problem, and it is quite easy to reproduce:

I am sorry that it is not the most minimal example I post. I am using the same code as for the other problem (viewtopic.php?f=1&t=44703) and have been to lazy removing the unneeded code here.
Anyway, the interesting part is in myTextCtl::on_key_down (line 132):

Code: Select all

  void on_key_down(wxKeyEvent& kd_info)
    {
        if (kd_info.GetModifiers() == wxMOD_ALT && kd_info.GetKeyCode() == 'G')
        {
            kd_info.Skip(false);
            this->SetValue("HELLO");
        }
    }
So pressing Alt-G should make the text "HELLO" appear, and it does. But the wxWidgets runtime does not accept my handling - thus the annoying Bell-sound on Windows. Interestingly, deriving MyFrame2 from wxDialog solves the problem which is why I could not reproduce the problem at first.

This is a very interesting behaviour: If you place MyTextCtrl in a frame, it will say HELLO. If you place MyTextCtrl in a dialog, it will also say HELLO - and perhaps unintentionally launch a few missiles. ;-)
I believe the problem is perhaps related to the WXLPARAM parameter which is 0x20220001 in the dialog case and 0x20200001 when in a frame.

/Peter
Update: The problem is that wxWidgets does not respect Skip for "SYSKEYs". I knew that already, just got thrilled when I saw the difference in parameters. ;-)

This is from the msw/windows.cpp file (line 3206):

Code: Select all

	if (message == WM_SYSKEYDOWN)  // Let Windows still handle the SYSKEYs
		processed = false;

Code: Select all

#include <wx/wx.h>
#include <wx/listctrl.h>
#include <wx/numdlg.h>
#include <wx/dialog.h>
#include <algorithm> 
#include <vector> 

const int my_cols = 7;
const int min_csize = 100;
const int max_csize = 200;
class MyListCtrl : public wxListCtrl
{
public:
    MyListCtrl(wxWindow *parent)
        : wxListCtrl(parent, wxID_ANY, wxDefaultPosition, wxSize(-1,-1), wxLC_REPORT | wxLC_VIRTUAL | wxLC_SINGLE_SEL)
    {       
        Bind(wxEVT_SIZE,[this](wxEvent& e) 
        { 
            e.Skip();
            CallAfter(&MyListCtrl::on_size);
        });

        Bind(wxEVT_CONTEXT_MENU,[this](wxEvent&) 
        { 
            on_right_click(); 
        });

        Bind(wxEVT_KEY_DOWN,[this](wxKeyEvent& kd_info)
        {
            this->on_key_down(kd_info);
        });

        for (int i{0}; i < my_cols; ++i)
        {
            wxString s;
            s.Printf("Col %d",i);
            InsertColumn(i,s);
            SetColumnWidth(i, 200);
        }
        Updated();
    }
    
    void on_size()
    {
        int wdw_width = GetClientSize().x;
        int col_size = std::max(100,wdw_width/my_cols);

        Freeze();
        for (auto  i = 0; i< my_cols; ++i)
            SetColumnWidth(i,col_size);
        Thaw();
    }

    void on_key_down(wxKeyEvent& kd_info)
    {
        if (kd_info.GetModifiers() == wxMOD_ALT && kd_info.GetKeyCode() == 'D')
        {
            RemoveData(m_items.size()/2);
            kd_info.Skip(false);
        }
    }

    void on_right_click()
    {
        wxMenu menu;
        menu.Append(9856,"Erase","");
        if (9856 == GetPopupMenuSelectionFromUser(menu))
        {
            auto pos = GetNextItem(-1,wxLIST_NEXT_ALL,wxLIST_STATE_SELECTED);
            if (pos >= 0 && pos < m_items.size())
            {
                RemoveData(pos);
            }
        }
    }
    void Updated()
    {
        SetItemCount(m_items.size());
        RefreshItems(0, GetItemCount() - 1);
        wxLogMessage("GetTopItem(): %ld", GetTopItem());
    }
    void AddData(size_t count)
    {
        m_items.clear();
        m_items.reserve(count);
        for (size_t i{0}; i < count; ++i)
            m_items.push_back(i);
        Updated();
    }

    void RemoveData(size_t keep)
    {
        if (keep < m_items.size())
        {
            m_items.erase(
                m_items.begin(),
                m_items.begin() + keep
            );
        }
        Updated();
    }

protected:                
    std::vector<size_t> m_items;
    
    virtual wxString OnGetItemText(long item, long col) const
    {                
//        OutputDebugStringA("Hello\n");
        wxString res;
        res.Printf("Item %u (%d)",m_items[item],col);
        return res;
    }
};

class MyTextCtrl : public wxTextCtrl 
{
public:
    MyTextCtrl(wxWindow *parent)
        : wxTextCtrl(parent, wxID_ANY, "",wxDefaultPosition,wxSize(-1,-1))
    {       
        Bind(wxEVT_CONTEXT_MENU,[this](wxEvent&) 
        { 
            on_right_click(); 
        });

        Bind(wxEVT_KEY_DOWN,[this](wxKeyEvent& kd_info)
        {
            this->on_key_down(kd_info);
        });
    }
    
    void on_key_down(wxKeyEvent& kd_info)
    {
        if (kd_info.GetModifiers() == wxMOD_ALT && kd_info.GetKeyCode() == 'G')
        {
            kd_info.Skip(false);
            this->SetValue("HELLO");
        }
    }

    void on_right_click()
    {
        wxMenu menu;
        menu.Append(9856,"Erase","");
        if (9856 == GetPopupMenuSelectionFromUser(menu))
        {
            SetValue("");
        }
    }

    
};

class MyFrame2 : public wxDialog
{
public:
    MyFrame2() : wxDialog(NULL, wxID_ANY, _("Test"))
    {
        wxBoxSizer* bSizer = new wxBoxSizer(wxVERTICAL);

        m_child = new MyTextCtrl(this);
        bSizer->Add(m_child, 1, wxEXPAND | wxALL, 5);
        //m_listCtrl = new MyListCtrl(this);
        //bSizer->Add(m_listCtrl, 1, wxEXPAND | wxALL, 5);

        wxButton* button = new wxButton(this, wxID_ANY, "Update items");
        bSizer->Add(button, 0, wxEXPAND | wxALL, 5);
        button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame2::OnButtonClicked, this);

        wxButton* button2 = new wxButton(this, wxID_ANY, "Erase items");
        bSizer->Add(button2, 0, wxEXPAND | wxALL, 5);
        button2->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame2::OnButtonClicked2, this);

        SetSizer(bSizer);
    }   
private:    
    MyTextCtrl* m_child = nullptr;
    MyListCtrl* m_listCtrl = nullptr;
    
    void OnButtonClicked(wxCommandEvent&)
    {       
        long newItemCount = 10;

        newItemCount = wxGetNumberFromUser("Input number of items", "Number", "New number of items in the list",
            newItemCount, 0, 25000, this);
      
        if (m_listCtrl && newItemCount >= 0 )
        {
            m_listCtrl->AddData(newItemCount);
        }
    }

    void OnButtonClicked2(wxCommandEvent&)
    {       
        long newItemCount = 10;

        newItemCount = wxGetNumberFromUser("Number of items to erase", "Number", "",
            newItemCount, 0, 25000, this);
        if (m_listCtrl) m_listCtrl->RemoveData(newItemCount);
    }
};

class MyApp : public wxApp
{
public:
    virtual bool OnInit()
    {     
        (new MyFrame2())->Show();               
        return true;
    }
}; 
wxIMPLEMENT_APP(MyApp);
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Keyboard event handled not always respected

Post by doublemax »

Code: Select all

if (message == WM_SYSKEYDOWN)  // Let Windows still handle the SYSKEYs
      processed = false;
Interesting find. I'm not sure why it is handed this way, it might be worth asking on the wx-users mailing list / Google group. https://groups.google.com/forum/#!forum/wx-users
Use the source, Luke!
pkl
Knows some wx things
Knows some wx things
Posts: 36
Joined: Mon Jan 30, 2017 11:46 pm

Re: Keyboard event handled not always respected

Post by pkl »

I will do that. Thank you for the link. Is that group more "official" than this forum. I find it confusing having two groups.
I must say that I have had great help in this forum, but if it is not the "official" group, it is difficult to know where to post.

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

Re: Keyboard event handled not always respected

Post by doublemax »

Is that group more "official" than this forum. I find it confusing having two groups.
This here is a pure user forum. On the mailing list you have a chance to get a response from the actual wxWidgets developers.
Use the source, Luke!
pkl
Knows some wx things
Knows some wx things
Posts: 36
Joined: Mon Jan 30, 2017 11:46 pm

Re: Keyboard event handled not always respected

Post by pkl »

Okay - I got that. So developers do not visit these sites - this is a little sad.
By the way: I posted on the wx-users group almost two hours ago, but can not see my post. Is that a problem or am I waiting to get a approved by a moderator?

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

Re: Keyboard event handled not always respected

Post by doublemax »

I posted on the wx-users group almost two hours ago, but can not see my post. Is that a problem or am I waiting to get a approved by a moderator?
Possible. But i honestly don't know.
Use the source, Luke!
pkl
Knows some wx things
Knows some wx things
Posts: 36
Joined: Mon Jan 30, 2017 11:46 pm

Re: Keyboard event handled not always respected

Post by pkl »

FYI, my post got through and has been responded to as well.
Post Reply