void CFrame::OnKeyDown(wxKeyEvent& event) { if(Core::GetState() != Core::CORE_UNINITIALIZED && (RendererHasFocus() || g_TASInputDlg->HasFocus())) { int WiimoteId = -1; // Toggle fullscreen if (IsHotkey(event, HK_FULLSCREEN)) DoFullscreen(!RendererIsFullscreen()); // Send Debugger keys to CodeWindow else if (g_pCodeWindow && (event.GetKeyCode() >= WXK_F9 && event.GetKeyCode() <= WXK_F11)) event.Skip(); // Pause and Unpause else if (IsHotkey(event, HK_PLAY_PAUSE)) DoPause(); // Stop else if (IsHotkey(event, HK_STOP)) DoStop(); // Screenshot hotkey else if (IsHotkey(event, HK_SCREENSHOT)) Core::SaveScreenShot(); // Wiimote connect and disconnect hotkeys else if (IsHotkey(event, HK_WIIMOTE1_CONNECT)) WiimoteId = 0; else if (IsHotkey(event, HK_WIIMOTE2_CONNECT)) WiimoteId = 1; else if (IsHotkey(event, HK_WIIMOTE3_CONNECT)) WiimoteId = 2; else if (IsHotkey(event, HK_WIIMOTE4_CONNECT)) WiimoteId = 3; // State save and state load hotkeys /*else if (event.GetKeyCode() >= WXK_F1 && event.GetKeyCode() <= WXK_F8) { int slot_number = event.GetKeyCode() - WXK_F1 + 1; if (event.GetModifiers() == wxMOD_NONE) State::Load(slot_number); else if (event.GetModifiers() == wxMOD_SHIFT) State::Save(slot_number); else event.Skip(); }*/ else if (event.GetKeyCode() == WXK_F11 && event.GetModifiers() == wxMOD_NONE) State::LoadLastSaved(); else if (event.GetKeyCode() == WXK_F12) { if (event.GetModifiers() == wxMOD_NONE) State::UndoSaveState(); else if (event.GetModifiers() == wxMOD_SHIFT) State::UndoLoadState(); else event.Skip(); } else { unsigned int i = NUM_HOTKEYS; if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain || g_TASInputDlg->HasFocus()) { for (i = 0; i < NUM_HOTKEYS; i++) { if (IsHotkey(event, i)) { int cmd = GetCmdForHotkey(i); if (cmd >= 0) { wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, cmd); wxMenuItem *item = GetMenuBar()->FindItem(cmd); if (item && item->IsCheckable()) { item->wxMenuItemBase::Toggle(); evt.SetInt(item->IsChecked()); } GetEventHandler()->AddPendingEvent(evt); break; } } } } // On OS X, we claim all keyboard events while // emulation is running to avoid wxWidgets sounding // the system beep for unhandled key events when // receiving pad/wiimote keypresses which take an // entirely different path through the HID subsystem. #ifndef __APPLE__ // On other platforms, we leave the key event alone // so it can be passed on to the windowing system. if (i == NUM_HOTKEYS) event.Skip(); #endif } // Actually perform the wiimote connection or disconnection if (WiimoteId >= 0) { bool connect = !GetMenuBar()->IsChecked(IDM_CONNECT_WIIMOTE1 + WiimoteId); ConnectWiimote(WiimoteId, connect); } // Send the OSD hotkeys to the video backend if (event.GetKeyCode() >= '3' && event.GetKeyCode() <= '7' && event.GetModifiers() == wxMOD_NONE) { #ifdef _WIN32 PostMessage((HWND)Core::GetWindowHandle(), WM_USER, WM_USER_KEYDOWN, event.GetKeyCode()); #elif defined(HAVE_X11) && HAVE_X11 X11Utils::SendKeyEvent(X11Utils::XDisplayFromHandle(GetHandle()), event.GetKeyCode()); #endif } // Send the freelook hotkeys to the video backend if ((event.GetKeyCode() == ')' || event.GetKeyCode() == '(' || event.GetKeyCode() == '0' || event.GetKeyCode() == '9' || event.GetKeyCode() == 'W' || event.GetKeyCode() == 'S' || event.GetKeyCode() == 'A' || event.GetKeyCode() == 'D' || event.GetKeyCode() == 'R') && event.GetModifiers() == wxMOD_SHIFT) { #ifdef _WIN32 PostMessage((HWND)Core::GetWindowHandle(), WM_USER, WM_USER_KEYDOWN, event.GetKeyCode()); #elif defined(HAVE_X11) && HAVE_X11 X11Utils::SendKeyEvent(X11Utils::XDisplayFromHandle(GetHandle()), event.GetKeyCode()); #endif } } else event.Skip(); }
void CFrame::OnStopped() { m_confirmStop = false; m_tried_graceful_shutdown = false; #if defined(HAVE_X11) && HAVE_X11 if (SConfig::GetInstance().bDisableScreenSaver) X11Utils::InhibitScreensaver(X11Utils::XDisplayFromHandle(GetHandle()), X11Utils::XWindowFromHandle(GetHandle()), false); #endif #ifdef _WIN32 // Allow windows to resume normal idling behavior SetThreadExecutionState(ES_CONTINUOUS); #endif m_RenderFrame->SetTitle(StrToWxStr(scm_rev_str)); // Destroy the renderer frame when not rendering to main m_RenderParent->Unbind(wxEVT_SIZE, &CFrame::OnRenderParentResize, this); // Mouse wxTheApp->Unbind(wxEVT_RIGHT_DOWN, &CFrame::OnMouse, this); wxTheApp->Unbind(wxEVT_RIGHT_UP, &CFrame::OnMouse, this); wxTheApp->Unbind(wxEVT_MIDDLE_DOWN, &CFrame::OnMouse, this); wxTheApp->Unbind(wxEVT_MIDDLE_UP, &CFrame::OnMouse, this); wxTheApp->Unbind(wxEVT_MOTION, &CFrame::OnMouse, this); if (SConfig::GetInstance().bHideCursor) m_RenderParent->SetCursor(wxNullCursor); DoFullscreen(false); if (!SConfig::GetInstance().bRenderToMain) { m_RenderFrame->Destroy(); } else { #if defined(__APPLE__) // Disable the full screen button when not in a game. m_RenderFrame->EnableFullScreenView(false); #endif // Make sure the window is not longer set to stay on top m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP); } m_RenderParent = nullptr; m_bRendererHasFocus = false; m_RenderFrame = nullptr; // Clean framerate indications from the status bar. GetStatusBar()->SetStatusText(" ", 0); // Clear Wii Remote connection status from the status bar. GetStatusBar()->SetStatusText(" ", 1); // If batch mode was specified on the command-line or we were already closing, exit now. if (m_bBatchMode || m_bClosing) Close(true); // If using auto size with render to main, reset the application size. if (SConfig::GetInstance().bRenderToMain && SConfig::GetInstance().bRenderWindowAutoSize) SetSize(SConfig::GetInstance().iWidth, SConfig::GetInstance().iHeight); m_GameListCtrl->Enable(); m_GameListCtrl->Show(); m_GameListCtrl->SetFocus(); UpdateGUI(); }
// Prepare the GUI to start the game. void CFrame::StartGame(const std::string& filename) { if (m_bGameLoading) return; m_bGameLoading = true; GetToolBar()->EnableTool(IDM_PLAY, false); GetMenuBar()->FindItem(IDM_PLAY)->Enable(false); if (SConfig::GetInstance().bRenderToMain) { // Game has been started, hide the game list m_GameListCtrl->Disable(); m_GameListCtrl->Hide(); m_RenderParent = m_Panel; m_RenderFrame = this; if (SConfig::GetInstance().bKeepWindowOnTop) m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() | wxSTAY_ON_TOP); else m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP); // No, I really don't want TAB_TRAVERSAL being set behind my back, // thanks. (Note that calling DisableSelfFocus would prevent this flag // from being set for new children, but wouldn't reset the existing // flag.) m_RenderParent->SetWindowStyle(m_RenderParent->GetWindowStyle() & ~wxTAB_TRAVERSAL); } else { wxRect window_geometry( SConfig::GetInstance().iRenderWindowXPos, SConfig::GetInstance().iRenderWindowYPos, SConfig::GetInstance().iRenderWindowWidth, SConfig::GetInstance().iRenderWindowHeight); // Set window size in framebuffer pixels since the 3D rendering will be operating at // that level. wxSize default_size{wxSize(640, 480) * (1.0 / GetContentScaleFactor())}; m_RenderFrame = new CRenderFrame(this, wxID_ANY, _("Dolphin"), wxDefaultPosition, default_size); // Convert ClientSize coordinates to frame sizes. wxSize decoration_fudge = m_RenderFrame->GetSize() - m_RenderFrame->GetClientSize(); default_size += decoration_fudge; if (!window_geometry.IsEmpty()) window_geometry.SetSize(window_geometry.GetSize() + decoration_fudge); WxUtils::SetWindowSizeAndFitToScreen(m_RenderFrame, window_geometry.GetPosition(), window_geometry.GetSize(), default_size); if (SConfig::GetInstance().bKeepWindowOnTop) m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() | wxSTAY_ON_TOP); else m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP); m_RenderFrame->SetBackgroundColour(*wxBLACK); m_RenderFrame->Bind(wxEVT_CLOSE_WINDOW, &CFrame::OnRenderParentClose, this); m_RenderFrame->Bind(wxEVT_ACTIVATE, &CFrame::OnActive, this); m_RenderFrame->Bind(wxEVT_MOVE, &CFrame::OnRenderParentMove, this); #ifdef _WIN32 // The renderer should use a top-level window for exclusive fullscreen support. m_RenderParent = m_RenderFrame; #else // To capture key events on Linux and Mac OS X the frame needs at least one child. m_RenderParent = new wxPanel(m_RenderFrame, IDM_MPANEL, wxDefaultPosition, wxDefaultSize, 0); #endif m_RenderFrame->Show(); } #if defined(__APPLE__) m_RenderFrame->EnableFullScreenView(true); #endif wxBusyCursor hourglass; DoFullscreen(SConfig::GetInstance().bFullscreen); if (!BootManager::BootCore(filename)) { DoFullscreen(false); // Destroy the renderer frame when not rendering to main if (!SConfig::GetInstance().bRenderToMain) m_RenderFrame->Destroy(); m_RenderFrame = nullptr; m_RenderParent = nullptr; m_bGameLoading = false; UpdateGUI(); } else { #if defined(HAVE_X11) && HAVE_X11 if (SConfig::GetInstance().bDisableScreenSaver) X11Utils::InhibitScreensaver(X11Utils::XDisplayFromHandle(GetHandle()), X11Utils::XWindowFromHandle(GetHandle()), true); #endif #ifdef _WIN32 // Prevents Windows from sleeping, turning off the display, or idling EXECUTION_STATE shouldScreenSave = SConfig::GetInstance().bDisableScreenSaver ? ES_DISPLAY_REQUIRED : 0; SetThreadExecutionState(ES_CONTINUOUS | shouldScreenSave | ES_SYSTEM_REQUIRED); #endif m_RenderParent->SetFocus(); wxTheApp->Bind(wxEVT_KEY_DOWN, &CFrame::OnKeyDown, this); wxTheApp->Bind(wxEVT_RIGHT_DOWN, &CFrame::OnMouse, this); wxTheApp->Bind(wxEVT_RIGHT_UP, &CFrame::OnMouse, this); wxTheApp->Bind(wxEVT_MIDDLE_DOWN, &CFrame::OnMouse, this); wxTheApp->Bind(wxEVT_MIDDLE_UP, &CFrame::OnMouse, this); wxTheApp->Bind(wxEVT_MOTION, &CFrame::OnMouse, this); m_RenderParent->Bind(wxEVT_SIZE, &CFrame::OnRenderParentResize, this); } }
// Stop the emulation void CFrame::DoStop() { if (!Core::IsRunningAndStarted()) return; if (m_confirmStop) return; // don't let this function run again until it finishes, or is aborted. m_confirmStop = true; m_bGameLoading = false; if (Core::GetState() != Core::CORE_UNINITIALIZED || m_RenderParent != nullptr) { #if defined __WXGTK__ wxMutexGuiLeave(); std::lock_guard<std::recursive_mutex> lk(keystate_lock); wxMutexGuiEnter(); #endif // Ask for confirmation in case the user accidentally clicked Stop / Escape if (SConfig::GetInstance().bConfirmStop) { // Exit fullscreen to ensure it does not cover the stop dialog. DoFullscreen(false); // Pause the state during confirmation and restore it afterwards Core::EState state = Core::GetState(); // Do not pause if netplay is running as CPU thread might be blocked // waiting on inputs bool should_pause = !NetPlayDialog::GetNetPlayClient(); // If exclusive fullscreen is not enabled then we can pause the emulation // before we've exited fullscreen. If not then we need to exit fullscreen first. should_pause = should_pause && (!RendererIsFullscreen() || !g_Config.ExclusiveFullscreenEnabled() || SConfig::GetInstance().bRenderToMain); if (should_pause) { Core::SetState(Core::CORE_PAUSE); } wxMessageDialog m_StopDlg( this, !m_tried_graceful_shutdown ? _("Do you want to stop the current emulation?") : _("A shutdown is already in progress. Unsaved data " "may be lost if you stop the current emulation " "before it completes. Force stop?"), _("Please confirm..."), wxYES_NO | wxSTAY_ON_TOP | wxICON_EXCLAMATION, wxDefaultPosition); HotkeyManagerEmu::Enable(false); int Ret = m_StopDlg.ShowModal(); HotkeyManagerEmu::Enable(true); if (Ret != wxID_YES) { if (should_pause) Core::SetState(state); m_confirmStop = false; return; } } const auto& stm = WII_IPC_HLE_Interface::GetDeviceByName("/dev/stm/eventhook"); if (!m_tried_graceful_shutdown && stm && std::static_pointer_cast<CWII_IPC_HLE_Device_stm_eventhook>(stm)->HasHookInstalled()) { Core::DisplayMessage("Shutting down", 30000); // Unpause because gracefully shutting down needs the game to actually request a shutdown if (Core::GetState() == Core::CORE_PAUSE) DoPause(); ProcessorInterface::PowerButton_Tap(); m_confirmStop = false; m_tried_graceful_shutdown = true; return; } if (UseDebugger && g_pCodeWindow) { if (g_pCodeWindow->HasPanel<CWatchWindow>()) g_pCodeWindow->GetPanel<CWatchWindow>()->SaveAll(); PowerPC::watches.Clear(); if (g_pCodeWindow->HasPanel<CBreakPointWindow>()) g_pCodeWindow->GetPanel<CBreakPointWindow>()->SaveAll(); PowerPC::breakpoints.Clear(); PowerPC::memchecks.Clear(); if (g_pCodeWindow->HasPanel<CBreakPointWindow>()) g_pCodeWindow->GetPanel<CBreakPointWindow>()->NotifyUpdate(); g_symbolDB.Clear(); Host_NotifyMapLoaded(); } // TODO: Show the author/description dialog here if (Movie::IsRecordingInput()) DoRecordingSave(); if (Movie::IsMovieActive()) Movie::EndPlayInput(false); if (NetPlayDialog::GetNetPlayClient()) NetPlayDialog::GetNetPlayClient()->Stop(); Core::Stop(); UpdateGUI(); } }
// Toggle fullscreen. In Windows the fullscreen mode is accomplished by expanding the m_Panel to // cover // the entire screen (when we render to the main window). void CFrame::OnToggleFullscreen(wxCommandEvent& WXUNUSED(event)) { DoFullscreen(!RendererIsFullscreen()); }