gui: close dialogs/frames on Esc, add Ctrl+Q exit shortcut

Several of Cemu's settings dialogs (GeneralSettings2, InputSettings2,
GraphicPacksWindow2, ...) and most of its tool wxFrames have no
Cancel/Close/OK button. On a Wayland compositor that doesn't draw
server-side decorations there is also no compositor-drawn close button,
so once opened these windows cannot be dismissed.

wxDialog's built-in Esc handling (wxDialogBase::OnCharHook in
src/common/dlgcmn.cpp) forwards Esc to a button with wxID_CANCEL or
the affirmative-id button via EmulateButtonClickIfPresent; with
neither button present, SendCloseButtonClickEvent returns false and
the handler just Skip()s. wxFrame has no Esc handling at all (the
event table in src/common/framecmn.cpp only carries menu-open/close
entries).

Add wxHelper::BindEscapeCloses(target), a one-liner that binds
WXK_ESCAPE on wxEVT_CHAR_HOOK to target->Close(). Close() goes
through the wxEVT_CLOSE_WINDOW path, where wxDialogBase::OnCloseWindow
does fall back to EndDialog(wxID_CANCEL) when no Cancel/OK button
is found - so the helper closes buttonless dialogs correctly. Apply
as the first statement of every wxDialog and wxFrame ctor in
src/gui/wxgui/, except:
  - MainWindow: Esc shouldn't quit Cemu.
  - PadViewFrame: already binds Esc to leave fullscreen.
  - HotkeySettings: inline variant guarded by !m_activeInputButton
    so an in-progress keyboard capture (whose cancel path is
    OnKeyUp + IsValidKeycodeUp rejecting WXK_ESCAPE) still wins.

Tag the File>Exit menu item label with "\tCtrl+Q"; wxMenuItemBase::
GetAccel() parses everything after the tab via wxAcceleratorEntry::
Create and wxMenuBar registers it as an accelerator.
This commit is contained in:
Jakob Linke 2026-05-23 07:34:16 +02:00
parent dfb9a99c3e
commit ed4213a3be
33 changed files with 114 additions and 1 deletions

View File

