[LINUX,WINDOWS] Key/Joy background input.

- Joystick background input.

Set as enabled by default.

- Linux: `X11` and `Wayland` done.

1. `Wayland` does not allow to listen for keypresses for security reasons.

Discussion here: https://github.com/albertlauncher/albert/issues/309

2. For `X11` we can use `XQueryKeymap` to check keyboard state.

- Windows: done.

We use `GetAsyncKeyState` most significant bit to check if the key
is being pressed.
This commit is contained in:
Edênis Freindorfer Azevedo 2020-07-25 20:05:16 -03:00 committed by Rafael Kitover
parent 84f3e8ce67
commit 7031c1d155
11 changed files with 2462 additions and 17 deletions

View File

@ -260,6 +260,8 @@ uint32_t throttle = 100;
uint32_t speedup_throttle = 100; uint32_t speedup_throttle = 100;
uint32_t speedup_frame_skip = 9; uint32_t speedup_frame_skip = 9;
bool speedup_throttle_frame_skip = false; bool speedup_throttle_frame_skip = false;
bool allowKeyboardBackgroundInput = false;
bool allowJoystickBackgroundInput = true;
const char* preparedCheatCodes[MAX_CHEATS]; const char* preparedCheatCodes[MAX_CHEATS];
@ -477,6 +479,8 @@ void ValidateConfig()
void LoadConfig() void LoadConfig()
{ {
agbPrint = ReadPrefHex("agbPrint"); agbPrint = ReadPrefHex("agbPrint");
allowKeyboardBackgroundInput = ReadPref("allowKeyboardBackgroundInput", false);
allowJoystickBackgroundInput = ReadPref("allowJoystickBackgroundInput", true);
autoFireMaxCount = fromDec(ReadPrefString("autoFireMaxCount")); autoFireMaxCount = fromDec(ReadPrefString("autoFireMaxCount"));
autoFrameSkip = ReadPref("autoFrameSkip", 0); autoFrameSkip = ReadPref("autoFrameSkip", 0);
autoLoadMostRecent = ReadPref("autoLoadMostRecent", 0); autoLoadMostRecent = ReadPref("autoLoadMostRecent", 0);

View File

@ -149,6 +149,8 @@ extern uint32_t throttle;
extern uint32_t speedup_throttle; extern uint32_t speedup_throttle;
extern uint32_t speedup_frame_skip; extern uint32_t speedup_frame_skip;
extern bool speedup_throttle_frame_skip; extern bool speedup_throttle_frame_skip;
extern bool allowKeyboardBackgroundInput;
extern bool allowJoystickBackgroundInput;
extern int preparedCheats; extern int preparedCheats;
extern const char *preparedCheatCodes[MAX_CHEATS]; extern const char *preparedCheatCodes[MAX_CHEATS];

View File

@ -718,6 +718,7 @@ add_custom_command(
set( set(
SRC_WX SRC_WX
wxvbam.cpp wxvbam.cpp
background-input.cpp
guiinit.cpp guiinit.cpp
viewers.cpp viewers.cpp
gfxviewers.cpp gfxviewers.cpp
@ -751,6 +752,7 @@ endif()
set( set(
HDR_WX HDR_WX
wxvbam.h wxvbam.h
background-input.h
wxlogdebug.h wxlogdebug.h
drawing.h drawing.h
filters.h filters.h

2345
src/wx/background-input.cpp Normal file

File diff suppressed because it is too large Load Diff

23
src/wx/background-input.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef BACKGROUND_INPUT_H
#define BACKGROUND_INPUT_H
#include <wx/event.h>
#include <wx/log.h>
#include <wx/thread.h>
#include <wx/utils.h>
#include <wx/window.h>
#include <unordered_map>
#if defined(__WXMSW__)
extern std::unordered_map<int, wxKeyCode> gs_specialKeys;
#elif defined(__WXMAC__)
#else // defined(__WXGTK__)
extern std::unordered_map<unsigned, int> x11KeySym;
#endif
void enableKeyboardBackgroundInput(wxEvtHandler* handler);
void disableKeyboardBackgroundInput();
#endif // BACKGROUND_INPUT_H

View File

@ -1565,6 +1565,36 @@ EVT_HANDLER(JoypadAutoholdStart, "Autohold Start (toggle)")
GetMenuOptionInt(keyName, autohold, keym); GetMenuOptionInt(keyName, autohold, keym);
} }
#include "background-input.h"
EVT_HANDLER(AllowKeyboardBackgroundInput, "Allow keyboard background input (toggle)")
{
bool menuPress;
GetMenuOptionBool("AllowKeyboardBackgroundInput", menuPress);
toggleBooleanVar(&menuPress, &allowKeyboardBackgroundInput);
SetMenuOption("AllowKeyboardBackgroundInput", allowKeyboardBackgroundInput ? 1 : 0);
disableKeyboardBackgroundInput();
if (allowKeyboardBackgroundInput) {
if (panel && panel->panel) {
enableKeyboardBackgroundInput(panel->panel->GetWindow());
}
}
update_opts();
}
EVT_HANDLER(AllowJoystickBackgroundInput, "Allow joystick background input (toggle)")
{
bool menuPress;
GetMenuOptionBool("AllowJoystickBackgroundInput", menuPress);
toggleBooleanVar(&menuPress, &allowJoystickBackgroundInput);
SetMenuOption("AllowJoystickBackgroundInput", allowJoystickBackgroundInput ? 1 : 0);
update_opts();
}
EVT_HANDLER_MASK(LoadGameRecent, "Load most recent save", CMDEN_SAVST) EVT_HANDLER_MASK(LoadGameRecent, "Load most recent save", CMDEN_SAVST)
{ {
panel->LoadState(); panel->LoadState();
@ -2611,7 +2641,7 @@ EVT_HANDLER_MASK(DisplayConfigure, "Display options...", CMDEN_NREC_ANY)
if (panel->panel) { if (panel->panel) {
panel->panel->Destroy(); panel->panel->Destroy();
panel->panel = NULL; panel->panel = nullptr;
} }
update_opts(); update_opts();
@ -2629,7 +2659,7 @@ EVT_HANDLER_MASK(ChangeFilter, "Change Pixel Filter", CMDEN_NREC_ANY)
if (panel->panel) { if (panel->panel) {
panel->panel->Destroy(); panel->panel->Destroy();
panel->panel = NULL; panel->panel = nullptr;
} }
wxString msg; wxString msg;
@ -2644,7 +2674,7 @@ EVT_HANDLER_MASK(ChangeIFB, "Change Interframe Blending", CMDEN_NREC_ANY)
if (panel->panel) { if (panel->panel) {
panel->panel->Destroy(); panel->panel->Destroy();
panel->panel = NULL; panel->panel = nullptr;
} }
wxString msg; wxString msg;

View File

@ -26,6 +26,10 @@
#include "../common/ConfigManager.h" #include "../common/ConfigManager.h"
#include "../gba/CheatSearch.h" #include "../gba/CheatSearch.h"
#if defined(__WXGTK__)
#include "wayland.h"
#endif
// The program icon, in case it's missing from .xrc (MSW gets it from .rc file) // The program icon, in case it's missing from .xrc (MSW gets it from .rc file)
#if !defined(__WXMSW__) && !defined(__WXPM__) #if !defined(__WXMSW__) && !defined(__WXPM__)
// ImageMagick makes the name wxvbam, but wx expects wxvbam_xpm // ImageMagick makes the name wxvbam, but wx expects wxvbam_xpm
@ -2834,6 +2838,22 @@ bool MainFrame::BindControls()
continue; continue;
} }
#endif
#if defined(__WXMAC__) || defined(__WXGTK__)
if (cmdtab[i].cmd_id == XRCID("AllowKeyboardBackgroundInput")
#if defined(__WXGTK__)
&& IsItWayland()
#endif
) {
if (mi)
mi->GetMenu()->Remove(mi);
cmdtab[i].cmd_id = XRCID("NOOP");
cmdtab[i].mi = NULL;
continue;
}
#endif #endif
#ifdef NO_LINK #ifdef NO_LINK

View File

@ -308,6 +308,8 @@ opt_desc opts[] = {
INTOPT("geometry/windowY", "Y", wxTRANSLATE("Window axis Y position at startup"), windowPositionY, -1, 99999), INTOPT("geometry/windowY", "Y", wxTRANSLATE("Window axis Y position at startup"), windowPositionY, -1, 99999),
/// UI /// UI
BOOLOPT("ui/allowKeyboardBackgroundInput", "AllowKeyboardBackgroundInput", wxTRANSLATE("Capture key events while on background"), allowKeyboardBackgroundInput),
BOOLOPT("ui/allowJoystickBackgroundInput", "AllowJoystickBackgroundInput", wxTRANSLATE("Capture joy events while on background"), allowJoystickBackgroundInput),
BOOLOPT("ui/hideMenuBar", "", wxTRANSLATE("Hide menu bar when mouse is inactive"), gopts.hide_menu_bar), BOOLOPT("ui/hideMenuBar", "", wxTRANSLATE("Hide menu bar when mouse is inactive"), gopts.hide_menu_bar),
/// Sound /// Sound

View File

@ -27,6 +27,7 @@
#include "wxvbam.h" #include "wxvbam.h"
#include "wxutil.h" #include "wxutil.h"
#include "wayland.h" #include "wayland.h"
#include "background-input.h"
#ifdef __WXMSW__ #ifdef __WXMSW__
#include <windows.h> #include <windows.h>
@ -328,7 +329,6 @@ void GameArea::LoadGame(const wxString& name)
emulating = true; emulating = true;
was_paused = true; was_paused = true;
MainFrame* mf = wxGetApp().frame; MainFrame* mf = wxGetApp().frame;
mf->StopJoyPollTimer();
mf->SetJoystick(); mf->SetJoystick();
mf->cmd_enable &= ~(CMDEN_GB | CMDEN_GBA); mf->cmd_enable &= ~(CMDEN_GB | CMDEN_GBA);
mf->cmd_enable |= ONLOAD_CMDEN; mf->cmd_enable |= ONLOAD_CMDEN;
@ -557,15 +557,17 @@ void GameArea::UnloadGame(bool destruct)
emusys = NULL; emusys = NULL;
soundShutdown(); soundShutdown();
disableKeyboardBackgroundInput();
if (destruct) if (destruct)
return; return;
// in destructor, panel should be auto-deleted by wx since all panels // in destructor, panel should be auto-deleted by wx since all panels
// are derived from a window attached as child to GameArea // are derived from a window attached as child to GameArea
if (panel) if (panel) {
panel->Destroy(); panel->Destroy();
panel = nullptr;
panel = NULL; }
// close any game-related viewer windows // close any game-related viewer windows
// in destructor, viewer windows are in process of being deleted anyway // in destructor, viewer windows are in process of being deleted anyway
@ -579,7 +581,6 @@ void GameArea::UnloadGame(bool destruct)
mf->enable_menus(); mf->enable_menus();
mf->SetJoystick(); mf->SetJoystick();
mf->ResetCheatSearch(); mf->ResetCheatSearch();
mf->StartJoyPollTimer();
if (rewind_mem) if (rewind_mem)
num_rewind_states = 0; num_rewind_states = 0;
@ -702,10 +703,10 @@ void GameArea::AddBorder()
wxGetApp().frame->Fit(); wxGetApp().frame->Fit();
GetSizer()->Detach(panel->GetWindow()); GetSizer()->Detach(panel->GetWindow());
if (panel) if (panel) {
panel->Destroy(); panel->Destroy();
panel = nullptr;
panel = NULL; }
} }
void GameArea::DelBorder() void GameArea::DelBorder()
@ -721,10 +722,10 @@ void GameArea::DelBorder()
wxGetApp().frame->Fit(); wxGetApp().frame->Fit();
GetSizer()->Detach(panel->GetWindow()); GetSizer()->Detach(panel->GetWindow());
if (panel) if (panel) {
panel->Destroy(); panel->Destroy();
panel = nullptr;
panel = NULL; }
} }
void GameArea::AdjustMinSize() void GameArea::AdjustMinSize()
@ -802,7 +803,7 @@ void GameArea::ShowFullScreen(bool full)
// delete panel to be recreated immediately after resize // delete panel to be recreated immediately after resize
if (panel) { if (panel) {
panel->Destroy(); panel->Destroy();
panel = NULL; panel = nullptr;
} }
// Windows does not restore old window size/pos // Windows does not restore old window size/pos
@ -1067,6 +1068,10 @@ void GameArea::OnIdle(wxIdleEvent& event)
w->SetBackgroundStyle(wxBG_STYLE_CUSTOM); w->SetBackgroundStyle(wxBG_STYLE_CUSTOM);
w->SetSize(wxSize(basic_width, basic_height)); w->SetSize(wxSize(basic_width, basic_height));
// Allow input while on background
if (allowKeyboardBackgroundInput)
enableKeyboardBackgroundInput(w);
if (maxScale) if (maxScale)
w->SetMaxSize(wxSize(basic_width * maxScale, w->SetMaxSize(wxSize(basic_width * maxScale,
basic_height * maxScale)); basic_height * maxScale));
@ -2060,6 +2065,8 @@ DrawingPanelBase::~DrawingPanelBase()
delete[] threads; delete[] threads;
} }
disableKeyboardBackgroundInput();
} }
BasicDrawingPanel::BasicDrawingPanel(wxWindow* parent, int _width, int _height) BasicDrawingPanel::BasicDrawingPanel(wxWindow* parent, int _width, int _height)

