mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-06-04 13:45:00 -06:00
UI: Small adjustments and cleanup, end emulation hotkey for debug builds (#1754)
This commit is contained in:
parent
13c6d497a0
commit
13683d417c
@ -219,14 +219,14 @@ wxPanel* GeneralSettings2::AddGeneralPage(wxNotebook* notebook)
|
|||||||
#ifndef ENABLE_DISCORD_RPC
|
#ifndef ENABLE_DISCORD_RPC
|
||||||
m_discord_presence->Disable();
|
m_discord_presence->Disable();
|
||||||
#endif
|
#endif
|
||||||
//third_row->AddSpacer(10);
|
// third_row->AddSpacer(10);
|
||||||
m_fullscreen_menubar = new wxCheckBox(box, wxID_ANY, _("Fullscreen menu bar"));
|
m_fullscreen_menubar = new wxCheckBox(box, wxID_ANY, _("Fullscreen menu bar"));
|
||||||
m_fullscreen_menubar->SetToolTip(_("Displays the menu bar when Cemu is running in fullscreen mode and the mouse cursor is moved to the top"));
|
m_fullscreen_menubar->SetToolTip(_("Displays the menu bar when Cemu is running in fullscreen mode and the mouse cursor is moved to the top"));
|
||||||
third_row->Add(m_fullscreen_menubar, 0, botflag, 5);
|
third_row->Add(m_fullscreen_menubar, 0, botflag, 5);
|
||||||
CountRowElement();
|
CountRowElement();
|
||||||
|
|
||||||
m_save_screenshot = new wxCheckBox(box, wxID_ANY, _("Save screenshot"));
|
m_save_screenshot = new wxCheckBox(box, wxID_ANY, _("Save screenshot"));
|
||||||
m_save_screenshot->SetToolTip(_("Pressing the screenshot key (F12) will save a screenshot directly to the screenshots folder"));
|
m_save_screenshot->SetToolTip(_("Pressing the screenshot key will save a screenshot directly to the screenshots folder instead of to the clipboard"));
|
||||||
third_row->Add(m_save_screenshot, 0, botflag, 5);
|
third_row->Add(m_save_screenshot, 0, botflag, 5);
|
||||||
CountRowElement();
|
CountRowElement();
|
||||||
|
|
||||||
@ -235,7 +235,7 @@ wxPanel* GeneralSettings2::AddGeneralPage(wxNotebook* notebook)
|
|||||||
third_row->Add(m_disable_screensaver, 0, botflag, 5);
|
third_row->Add(m_disable_screensaver, 0, botflag, 5);
|
||||||
CountRowElement();
|
CountRowElement();
|
||||||
|
|
||||||
// Enable/disable feral interactive gamemode
|
// enable/disable feral interactive gamemode
|
||||||
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
|
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
|
||||||
m_feral_gamemode = new wxCheckBox(box, wxID_ANY, _("Enable Feral GameMode"));
|
m_feral_gamemode = new wxCheckBox(box, wxID_ANY, _("Enable Feral GameMode"));
|
||||||
m_feral_gamemode->SetToolTip(_("Use FeralInteractive GameMode if installed."));
|
m_feral_gamemode->SetToolTip(_("Use FeralInteractive GameMode if installed."));
|
||||||
@ -1099,7 +1099,7 @@ void GeneralSettings2::StoreConfig()
|
|||||||
#endif
|
#endif
|
||||||
config.play_boot_sound = m_play_boot_sound->IsChecked();
|
config.play_boot_sound = m_play_boot_sound->IsChecked();
|
||||||
config.disable_screensaver = m_disable_screensaver->IsChecked();
|
config.disable_screensaver = m_disable_screensaver->IsChecked();
|
||||||
// Toggle while a game is running
|
// toggle while a game is running
|
||||||
if (CafeSystem::IsTitleRunning())
|
if (CafeSystem::IsTitleRunning())
|
||||||
{
|
{
|
||||||
ScreenSaver::SetInhibit(config.disable_screensaver);
|
ScreenSaver::SetInhibit(config.disable_screensaver);
|
||||||
|
|||||||
@ -331,59 +331,59 @@ MainWindow::MainWindow()
|
|||||||
auto load_title_id = LaunchSettings::GetLoadTitleID();
|
auto load_title_id = LaunchSettings::GetLoadTitleID();
|
||||||
bool quick_launch = false;
|
bool quick_launch = false;
|
||||||
|
|
||||||
if (load_file)
|
if (load_file)
|
||||||
{
|
{
|
||||||
MainWindow::RequestLaunchGame(load_file.value(), wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE);
|
MainWindow::RequestLaunchGame(load_file.value(), wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE);
|
||||||
quick_launch = true;
|
quick_launch = true;
|
||||||
}
|
}
|
||||||
else if (load_title_id)
|
else if (load_title_id)
|
||||||
{
|
{
|
||||||
TitleInfo info;
|
TitleInfo info;
|
||||||
TitleId baseId;
|
TitleId baseId;
|
||||||
if (CafeTitleList::FindBaseTitleId(load_title_id.value(), baseId) && CafeTitleList::GetFirstByTitleId(baseId, info))
|
if (CafeTitleList::FindBaseTitleId(load_title_id.value(), baseId) && CafeTitleList::GetFirstByTitleId(baseId, info))
|
||||||
{
|
{
|
||||||
MainWindow::RequestLaunchGame(info.GetPath(), wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE);
|
MainWindow::RequestLaunchGame(info.GetPath(), wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE);
|
||||||
quick_launch = true;
|
quick_launch = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
wxString errorMsg = fmt::format("Title ID {:016x} not found", load_title_id.value());
|
wxString errorMsg = fmt::format("Title ID {:016x} not found", load_title_id.value());
|
||||||
wxMessageBox(errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
wxMessageBox(errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetSizer(main_sizer);
|
SetSizer(main_sizer);
|
||||||
if (!quick_launch)
|
if (!quick_launch)
|
||||||
{
|
{
|
||||||
CreateGameListAndStatusBar();
|
CreateGameListAndStatusBar();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// launching game via -g or -t option. Don't set up or load game list
|
// launching game via -g or -t option. Don't set up or load game list
|
||||||
m_game_list = nullptr;
|
m_game_list = nullptr;
|
||||||
m_info_bar = nullptr;
|
m_info_bar = nullptr;
|
||||||
}
|
}
|
||||||
SetSizer(main_sizer);
|
SetSizer(main_sizer);
|
||||||
|
|
||||||
m_last_mouse_move_time = std::chrono::steady_clock::now();
|
m_last_mouse_move_time = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
m_timer = new wxTimer(this, MAINFRAME_ID_TIMER1);
|
m_timer = new wxTimer(this, MAINFRAME_ID_TIMER1);
|
||||||
m_timer->Start(500);
|
m_timer->Start(500);
|
||||||
|
|
||||||
LoadSettings();
|
LoadSettings();
|
||||||
|
|
||||||
#ifdef ENABLE_DISCORD_RPC
|
#ifdef ENABLE_DISCORD_RPC
|
||||||
if (GetWxGUIConfig().use_discord_presence)
|
if (GetWxGUIConfig().use_discord_presence)
|
||||||
m_discord = std::make_unique<DiscordPresence>();
|
m_discord = std::make_unique<DiscordPresence>();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Bind(wxEVT_OPEN_GRAPHIC_PACK, &MainWindow::OnGraphicWindowOpen, this);
|
Bind(wxEVT_OPEN_GRAPHIC_PACK, &MainWindow::OnGraphicWindowOpen, this);
|
||||||
Bind(wxEVT_LAUNCH_GAME, &MainWindow::OnLaunchFromFile, this);
|
Bind(wxEVT_LAUNCH_GAME, &MainWindow::OnLaunchFromFile, this);
|
||||||
|
|
||||||
if (LaunchSettings::GDBStubEnabled())
|
if (LaunchSettings::GDBStubEnabled())
|
||||||
{
|
{
|
||||||
g_gdbstub = std::make_unique<GDBServer>(GetConfig().gdb_port);
|
g_gdbstub = std::make_unique<GDBServer>(GetConfig().gdb_port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
@ -599,12 +599,7 @@ bool MainWindow::FileLoad(const fs::path launchPath, wxLaunchGameEvent::INITIATE
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (GetConfig().disable_screensaver)
|
if (GetConfig().disable_screensaver)
|
||||||
{
|
|
||||||
ScreenSaver::SetInhibit(true);
|
ScreenSaver::SetInhibit(true);
|
||||||
// TODO: disable when only the game, not Cemu, is closed (a feature not yet implemented)
|
|
||||||
// currently unnecessary because this will happen automatically when Cemu closes
|
|
||||||
// ScreenSaver::SetInhibit(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FullscreenEnabled())
|
if (FullscreenEnabled())
|
||||||
SetFullScreen(true);
|
SetFullScreen(true);
|
||||||
@ -684,13 +679,7 @@ void MainWindow::OnFileMenu(wxCommandEvent& event)
|
|||||||
}
|
}
|
||||||
else if (menuId == MAINFRAME_MENU_ID_FILE_END_EMULATION)
|
else if (menuId == MAINFRAME_MENU_ID_FILE_END_EMULATION)
|
||||||
{
|
{
|
||||||
CafeSystem::ShutdownTitle();
|
EndEmulation();
|
||||||
DestroyCanvas();
|
|
||||||
m_game_launched = false;
|
|
||||||
RecreateMenu();
|
|
||||||
CreateGameListAndStatusBar();
|
|
||||||
DoLayout();
|
|
||||||
UpdateChildWindowTitleRunningState();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1046,14 +1035,13 @@ void MainWindow::OnDebugSetting(wxCommandEvent& event)
|
|||||||
if(!GetConfig().vk_accurate_barriers)
|
if(!GetConfig().vk_accurate_barriers)
|
||||||
wxMessageBox(_("Warning: Disabling the accurate barriers option will lead to flickering graphics but may improve performance. It is highly recommended to leave it turned on."), _("Accurate barriers are off"), wxOK);
|
wxMessageBox(_("Warning: Disabling the accurate barriers option will lead to flickering graphics but may improve performance. It is highly recommended to leave it turned on."), _("Accurate barriers are off"), wxOK);
|
||||||
}
|
}
|
||||||
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_GPU_CAPTURE)
|
|
||||||
{
|
|
||||||
cemu_assert_debug(g_renderer->GetType() == RendererAPI::Metal);
|
|
||||||
|
|
||||||
#if ENABLE_METAL
|
#if ENABLE_METAL
|
||||||
static_cast<MetalRenderer*>(g_renderer.get())->CaptureFrame();
|
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_GPU_CAPTURE)
|
||||||
|
{
|
||||||
|
cemu_assert_debug(g_renderer->GetType() == RendererAPI::Metal);
|
||||||
|
static_cast<MetalRenderer*>(g_renderer.get())->CaptureFrame();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_AUDIO_AUX_ONLY)
|
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_AUDIO_AUX_ONLY)
|
||||||
ActiveSettings::EnableAudioOnlyAux(event.IsChecked());
|
ActiveSettings::EnableAudioOnlyAux(event.IsChecked());
|
||||||
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_DUMP_RAM)
|
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_DUMP_RAM)
|
||||||
@ -1767,6 +1755,34 @@ void MainWindow::SetFullScreen(bool state)
|
|||||||
SetMenuVisible(true);
|
SetMenuVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::EndEmulation() // unfinished - memory leaks and crashes after repeated use (after 3x usually)
|
||||||
|
{
|
||||||
|
CafeSystem::ShutdownTitle();
|
||||||
|
DestroyCanvas();
|
||||||
|
m_game_launched = false;
|
||||||
|
m_launched_game_name.clear();
|
||||||
|
#ifdef ENABLE_DISCORD_RPC
|
||||||
|
if (m_discord)
|
||||||
|
m_discord->UpdatePresence(DiscordPresence::Idling, "");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (GetConfig().disable_screensaver)
|
||||||
|
ScreenSaver::SetInhibit(false);
|
||||||
|
|
||||||
|
// close memory searcher if created
|
||||||
|
if (m_toolWindow)
|
||||||
|
{
|
||||||
|
m_toolWindow->Close();
|
||||||
|
m_toolWindow = nullptr;
|
||||||
|
m_memorySearcherMenuItem->Enable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
RecreateMenu();
|
||||||
|
CreateGameListAndStatusBar();
|
||||||
|
DoLayout();
|
||||||
|
UpdateChildWindowTitleRunningState();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::SetMenuVisible(bool state)
|
void MainWindow::SetMenuVisible(bool state)
|
||||||
{
|
{
|
||||||
if (m_menu_visible == state)
|
if (m_menu_visible == state)
|
||||||
@ -2163,6 +2179,7 @@ void MainWindow::RecreateMenu()
|
|||||||
// add 'Stop emulation' menu entry to file menu
|
// add 'Stop emulation' menu entry to file menu
|
||||||
#ifdef CEMU_DEBUG_ASSERT
|
#ifdef CEMU_DEBUG_ASSERT
|
||||||
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_END_EMULATION, _("Stop emulation"));
|
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_END_EMULATION, _("Stop emulation"));
|
||||||
|
m_fileMenuSeparator1 = m_fileMenu->AppendSeparator()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2264,7 +2281,7 @@ void MainWindow::RecreateMenu()
|
|||||||
// nfc submenu
|
// nfc submenu
|
||||||
wxMenu* nfcMenu = new wxMenu();
|
wxMenu* nfcMenu = new wxMenu();
|
||||||
m_nfcMenu = nfcMenu;
|
m_nfcMenu = nfcMenu;
|
||||||
nfcMenu->Append(MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE, _("&Scan NFC tag from file"))->Enable(false);
|
nfcMenu->Append(MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE, _("&Scan NFC tag/amiibo from file"))->Enable(false);
|
||||||
m_menuBar->Append(nfcMenu, _("&NFC"));
|
m_menuBar->Append(nfcMenu, _("&NFC"));
|
||||||
m_nfcMenuSeparator0 = nullptr;
|
m_nfcMenuSeparator0 = nullptr;
|
||||||
// debug->logging submenu
|
// debug->logging submenu
|
||||||
|
|||||||
@ -71,6 +71,7 @@ public:
|
|||||||
[[nodiscard]] bool IsGameLaunched() const { return m_game_launched; }
|
[[nodiscard]] bool IsGameLaunched() const { return m_game_launched; }
|
||||||
|
|
||||||
void SetFullScreen(bool state);
|
void SetFullScreen(bool state);
|
||||||
|
void EndEmulation();
|
||||||
void SetMenuVisible(bool state);
|
void SetMenuVisible(bool state);
|
||||||
void UpdateNFCMenu();
|
void UpdateNFCMenu();
|
||||||
bool IsMenuHidden() const;
|
bool IsMenuHidden() const;
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "HotkeySettings.h"
|
#include "HotkeySettings.h"
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
|
||||||
|
#include <wx/app.h>
|
||||||
#include <wx/clipbrd.h>
|
#include <wx/clipbrd.h>
|
||||||
|
|
||||||
#if BOOST_OS_WINDOWS
|
#if BOOST_OS_WINDOWS
|
||||||
@ -157,6 +158,9 @@ HotkeySettings::HotkeySettings(wxWindow* parent)
|
|||||||
CreateHotkeyRow(_tr("Toggle fullscreen"), s_cfgHotkeys.toggleFullscreen);
|
CreateHotkeyRow(_tr("Toggle fullscreen"), s_cfgHotkeys.toggleFullscreen);
|
||||||
CreateHotkeyRow(_tr("Take screenshot"), s_cfgHotkeys.takeScreenshot);
|
CreateHotkeyRow(_tr("Take screenshot"), s_cfgHotkeys.takeScreenshot);
|
||||||
CreateHotkeyRow(_tr("Toggle fast-forward"), s_cfgHotkeys.toggleFastForward);
|
CreateHotkeyRow(_tr("Toggle fast-forward"), s_cfgHotkeys.toggleFastForward);
|
||||||
|
#ifdef CEMU_DEBUG_ASSERT
|
||||||
|
CreateHotkeyRow(_tr("End emulation"), s_cfgHotkeys.endEmulation);
|
||||||
|
#endif
|
||||||
|
|
||||||
m_controllerTimer = new wxTimer(this);
|
m_controllerTimer = new wxTimer(this);
|
||||||
Bind(wxEVT_TIMER, &HotkeySettings::OnControllerTimer, this);
|
Bind(wxEVT_TIMER, &HotkeySettings::OnControllerTimer, this);
|
||||||
@ -192,6 +196,13 @@ void HotkeySettings::Init(MainWindow* mainWindowFrame)
|
|||||||
{&s_cfgHotkeys.toggleFastForward, [](void) {
|
{&s_cfgHotkeys.toggleFastForward, [](void) {
|
||||||
ActiveSettings::SetTimerShiftFactor((ActiveSettings::GetTimerShiftFactor() < 3) ? 3 : 1);
|
ActiveSettings::SetTimerShiftFactor((ActiveSettings::GetTimerShiftFactor() < 3) ? 3 : 1);
|
||||||
}},
|
}},
|
||||||
|
#ifdef CEMU_DEBUG_ASSERT
|
||||||
|
{&s_cfgHotkeys.endEmulation, [](void) {
|
||||||
|
wxTheApp->CallAfter([]() {
|
||||||
|
s_mainWindow->EndEmulation();
|
||||||
|
});
|
||||||
|
}},
|
||||||
|
#endif
|
||||||
});
|
});
|
||||||
|
|
||||||
s_keyboardHotkeyToFuncMap.reserve(s_cfgHotkeyToFuncMap.size());
|
s_keyboardHotkeyToFuncMap.reserve(s_cfgHotkeyToFuncMap.size());
|
||||||
|
|||||||
@ -115,6 +115,9 @@ void wxCemuConfig::Load(XMLConfigParser& parser)
|
|||||||
hotkeys.toggleFullscreenAlt = xml_hotkeys.get("ToggleFullscreenAlt", sHotkeyCfg{uKeyboardHotkey{WXK_CONTROL_M, true}}); // ALT+ENTER
|
hotkeys.toggleFullscreenAlt = xml_hotkeys.get("ToggleFullscreenAlt", sHotkeyCfg{uKeyboardHotkey{WXK_CONTROL_M, true}}); // ALT+ENTER
|
||||||
hotkeys.takeScreenshot = xml_hotkeys.get("TakeScreenshot", sHotkeyCfg{uKeyboardHotkey{WXK_F12}});
|
hotkeys.takeScreenshot = xml_hotkeys.get("TakeScreenshot", sHotkeyCfg{uKeyboardHotkey{WXK_F12}});
|
||||||
hotkeys.toggleFastForward = xml_hotkeys.get("ToggleFastForward", sHotkeyCfg{});
|
hotkeys.toggleFastForward = xml_hotkeys.get("ToggleFastForward", sHotkeyCfg{});
|
||||||
|
#ifdef CEMU_DEBUG_ASSERT
|
||||||
|
hotkeys.endEmulation = xml_hotkeys.get("EndEmulation", sHotkeyCfg{uKeyboardHotkey{WXK_F5}});
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxCemuConfig::Save(XMLConfigParser& config)
|
void wxCemuConfig::Save(XMLConfigParser& config)
|
||||||
|
|||||||
@ -127,6 +127,9 @@ struct wxCemuConfig
|
|||||||
sHotkeyCfg exitFullscreen;
|
sHotkeyCfg exitFullscreen;
|
||||||
sHotkeyCfg takeScreenshot;
|
sHotkeyCfg takeScreenshot;
|
||||||
sHotkeyCfg toggleFastForward;
|
sHotkeyCfg toggleFastForward;
|
||||||
|
#ifdef CEMU_DEBUG_ASSERT
|
||||||
|
sHotkeyCfg endEmulation;
|
||||||
|
#endif
|
||||||
} hotkeys{};
|
} hotkeys{};
|
||||||
|
|
||||||
void AddRecentlyLaunchedFile(std::string_view file);
|
void AddRecentlyLaunchedFile(std::string_view file);
|
||||||
|
|||||||
@ -84,7 +84,7 @@ void WindowSystem::UpdateWindowTitles(bool isIdle, bool isLoading, double fps)
|
|||||||
}
|
}
|
||||||
if (isLoading)
|
if (isLoading)
|
||||||
{
|
{
|
||||||
windowText.append(" - loading...");
|
windowText.append(" - Loading...");
|
||||||
if (g_mainFrame)
|
if (g_mainFrame)
|
||||||
g_mainFrame->AsyncSetTitle(windowText);
|
g_mainFrame->AsyncSetTitle(windowText);
|
||||||
return;
|
return;
|
||||||
@ -101,6 +101,11 @@ void WindowSystem::UpdateWindowTitles(bool isIdle, bool isLoading, double fps)
|
|||||||
case RendererAPI::Vulkan:
|
case RendererAPI::Vulkan:
|
||||||
renderer = "[Vulkan]";
|
renderer = "[Vulkan]";
|
||||||
break;
|
break;
|
||||||
|
#if ENABLE_METAL
|
||||||
|
case RendererAPI::Metal:
|
||||||
|
renderer = "[Metal]";
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -90,7 +90,7 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
BLOCK "040904b0"
|
BLOCK "040904b0"
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "FileDescription", "Wii U emulator"
|
VALUE "FileDescription", "Cemu Wii U emulator"
|
||||||
VALUE "InternalName", "Cemu"
|
VALUE "InternalName", "Cemu"
|
||||||
VALUE "LegalCopyright", "Team Cemu"
|
VALUE "LegalCopyright", "Team Cemu"
|
||||||
VALUE "OriginalFilename", "Cemu.exe"
|
VALUE "OriginalFilename", "Cemu.exe"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user