skip to Main Content

I have run into a wxGetKeyState() issue with Wayland. Let me explain: In some of my apps, I add a test for the Shift key being pressed in the ctor of my app’s top wxFrame window. If the Shift key is down during launch, I run diagnostic code relevant to my app. This has always worked just fine until I switched to Ubuntu 22.04 with the Wayland display server. If I run my app in Ubuntu 22.04 with the X.org display sever, everything runs as expected. By the way, I’m using wxWidgets 3.2.0.

To test this possible bug just add these few lines of code to the end of the top wxFrame ctor.

MyFrame::MyFrame()
{
    ...
    if (wxGetKeyState(WXK_SHIFT))
    {
        wxMessageBox("Hello there");
    }
}

Does anyone have run into this issue? Is there a known work-around?

Regards,
Bob

EDIT:
When I run the minimal app (shown below) I see these results for X and Wayland.

Output when launching the app while holding the shift key down in X.

18:40:25: Debug: from CTOR: 1
18:40:25: Debug: from idle: 1
18:40:25: Debug: from idle: 1
18:40:25: Debug: from idle: 1
18:40:25: Debug: from idle: 1
18:40:25: Debug: from idle: 1
18:40:25: Debug: from idle: 1
18:40:25: Debug: from idle: 1
18:40:25: Debug: from idle: 1
18:40:25: Debug: from idle: 1
18:40:25: Debug: from idle: 1
18:40:25: Debug: from idle: 1
18:40:25: Debug: from idle: 1
18:40:25: Debug: from idle: 1
18:40:25: Debug: from idle: 1
18:40:25: Debug: from idle: 1

Under X, wxGetKeyState() behaves as expected. It goes thru 16 idle cycles before stopping while showing the correct value all along.

Now, this is the output when launching the app while holding the shift key down in Waylan.

18:32:43: Debug: from CTOR: 0
18:32:43: Debug: from idle: 0
18:32:43: Debug: from idle: 0
18:32:43: Debug: from idle: 0
18:32:43: Debug: from idle: 1

Under Wayland, the test at the ctor fails and it takes 3 idle cycles before reporting the correct value.
I hope this test helps to identify and solve this issue.

Minimal test program:

#include <wx/wx.h>

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

class MyFrame: public wxFrame
{
public:
            MyFrame();
    void    on_idle(wxIdleEvent& event);
};

wxIMPLEMENT_APP(MyApp);

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

MyFrame::MyFrame() : wxFrame(NULL, wxID_ANY, "minimal")
{
    Bind(wxEVT_IDLE, &MyFrame::on_idle, this);
    wxLogDebug("from CTOR: %d", wxGetKeyState(WXK_SHIFT));
}

void MyFrame::on_idle(wxIdleEvent& event)
{
    wxLogDebug("from idle: %d", wxGetKeyState(WXK_SHIFT));
}

2

Answers


  1. Chosen as BEST ANSWER

    I implemented a temporary solution to my problem with the Wayland/wxGetKeyState() issue. The function get_key_state_hack(), below, offers the same functionally of wxGetKeyState() with the following caveats:

    1. The use of this function only makes sense when targeting Linux/Wayland. It does not provide any advantage in any other context. The day that wxGetKeyState() starts working correctly with Wayland, you won’t need this function anymore. As suggested by VZ, the problem seems to be with GDK.

    2. This function is only useful during the start-up of the program since after a few idle event cycles wxGetKeyState() works correctly.

    3. This function will block for a few idle event cycles. This is not a problem in my case since I use it as a one-time test to detect if the Shift key was held down during program launch and as soon as the user moves the mouse or touches the keyboard there will be an avalanche of idle events.

    #include <wx/evtloop.h>
    
    bool get_key_state_hack(wxKeyCode key)
    {
        int   count = 5;
        bool  pressed = false;
        wxEventLoop loop;
    
        auto on_idle = [&](wxIdleEvent& event)
        {
            pressed = wxGetKeyState(key);
    
            if (pressed || (--count < 1))
            {
                loop.Exit();
            }
        };
    
        wxTheApp->Bind(wxEVT_IDLE, on_idle);
        loop.Run();
        wxTheApp->Unbind(wxEVT_IDLE, on_idle);
    
        return pressed;
    }
    

    By the way, I decided to use a lambda function as event handler to keep all the code nicely packed in a single C++ function.

    I hope this function can be useful to anyone who faces this problem.


  2. This is supposed to work and I’ve just added a demonstration of this function to the keyboard sample and it behaves as expected both with X and Wayland for me, including showing "Shift" in the status bar when the corresponding key is pressed while launching the sample.

    Looking at the code, Wayland support requires GTK 3.4 or later, but you definitely should have this (and actually a much more recent version) under Ubuntu 22.04, so I have no idea why it doesn’t work. If you also see the problem in the keyboard sample, please try debugging this yourself, i.e. check what happens inside wxGetKeyStateGTK() function.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search