@ -3,6 +3,7 @@
#include "Cafe/OS/libs/snd_core/ax.h" #include "Cafe/OS/libs/snd_core/ax.h"
#include "Cafe/OS/libs/snd_core/ax_internal.h" #include "Cafe/OS/libs/snd_core/ax_internal.h"
#include "wxgui/helpers/wxHelpers.h"
enum enum
{ {
@ -24,6 +25,8 @@ wxEND_EVENT_TABLE()
AudioDebuggerWindow::AudioDebuggerWindow(wxFrame& parent) AudioDebuggerWindow::AudioDebuggerWindow(wxFrame& parent)
: wxFrame(&parent, wxID_ANY, _("AX voice viewer"), wxDefaultPosition, wxSize(1126, 580), wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER) : wxFrame(&parent, wxID_ANY, _("AX voice viewer"), wxDefaultPosition, wxSize(1126, 580), wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER)
{ {
wxHelper::BindEscapeCloses(this);
wxPanel* mainPane = new wxPanel(this); wxPanel* mainPane = new wxPanel(this);
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);

View File

@ -21,6 +21,7 @@
#include <curl/curl.h> #include <curl/curl.h>
#include <zip.h> #include <zip.h>
#include <boost/tokenizer.hpp> #include <boost/tokenizer.hpp>
#include "wxgui/helpers/wxHelpers.h"
wxDECLARE_EVENT(wxEVT_RESULT, wxCommandEvent); wxDECLARE_EVENT(wxEVT_RESULT, wxCommandEvent);
@ -33,6 +34,8 @@ CemuUpdateWindow::CemuUpdateWindow(wxWindow* parent)
: wxDialog(parent, wxID_ANY, _("Cemu update"), wxDefaultPosition, wxDefaultSize, : wxDialog(parent, wxID_ANY, _("Cemu update"), wxDefaultPosition, wxDefaultSize,
wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX) wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX)
{ {
wxHelper::BindEscapeCloses(this);
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);
m_gauge = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(500, 20), wxGA_HORIZONTAL); m_gauge = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(500, 20), wxGA_HORIZONTAL);
m_gauge->SetValue(0); m_gauge->SetValue(0);

View File

@ -85,6 +85,8 @@ ChecksumTool::ChecksumTool(wxWindow* parent, wxTitleManagerList::TitleEntry& ent
formatWxString(_("Title checksum of {:08x}-{:08x}"), (uint32) (entry.title_id >> 32), (uint32) (entry.title_id & 0xFFFFFFFF)), formatWxString(_("Title checksum of {:08x}-{:08x}"), (uint32) (entry.title_id >> 32), (uint32) (entry.title_id & 0xFFFFFFFF)),
wxDefaultPosition, wxDefaultSize, wxCAPTION | wxFRAME_TOOL_WINDOW | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX), m_entry(entry) wxDefaultPosition, wxDefaultSize, wxCAPTION | wxFRAME_TOOL_WINDOW | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX), m_entry(entry)
{ {
wxHelper::BindEscapeCloses(this);
m_info = CafeTitleList::GetTitleInfoByUID(m_entry.location_uid); m_info = CafeTitleList::GetTitleInfoByUID(m_entry.location_uid);
if (!m_info.IsValid()) if (!m_info.IsValid())

View File

@ -16,6 +16,7 @@
#include <curl/curl.h> #include <curl/curl.h>
#include <zip.h> #include <zip.h>
#include "wxgui/helpers/wxHelpers.h"
static size_t curlDownloadFile_writeData(void *ptr, size_t size, size_t nmemb, DownloadCustomGraphicPackWindow::curlDownloadFileState_t* downloadState) static size_t curlDownloadFile_writeData(void *ptr, size_t size, size_t nmemb, DownloadCustomGraphicPackWindow::curlDownloadFileState_t* downloadState)
{ {
@ -67,6 +68,8 @@ DownloadCustomGraphicPackWindow::DownloadCustomGraphicPackWindow(wxWindow* paren
: wxDialog(parent, wxID_ANY, _("Download Graphic Pack from URL"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX), : wxDialog(parent, wxID_ANY, _("Download Graphic Pack from URL"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX),
m_stage(StageDone), m_currentStage(StageDone) m_stage(StageDone), m_currentStage(StageDone)
{ {
wxHelper::BindEscapeCloses(this);
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);
m_urlField = new wxTextCtrl(this, wxID_ANY, wxEmptyString); m_urlField = new wxTextCtrl(this, wxID_ANY, wxEmptyString);

View File

@ -11,6 +11,7 @@
#include "Common/FileStream.h" #include "Common/FileStream.h"
#include "Cafe/CafeSystem.h" #include "Cafe/CafeSystem.h"
#include "wxgui/helpers/wxHelpers.h"
struct DownloadGraphicPacksWindow::curlDownloadFileState_t struct DownloadGraphicPacksWindow::curlDownloadFileState_t
{ {
@ -294,6 +295,8 @@ DownloadGraphicPacksWindow::DownloadGraphicPacksWindow(wxWindow* parent)
: wxDialog(parent, wxID_ANY, _("Checking version..."), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX), : wxDialog(parent, wxID_ANY, _("Checking version..."), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX),
m_threadState(ThreadRunning), m_stage(StageCheckVersion), m_currentStage(StageCheckVersion) m_threadState(ThreadRunning), m_stage(StageCheckVersion), m_currentStage(StageCheckVersion)
{ {
wxHelper::BindEscapeCloses(this);
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);
m_processBar = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(500, 20), wxGA_HORIZONTAL); m_processBar = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(500, 20), wxGA_HORIZONTAL);

View File

@ -37,6 +37,8 @@ EmulatedUSBDeviceFrame::EmulatedUSBDeviceFrame(wxWindow* parent)
: wxFrame(parent, wxID_ANY, _("Emulated USB Devices"), wxDefaultPosition, : wxFrame(parent, wxID_ANY, _("Emulated USB Devices"), wxDefaultPosition,
wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL) wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL)
{ {
wxHelper::BindEscapeCloses(this);
SetIcon(wxICON(X_BOX)); SetIcon(wxICON(X_BOX));
auto& config = GetConfig(); auto& config = GetConfig();
@ -330,6 +332,8 @@ void EmulatedUSBDeviceFrame::ClearSkylander(uint8 slot)
CreateSkylanderDialog::CreateSkylanderDialog(wxWindow* parent, uint8 slot) CreateSkylanderDialog::CreateSkylanderDialog(wxWindow* parent, uint8 slot)
: wxDialog(parent, wxID_ANY, _("Skylander Figure Creator"), wxDefaultPosition, wxSize(500, 150)) : wxDialog(parent, wxID_ANY, _("Skylander Figure Creator"), wxDefaultPosition, wxSize(500, 150))
{ {
wxHelper::BindEscapeCloses(this);
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);
auto* comboRow = new wxBoxSizer(wxHORIZONTAL); auto* comboRow = new wxBoxSizer(wxHORIZONTAL);
@ -511,6 +515,8 @@ void EmulatedUSBDeviceFrame::ClearFigure(uint8 slot)
CreateInfinityFigureDialog::CreateInfinityFigureDialog(wxWindow* parent, uint8 slot) CreateInfinityFigureDialog::CreateInfinityFigureDialog(wxWindow* parent, uint8 slot)
: wxDialog(parent, wxID_ANY, _("Infinity Figure Creator"), wxDefaultPosition, wxSize(500, 150)) : wxDialog(parent, wxID_ANY, _("Infinity Figure Creator"), wxDefaultPosition, wxSize(500, 150))
{ {
wxHelper::BindEscapeCloses(this);
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);
auto* comboRow = new wxBoxSizer(wxHORIZONTAL); auto* comboRow = new wxBoxSizer(wxHORIZONTAL);
@ -686,6 +692,8 @@ void EmulatedUSBDeviceFrame::MoveMinifig(uint8 pad, uint8 index)
CreateDimensionFigureDialog::CreateDimensionFigureDialog(wxWindow* parent) CreateDimensionFigureDialog::CreateDimensionFigureDialog(wxWindow* parent)
: wxDialog(parent, wxID_ANY, _("Dimensions Figure Creator"), wxDefaultPosition, wxSize(500, 200)) : wxDialog(parent, wxID_ANY, _("Dimensions Figure Creator"), wxDefaultPosition, wxSize(500, 200))
{ {
wxHelper::BindEscapeCloses(this);
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);
auto* comboRow = new wxBoxSizer(wxHORIZONTAL); auto* comboRow = new wxBoxSizer(wxHORIZONTAL);
@ -774,6 +782,8 @@ wxString CreateDimensionFigureDialog::GetFilePath() const
MoveDimensionFigureDialog::MoveDimensionFigureDialog(EmulatedUSBDeviceFrame* parent, uint8 currentIndex) MoveDimensionFigureDialog::MoveDimensionFigureDialog(EmulatedUSBDeviceFrame* parent, uint8 currentIndex)
: wxDialog(parent, wxID_ANY, _("Dimensions Figure Mover"), wxDefaultPosition, wxSize(700, 300)) : wxDialog(parent, wxID_ANY, _("Dimensions Figure Mover"), wxDefaultPosition, wxSize(700, 300))
{ {
wxHelper::BindEscapeCloses(this);
auto* sizer = new wxGridSizer(2, 5, 10, 10); auto* sizer = new wxGridSizer(2, 5, 10, 10);
std::array<std::optional<uint32>, 7> ids = parent->GetCurrentMinifigs(); std::array<std::optional<uint32>, 7> ids = parent->GetCurrentMinifigs();

View File

@ -18,6 +18,8 @@
GameProfileWindow::GameProfileWindow(wxWindow* parent, uint64_t title_id) GameProfileWindow::GameProfileWindow(wxWindow* parent, uint64_t title_id)
: wxFrame(parent, wxID_ANY, _("Edit game profile"), wxDefaultPosition, wxSize{ 390, 350 }, wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER | wxTAB_TRAVERSAL | wxSYSTEM_MENU), m_title_id(title_id) : wxFrame(parent, wxID_ANY, _("Edit game profile"), wxDefaultPosition, wxSize{ 390, 350 }, wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER | wxTAB_TRAVERSAL | wxSYSTEM_MENU), m_title_id(title_id)
{ {
wxHelper::BindEscapeCloses(this);
SetIcon(wxICON(X_GAME_PROFILE)); SetIcon(wxICON(X_GAME_PROFILE));
m_game_profile.Reset(); m_game_profile.Reset();

View File

@ -138,6 +138,8 @@ GameUpdateWindow::GameUpdateWindow(wxWindow& parent, const fs::path& filePath)
: wxDialog(&parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX), : wxDialog(&parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX),
m_thread_state(ThreadRunning) m_thread_state(ThreadRunning)
{ {
wxHelper::BindEscapeCloses(this);
try try
{ {
#if BOOST_OS_WINDOWS #if BOOST_OS_WINDOWS

View File

@ -1079,6 +1079,8 @@ wxPanel* GeneralSettings2::AddDebugPage(wxNotebook* notebook)
GeneralSettings2::GeneralSettings2(wxWindow* parent, bool game_launched) GeneralSettings2::GeneralSettings2(wxWindow* parent, bool game_launched)
: wxDialog(parent, wxID_ANY, _("General settings"), wxDefaultPosition, wxDefaultSize, wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER), m_game_launched(game_launched) : wxDialog(parent, wxID_ANY, _("General settings"), wxDefaultPosition, wxDefaultSize, wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER), m_game_launched(game_launched)
{ {
wxHelper::BindEscapeCloses(this);
SetIcon(wxICON(X_SETTINGS)); SetIcon(wxICON(X_SETTINGS));
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);

View File

@ -22,6 +22,7 @@
#endif #endif
#include "wxHelper.h" #include "wxHelper.h"
#include "wxgui/helpers/wxHelpers.h"
wxDEFINE_EVENT(EVT_REFRESH_FIRST_PAGE, wxCommandEvent); // used to refresh the first page after the language change wxDEFINE_EVENT(EVT_REFRESH_FIRST_PAGE, wxCommandEvent); // used to refresh the first page after the language change
@ -247,6 +248,8 @@ void GettingStartedDialog::OnClose(wxCloseEvent& event)
GettingStartedDialog::GettingStartedDialog(wxWindow* parent) GettingStartedDialog::GettingStartedDialog(wxWindow* parent)
: wxDialog(parent, wxID_ANY, _("Getting started"), wxDefaultPosition, { 740,530 }, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) : wxDialog(parent, wxID_ANY, _("Getting started"), wxDefaultPosition, { 740,530 }, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{ {
wxHelper::BindEscapeCloses(this);
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);
m_notebook = new wxSimplebook(this, wxID_ANY); m_notebook = new wxSimplebook(this, wxID_ANY);

View File

@ -198,6 +198,8 @@ GraphicPacksWindow2::GraphicPacksWindow2(wxWindow* parent, uint64_t title_id_fil
: wxDialog(parent, wxID_ANY, _("Graphic packs"), wxDefaultPosition, wxSize(1000,670), wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER), : wxDialog(parent, wxID_ANY, _("Graphic packs"), wxDefaultPosition, wxSize(1000,670), wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER),
m_installed_games(CafeTitleList::GetAllTitleIds()) m_installed_games(CafeTitleList::GetAllTitleIds())
{ {
wxHelper::BindEscapeCloses(this);
if (title_id_filter != 0) if (title_id_filter != 0)
m_filter = fmt::format("{:x}", title_id_filter); m_filter = fmt::format("{:x}", title_id_filter);

View File

@ -6,12 +6,15 @@
#include <wx/sizer.h> #include <wx/sizer.h>
#include <wx/stattext.h> #include <wx/stattext.h>
#include <wx/wupdlock.h> #include <wx/wupdlock.h>
#include "wxgui/helpers/wxHelpers.h"
wxDEFINE_EVENT(EVT_LOG, wxLogEvent); wxDEFINE_EVENT(EVT_LOG, wxLogEvent);
LoggingWindow::LoggingWindow(wxFrame* parent) LoggingWindow::LoggingWindow(wxFrame* parent)
: wxFrame(parent, wxID_ANY, _("Logging window"), wxDefaultPosition, wxSize(800, 600), wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL) : wxFrame(parent, wxID_ANY, _("Logging window"), wxDefaultPosition, wxSize(800, 600), wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL)
{ {
wxHelper::BindEscapeCloses(this);
auto* sizer = new wxBoxSizer( wxVERTICAL ); auto* sizer = new wxBoxSizer( wxVERTICAL );
{ {
auto filter_row = new wxBoxSizer( wxHORIZONTAL ); auto filter_row = new wxBoxSizer( wxHORIZONTAL );

View File

@ -1896,6 +1896,7 @@ public:
CemuAboutDialog(wxWindow* parent = NULL) CemuAboutDialog(wxWindow* parent = NULL)
: wxDialog(NULL, wxID_ANY, _("About Cemu"), wxDefaultPosition, wxSize(500, 700)) : wxDialog(NULL, wxID_ANY, _("About Cemu"), wxDefaultPosition, wxSize(500, 700))
{ {
wxHelper::BindEscapeCloses(this);
Create(parent); Create(parent);
} }
@ -2207,7 +2208,7 @@ void MainWindow::RecreateMenu()
if (m_game_launched) if (m_game_launched)
m_fileMenu->Enable(MAINFRAME_MENU_ID_FILE_CLEAR_SPOTPASS_CACHE, false); m_fileMenu->Enable(MAINFRAME_MENU_ID_FILE_CLEAR_SPOTPASS_CACHE, false);
m_fileMenu->AppendSeparator(); m_fileMenu->AppendSeparator();
m_exitMenuItem = m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_EXIT, _("&Exit")); m_exitMenuItem = m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_EXIT, _("&Exit\tCtrl+Q"));
m_menuBar->Append(m_fileMenu, _("&File")); m_menuBar->Append(m_fileMenu, _("&File"));
// options->account submenu // options->account submenu
m_optionsAccountMenu = new wxMenu(); m_optionsAccountMenu = new wxMenu();

View File

@ -50,6 +50,8 @@ const wxString kDataTypeNames[] = {kDatatypeFloat,kDatatypeDouble,/*DATATYPE_STR
MemorySearcherTool::MemorySearcherTool(wxFrame* parent) MemorySearcherTool::MemorySearcherTool(wxFrame* parent)
: wxFrame(parent, wxID_ANY, _("Memory Searcher"), wxDefaultPosition, wxSize(600, 540), wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL) : wxFrame(parent, wxID_ANY, _("Memory Searcher"), wxDefaultPosition, wxSize(600, 540), wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL)
{ {
wxHelper::BindEscapeCloses(this);
this->SetSizeHints(wxDefaultSize, wxDefaultSize); this->SetSizeHints(wxDefaultSize, wxDefaultSize);
this->wxTopLevelWindowBase::SetMinSize(wxSize(600, 540)); this->wxTopLevelWindowBase::SetMinSize(wxSize(600, 540));

View File

@ -233,6 +233,8 @@ wxPanel* TitleManager::CreateDownloadManagerPage()
TitleManager::TitleManager(wxWindow* parent, TitleManagerPage default_page) TitleManager::TitleManager(wxWindow* parent, TitleManagerPage default_page)
: wxFrame(parent, wxID_ANY, _("Title Manager"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL) : wxFrame(parent, wxID_ANY, _("Title Manager"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL)
{ {
wxHelper::BindEscapeCloses(this);
SetIcon(wxICON(X_BOX)); SetIcon(wxICON(X_BOX));
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);

View File

@ -7,6 +7,7 @@
#include "Cafe/HW/Espresso/Debugger/Debugger.h" #include "Cafe/HW/Espresso/Debugger/Debugger.h"
#include "Cemu/ExpressionParser/ExpressionParser.h" #include "Cemu/ExpressionParser/ExpressionParser.h"
#include "wxgui/helpers/wxHelpers.h"
enum enum
{ {
@ -28,6 +29,8 @@ enum ItemColumns
BreakpointWindow::BreakpointWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size) BreakpointWindow::BreakpointWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size)
: wxFrame(&parent, wxID_ANY, _("Breakpoints"), wxDefaultPosition, wxSize(420, 250), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT) : wxFrame(&parent, wxID_ANY, _("Breakpoints"), wxDefaultPosition, wxSize(420, 250), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT)
{ {
wxHelper::BindEscapeCloses(this);
this->SetSizeHints(wxDefaultSize, wxDefaultSize); this->SetSizeHints(wxDefaultSize, wxDefaultSize);
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);

View File

@ -26,6 +26,7 @@
#include "Cemu/Logging/CemuLogging.h" #include "Cemu/Logging/CemuLogging.h"
#include "resource/embedded/resources.h" #include "resource/embedded/resources.h"
#include "wxgui/helpers/wxHelpers.h"
enum enum
{ {
@ -421,6 +422,8 @@ DebuggerWindow2::DebuggerWindow2(wxFrame& parent, const wxRect& display_size)
: wxFrame(&parent, wxID_ANY, _("PPC Debugger"), wxDefaultPosition, wxSize(1280, 300), wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT), : wxFrame(&parent, wxID_ANY, _("PPC Debugger"), wxDefaultPosition, wxSize(1280, 300), wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT),
m_module_address(0) m_module_address(0)
{ {
wxHelper::BindEscapeCloses(this);
g_debuggerDispatcher.SetDebuggerCallbacks(this); g_debuggerDispatcher.SetDebuggerCallbacks(this);
const auto file = ActiveSettings::GetConfigPath("debugger/config.xml"); const auto file = ActiveSettings::GetConfigPath("debugger/config.xml");

View File

@ -4,6 +4,7 @@
#include "wxgui/debugger/DebuggerWindow2.h" #include "wxgui/debugger/DebuggerWindow2.h"
#include "Cafe/HW/Espresso/Debugger/Debugger.h" #include "Cafe/HW/Espresso/Debugger/Debugger.h"
#include "wxgui/debugger/DumpCtrl.h" #include "wxgui/debugger/DumpCtrl.h"
#include "wxgui/helpers/wxHelpers.h"
enum enum
{ {
@ -17,6 +18,8 @@ enum
DumpWindow::DumpWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size) DumpWindow::DumpWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size)
: wxFrame(&parent, wxID_ANY, _("Memory Dump"), wxDefaultPosition, wxSize(600, 250), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT) : wxFrame(&parent, wxID_ANY, _("Memory Dump"), wxDefaultPosition, wxSize(600, 250), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT)
{ {
wxHelper::BindEscapeCloses(this);
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
m_dump_ctrl = new DumpCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxScrolledWindowStyle); m_dump_ctrl = new DumpCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxScrolledWindowStyle);
main_sizer->Add(m_dump_ctrl, 1, wxEXPAND); main_sizer->Add(m_dump_ctrl, 1, wxEXPAND);

View File

@ -10,6 +10,7 @@
#include "Cafe/OS/RPL/rpl_structs.h" #include "Cafe/OS/RPL/rpl_structs.h"
#include "Cafe/GraphicPack/GraphicPack2.h" #include "Cafe/GraphicPack/GraphicPack2.h"
#include "wxgui/helpers/wxHelpers.h"
enum ItemColumns enum ItemColumns
{ {
@ -21,6 +22,8 @@ enum ItemColumns
ModuleWindow::ModuleWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size) ModuleWindow::ModuleWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size)
: wxFrame(&parent, wxID_ANY, _("Modules"), wxDefaultPosition, wxSize(420, 250), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT) : wxFrame(&parent, wxID_ANY, _("Modules"), wxDefaultPosition, wxSize(420, 250), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT)
{ {
wxHelper::BindEscapeCloses(this);
this->SetSizeHints(wxDefaultSize, wxDefaultSize); this->SetSizeHints(wxDefaultSize, wxDefaultSize);
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);

View File

@ -8,6 +8,7 @@
#include "Cafe/OS/RPL/rpl.h" #include "Cafe/OS/RPL/rpl.h"
#include "Cafe/OS/RPL/rpl_structs.h" #include "Cafe/OS/RPL/rpl_structs.h"
#include "Cafe/HW/Espresso/EspressoISA.h" #include "Cafe/HW/Espresso/EspressoISA.h"
#include "wxgui/helpers/wxHelpers.h"
enum enum
{ {
@ -31,6 +32,8 @@ RegisterWindow::RegisterWindow(DebuggerWindow2& parent, const wxPoint& main_posi
: wxFrame(&parent, wxID_ANY, _("Registers"), wxDefaultPosition, wxSize(400, 975), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT), : wxFrame(&parent, wxID_ANY, _("Registers"), wxDefaultPosition, wxSize(400, 975), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT),
m_prev_snapshot({}), m_show_double_values(true), m_context_ctrl(nullptr) m_prev_snapshot({}), m_show_double_values(true), m_context_ctrl(nullptr)
{ {
wxHelper::BindEscapeCloses(this);
SetSizeHints(wxDefaultSize, wxDefaultSize); SetSizeHints(wxDefaultSize, wxDefaultSize);
SetMaxSize({ 400, 975 }); SetMaxSize({ 400, 975 });
this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));

View File

@ -3,6 +3,7 @@
#include "wxgui/debugger/DebuggerWindow2.h" #include "wxgui/debugger/DebuggerWindow2.h"
#include "Cafe/HW/Espresso/Debugger/Debugger.h" #include "Cafe/HW/Espresso/Debugger/Debugger.h"
#include "Cafe/OS/RPL/rpl_symbol_storage.h" #include "Cafe/OS/RPL/rpl_symbol_storage.h"
#include "wxgui/helpers/wxHelpers.h"
enum ItemColumns enum ItemColumns
{ {
@ -14,6 +15,8 @@ enum ItemColumns
SymbolWindow::SymbolWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size) SymbolWindow::SymbolWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size)
: wxFrame(&parent, wxID_ANY, _("Symbols"), wxDefaultPosition, wxSize(600, 250), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT) : wxFrame(&parent, wxID_ANY, _("Symbols"), wxDefaultPosition, wxSize(600, 250), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT)
{ {
wxHelper::BindEscapeCloses(this);
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
m_symbol_ctrl = new SymbolListCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize); m_symbol_ctrl = new SymbolListCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
main_sizer->Add(m_symbol_ctrl, 1, wxEXPAND); main_sizer->Add(m_symbol_ctrl, 1, wxEXPAND);

View File

@ -13,6 +13,8 @@
wxCreateAccountDialog::wxCreateAccountDialog(wxWindow* parent) wxCreateAccountDialog::wxCreateAccountDialog(wxWindow* parent)
: wxDialog(parent, wxID_ANY, _("Create new account")) : wxDialog(parent, wxID_ANY, _("Create new account"))
{ {
wxHelper::BindEscapeCloses(this);
auto* main_sizer = new wxFlexGridSizer(0, 2, 0, 0); auto* main_sizer = new wxFlexGridSizer(0, 2, 0, 0);
main_sizer->AddGrowableCol(1); main_sizer->AddGrowableCol(1);
main_sizer->SetFlexibleDirection(wxBOTH); main_sizer->SetFlexibleDirection(wxBOTH);

View File

@ -22,6 +22,8 @@ SaveImportWindow::SaveImportWindow(wxWindow* parent, uint64 title_id)
: wxDialog(parent, wxID_ANY, _("Import save entry"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxFRAME_TOOL_WINDOW | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX), : wxDialog(parent, wxID_ANY, _("Import save entry"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxFRAME_TOOL_WINDOW | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX),
m_title_id(title_id) m_title_id(title_id)
{ {
wxHelper::BindEscapeCloses(this);
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);
{ {

View File

@ -18,6 +18,8 @@ SaveTransfer::SaveTransfer(wxWindow* parent, uint64 title_id, const wxString& so
: wxDialog(parent, wxID_ANY, _("Save transfer"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxFRAME_TOOL_WINDOW | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX), : wxDialog(parent, wxID_ANY, _("Save transfer"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxFRAME_TOOL_WINDOW | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX),
m_title_id(title_id), m_source_id(source_id) m_title_id(title_id), m_source_id(source_id)
{ {
wxHelper::BindEscapeCloses(this);
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);
{ {

View File

@ -2,8 +2,27 @@
#include "interface/WindowSystem.h" #include "interface/WindowSystem.h"
#include <wx/control.h> #include <wx/control.h>
#include <wx/event.h>
#include <wx/listbase.h> #include <wx/listbase.h>
#include <wx/string.h> #include <wx/string.h>
#include <wx/window.h>
namespace wxHelper
{
// Use CHAR_HOOK rather than wxDialog::SetEscapeId so the key is caught
// before a focused child control (notebook, combobox, ...) can consume it.
inline void BindEscapeCloses(wxWindow* target)
{
target->Bind(wxEVT_CHAR_HOOK, [target](wxKeyEvent& event) {
if (event.GetKeyCode() == WXK_ESCAPE)
{
target->Close();
return;
}
event.Skip();
});
}
}
template <> template <>
struct fmt::formatter<wxString> : formatter<string_view> struct fmt::formatter<wxString> : formatter<string_view>

View File

@ -135,6 +135,17 @@ struct HotkeyEntry
HotkeySettings::HotkeySettings(wxWindow* parent) HotkeySettings::HotkeySettings(wxWindow* parent)
: wxFrame(parent, wxID_ANY, _("Hotkey Settings")) : wxFrame(parent, wxID_ANY, _("Hotkey Settings"))
{ {
// Esc closes the window, but yield to in-progress key capture so its own
// cancel path (OnKeyUp -> IsValidKeycodeUp rejects WXK_ESCAPE) still runs.
Bind(wxEVT_CHAR_HOOK, [this](wxKeyEvent& event) {
if (event.GetKeyCode() == WXK_ESCAPE && !m_activeInputButton)
{
Close();
return;
}
event.Skip();
});
SetIcon(wxICON(X_HOTKEY_SETTINGS)); SetIcon(wxICON(X_HOTKEY_SETTINGS));
m_sizer = new wxFlexGridSizer(0, 3, 5, 5); m_sizer = new wxFlexGridSizer(0, 3, 5, 5);

View File

@ -25,6 +25,8 @@ InputAPIAddWindow::InputAPIAddWindow(wxWindow* parent, const wxPoint& position,
const std::vector<ControllerPtr>& controllers) const std::vector<ControllerPtr>& controllers)
: wxDialog(parent, wxID_ANY, "Add input API", position, wxDefaultSize, wxCAPTION), m_controllers(controllers) : wxDialog(parent, wxID_ANY, "Add input API", position, wxDefaultSize, wxCAPTION), m_controllers(controllers)
{ {
wxHelper::BindEscapeCloses(this);
this->SetSizeHints(wxDefaultSize, wxDefaultSize); this->SetSizeHints(wxDefaultSize, wxDefaultSize);
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);

View File

@ -69,6 +69,8 @@ using wxControllerPageData = wxCustomData<ControllerPage>;
InputSettings2::InputSettings2(wxWindow* parent) InputSettings2::InputSettings2(wxWindow* parent)
: wxDialog(parent, wxID_ANY, _("Input settings")) : wxDialog(parent, wxID_ANY, _("Input settings"))
{ {
wxHelper::BindEscapeCloses(this);
this->SetSizeHints(wxDefaultSize, wxDefaultSize); this->SetSizeHints(wxDefaultSize, wxDefaultSize);
g_inputConfigWindowHasFocus = true; g_inputConfigWindowHasFocus = true;

View File

@ -9,6 +9,7 @@
#include <bluetooth/hci.h> #include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h> #include <bluetooth/hci_lib.h>
#include <input/api/Wiimote/l2cap/L2CapWiimote.h> #include <input/api/Wiimote/l2cap/L2CapWiimote.h>
#include "wxgui/helpers/wxHelpers.h"
#endif #endif
wxDECLARE_EVENT(wxEVT_PROGRESS_PAIR, wxCommandEvent); wxDECLARE_EVENT(wxEVT_PROGRESS_PAIR, wxCommandEvent);
@ -17,6 +18,8 @@ wxDEFINE_EVENT(wxEVT_PROGRESS_PAIR, wxCommandEvent);
PairingDialog::PairingDialog(wxWindow* parent) PairingDialog::PairingDialog(wxWindow* parent)
: wxDialog(parent, wxID_ANY, _("Pairing..."), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX) : wxDialog(parent, wxID_ANY, _("Pairing..."), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX)
{ {
wxHelper::BindEscapeCloses(this);
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);
m_gauge = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(350, 20), wxGA_HORIZONTAL); m_gauge = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(350, 20), wxGA_HORIZONTAL);
m_gauge->SetValue(0); m_gauge->SetValue(0);

View File

@ -19,6 +19,8 @@ DefaultControllerSettings::DefaultControllerSettings(wxWindow* parent, const wxP
: wxDialog(parent, wxID_ANY, _("Controller settings"), position, wxDefaultSize, : wxDialog(parent, wxID_ANY, _("Controller settings"), position, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE), m_controller(std::move(controller)) wxDEFAULT_DIALOG_STYLE), m_controller(std::move(controller))
{ {
wxHelper::BindEscapeCloses(this);
m_settings = m_controller->get_settings(); m_settings = m_controller->get_settings();
m_rumble_backup = m_settings.rumble; m_rumble_backup = m_settings.rumble;

View File

@ -20,6 +20,8 @@ WiimoteControllerSettings::WiimoteControllerSettings(wxWindow* parent, const wxP
: wxDialog(parent, wxID_ANY, _("Controller settings"), position, wxDefaultSize, : wxDialog(parent, wxID_ANY, _("Controller settings"), position, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE), m_controller(std::move(controller)) wxDEFAULT_DIALOG_STYLE), m_controller(std::move(controller))
{ {
wxHelper::BindEscapeCloses(this);
m_settings = m_controller->get_settings(); m_settings = m_controller->get_settings();
m_rumble_backup = m_settings.rumble; m_rumble_backup = m_settings.rumble;
m_packet_delay_backup = m_controller->get_packet_delay(); m_packet_delay_backup = m_controller->get_packet_delay();

View File

@ -40,6 +40,8 @@ wxBEGIN_EVENT_TABLE(DebugPPCThreadsWindow, wxFrame)
: wxFrame(&parent, wxID_ANY, _("PPC threads"), wxDefaultPosition, wxSize(930, 280), : wxFrame(&parent, wxID_ANY, _("PPC threads"), wxDefaultPosition, wxSize(930, 280),
wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER) wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER)
{ {
wxHelper::BindEscapeCloses(this);
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);
m_thread_list = new wxListView(this, GPLIST_ID, wxPoint(0, 0), wxSize(930, 240), wxLC_REPORT); m_thread_list = new wxListView(this, GPLIST_ID, wxPoint(0, 0), wxSize(930, 240), wxLC_REPORT);

View File

@ -2,6 +2,7 @@
#include "wxHelper.h" #include "wxHelper.h"
#include "TextureRelationWindow.h" #include "TextureRelationWindow.h"
#include "Cafe/HW/Latte/Core/LatteTexture.h" #include "Cafe/HW/Latte/Core/LatteTexture.h"
#include "wxgui/helpers/wxHelpers.h"
enum enum
{ {
@ -37,6 +38,8 @@ void openTextureViewer(wxFrame& parentFrame)
TextureRelationViewerWindow::TextureRelationViewerWindow(wxFrame& parent) TextureRelationViewerWindow::TextureRelationViewerWindow(wxFrame& parent)
: wxFrame(&parent, wxID_ANY, _("Texture cache"), wxDefaultPosition, wxSize(1000, 480), wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER) : wxFrame(&parent, wxID_ANY, _("Texture cache"), wxDefaultPosition, wxSize(1000, 480), wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER)
{ {
wxHelper::BindEscapeCloses(this);
isTextureViewerOpen = true; isTextureViewerOpen = true;
this->showOnlyActive = false; this->showOnlyActive = false;