Example #1
0
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());
}