From b0ec84693eeac4ac37f12c381f5907c4c07c12b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ed=C3=AAnis=20Freindorfer=20Azevedo?= Date: Wed, 29 May 2019 16:08:18 -0300 Subject: [PATCH] fix stuck keys on ubuntu and on focus loss #142 In the `OnKeyDown` event handler, check if the key is actually pressed using `wxGetKeyState()`, because for some reason on Ubuntu 18 spurious events are generated when the key is not actually pressed. Also, if a game is paused by the frontend while a key is being pressed, the key will remain active for the game when unpaused. This is an issue because the key will likely be released outside of the game zone; therefore, we would not process the key release for the game itself. The same bug happens if clicking outside of the game zone while holding a key. For the case of a directional key, this means a continuous movement in the direction of the key pressed before the pause until the key is pressed and released. --- src/wx/panel.cpp | 31 ++++++++++++++++++++++++++++++- src/wx/wxvbam.h | 1 + 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/wx/panel.cpp b/src/wx/panel.cpp index 589019b0..3b8fe476 100644 --- a/src/wx/panel.cpp +++ b/src/wx/panel.cpp @@ -16,6 +16,9 @@ #include "filters.h" #include "wxvbam.h" +// release all buttons currently pressed +static void clear_input_press(); + int emulating; IMPLEMENT_DYNAMIC_CLASS(GameArea, wxPanel) @@ -919,6 +922,12 @@ GameArea::~GameArea() } } +void GameArea::OnKillFocus(wxFocusEvent& ev) +{ + clear_input_press(); + ev.Skip(true); +} + void GameArea::Pause() { if (paused) @@ -932,6 +941,11 @@ void GameArea::Pause() paused = was_paused = true; + // when the game is paused like this, we should not allow any + // input to remain pressed, because they could be released + // outside of the game zone and we would not know about it. + clear_input_press(); + if (loaded != IMAGE_UNKNOWN) soundPause(); } @@ -1022,6 +1036,9 @@ void GameArea::OnIdle(wxIdleEvent& event) // the userdata is freed on disconnect/destruction this->Connect(wxEVT_SIZE, wxSizeEventHandler(GameArea::OnSize), NULL, this); + // we need to check if the buttons stayed pressed when focus the panel + w->Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(GameArea::OnKillFocus), NULL, this); + w->SetBackgroundStyle(wxBG_STYLE_CUSTOM); w->SetSize(wxSize(basic_width, basic_height)); @@ -1141,6 +1158,16 @@ static uint32_t bmask[NUM_KEYS] = { static wxJoyKeyBinding_v keys_pressed; +static void clear_input_press() +{ + int i; + for (i = 0; i < 4; ++i) + { + joypress[i] = 0; + } + keys_pressed.clear(); +} + struct game_key { int player; int key_num; @@ -1257,7 +1284,9 @@ static void draw_black_background(wxWindow* win) { void GameArea::OnKeyDown(wxKeyEvent& ev) { - if (process_key_press(true, ev.GetKeyCode(), ev.GetModifiers())) { + // check if the key is pressed indeed and then process it + wxKeyCode keyCode = (wxKeyCode)ev.GetKeyCode(); + if (wxGetKeyState(keyCode) && process_key_press(true, ev.GetKeyCode(), ev.GetModifiers())) { ev.Skip(false); ev.StopPropagation(); wxWakeUpIdle(); diff --git a/src/wx/wxvbam.h b/src/wx/wxvbam.h index cca29123..b254ca0a 100644 --- a/src/wx/wxvbam.h +++ b/src/wx/wxvbam.h @@ -621,6 +621,7 @@ protected: void PaintEv(wxPaintEvent& ev); void EraseBackground(wxEraseEvent& ev); void OnSize(wxSizeEvent& ev); + void OnKillFocus(wxFocusEvent& ev); #ifndef NO_FFMPEG MediaRecorder snd_rec, vid_rec;