From c66a63b0f3997161e7dfd1e7efb1732162784ec7 Mon Sep 17 00:00:00 2001 From: Sour Date: Fri, 15 Mar 2019 11:39:57 -0400 Subject: [PATCH] Video: Exclusive fullscreen mode support --- Core/SettingTypes.h | 2 +- UI/Config/VideoConfig.cs | 2 +- UI/Emulation/DisplayManager.cs | 46 +++++++++-- UI/Emulation/ShortcutHandler.cs | 16 ++-- UI/Forms/Config/frmVideoConfig.Designer.cs | 13 +-- UI/Forms/Config/frmVideoConfig.cs | 5 ++ UI/Forms/frmFullscreenRenderer.cs | 94 ++++++++++++++++++++++ UI/Forms/frmMain.cs | 3 + UI/Interop/EmuApi.cs | 1 + UI/UI.csproj | 3 + 10 files changed, 161 insertions(+), 24 deletions(-) create mode 100644 UI/Forms/frmFullscreenRenderer.cs diff --git a/Core/SettingTypes.h b/Core/SettingTypes.h index b022883..b090d35 100644 --- a/Core/SettingTypes.h +++ b/Core/SettingTypes.h @@ -93,7 +93,7 @@ struct VideoConfig bool FullscreenForceIntegerScale = false; bool UseExclusiveFullscreen = false; - int32_t ExclusiveFullscreenRefreshRate = 60; + uint32_t ExclusiveFullscreenRefreshRate = 60; }; struct AudioConfig diff --git a/UI/Config/VideoConfig.cs b/UI/Config/VideoConfig.cs index 9988ea0..8b93622 100644 --- a/UI/Config/VideoConfig.cs +++ b/UI/Config/VideoConfig.cs @@ -40,7 +40,7 @@ namespace Mesen.GUI.Config [MarshalAs(UnmanagedType.I1)] public bool FullscreenForceIntegerScale = false; [MarshalAs(UnmanagedType.I1)] public bool UseExclusiveFullscreen = false; - public Int32 ExclusiveFullscreenRefreshRate = 60; + public UInt32 ExclusiveFullscreenRefreshRate = 60; public void ApplyConfig() { diff --git a/UI/Emulation/DisplayManager.cs b/UI/Emulation/DisplayManager.cs index be2e5e1..1b091f4 100644 --- a/UI/Emulation/DisplayManager.cs +++ b/UI/Emulation/DisplayManager.cs @@ -22,8 +22,10 @@ namespace Mesen.GUI.Emulation private bool _fullscreenMode; private FormWindowState _originalWindowState; private Size _originalWindowMinimumSize; + private frmFullscreenRenderer _frmFullscreenRenderer = null; public bool Fullscreen { get { return _fullscreenMode; } } + public bool ExclusiveFullscreen { get { return _frmFullscreenRenderer != null; } } public DisplayManager(frmMain frm, ctrlRenderer renderer, Panel panel, MenuStrip menu, ctrlRecentGames recentGames) { @@ -162,7 +164,7 @@ namespace Mesen.GUI.Emulation SetFullscreenState(!_fullscreenMode); } - private void SetFullscreenState(bool enabled) + public void SetFullscreenState(bool enabled) { if(_fullscreenMode == enabled) { //Fullscreen mode already matches, no need to do anything @@ -173,12 +175,10 @@ namespace Mesen.GUI.Emulation _fullscreenMode = enabled; if(ConfigManager.Config.Video.UseExclusiveFullscreen) { - if(EmuRunner.IsRunning()) { - if(enabled) { - //StartExclusiveFullscreenMode(); - } else { - //StopExclusiveFullscreenMode(); - } + if(enabled && EmuRunner.IsRunning()) { + StartExclusiveFullscreenMode(); + } else { + StopExclusiveFullscreenMode(); } } else { _frm.Resize -= frmMain_Resize; @@ -214,5 +214,37 @@ namespace Mesen.GUI.Emulation _frm.FormBorderStyle = FormBorderStyle.Sizable; frmMain_Resize(null, EventArgs.Empty); } + + private void StopExclusiveFullscreenMode() + { + if(_frmFullscreenRenderer != null) { + _frmFullscreenRenderer.Close(); + } + _fullscreenMode = false; + } + + private void StartExclusiveFullscreenMode() + { + Size screenSize = Screen.FromControl(_frm).Bounds.Size; + _frmFullscreenRenderer = new frmFullscreenRenderer(); + _frmFullscreenRenderer.Shown += (object sender, EventArgs e) => { + _renderer.Visible = false; + SetScaleBasedOnScreenSize(); + EmuApi.SetFullscreenMode(true, _frmFullscreenRenderer.Handle, (UInt32)screenSize.Width, (UInt32)screenSize.Height); + }; + _frmFullscreenRenderer.FormClosing += (object sender, FormClosingEventArgs e) => { + EmuApi.SetFullscreenMode(false, _renderer.Handle, (UInt32)screenSize.Width, (UInt32)screenSize.Height); + _frmFullscreenRenderer = null; + _renderer.Visible = true; + _fullscreenMode = false; + frmMain_Resize(null, EventArgs.Empty); + }; + + Screen currentScreen = Screen.FromHandle(_frm.Handle); + _frmFullscreenRenderer.StartPosition = FormStartPosition.Manual; + _frmFullscreenRenderer.Top = currentScreen.Bounds.Top; + _frmFullscreenRenderer.Left = currentScreen.Bounds.Left; + _frmFullscreenRenderer.Show(); + } } } diff --git a/UI/Emulation/ShortcutHandler.cs b/UI/Emulation/ShortcutHandler.cs index 52ca3c2..c329eae 100644 --- a/UI/Emulation/ShortcutHandler.cs +++ b/UI/Emulation/ShortcutHandler.cs @@ -67,14 +67,14 @@ namespace Mesen.GUI.Emulation } } - //TODO bool restoreFullscreen = _frmFullscreenRenderer != null; + bool restoreFullscreen = _displayManager.ExclusiveFullscreen; switch(shortcut) { case EmulatorShortcut.Pause: TogglePause(); break; case EmulatorShortcut.Reset: ResetEmu(); break; case EmulatorShortcut.PowerCycle: PowerCycleEmu(); break; - case EmulatorShortcut.PowerOff: Task.Run(() => EmuApi.Stop()); break; - case EmulatorShortcut.Exit: Application.OpenForms[0].Close(); break; + case EmulatorShortcut.PowerOff: Task.Run(() => EmuApi.Stop()); restoreFullscreen = false; break; + case EmulatorShortcut.Exit: Application.OpenForms[0].Close(); restoreFullscreen = false; break; case EmulatorShortcut.ToggleAudio: ToggleAudio(); break; case EmulatorShortcut.ToggleFps: ToggleFps(); break; @@ -84,7 +84,7 @@ namespace Mesen.GUI.Emulation case EmulatorShortcut.ToggleAlwaysOnTop: ToggleAlwaysOnTop(); break; case EmulatorShortcut.ToggleDebugInfo: ToggleDebugInfo(); break; case EmulatorShortcut.MaxSpeed: ToggleMaxSpeed(); break; - case EmulatorShortcut.ToggleFullscreen: _displayManager.ToggleFullscreen(); break; + case EmulatorShortcut.ToggleFullscreen: _displayManager.ToggleFullscreen(); restoreFullscreen = false; break; case EmulatorShortcut.OpenFile: OpenFile(); break; case EmulatorShortcut.IncreaseSpeed: IncreaseEmulationSpeed(); break; @@ -125,12 +125,10 @@ namespace Mesen.GUI.Emulation case EmulatorShortcut.LoadStateSlotAuto: SaveStateManager.LoadState(11); break; } - //TODO - /* - if(restoreFullscreen && _frmFullscreenRenderer == null && !_shuttingDown) { + if(restoreFullscreen && !_displayManager.ExclusiveFullscreen) { //Need to restore fullscreen mode after showing a dialog - this.SetFullscreenState(true); - }*/ + _displayManager.SetFullscreenState(true); + } } private void OpenFile() diff --git a/UI/Forms/Config/frmVideoConfig.Designer.cs b/UI/Forms/Config/frmVideoConfig.Designer.cs index 1475f33..0fedf82 100644 --- a/UI/Forms/Config/frmVideoConfig.Designer.cs +++ b/UI/Forms/Config/frmVideoConfig.Designer.cs @@ -185,7 +185,7 @@ this.chkUseExclusiveFullscreen.TabIndex = 24; this.chkUseExclusiveFullscreen.Text = "Use exclusive fullscreen mode"; this.chkUseExclusiveFullscreen.UseVisualStyleBackColor = true; - this.chkUseExclusiveFullscreen.Visible = false; + this.chkUseExclusiveFullscreen.CheckedChanged += new System.EventHandler(this.chkUseExclusiveFullscreen_CheckedChanged); // // lblVideoScale // @@ -373,11 +373,12 @@ this.cboRefreshRate.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.cboRefreshRate.FormattingEnabled = true; this.cboRefreshRate.Items.AddRange(new object[] { - "Auto", - "NTSC (8:7)", - "PAL (18:13)", - "Standard (4:3)", - "Widescreen (16:9)"}); + "50 Hz", + "60 Hz", + "100 Hz", + "120 Hz", + "200 Hz", + "240 Hz"}); this.cboRefreshRate.Location = new System.Drawing.Point(137, 3); this.cboRefreshRate.Name = "cboRefreshRate"; this.cboRefreshRate.Size = new System.Drawing.Size(68, 21); diff --git a/UI/Forms/Config/frmVideoConfig.cs b/UI/Forms/Config/frmVideoConfig.cs index 133b5ad..5338e7e 100644 --- a/UI/Forms/Config/frmVideoConfig.cs +++ b/UI/Forms/Config/frmVideoConfig.cs @@ -147,5 +147,10 @@ namespace Mesen.GUI.Forms.Config { UpdateOverscanImage(picOverscan, (int)nudOverscanTop.Value, (int)nudOverscanBottom.Value, (int)nudOverscanLeft.Value, (int)nudOverscanRight.Value); } + + private void chkUseExclusiveFullscreen_CheckedChanged(object sender, EventArgs e) + { + flpRefreshRate.Visible = chkUseExclusiveFullscreen.Checked; + } } } diff --git a/UI/Forms/frmFullscreenRenderer.cs b/UI/Forms/frmFullscreenRenderer.cs new file mode 100644 index 0000000..f26f421 --- /dev/null +++ b/UI/Forms/frmFullscreenRenderer.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Mesen.GUI.Forms +{ + public class frmFullscreenRenderer : BaseInputForm + { + private const int LeftMouseButtonKeyCode = 0x200; + private const int RightMouseButtonKeyCode = 0x201; + private const int MiddleMouseButtonKeyCode = 0x202; + private bool _closing = false; + + public frmFullscreenRenderer() + { + this.BackColor = Color.Black; + this.Text = "Mesen Fullscreen Window"; + this.FormBorderStyle = FormBorderStyle.None; + this.WindowState = FormWindowState.Maximized; + } + + protected override void OnFormClosing(FormClosingEventArgs e) + { + _closing = true; + base.OnFormClosing(e); + } + + protected override void OnDeactivate(EventArgs e) + { + base.OnDeactivate(e); + + if(!_closing) { + //Close fullscreen mode if window loses focus + this.Close(); + } + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + //CursorManager.CaptureMouse(); + SetMouseButtonState(Control.MouseButtons); + } + + protected override void OnMouseUp(MouseEventArgs e) + { + base.OnMouseUp(e); + SetMouseButtonState(Control.MouseButtons); + } + + private void SetMouseButtonState(MouseButtons pressedButtons) + { + InputApi.SetKeyState(LeftMouseButtonKeyCode, pressedButtons.HasFlag(MouseButtons.Left)); + InputApi.SetKeyState(RightMouseButtonKeyCode, pressedButtons.HasFlag(MouseButtons.Right)); + InputApi.SetKeyState(MiddleMouseButtonKeyCode, pressedButtons.HasFlag(MouseButtons.Middle)); + } + + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + + ScreenSize size = EmuApi.GetScreenSize(false); + int leftMargin = (this.Width - size.Width) / 2; + int topMargin = (this.Height - size.Height) / 2; + + //CursorManager.OnMouseMove(this); + + /*if(CursorManager.NeedMouseIcon) { + this.Cursor = Cursors.Cross; + }*/ + + double xPos = (double)(e.X - leftMargin) / size.Width; + double yPos = (double)(e.Y - topMargin) / size.Height; + + xPos = Math.Max(0.0, Math.Min(1.0, xPos)); + yPos = Math.Max(0.0, Math.Min(1.0, yPos)); + + InputApi.SetMousePosition(xPos, yPos); + } + + protected override void OnMouseLeave(EventArgs e) + { + base.OnMouseLeave(e); + + //CursorManager.OnMouseLeave(); + InputApi.SetMousePosition(-1, -1); + } + } +} diff --git a/UI/Forms/frmMain.cs b/UI/Forms/frmMain.cs index c98d28e..8d7dc80 100644 --- a/UI/Forms/frmMain.cs +++ b/UI/Forms/frmMain.cs @@ -109,6 +109,9 @@ namespace Mesen.GUI.Forms ctrlRecentGames.Initialize(); ctrlRecentGames.Visible = true; ResizeRecentGames(); + if(_displayManager.ExclusiveFullscreen) { + _displayManager.SetFullscreenState(false); + } })); break; diff --git a/UI/Interop/EmuApi.cs b/UI/Interop/EmuApi.cs index 150b41d..96cb4a5 100644 --- a/UI/Interop/EmuApi.cs +++ b/UI/Interop/EmuApi.cs @@ -59,6 +59,7 @@ namespace Mesen.GUI ); [DllImport(DllPath)] public static extern void SetDisplayLanguage(Language lang); + [DllImport(DllPath)] public static extern void SetFullscreenMode([MarshalAs(UnmanagedType.I1)]bool fullscreen, IntPtr windowHandle, UInt32 monitorWidth, UInt32 monitorHeight); [DllImport(DllPath)] public static extern ScreenSize GetScreenSize([MarshalAs(UnmanagedType.I1)]bool ignoreScale); diff --git a/UI/UI.csproj b/UI/UI.csproj index 68eec07..a8835c3 100644 --- a/UI/UI.csproj +++ b/UI/UI.csproj @@ -555,6 +555,9 @@ frmAbout.cs + + Form + Form