View File

@ -45,8 +45,10 @@ void wxSDLJoy::CreateAndSendEvent(wxEvtHandler* handler, unsigned short joy, uns
{ {
if (!handler) { if (!handler) {
GameArea *panel = wxGetApp().frame->GetPanel(); GameArea *panel = wxGetApp().frame->GetPanel();
if (panel) handler = panel->GetEventHandler(); if (panel && allowJoystickBackgroundInput)
else return; handler = panel->GetEventHandler();
else
return;
} }
wxSDLJoyEvent *ev = new wxSDLJoyEvent(wxEVT_SDLJOY); wxSDLJoyEvent *ev = new wxSDLJoyEvent(wxEVT_SDLJOY);

View File

@ -426,6 +426,14 @@
<object class="wxMenuItem" name="JoypadConfigure"> <object class="wxMenuItem" name="JoypadConfigure">
<label>_Configure ...</label> <label>_Configure ...</label>
</object> </object>
<object class="wxMenuItem" name="AllowKeyboardBackgroundInput">
<label>Allow _keyboard background input</label>
<checkable>1</checkable>
</object>
<object class="wxMenuItem" name="AllowJoystickBackgroundInput">
<label>Allow _joystick background input</label>
<checkable>1</checkable>
</object>
<object class="separator"/> <object class="separator"/>
<object class="wxMenu"> <object class="wxMenu">
<label>_Autofire</label> <label>_Autofire</label>