1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Diagnostics;
5 using System.Drawing;
6 using System.Drawing.Text;
7 using System.IO;
8 using System.Linq;
9 using System.Net;
10 using System.Text;
11 using System.Text.RegularExpressions;
12 using System.Threading;
13 using System.Threading.Tasks;
14 using System.Windows.Forms;
15 using System.Xml;
16 using Mesen.GUI.Config;
17 using Mesen.GUI.Debugger;
18 using Mesen.GUI.Forms.Cheats;
19 using Mesen.GUI.Forms.Config;
20 using Mesen.GUI.Forms.HdPackEditor;
21 using Mesen.GUI.Forms.NetPlay;
22 using Mesen.GUI.GoogleDriveIntegration;
23 using Mesen.GUI.Properties;
24 
25 namespace Mesen.GUI.Forms
26 {
27 	public partial class frmMain : BaseInputForm
28 	{
29 		private InteropEmu.NotificationListener _notifListener;
30 		private Thread _emuThread;
31 		private frmLogWindow _logWindow;
32 		private frmCheatList _cheatListWindow;
33 		private frmHistoryViewer _historyViewerWindow;
34 		private frmHdPackEditor _hdPackEditorWindow;
35 		private ResourcePath? _currentRomPath = null;
36 
37 		private string _movieToRecord = null;
38 		private List<string> _luaScriptsToLoad = new List<string>();
39 		private bool _loadLastSessionRequested = false;
40 
41 		private Image _pauseButton = Resources.Pause;
42 		private Image _playButton = Resources.Play;
43 		private string _currentGame = null;
44 		private bool _customSize = false;
45 		private double? _switchOptionScale = null;
46 		private bool _fullscreenRequested = false;
47 		private FormWindowState _originalWindowState;
48 		private Size _originalWindowMinimumSize;
49 		private bool _fullscreenMode = false;
50 		private Size? _nonNsfSize = null;
51 		private Size _nonNsfMinimumSize;
52 		private bool _isNsfPlayerMode = false;
53 		private object _loadRomLock = new object();
54 		private int _romLoadCounter = 0;
55 		private bool _showUpgradeMessage = false;
56 		private float _yFactor = 1;
57 		private bool _enableResize = false;
58 		private bool _overrideWindowSize = false;
59 		private bool _shuttingDown = false;
60 		private bool _isDualSystem = false;
61 
62 		private frmFullscreenRenderer _frmFullscreenRenderer = null;
63 
64 		private Dictionary<EmulatorShortcut, Func<bool>> _actionEnabledFuncs = new Dictionary<EmulatorShortcut, Func<bool>>();
65 
66 		private string[] _commandLineArgs;
67 		private bool _noAudio = false;
68 		private bool _noVideo = false;
69 		private bool _noInput = false;
70 
71 		private PrivateFontCollection _fonts = new PrivateFontCollection();
72 
frmMain(string[] args)73 		public frmMain(string[] args)
74 		{
75 			ThemeHelper.InitTheme(this.BackColor);
76 			InitializeComponent();
77 
78 			ThemeHelper.ExcludeFromTheme(panelInfo);
79 			ThemeHelper.ExcludeFromTheme(panelRenderer);
80 
81 			this.StartPosition = FormStartPosition.CenterScreen;
82 
83 			Version currentVersion = new Version(InteropEmu.GetMesenVersion());
84 			lblVersion.Text = currentVersion.ToString();
85 
86 			if(!Program.IsMono) {
87 				_fonts.AddFontFile(Path.Combine(ConfigManager.HomeFolder, "Resources", "PixelFont.ttf"));
88 				lblVersion.Font = new Font(_fonts.Families[0], 10);
89 			} else {
90 				lblVersion.Margin = new Padding(0, 0, 3, 0);
91 				picIcon.Margin = new Padding(3, 5, 3, 3);
92 			}
93 
94 #if AUTOBUILD
95 			string devVersion = ResourceManager.ReadZippedResource("DevBuild.txt");
96 			if(devVersion != null) {
97 				Size versionSize = TextRenderer.MeasureText(devVersion, lblVersion.Font);
98 				lblVersion.Text = devVersion;
99 				lblVersion.Anchor = AnchorStyles.Right;
100 				int newWidth = versionSize.Width + 30;
101 				panelInfo.Left -= newWidth - panelInfo.Width;
102 				panelInfo.Width = newWidth;
103 			}
104 #endif
105 
106 			_commandLineArgs = (string[])args.Clone();
107 
108 			Application.AddMessageFilter(this);
109 			this.Resize += ResizeRecentGames;
110 			this.FormClosed += (s, e) => Application.RemoveMessageFilter(this);
111 		}
112 
ProcessCommandLineArguments(List<string> switches, bool forStartup)113 		public void ProcessCommandLineArguments(List<string> switches, bool forStartup)
114 		{
115 			if(forStartup) {
116 				_noVideo = switches.Contains("/novideo");
117 				_noAudio = switches.Contains("/noaudio");
118 				_noInput = switches.Contains("/noinput");
119 			}
120 
121 			if(switches.Contains("/donotsavesettings")) {
122 				ConfigManager.DoNotSaveSettings = true;
123 			}
124 
125 			if(switches.Contains("/loadlastsession")) {
126 				_loadLastSessionRequested = true;
127 			}
128 
129 			Regex recordMovieCommand = new Regex("/recordmovie=([^\"]+)");
130 			foreach(string command in switches) {
131 				Match match = recordMovieCommand.Match(command);
132 				if(match.Success) {
133 					string moviePath = match.Groups[1].Value;
134 					string folder = Path.GetDirectoryName(moviePath);
135 					if(string.IsNullOrWhiteSpace(folder)) {
136 						moviePath = Path.Combine(ConfigManager.MovieFolder, moviePath);
137 					} else if(!Path.IsPathRooted(moviePath)) {
138 						moviePath = Path.Combine(Program.OriginalFolder, moviePath);
139 					}
140 					if(!moviePath.ToLower().EndsWith(".mmo")) {
141 						moviePath += ".mmo";
142 					}
143 					_movieToRecord = moviePath;
144 					break;
145 				}
146 			}
147 
148 			ConfigManager.ProcessSwitches(switches);
149 		}
150 
LoadGameFromCommandLine(List<string> switches)151 		public void LoadGameFromCommandLine(List<string> switches)
152 		{
153 			string romPath;
154 			CommandLineHelper.GetRomPathFromCommandLine(switches, out romPath, out _luaScriptsToLoad);
155 
156 			if(romPath != null) {
157 				this.LoadFile(romPath);
158 			} else {
159 				if(_emuThread == null) {
160 					//When no ROM is loaded, only process Lua scripts if a ROM was specified as a command line param
161 					_luaScriptsToLoad.Clear();
162 					_movieToRecord = null;
163 					_loadLastSessionRequested = false;
164 				} else {
165 					//No game was specified, but a game is running already, load the scripts right away
166 					ProcessPostLoadCommandSwitches();
167 				}
168 			}
169 		}
170 
ProcessPostLoadCommandSwitches()171 		private void ProcessPostLoadCommandSwitches()
172 		{
173 			if(_luaScriptsToLoad.Count > 0) {
174 				foreach(string luaScript in _luaScriptsToLoad) {
175 					frmScript scriptWindow = DebugWindowManager.OpenScriptWindow(true);
176 					scriptWindow.LoadScriptFile(luaScript);
177 				}
178 				_luaScriptsToLoad.Clear();
179 			}
180 
181 			if(_movieToRecord != null) {
182 				if(InteropEmu.MovieRecording()) {
183 					InteropEmu.MovieStop();
184 				}
185 				RecordMovieOptions options = new RecordMovieOptions(_movieToRecord, "", "", RecordMovieFrom.StartWithSaveData);
186 				InteropEmu.MovieRecord(ref options);
187 				_movieToRecord = null;
188 			}
189 
190 			if(_loadLastSessionRequested) {
191 				_loadLastSessionRequested = false;
192 				LoadLastSession();
193 			}
194 		}
195 
OnLoad(EventArgs e)196 		protected override void OnLoad(EventArgs e)
197 		{
198 			ResourceHelper.LoadResources(ConfigManager.Config.PreferenceInfo.DisplayLanguage);
199 			ResourceHelper.UpdateEmuLanguage();
200 
201 			base.OnLoad(e);
202 
203 #if HIDETESTMENU
204 			mnuTests.Visible = false;
205 #endif
206 			InteropEmu.InitDll();
207 
208 			_notifListener = new InteropEmu.NotificationListener(InteropEmu.ConsoleId.Master);
209 			_notifListener.OnNotification += _notifListener_OnNotification;
210 
211 			menuTimer.Start();
212 
213 			InteropEmu.ScreenSize originalSize = InteropEmu.GetScreenSize(false);
214 			VideoInfo.ApplyConfig();
215 			this.ProcessCommandLineArguments(CommandLineHelper.PreprocessCommandLineArguments(_commandLineArgs, true), true);
216 			VideoInfo.ApplyConfig();
217 			InteropEmu.ScreenSize newSize = InteropEmu.GetScreenSize(false);
218 			if(originalSize.Width != newSize.Width || originalSize.Height != newSize.Height) {
219 				_overrideWindowSize = true;
220 			}
221 
222 			InitializeEmulationSpeedMenu();
223 
224 			UpdateVideoSettings();
225 
226 			InitializeCore();
227 			PerformUpgrade();
228 			InitializeEmu();
229 
230 			TopMost = ConfigManager.Config.PreferenceInfo.AlwaysOnTop;
231 
232 			UpdateMenus();
233 			UpdateRecentFiles();
234 
235 			UpdateViewerSize();
236 
237 			InitializeStateMenu(mnuSaveState, true);
238 			InitializeStateMenu(mnuLoadState, false);
239 
240 			if(ConfigManager.Config.WindowLocation.HasValue) {
241 				this.StartPosition = FormStartPosition.Manual;
242 				this.Location = ConfigManager.Config.WindowLocation.Value;
243 			}
244 
245 			if(ConfigManager.Config.PreferenceInfo.CloudSaveIntegration) {
246 				Task.Run(() => CloudSyncHelper.Sync());
247 			}
248 
249 			if(ConfigManager.Config.PreferenceInfo.AutomaticallyCheckForUpdates) {
250 				CheckForUpdates(false);
251 			}
252 
253 			if(ConfigManager.Config.WindowSize.HasValue && !_overrideWindowSize) {
254 				this.ClientSize = ConfigManager.Config.WindowSize.Value;
255 			}
256 
257 			mnuDebugDualSystemSecondaryCpu.Checked = ConfigManager.Config.DebugInfo.DebugConsoleId == InteropEmu.ConsoleId.Slave;
258 			InteropEmu.DebugSetDebuggerConsole(ConfigManager.Config.DebugInfo.DebugConsoleId);
259 
260 			BaseForm.StartBackgroundTimer();
261 		}
262 
ProcessFullscreenSwitch(List<string> switches)263 		private void ProcessFullscreenSwitch(List<string> switches)
264 		{
265 			if(switches.Contains("/fullscreen")) {
266 				double scale = ConfigManager.Config.VideoInfo.VideoScale;
267 				if(!ConfigManager.Config.VideoInfo.UseExclusiveFullscreen) {
268 					//Go into fullscreen mode right away
269 					SetFullscreenState(true);
270 				}
271 
272 				_fullscreenRequested = true;
273 				foreach(string option in switches) {
274 					if(option.StartsWith("/videoscale=")) {
275 						_switchOptionScale = scale;
276 					}
277 				}
278 			}
279 		}
280 
OnShown(EventArgs e)281 		protected override void OnShown(EventArgs e)
282 		{
283 			base.OnShown(e);
284 
285 			if(ConfigManager.Config.PreferenceInfo.DisableMouseResize) {
286 				//This must be in the OnShown event, otherwise the application won't show up in the taskbar until it is given focus
287 				this.FormBorderStyle = FormBorderStyle.Fixed3D;
288 			}
289 
290 			this.BindShortcuts();
291 
292 			if(ConfigManager.Config.WindowSize.HasValue && !_overrideWindowSize) {
293 				this.Size = ConfigManager.Config.WindowSize.Value;
294 			}
295 
296 			this.LoadGameFromCommandLine(CommandLineHelper.PreprocessCommandLineArguments(_commandLineArgs, false));
297 
298 			this.menuStrip.VisibleChanged += new System.EventHandler(this.menuStrip_VisibleChanged);
299 			this.UpdateRendererLocation();
300 
301 			if(_showUpgradeMessage) {
302 				MesenMsgBox.Show("UpgradeSuccess", MessageBoxButtons.OK, MessageBoxIcon.Information);
303 				_showUpgradeMessage = false;
304 			}
305 
306 			//Ensure the resize event is not fired until the form is fully shown
307 			//This is needed when DPI display settings is not set to 100%
308 			_enableResize = true;
309 
310 			ProcessFullscreenSwitch(CommandLineHelper.PreprocessCommandLineArguments(_commandLineArgs, true));
311 		}
312 
OnClosing(CancelEventArgs e)313 		protected override void OnClosing(CancelEventArgs e)
314 		{
315 			if(ConfigManager.Config.PreferenceInfo.ConfirmExitResetPower && MesenMsgBox.Show("ConfirmExit", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK) {
316 				e.Cancel = true;
317 				return;
318 			}
319 
320 			if(!_shuttingDown && Program.IsMono) {
321 				//This appears to prevent Mono from locking up when closing the form
322 				Task.Run(() => {
323 					StopEmu();
324 					_shuttingDown = true;
325 					this.BeginInvoke((Action)(() => this.Close()));
326 				});
327 				e.Cancel = true;
328 				return;
329 			}
330 
331 			_shuttingDown = true;
332 			CursorManager.StopTimers();
333 			BaseForm.StopBackgroundTimer();
334 			_logWindow?.Close();
335 			_historyViewerWindow?.Close();
336 			_cheatListWindow?.Close();
337 			_hdPackEditorWindow?.Close();
338 			_frmFullscreenRenderer?.Close();
339 
340 			//Stop menu update timer, and process all pending events before stopping the core
341 			//This prevents some rare crashes on shutdown
342 			menuTimer.Stop();
343 			Application.DoEvents();
344 
345 			if(_notifListener != null) {
346 				_notifListener.Dispose();
347 				_notifListener = null;
348 			}
349 			DebugWindowManager.CloseAll();
350 
351 			ConfigManager.Config.EmulationInfo.EmulationSpeed = InteropEmu.GetEmulationSpeed();
352 			ConfigManager.Config.WindowLocation = this.WindowState == FormWindowState.Normal ? this.Location : this.RestoreBounds.Location;
353 			ConfigManager.Config.WindowSize = this.WindowState == FormWindowState.Normal ? this.Size : this.RestoreBounds.Size;
354 
355 			if(this._nonNsfSize.HasValue) {
356 				ConfigManager.Config.WindowSize = this._nonNsfSize.Value;
357 			}
358 
359 			ConfigManager.ApplyChanges();
360 
361 			StopEmu();
362 
363 			if(ConfigManager.Config.PreferenceInfo.CloudSaveIntegration) {
364 				CloudSyncHelper.Sync();
365 			}
366 
367 			InteropEmu.Release();
368 
369 			ConfigManager.SaveConfig();
370 
371 			base.OnClosing(e);
372 		}
373 
menuTimer_Tick(object sender, EventArgs e)374 		private void menuTimer_Tick(object sender, EventArgs e)
375 		{
376 			this.UpdateMenus();
377 		}
378 
InitializeCore()379 		void InitializeCore()
380 		{
381 			InteropEmu.InitializeEmu(ConfigManager.HomeFolder, this.Handle, ctrlRenderer.Handle, _noAudio, _noVideo, _noInput);
382 		}
383 
InitializeEmu()384 		void InitializeEmu()
385 		{
386 			if(ConfigManager.Config.PreferenceInfo.OverrideGameFolder && Directory.Exists(ConfigManager.Config.PreferenceInfo.GameFolder)) {
387 				InteropEmu.AddKnownGameFolder(ConfigManager.Config.PreferenceInfo.GameFolder);
388 			}
389 			foreach(RecentItem recentItem in ConfigManager.Config.RecentFiles) {
390 				InteropEmu.AddKnownGameFolder(recentItem.RomFile.Folder);
391 			}
392 
393 			ConfigManager.Config.InitializeDefaults();
394 			ConfigManager.ApplyChanges();
395 			ConfigManager.Config.ApplyConfig();
396 
397 			UpdateEmulationFlags();
398 		}
399 
UpdateViewerSize(bool forceUpdate = false)400 		private void UpdateViewerSize(bool forceUpdate = false)
401 		{
402 			this.Resize -= frmMain_Resize;
403 
404 			InteropEmu.ScreenSize size = InteropEmu.GetScreenSize(false);
405 
406 			if(forceUpdate || (!_customSize && this.WindowState != FormWindowState.Maximized)) {
407 				Size sizeGap = this.Size - this.ClientSize;
408 
409 				bool doubleScreenMode = _isDualSystem && ConfigManager.Config.PreferenceInfo.VsDualVideoOutput == VsDualOutputOption.Both;
410 				int width = doubleScreenMode ? (size.Width * 2) : size.Width;
411 
412 				UpdateScaleMenu(size.Scale);
413 				this.ClientSize = new Size(Math.Max(this.MinimumSize.Width - sizeGap.Width, width), Math.Max(this.MinimumSize.Height - sizeGap.Height, size.Height + (this.HideMenuStrip ? 0 : menuStrip.Height)));
414 			}
415 
416 			ctrlRenderer.Size = new Size(size.Width, size.Height);
417 			UpdateRendererPosition();
418 
419 			if(this.HideMenuStrip) {
420 				this.menuStrip.Visible = false;
421 			}
422 
423 			this.Resize += frmMain_Resize;
424 		}
425 
UpdateRendererPosition()426 		private void UpdateRendererPosition()
427 		{
428 			ctrlRenderer.Top = (panelRenderer.Height - ctrlRenderer.Height) / 2;
429 
430 			if(_isDualSystem) {
431 				UpdateDualSystemViewer();
432 			} else {
433 				ctrlRenderer.Left = (panelRenderer.Width - ctrlRenderer.Width) / 2;
434 				ctrlRendererDualSystem.Visible = false;
435 			}
436 		}
437 
UpdateDualSystemViewer()438 		private void UpdateDualSystemViewer()
439 		{
440 			ctrlRendererDualSystem.Size = new Size(ctrlRenderer.Width, ctrlRenderer.Height);
441 			ctrlRendererDualSystem.Top = (panelRenderer.Height - ctrlRenderer.Height) / 2;
442 
443 			if(ConfigManager.Config.PreferenceInfo.VsDualVideoOutput == VsDualOutputOption.Both) {
444 				ctrlRenderer.Left = (panelRenderer.Width / 2 - ctrlRenderer.Width) / 2;
445 				ctrlRendererDualSystem.Left = ctrlRenderer.Left + ctrlRenderer.Width;
446 
447 				ctrlRendererDualSystem.Visible = true;
448 			} else {
449 				ctrlRenderer.Left = (panelRenderer.Width - ctrlRenderer.Width) / 2;
450 				ctrlRendererDualSystem.Left = (panelRenderer.Width - ctrlRenderer.Width) / 2;
451 
452 				if(ConfigManager.Config.PreferenceInfo.VsDualVideoOutput == VsDualOutputOption.SlaveOnly) {
453 					ctrlRendererDualSystem.Visible = true;
454 					ctrlRendererDualSystem.BringToFront();
455 				} else {
456 					ctrlRendererDualSystem.Visible = false;
457 				}
458 			}
459 		}
460 
ScaleControl(SizeF factor, BoundsSpecified specified)461 		protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
462 		{
463 			_yFactor = factor.Height;
464 			base.ScaleControl(factor, specified);
465 		}
466 
ResizeRecentGames(object sender, EventArgs e)467 		private void ResizeRecentGames(object sender, EventArgs e)
468 		{
469 			if(this.ClientSize.Height < 400 * _yFactor) {
470 				ctrlRecentGames.Height = this.ClientSize.Height - (int)((125 - Math.Min(50, 400 - (int)(this.ClientSize.Height / _yFactor))) * _yFactor);
471 			} else {
472 				ctrlRecentGames.Height = this.ClientSize.Height - (int)(125 * _yFactor);
473 			}
474 			ctrlRecentGames.Width = this.ClientSize.Width;
475 			ctrlRecentGames.Top = (this.HideMenuStrip && this.menuStrip.Visible) ? -menuStrip.Height : 0;
476 		}
477 
frmMain_Resize(object sender, EventArgs e)478 		private void frmMain_Resize(object sender, EventArgs e)
479 		{
480 			if(_enableResize && this.WindowState != FormWindowState.Minimized) {
481 				SetScaleBasedOnWindowSize();
482 				UpdateRendererPosition();
483 			}
484 		}
485 
SetScaleBasedOnDimensions(Size dimensions, bool allowVsDualScreen)486 		private void SetScaleBasedOnDimensions(Size dimensions, bool allowVsDualScreen)
487 		{
488 			_customSize = true;
489 			InteropEmu.ScreenSize size = InteropEmu.GetScreenSize(true);
490 
491 			if(allowVsDualScreen && _isDualSystem && ConfigManager.Config.PreferenceInfo.VsDualVideoOutput == VsDualOutputOption.Both) {
492 				size = new InteropEmu.ScreenSize() {
493 					Width = size.Width * 2,
494 					Height = size.Height,
495 					Scale = size.Scale
496 				};
497 			}
498 
499 			double verticalScale = (double)dimensions.Height / size.Height;
500 			double horizontalScale = (double)dimensions.Width / size.Width;
501 			double scale = Math.Min(verticalScale, horizontalScale);
502 			if(_fullscreenMode && ConfigManager.Config.VideoInfo.FullscreenForceIntegerScale) {
503 				scale = Math.Floor(scale);
504 			}
505 			UpdateScaleMenu(scale);
506 			VideoInfo.ApplyConfig();
507 		}
508 
SetScaleBasedOnWindowSize()509 		private void SetScaleBasedOnWindowSize()
510 		{
511 			SetScaleBasedOnDimensions(panelRenderer.ClientSize, true);
512 		}
513 
SetScaleBasedOnScreenSize()514 		private void SetScaleBasedOnScreenSize()
515 		{
516 			SetScaleBasedOnDimensions(Screen.FromControl(this).Bounds.Size, false);
517 		}
518 
StopExclusiveFullscreenMode()519 		private void StopExclusiveFullscreenMode()
520 		{
521 			if(_frmFullscreenRenderer != null) {
522 				_frmFullscreenRenderer.Close();
523 			}
524 		}
525 
StartExclusiveFullscreenMode()526 		private void StartExclusiveFullscreenMode()
527 		{
528 			Size screenSize = Screen.FromControl(this).Bounds.Size;
529 			_frmFullscreenRenderer = new frmFullscreenRenderer();
530 			_frmFullscreenRenderer.Shown += (object sender, EventArgs e) => {
531 				ctrlRenderer.Visible = false;
532 				SetScaleBasedOnScreenSize();
533 				InteropEmu.SetFullscreenMode(true, _frmFullscreenRenderer.Handle, (UInt32)screenSize.Width, (UInt32)screenSize.Height);
534 			};
535 			_frmFullscreenRenderer.FormClosing += (object sender, FormClosingEventArgs e) => {
536 				InteropEmu.SetFullscreenMode(false, ctrlRenderer.Handle, (UInt32)screenSize.Width, (UInt32)screenSize.Height);
537 				_frmFullscreenRenderer = null;
538 				ctrlRenderer.Visible = true;
539 				_fullscreenMode = false;
540 				frmMain_Resize(null, EventArgs.Empty);
541 			};
542 
543 			Screen currentScreen = Screen.FromHandle(this.Handle);
544 			_frmFullscreenRenderer.StartPosition = FormStartPosition.Manual;
545 			_frmFullscreenRenderer.Top = currentScreen.Bounds.Top;
546 			_frmFullscreenRenderer.Left = currentScreen.Bounds.Left;
547 			_frmFullscreenRenderer.Show();
548 		}
549 
StartFullscreenWindowMode(bool saveState)550 		private void StartFullscreenWindowMode(bool saveState)
551 		{
552 			this.menuStrip.Visible = false;
553 			if(saveState) {
554 				_originalWindowState = this.WindowState;
555 				_originalWindowMinimumSize = this.MinimumSize;
556 			}
557 			this.MinimumSize = new Size(0, 0);
558 			this.WindowState = FormWindowState.Normal;
559 			this.FormBorderStyle = FormBorderStyle.None;
560 			this.WindowState = FormWindowState.Maximized;
561 			SetScaleBasedOnWindowSize();
562 		}
563 
StopFullscreenWindowMode()564 		private void StopFullscreenWindowMode()
565 		{
566 			this.menuStrip.Visible = true;
567 			this.WindowState = _originalWindowState;
568 			this.MinimumSize = _originalWindowMinimumSize;
569 			this.FormBorderStyle = ConfigManager.Config.PreferenceInfo.DisableMouseResize ? FormBorderStyle.Fixed3D : FormBorderStyle.Sizable;
570 			this.frmMain_Resize(null, EventArgs.Empty);
571 		}
572 
SetFullscreenState(bool enabled)573 		private void SetFullscreenState(bool enabled)
574 		{
575 			if(this._isNsfPlayerMode) {
576 				enabled = false;
577 			}
578 
579 			if(_fullscreenMode == enabled) {
580 				//Fullscreen mode already matches, no need to do anything
581 				return;
582 			}
583 
584 			//Setup message to show on screen when paused while in fullscreen (instructions to revert to windowed mode)
585 			InteropEmu.SetPauseScreenMessage("");
586 			if(enabled) {
587 				ShortcutKeyInfo shortcut = ConfigManager.Config.PreferenceInfo.ShortcutKeys1.Find(ski => ski.Shortcut == EmulatorShortcut.ToggleFullscreen);
588 				if(shortcut == null || shortcut.KeyCombination.IsEmpty) {
589 					shortcut = ConfigManager.Config.PreferenceInfo.ShortcutKeys2.Find(ski => ski.Shortcut == EmulatorShortcut.ToggleFullscreen);
590 				}
591 
592 				if(shortcut != null && !shortcut.KeyCombination.IsEmpty) {
593 					InteropEmu.SetPauseScreenMessage(ResourceHelper.GetMessage("PressToExitFullscreen", shortcut.KeyCombination.ToString()));
594 				}
595 			}
596 
597 			bool saveState = !_fullscreenMode;
598 			_fullscreenMode = enabled;
599 			mnuFullscreen.Checked = enabled;
600 
601 			if(ConfigManager.Config.VideoInfo.UseExclusiveFullscreen) {
602 				if(_emuThread != null) {
603 					if(enabled) {
604 						StartExclusiveFullscreenMode();
605 					} else {
606 						StopExclusiveFullscreenMode();
607 					}
608 				}
609 			} else {
610 				this.Resize -= frmMain_Resize;
611 				if(enabled) {
612 					StartFullscreenWindowMode(saveState);
613 				} else {
614 					StopFullscreenWindowMode();
615 				}
616 				this.Resize += frmMain_Resize;
617 				UpdateViewerSize();
618 			}
619 		}
620 
621 		private bool HideMenuStrip
622 		{
623 			get
624 			{
625 				return (_fullscreenMode && !ConfigManager.Config.VideoInfo.UseExclusiveFullscreen) || ConfigManager.Config.PreferenceInfo.AutoHideMenu;
626 			}
627 		}
628 
ctrlRenderer_MouseMove(object sender, MouseEventArgs e)629 		private void ctrlRenderer_MouseMove(object sender, MouseEventArgs e)
630 		{
631 			if(sender != this.ctrlRecentGames) {
632 				CursorManager.OnMouseMove((Control)sender);
633 			}
634 
635 			if(this.HideMenuStrip && !this.menuStrip.ContainsFocus) {
636 				if(sender == ctrlRenderer) {
637 					this.menuStrip.Visible = ctrlRenderer.Top + e.Y < 30;
638 				} else {
639 					this.menuStrip.Visible = e.Y < 30;
640 				}
641 			}
642 		}
643 
ctrlRenderer_MouseClick(object sender, MouseEventArgs e)644 		private void ctrlRenderer_MouseClick(object sender, MouseEventArgs e)
645 		{
646 			if(this.HideMenuStrip) {
647 				this.menuStrip.Visible = false;
648 			}
649 			CursorManager.CaptureMouse();
650 		}
651 
_notifListener_OnNotification(InteropEmu.NotificationEventArgs e)652 		private void _notifListener_OnNotification(InteropEmu.NotificationEventArgs e)
653 		{
654 			switch(e.NotificationType) {
655 				case InteropEmu.ConsoleNotificationType.GameLoaded:
656 					VideoInfo.ApplyOverscanConfig();
657 					_currentGame = InteropEmu.GetRomInfo().GetRomName();
658 					InteropEmu.SetNesModel(ConfigManager.Config.Region);
659 					InitializeNsfMode(true);
660 					CheatInfo.ApplyCheats();
661 					GameSpecificInfo.ApplyGameSpecificConfig();
662 					UpdateStateMenu(mnuSaveState, true);
663 					UpdateStateMenu(mnuLoadState, false);
664 					if(ConfigManager.Config.PreferenceInfo.ShowVsConfigOnLoad && InteropEmu.IsVsSystem()) {
665 						this.Invoke((MethodInvoker)(() => {
666 							this.ShowGameConfig();
667 						}));
668 					}
669 
670 					this.StartEmuThread();
671 					this.BeginInvoke((MethodInvoker)(() => {
672 						UpdateViewerSize();
673 						ProcessPostLoadCommandSwitches();
674 					}));
675 					break;
676 
677 				case InteropEmu.ConsoleNotificationType.GameReset:
678 					InitializeNsfMode();
679 					break;
680 
681 				case InteropEmu.ConsoleNotificationType.DisconnectedFromServer:
682 					this.BeginInvoke((MethodInvoker)(() => {
683 						ConfigManager.Config.ApplyConfig();
684 					}));
685 					break;
686 
687 				case InteropEmu.ConsoleNotificationType.EmulationStopped:
688 					InitializeNsfMode();
689 					break;
690 
691 				case InteropEmu.ConsoleNotificationType.GameStopped:
692 					this._currentGame = null;
693 					CheatInfo.ClearCheats();
694 					this.BeginInvoke((MethodInvoker)(() => {
695 						if(_hdPackEditorWindow != null) {
696 							_hdPackEditorWindow.Close();
697 						}
698 						if(!ConfigManager.Config.PreferenceInfo.DisableGameSelectionScreen) {
699 							ctrlRecentGames.Initialize();
700 						}
701 						if(e.Parameter == IntPtr.Zero) {
702 							//We are completely stopping the emulation, close fullscreen mode
703 							StopExclusiveFullscreenMode();
704 						}
705 					}));
706 					break;
707 
708 				case InteropEmu.ConsoleNotificationType.BeforeEmulationStop:
709 					//Close all debugger windows before continuing.
710 					this.Invoke((Action)(() => {
711 						DebugWindowManager.CloseAll();
712 					}));
713 					break;
714 
715 				case InteropEmu.ConsoleNotificationType.ResolutionChanged:
716 					this.BeginInvoke((MethodInvoker)(() => {
717 						ProcessResolutionChanged();
718 					}));
719 					break;
720 
721 				case InteropEmu.ConsoleNotificationType.FdsBiosNotFound:
722 					this.BeginInvoke((MethodInvoker)(() => {
723 						SelectFdsBiosPrompt();
724 					}));
725 					break;
726 
727 				case InteropEmu.ConsoleNotificationType.ExecuteShortcut:
728 					this.BeginInvoke((MethodInvoker)(() => {
729 						ExecuteShortcut((EmulatorShortcut)e.Parameter);
730 					}));
731 					break;
732 
733 				case InteropEmu.ConsoleNotificationType.CodeBreak:
734 					this.BeginInvoke((MethodInvoker)(() => {
735 						if(DebugWindowManager.GetDebugger() == null) {
736 							DebugWindowManager.OpenDebugWindow(DebugWindow.Debugger);
737 						}
738 					}));
739 					break;
740 
741 				case InteropEmu.ConsoleNotificationType.VsDualSystemStarted:
742 					_isDualSystem = true;
743 					this.BeginInvoke((MethodInvoker)(() => {
744 						UpdateViewerSize(true);
745 						InteropEmu.InitializeDualSystem(this.Handle, ctrlRendererDualSystem.Handle);
746 					}));
747 					break;
748 
749 				case InteropEmu.ConsoleNotificationType.VsDualSystemStopped:
750 					_isDualSystem = false;
751 					InteropEmu.ReleaseDualSystemAudioVideo();
752 					this.BeginInvoke((MethodInvoker)(() => {
753 						UpdateViewerSize(true);
754 					}));
755 					break;
756 			}
757 
758 			if(e.NotificationType != InteropEmu.ConsoleNotificationType.PpuFrameDone) {
759 				UpdateMenus();
760 			}
761 		}
762 
ProcessResolutionChanged()763 		private void ProcessResolutionChanged()
764 		{
765 			//Force scale specified by command line options, when using /fullscreen
766 			if(_fullscreenRequested) {
767 				SetFullscreenState(true);
768 				if(_switchOptionScale.HasValue) {
769 					//If a VideoScale is specified in command line, apply it
770 					SetScale(_switchOptionScale.Value);
771 				}
772 				_fullscreenRequested = false;
773 			} else if(_switchOptionScale.HasValue) {
774 				//For exclusive fullscreen, resolution changed will be called twice, need to set the scale one more time here
775 				SetScale(_switchOptionScale.Value);
776 				_switchOptionScale = null;
777 			} else {
778 				UpdateViewerSize();
779 			}
780 		}
781 
BindShortcuts()782 		private void BindShortcuts()
783 		{
784 			Func<bool> notClient = () => { return !InteropEmu.IsConnected(); };
785 			Func<bool> runningNotClient = () => { return _emuThread != null && !InteropEmu.IsConnected(); };
786 			Func<bool> runningNotClientNotMovie = () => { return _emuThread != null && !InteropEmu.IsConnected() && !InteropEmu.MoviePlaying(); };
787 
788 			Func<bool> runningNotNsf = () => { return _emuThread != null && !InteropEmu.IsNsf(); };
789 			Func<bool> runningFdsNoAutoInsert = () => { return _emuThread != null && InteropEmu.FdsGetSideCount() > 0 && !InteropEmu.FdsIsAutoInsertDiskEnabled() && !InteropEmu.MoviePlaying() && !InteropEmu.IsConnected(); };
790 			Func<bool> runningFdsMultipleDisks = () => { return runningFdsNoAutoInsert() && InteropEmu.FdsGetSideCount() > 1; };
791 			Func<bool> runningVsSystem = () => { return _emuThread != null && InteropEmu.IsVsSystem() && !InteropEmu.MoviePlaying() && !InteropEmu.IsConnected(); };
792 			Func<bool> runningVsDualSystem = () => { return runningVsSystem() && InteropEmu.IsVsDualSystem(); };
793 			Func<bool> hasBarcodeReader = () => { return InteropEmu.GetAvailableFeatures().HasFlag(ConsoleFeatures.BarcodeReader) && !InteropEmu.IsConnected(); };
794 
795 			Func<bool> enableLoadLastSession = () => {
796 				string recentGameFile = _currentRomPath.HasValue ? Path.Combine(ConfigManager.RecentGamesFolder, Path.GetFileNameWithoutExtension(_currentRomPath.Value.FileName) + ".rgd") : "";
797 				return _emuThread != null && File.Exists(recentGameFile) && !ConfigManager.Config.PreferenceInfo.DisableGameSelectionScreen;
798 			};
799 
800 			BindShortcut(mnuOpen, EmulatorShortcut.OpenFile);
801 			BindShortcut(mnuExit, EmulatorShortcut.Exit);
802 			BindShortcut(mnuIncreaseSpeed, EmulatorShortcut.IncreaseSpeed, notClient);
803 			BindShortcut(mnuDecreaseSpeed, EmulatorShortcut.DecreaseSpeed, notClient);
804 			BindShortcut(mnuEmuSpeedMaximumSpeed, EmulatorShortcut.MaxSpeed, notClient);
805 
806 			BindShortcut(mnuPause, EmulatorShortcut.Pause, runningNotClient);
807 			BindShortcut(mnuReset, EmulatorShortcut.Reset, runningNotClientNotMovie);
808 			BindShortcut(mnuPowerCycle, EmulatorShortcut.PowerCycle, runningNotClientNotMovie);
809 			BindShortcut(mnuPowerOff, EmulatorShortcut.PowerOff, runningNotClient);
810 
811 			BindShortcut(mnuSwitchDiskSide, EmulatorShortcut.SwitchDiskSide, runningFdsMultipleDisks);
812 			BindShortcut(mnuEjectDisk, EmulatorShortcut.EjectDisk, runningFdsNoAutoInsert);
813 
814 			BindShortcut(mnuInsertCoin1, EmulatorShortcut.InsertCoin1, runningVsSystem);
815 			BindShortcut(mnuInsertCoin2, EmulatorShortcut.InsertCoin2, runningVsSystem);
816 			BindShortcut(mnuInsertCoin3, EmulatorShortcut.InsertCoin3, runningVsDualSystem);
817 			BindShortcut(mnuInsertCoin4, EmulatorShortcut.InsertCoin4, runningVsDualSystem);
818 
819 			BindShortcut(mnuInputBarcode, EmulatorShortcut.InputBarcode, hasBarcodeReader);
820 
821 			BindShortcut(mnuShowFPS, EmulatorShortcut.ToggleFps);
822 
823 			BindShortcut(mnuScale1x, EmulatorShortcut.SetScale1x);
824 			BindShortcut(mnuScale2x, EmulatorShortcut.SetScale2x);
825 			BindShortcut(mnuScale3x, EmulatorShortcut.SetScale3x);
826 			BindShortcut(mnuScale4x, EmulatorShortcut.SetScale4x);
827 			BindShortcut(mnuScale5x, EmulatorShortcut.SetScale5x);
828 			BindShortcut(mnuScale6x, EmulatorShortcut.SetScale6x);
829 
830 			BindShortcut(mnuFullscreen, EmulatorShortcut.ToggleFullscreen);
831 
832 			BindShortcut(mnuLoadLastSession, EmulatorShortcut.LoadLastSession, enableLoadLastSession);
833 
834 			BindShortcut(mnuTakeScreenshot, EmulatorShortcut.TakeScreenshot, runningNotNsf);
835 			BindShortcut(mnuRandomGame, EmulatorShortcut.LoadRandomGame);
836 
837 			mnuDebugDebugger.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenDebugger));
838 			mnuDebugger.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenDebugger));
839 			mnuApuViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenApuViewer));
840 			mnuAssembler.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenAssembler));
841 			mnuMemoryViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenMemoryTools));
842 			mnuEventViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenEventViewer));
843 			mnuPpuViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenPpuViewer));
844 			mnuScriptWindow.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenScriptWindow));
845 			mnuTraceLogger.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenTraceLogger));
846 			mnuTextHooker.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenTextHooker));
847 			mnuProfiler.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenProfiler));
848 			mnuWatchWindow.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenWatchWindow));
849 
850 			mnuOpenNametableViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenNametableViewer));
851 			mnuOpenChrViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenChrViewer));
852 			mnuOpenSpriteViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenSpriteViewer));
853 			mnuOpenPaletteViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenPaletteViewer));
854 		}
855 
BindShortcut(ToolStripMenuItem item, EmulatorShortcut shortcut, Func<bool> isActionEnabled = null)856 		private void BindShortcut(ToolStripMenuItem item, EmulatorShortcut shortcut, Func<bool> isActionEnabled = null)
857 		{
858 			item.Click += (object sender, EventArgs e) => {
859 				if(isActionEnabled == null || isActionEnabled()) {
860 					ExecuteShortcut(shortcut);
861 				}
862 			};
863 
864 			_actionEnabledFuncs[shortcut] = isActionEnabled;
865 
866 			if(item.OwnerItem is ToolStripMenuItem) {
867 				Action updateShortcut = () => {
868 					int keyIndex = ConfigManager.Config.PreferenceInfo.ShortcutKeys1.FindIndex((ShortcutKeyInfo shortcutInfo) => shortcutInfo.Shortcut == shortcut);
869 					if(keyIndex >= 0) {
870 						item.ShortcutKeyDisplayString = ConfigManager.Config.PreferenceInfo.ShortcutKeys1[keyIndex].KeyCombination.ToString();
871 					} else {
872 						keyIndex = ConfigManager.Config.PreferenceInfo.ShortcutKeys2.FindIndex((ShortcutKeyInfo shortcutInfo) => shortcutInfo.Shortcut == shortcut);
873 						if(keyIndex >= 0) {
874 							item.ShortcutKeyDisplayString = ConfigManager.Config.PreferenceInfo.ShortcutKeys2[keyIndex].KeyCombination.ToString();
875 						} else {
876 							item.ShortcutKeyDisplayString = "";
877 						}
878 					}
879 					item.Enabled = isActionEnabled == null || isActionEnabled();
880 				};
881 
882 				updateShortcut();
883 
884 				//Update item shortcut text when its parent opens
885 				((ToolStripMenuItem)item.OwnerItem).DropDownOpening += (object sender, EventArgs e) => { updateShortcut(); };
886 			}
887 		}
888 
ExecuteShortcut(EmulatorShortcut shortcut)889 		private void ExecuteShortcut(EmulatorShortcut shortcut)
890 		{
891 			Func<bool> isActionEnabled;
892 			if(_actionEnabledFuncs.TryGetValue(shortcut, out isActionEnabled)) {
893 				isActionEnabled = _actionEnabledFuncs[shortcut];
894 				if(isActionEnabled != null && !isActionEnabled()) {
895 					//Action disabled
896 					return;
897 				}
898 			}
899 
900 			bool restoreFullscreen = _frmFullscreenRenderer != null;
901 
902 			switch(shortcut) {
903 				case EmulatorShortcut.Pause: PauseEmu(); break;
904 				case EmulatorShortcut.Reset: this.ResetEmu(); break;
905 				case EmulatorShortcut.PowerCycle: this.PowerCycleEmu(); break;
906 				case EmulatorShortcut.PowerOff: Task.Run(() => InteropEmu.Stop()); break;
907 				case EmulatorShortcut.Exit: this.Close(); break;
908 
909 				case EmulatorShortcut.ToggleCheats: ToggleCheats(); break;
910 				case EmulatorShortcut.ToggleAudio: ToggleAudio(); break;
911 				case EmulatorShortcut.ToggleFps: ToggleFps(); break;
912 				case EmulatorShortcut.ToggleBackground: ToggleBackground(); break;
913 				case EmulatorShortcut.ToggleSprites: ToggleSprites(); break;
914 				case EmulatorShortcut.ToggleGameTimer: ToggleGameTimer(); break;
915 				case EmulatorShortcut.ToggleFrameCounter: ToggleFrameCounter(); break;
916 				case EmulatorShortcut.ToggleLagCounter: ToggleLagCounter(); break;
917 				case EmulatorShortcut.ToggleOsd: ToggleOsd(); break;
918 				case EmulatorShortcut.ToggleAlwaysOnTop: ToggleAlwaysOnTop(); break;
919 				case EmulatorShortcut.ToggleDebugInfo: ToggleDebugInfo(); break;
920 				case EmulatorShortcut.MaxSpeed: ToggleMaxSpeed(); break;
921 				case EmulatorShortcut.ToggleFullscreen: ToggleFullscreen(); restoreFullscreen = false; break;
922 
923 				case EmulatorShortcut.OpenFile: OpenFile(); break;
924 				case EmulatorShortcut.IncreaseSpeed: InteropEmu.IncreaseEmulationSpeed(); break;
925 				case EmulatorShortcut.DecreaseSpeed: InteropEmu.DecreaseEmulationSpeed(); break;
926 				case EmulatorShortcut.SwitchDiskSide: InteropEmu.FdsSwitchDiskSide(); break;
927 				case EmulatorShortcut.EjectDisk: InteropEmu.FdsEjectDisk(); break;
928 
929 				case EmulatorShortcut.SetScale1x: SetScale(1); break;
930 				case EmulatorShortcut.SetScale2x: SetScale(2); break;
931 				case EmulatorShortcut.SetScale3x: SetScale(3); break;
932 				case EmulatorShortcut.SetScale4x: SetScale(4); break;
933 				case EmulatorShortcut.SetScale5x: SetScale(5); break;
934 				case EmulatorShortcut.SetScale6x: SetScale(6); break;
935 
936 				case EmulatorShortcut.InsertCoin1: InteropEmu.VsInsertCoin(0); break;
937 				case EmulatorShortcut.InsertCoin2: InteropEmu.VsInsertCoin(1); break;
938 				case EmulatorShortcut.InsertCoin3: InteropEmu.VsInsertCoin(2); break;
939 				case EmulatorShortcut.InsertCoin4: InteropEmu.VsInsertCoin(3); break;
940 
941 				case EmulatorShortcut.InputBarcode:
942 					using(frmInputBarcode frm = new frmInputBarcode()) {
943 						frm.ShowDialog(this, this);
944 					}
945 					break;
946 
947 				case EmulatorShortcut.TakeScreenshot: InteropEmu.TakeScreenshot(); break;
948 				case EmulatorShortcut.LoadRandomGame: LoadRandomGame(); break;
949 
950 				case EmulatorShortcut.LoadStateFromFile: LoadStateFromFile(); break;
951 				case EmulatorShortcut.SaveStateToFile: SaveStateToFile(); break;
952 
953 				case EmulatorShortcut.SaveStateSlot1: SaveState(1); break;
954 				case EmulatorShortcut.SaveStateSlot2: SaveState(2); break;
955 				case EmulatorShortcut.SaveStateSlot3: SaveState(3); break;
956 				case EmulatorShortcut.SaveStateSlot4: SaveState(4); break;
957 				case EmulatorShortcut.SaveStateSlot5: SaveState(5); break;
958 				case EmulatorShortcut.SaveStateSlot6: SaveState(6); break;
959 				case EmulatorShortcut.SaveStateSlot7: SaveState(7); break;
960 				case EmulatorShortcut.SaveStateSlot8: SaveState(8); break;
961 				case EmulatorShortcut.SaveStateSlot9: SaveState(9); break;
962 				case EmulatorShortcut.SaveStateSlot10: SaveState(10); break;
963 				case EmulatorShortcut.LoadStateSlot1: LoadState(1); break;
964 				case EmulatorShortcut.LoadStateSlot2: LoadState(2); break;
965 				case EmulatorShortcut.LoadStateSlot3: LoadState(3); break;
966 				case EmulatorShortcut.LoadStateSlot4: LoadState(4); break;
967 				case EmulatorShortcut.LoadStateSlot5: LoadState(5); break;
968 				case EmulatorShortcut.LoadStateSlot6: LoadState(6); break;
969 				case EmulatorShortcut.LoadStateSlot7: LoadState(7); break;
970 				case EmulatorShortcut.LoadStateSlot8: LoadState(8); break;
971 				case EmulatorShortcut.LoadStateSlot9: LoadState(9); break;
972 				case EmulatorShortcut.LoadStateSlot10: LoadState(10); break;
973 				case EmulatorShortcut.LoadStateSlotAuto: LoadState(11); break;
974 
975 				case EmulatorShortcut.LoadLastSession: LoadLastSession(); break;
976 			}
977 
978 			if(restoreFullscreen && _frmFullscreenRenderer == null && !_shuttingDown) {
979 				//Need to restore fullscreen mode after showing a dialog
980 				this.SetFullscreenState(true);
981 			}
982 		}
983 
ToggleFullscreen()984 		private void ToggleFullscreen()
985 		{
986 			SetFullscreenState(!_fullscreenMode);
987 		}
988 
ToggleMaxSpeed()989 		private void ToggleMaxSpeed()
990 		{
991 			if(ConfigManager.Config.EmulationInfo.EmulationSpeed == 0) {
992 				SetEmulationSpeed(100);
993 			} else {
994 				SetEmulationSpeed(0);
995 			}
996 		}
997 
ToggleFps()998 		private void ToggleFps()
999 		{
1000 			mnuShowFPS.Checked = !mnuShowFPS.Checked;
1001 			UpdateEmulationFlags();
1002 		}
1003 
ToggleAudio()1004 		private void ToggleAudio()
1005 		{
1006 			ConfigManager.Config.AudioInfo.EnableAudio = !ConfigManager.Config.AudioInfo.EnableAudio;
1007 			AudioInfo.ApplyConfig();
1008 			ConfigManager.ApplyChanges();
1009 		}
1010 
ToggleFrameCounter()1011 		private void ToggleFrameCounter()
1012 		{
1013 			ConfigManager.Config.PreferenceInfo.ShowFrameCounter = !ConfigManager.Config.PreferenceInfo.ShowFrameCounter;
1014 			PreferenceInfo.ApplyConfig();
1015 			ConfigManager.ApplyChanges();
1016 		}
1017 
ToggleLagCounter()1018 		private void ToggleLagCounter()
1019 		{
1020 			ConfigManager.Config.EmulationInfo.ShowLagCounter = !ConfigManager.Config.EmulationInfo.ShowLagCounter;
1021 			EmulationInfo.ApplyConfig();
1022 			ConfigManager.ApplyChanges();
1023 		}
1024 
ToggleGameTimer()1025 		private void ToggleGameTimer()
1026 		{
1027 			ConfigManager.Config.PreferenceInfo.ShowGameTimer = !ConfigManager.Config.PreferenceInfo.ShowGameTimer;
1028 			PreferenceInfo.ApplyConfig();
1029 			ConfigManager.ApplyChanges();
1030 		}
1031 
ToggleOsd()1032 		private void ToggleOsd()
1033 		{
1034 			ConfigManager.Config.PreferenceInfo.DisableOsd = !ConfigManager.Config.PreferenceInfo.DisableOsd;
1035 			PreferenceInfo.ApplyConfig();
1036 			ConfigManager.ApplyChanges();
1037 		}
1038 
ToggleAlwaysOnTop()1039 		private void ToggleAlwaysOnTop()
1040 		{
1041 			ConfigManager.Config.PreferenceInfo.AlwaysOnTop = !ConfigManager.Config.PreferenceInfo.AlwaysOnTop;
1042 			ConfigManager.ApplyChanges();
1043 			this.TopMost = ConfigManager.Config.PreferenceInfo.AlwaysOnTop;
1044 		}
1045 
ToggleSprites()1046 		private void ToggleSprites()
1047 		{
1048 			ConfigManager.Config.VideoInfo.DisableSprites = !ConfigManager.Config.VideoInfo.DisableSprites;
1049 			VideoInfo.ApplyConfig();
1050 			ConfigManager.ApplyChanges();
1051 		}
1052 
ToggleBackground()1053 		private void ToggleBackground()
1054 		{
1055 			ConfigManager.Config.VideoInfo.DisableBackground = !ConfigManager.Config.VideoInfo.DisableBackground;
1056 			VideoInfo.ApplyConfig();
1057 			ConfigManager.ApplyChanges();
1058 		}
1059 
ToggleDebugInfo()1060 		private void ToggleDebugInfo()
1061 		{
1062 			ConfigManager.Config.PreferenceInfo.DisplayDebugInfo = !ConfigManager.Config.PreferenceInfo.DisplayDebugInfo;
1063 			PreferenceInfo.ApplyConfig();
1064 			ConfigManager.ApplyChanges();
1065 		}
1066 
ToggleCheats()1067 		private void ToggleCheats()
1068 		{
1069 			ConfigManager.Config.DisableAllCheats = !ConfigManager.Config.DisableAllCheats;
1070 			if(ConfigManager.Config.DisableAllCheats) {
1071 				InteropEmu.DisplayMessage("Cheats", "CheatsDisabled");
1072 			}
1073 			CheatInfo.ApplyCheats();
1074 			ConfigManager.ApplyChanges();
1075 		}
1076 
UpdateMenus()1077 		private void UpdateMenus()
1078 		{
1079 			if(_shuttingDown) {
1080 				return;
1081 			}
1082 
1083 			try {
1084 				if(this.InvokeRequired) {
1085 					this.BeginInvoke((MethodInvoker)(() => this.UpdateMenus()));
1086 				} else {
1087 					bool running = _emuThread != null;
1088 					bool devMode = ConfigManager.Config.PreferenceInfo.DeveloperMode;
1089 					mnuDebug.Visible = devMode;
1090 
1091 					panelInfo.Visible = !running;
1092 					ctrlRecentGames.Visible = !running;
1093 
1094 					ctrlLoading.Visible = (_romLoadCounter > 0);
1095 
1096 					UpdateWindowTitle();
1097 
1098 					bool isNetPlayClient = InteropEmu.IsConnected();
1099 
1100 					mnuSaveState.Enabled = (running && !isNetPlayClient && !InteropEmu.IsNsf());
1101 					mnuLoadState.Enabled = (running && !isNetPlayClient && !InteropEmu.IsNsf() && !InteropEmu.MoviePlaying() && !InteropEmu.MovieRecording());
1102 
1103 					mnuPause.Text = InteropEmu.IsPaused() ? ResourceHelper.GetMessage("Resume") : ResourceHelper.GetMessage("Pause");
1104 					mnuPause.Image = InteropEmu.IsPaused() ? _playButton : _pauseButton;
1105 
1106 					bool netPlay = InteropEmu.IsServerRunning() || isNetPlayClient;
1107 
1108 					mnuStartServer.Enabled = !isNetPlayClient;
1109 					mnuConnect.Enabled = !InteropEmu.IsServerRunning();
1110 					mnuNetPlaySelectController.Enabled = isNetPlayClient || InteropEmu.IsServerRunning();
1111 					if(mnuNetPlaySelectController.Enabled) {
1112 						int availableControllers = InteropEmu.NetPlayGetAvailableControllers();
1113 						int currentControllerPort = InteropEmu.NetPlayGetControllerPort();
1114 						mnuNetPlayPlayer1.Enabled = (availableControllers & 0x01) == 0x01;
1115 						mnuNetPlayPlayer2.Enabled = (availableControllers & 0x02) == 0x02;
1116 						mnuNetPlayPlayer3.Enabled = (availableControllers & 0x04) == 0x04;
1117 						mnuNetPlayPlayer4.Enabled = (availableControllers & 0x08) == 0x08;
1118 
1119 						bool isFamicom = InteropEmu.GetConsoleType() == ConsoleType.Famicom;
1120 						mnuNetPlayPlayer5.Visible = isFamicom;
1121 						mnuNetPlayPlayer5.Enabled = (availableControllers & 0x10) == 0x10 && InteropEmu.GetExpansionDevice() != InteropEmu.ExpansionPortDevice.FourPlayerAdapter;
1122 
1123 						mnuNetPlayPlayer1.Text = ResourceHelper.GetMessage("PlayerNumber", "1") + " (" + ResourceHelper.GetEnumText(InteropEmu.NetPlayGetControllerType(0)) + ")";
1124 						mnuNetPlayPlayer2.Text = ResourceHelper.GetMessage("PlayerNumber", "2") + " (" + ResourceHelper.GetEnumText(InteropEmu.NetPlayGetControllerType(1)) + ")";
1125 						mnuNetPlayPlayer3.Text = ResourceHelper.GetMessage("PlayerNumber", "3") + " (" + ResourceHelper.GetEnumText(InteropEmu.NetPlayGetControllerType(2)) + ")";
1126 						mnuNetPlayPlayer4.Text = ResourceHelper.GetMessage("PlayerNumber", "4") + " (" + ResourceHelper.GetEnumText(InteropEmu.NetPlayGetControllerType(3)) + ")";
1127 						mnuNetPlayPlayer5.Text = ResourceHelper.GetMessage("ExpansionDevice") + " (" + ResourceHelper.GetEnumText(InteropEmu.GetExpansionDevice()) + ")";
1128 
1129 						mnuNetPlayPlayer1.Checked = (currentControllerPort == 0);
1130 						mnuNetPlayPlayer2.Checked = (currentControllerPort == 1);
1131 						mnuNetPlayPlayer3.Checked = (currentControllerPort == 2);
1132 						mnuNetPlayPlayer4.Checked = (currentControllerPort == 3);
1133 						mnuNetPlayPlayer5.Checked = (currentControllerPort == 4);
1134 						mnuNetPlaySpectator.Checked = (currentControllerPort == 0xFF);
1135 
1136 						mnuNetPlaySpectator.Enabled = true;
1137 					}
1138 
1139 					mnuStartServer.Text = InteropEmu.IsServerRunning() ? ResourceHelper.GetMessage("StopServer") : ResourceHelper.GetMessage("StartServer");
1140 					mnuConnect.Text = isNetPlayClient ? ResourceHelper.GetMessage("Disconnect") : ResourceHelper.GetMessage("ConnectToServer");
1141 
1142 					mnuCheats.Enabled = !isNetPlayClient;
1143 					mnuEmulationSpeed.Enabled = !isNetPlayClient;
1144 					mnuInput.Enabled = !isNetPlayClient;
1145 					mnuRegion.Enabled = !isNetPlayClient;
1146 
1147 					bool moviePlaying = InteropEmu.MoviePlaying();
1148 					bool movieRecording = InteropEmu.MovieRecording();
1149 					mnuPlayMovie.Enabled = !netPlay && !moviePlaying && !movieRecording;
1150 					mnuStopMovie.Enabled = running && !netPlay && (moviePlaying || movieRecording);
1151 					mnuRecordMovie.Enabled = running && !moviePlaying && !movieRecording && !isNetPlayClient;
1152 					mnuGameConfig.Enabled = !moviePlaying && !movieRecording;
1153 					mnuHistoryViewer.Enabled = running && InteropEmu.HistoryViewerEnabled();
1154 
1155 					bool waveRecording = InteropEmu.WaveIsRecording();
1156 					mnuWaveRecord.Enabled = running && !waveRecording;
1157 					mnuWaveStop.Enabled = running && waveRecording;
1158 
1159 					bool aviRecording = InteropEmu.AviIsRecording();
1160 					mnuAviRecord.Enabled = running && !aviRecording;
1161 					mnuAviStop.Enabled = running && aviRecording;
1162 					mnuVideoRecorder.Enabled = !_isNsfPlayerMode;
1163 
1164 					bool testRecording = InteropEmu.RomTestRecording();
1165 					mnuTestRun.Enabled = !netPlay && !moviePlaying && !movieRecording;
1166 					mnuTestStopRecording.Enabled = running && testRecording;
1167 					mnuTestRecordStart.Enabled = running && !isNetPlayClient && !moviePlaying && !movieRecording;
1168 					mnuTestRecordNow.Enabled = running && !moviePlaying && !movieRecording;
1169 					mnuTestRecordMovie.Enabled = !netPlay && !moviePlaying && !movieRecording;
1170 					mnuTestRecordTest.Enabled = !netPlay && !moviePlaying && !movieRecording;
1171 					mnuTestRecordFrom.Enabled = (mnuTestRecordStart.Enabled || mnuTestRecordNow.Enabled || mnuTestRecordMovie.Enabled || mnuTestRecordTest.Enabled);
1172 
1173 					bool tapeRecording = InteropEmu.IsRecordingTapeFile();
1174 					mnuTapeRecorder.Enabled = !isNetPlayClient;
1175 					mnuLoadTapeFile.Enabled = !isNetPlayClient;
1176 					mnuStartRecordTapeFile.Enabled = !tapeRecording && !isNetPlayClient;
1177 					mnuStopRecordTapeFile.Enabled = tapeRecording;
1178 
1179 					mnuDebugger.Visible = !devMode;
1180 					mnuDebugger.Enabled = !devMode && running;
1181 					mnuDebugDebugger.Enabled = devMode && running;
1182 					mnuApuViewer.Enabled = running;
1183 					mnuAssembler.Enabled = running;
1184 					mnuMemoryViewer.Enabled = running;
1185 					mnuEventViewer.Enabled = running;
1186 					mnuPpuViewer.Enabled = running;
1187 					mnuScriptWindow.Enabled = running;
1188 					mnuTextHooker.Enabled = running;
1189 					mnuTraceLogger.Enabled = running;
1190 					mnuProfiler.Enabled = running;
1191 					mnuWatchWindow.Enabled = running;
1192 
1193 					mnuPpuViewerCompact.Enabled = running;
1194 					mnuOpenNametableViewer.Enabled = running;
1195 					mnuOpenChrViewer.Enabled = running;
1196 					mnuOpenSpriteViewer.Enabled = running;
1197 					mnuOpenPaletteViewer.Enabled = running;
1198 
1199 #if !HIDETESTMENU
1200 					//Keep this option hidden for now, until some remaining issues are fixed.
1201 					mnuDebugDualSystemSecondaryCpu.Visible = _isDualSystem;
1202 					sepDebugDualSystemSecondaryCpu.Visible = _isDualSystem;
1203 #else
1204 					mnuDebugDualSystemSecondaryCpu.Visible = false;
1205 					sepDebugDualSystemSecondaryCpu.Visible = false;
1206 #endif
1207 
1208 					mnuInstallHdPack.Enabled = running;
1209 					mnuHdPackEditor.Enabled = !netPlay && running;
1210 
1211 					mnuNetPlay.Enabled = !InteropEmu.IsNsf();
1212 					if(running && InteropEmu.IsNsf()) {
1213 						mnuPowerCycle.Enabled = false;
1214 						mnuMovies.Enabled = mnuPlayMovie.Enabled = mnuStopMovie.Enabled = mnuRecordMovie.Enabled = false;
1215 					}
1216 
1217 					mnuRegionAuto.Checked = ConfigManager.Config.Region == NesModel.Auto;
1218 					mnuRegionNtsc.Checked = ConfigManager.Config.Region == NesModel.NTSC;
1219 					mnuRegionPal.Checked = ConfigManager.Config.Region == NesModel.PAL;
1220 					mnuRegionDendy.Checked = ConfigManager.Config.Region == NesModel.Dendy;
1221 
1222 					bool autoInsertDisabled = !InteropEmu.FdsIsAutoInsertDiskEnabled();
1223 					mnuSelectDisk.Enabled = autoInsertDisabled;
1224 
1225 					bool isHdPackLoader = InteropEmu.IsHdPpu();
1226 					mnuNtscFilter.Enabled = !isHdPackLoader;
1227 					mnuNtscBisqwitQuarterFilter.Enabled = !isHdPackLoader;
1228 					mnuNtscBisqwitHalfFilter.Enabled = !isHdPackLoader;
1229 					mnuNtscBisqwitFullFilter.Enabled = !isHdPackLoader;
1230 				}
1231 			} catch { }
1232 		}
1233 
UpdateWindowTitle()1234 		private void UpdateWindowTitle()
1235 		{
1236 			string title = "Mesen";
1237 			if(!string.IsNullOrWhiteSpace(_currentGame)) {
1238 				title += " - " + _currentGame;
1239 			}
1240 			if(ConfigManager.Config.PreferenceInfo.DisplayTitleBarInfo) {
1241 				title += string.Format(" - {0}x{1} ({2:0.##}x, {3}) - {4}", ctrlRenderer.Width, ctrlRenderer.Height, ConfigManager.Config.VideoInfo.VideoScale, ResourceHelper.GetEnumText(ConfigManager.Config.VideoInfo.AspectRatio), ResourceHelper.GetEnumText(ConfigManager.Config.VideoInfo.VideoFilter));
1242 			}
1243 			this.Text = title;
1244 		}
1245 
StartEmuThread()1246 		private void StartEmuThread()
1247 		{
1248 			if(_emuThread == null) {
1249 				_emuThread = new Thread(() => {
1250 					try {
1251 						InteropEmu.Run();
1252 						_emuThread = null;
1253 					} catch(Exception ex) {
1254 						MesenMsgBox.Show("UnexpectedError", MessageBoxButtons.OK, MessageBoxIcon.Error, ex.ToString());
1255 						_emuThread = null;
1256 					}
1257 				});
1258 				_emuThread.Start();
1259 			}
1260 			UpdateMenus();
1261 		}
1262 
StopEmu()1263 		private void StopEmu()
1264 		{
1265 			InteropEmu.Stop();
1266 		}
1267 
PauseEmu()1268 		private void PauseEmu()
1269 		{
1270 			frmDebugger debugger = DebugWindowManager.GetDebugger();
1271 			if(debugger != null) {
1272 				debugger.TogglePause();
1273 			} else {
1274 				if(InteropEmu.IsPaused()) {
1275 					InteropEmu.Resume();
1276 				} else {
1277 					InteropEmu.Pause();
1278 				}
1279 
1280 				ctrlNsfPlayer.UpdateText();
1281 			}
1282 		}
1283 
ResetEmu()1284 		private void ResetEmu()
1285 		{
1286 			if(!ConfigManager.Config.PreferenceInfo.ConfirmExitResetPower || MesenMsgBox.Show("ConfirmReset", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK) {
1287 				InteropEmu.Reset();
1288 			}
1289 		}
1290 
PowerCycleEmu()1291 		private void PowerCycleEmu()
1292 		{
1293 			if(!ConfigManager.Config.PreferenceInfo.ConfirmExitResetPower || MesenMsgBox.Show("ConfirmPowerCycle", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK) {
1294 				InteropEmu.PowerCycle();
1295 			}
1296 		}
1297 
ProcessCmdKey(ref Message msg, Keys keyData)1298 		protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
1299 		{
1300 			if(!this.menuStrip.Enabled) {
1301 				//Make sure we disable all shortcut keys while the bar is disabled (i.e when running tests)
1302 				return false;
1303 			}
1304 
1305 			if(this.HideMenuStrip && (keyData & Keys.Alt) == Keys.Alt) {
1306 				if(this.menuStrip.Visible && !this.menuStrip.ContainsFocus) {
1307 					this.menuStrip.Visible = false;
1308 				} else {
1309 					this.menuStrip.Visible = true;
1310 					this.menuStrip.Focus();
1311 				}
1312 			}
1313 
1314 #if !HIDETESTMENU
1315 			if(keyData == Keys.Pause) {
1316 				if(InteropEmu.RomTestRecording()) {
1317 					InteropEmu.RomTestStop();
1318 				} else {
1319 					InteropEmu.RomTestRecord(ConfigManager.TestFolder + "\\" + InteropEmu.GetRomInfo().GetRomName() + ".mtp", true);
1320 				}
1321 			}
1322 #endif
1323 
1324 			return base.ProcessCmdKey(ref msg, keyData);
1325 		}
1326 
SelectFdsBiosPrompt()1327 		private void SelectFdsBiosPrompt()
1328 		{
1329 			if(MesenMsgBox.Show("FdsBiosNotFound", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) {
1330 				using(OpenFileDialog ofd = new OpenFileDialog()) {
1331 					ofd.SetFilter(ResourceHelper.GetMessage("FilterAll"));
1332 					if(ofd.ShowDialog(this) == DialogResult.OK) {
1333 						string hash = MD5Helper.GetMD5Hash(ofd.FileName).ToLowerInvariant();
1334 						if(hash == "ca30b50f880eb660a320674ed365ef7a" || hash == "c1a9e9415a6adde3c8563c622d4c9fce") {
1335 							File.Copy(ofd.FileName, Path.Combine(ConfigManager.HomeFolder, "FdsBios.bin"));
1336 							LoadROM(_currentRomPath.Value, ConfigManager.Config.PreferenceInfo.AutoLoadIpsPatches);
1337 						} else {
1338 							MesenMsgBox.Show("InvalidFdsBios", MessageBoxButtons.OK, MessageBoxIcon.Error);
1339 						}
1340 					}
1341 				}
1342 			}
1343 		}
1344 
frmMain_DragDrop(object sender, DragEventArgs e)1345 		private void frmMain_DragDrop(object sender, DragEventArgs e)
1346 		{
1347 			try {
1348 				string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
1349 				if(File.Exists(files[0])) {
1350 					LoadFile(files[0]);
1351 					this.Activate();
1352 				} else {
1353 					InteropEmu.DisplayMessage("Error", "File not found: " + files[0]);
1354 				}
1355 			} catch(Exception ex) {
1356 				MesenMsgBox.Show("UnexpectedError", MessageBoxButtons.OK, MessageBoxIcon.Error, ex.ToString());
1357 			}
1358 		}
1359 
frmMain_DragEnter(object sender, DragEventArgs e)1360 		private void frmMain_DragEnter(object sender, DragEventArgs e)
1361 		{
1362 			try {
1363 				if(e.Data != null && e.Data.GetDataPresent(DataFormats.FileDrop)) {
1364 					e.Effect = DragDropEffects.Copy;
1365 				} else {
1366 					InteropEmu.DisplayMessage("Error", "Unsupported operation.");
1367 				}
1368 			} catch(Exception ex) {
1369 				MesenMsgBox.Show("UnexpectedError", MessageBoxButtons.OK, MessageBoxIcon.Error, ex.ToString());
1370 			}
1371 		}
1372 
ctrlRenderer_DoubleClick(object sender, EventArgs e)1373 		private void ctrlRenderer_DoubleClick(object sender, EventArgs e)
1374 		{
1375 			if(!CursorManager.NeedMouseIcon && !CursorManager.AllowMouseCapture && !DebugWindowManager.HasOpenedWindow) {
1376 				//Disable double clicking (used to switch to fullscreen mode) when using a mouse-controlled device (or when debugger is opened)
1377 				ToggleFullscreen();
1378 			}
1379 		}
1380 
panelRenderer_Click(object sender, EventArgs e)1381 		private void panelRenderer_Click(object sender, EventArgs e)
1382 		{
1383 			if(this.HideMenuStrip) {
1384 				this.menuStrip.Visible = false;
1385 			}
1386 			CursorManager.CaptureMouse();
1387 
1388 			ctrlRenderer.Focus();
1389 		}
1390 
ctrlRenderer_Enter(object sender, EventArgs e)1391 		private void ctrlRenderer_Enter(object sender, EventArgs e)
1392 		{
1393 			if(this.HideMenuStrip) {
1394 				this.menuStrip.Visible = false;
1395 			}
1396 		}
1397 
menuStrip_VisibleChanged(object sender, EventArgs e)1398 		private void menuStrip_VisibleChanged(object sender, EventArgs e)
1399 		{
1400 			this.UpdateRendererLocation();
1401 		}
1402 
UpdateRendererLocation()1403 		private void UpdateRendererLocation()
1404 		{
1405 			if(this.HideMenuStrip) {
1406 				IntPtr handle = this.Handle;
1407 				this.BeginInvoke((MethodInvoker)(() => {
1408 					int rendererTop = (panelRenderer.Height + (this.menuStrip.Visible ? menuStrip.Height : 0) - ctrlRenderer.Height) / 2;
1409 					this.ctrlRenderer.Top = rendererTop + (this.menuStrip.Visible ? -menuStrip.Height : 0);
1410 					this.ctrlRecentGames.Top = this.menuStrip.Visible ? -menuStrip.Height : 0;
1411 				}));
1412 			}
1413 		}
1414 
InitializeNsfMode(bool gameLoaded = false)1415 		private void InitializeNsfMode(bool gameLoaded = false)
1416 		{
1417 			if(this.InvokeRequired) {
1418 				if(InteropEmu.IsNsf()) {
1419 					if(InteropEmu.IsConnected()) {
1420 						InteropEmu.Disconnect();
1421 					}
1422 					if(InteropEmu.IsServerRunning()) {
1423 						InteropEmu.StopServer();
1424 					}
1425 				}
1426 				this.BeginInvoke((MethodInvoker)(() => this.InitializeNsfMode(gameLoaded)));
1427 			} else {
1428 				if(InteropEmu.IsNsf()) {
1429 					this.SetFullscreenState(false);
1430 
1431 					if(gameLoaded) {
1432 						//Force emulation speed to 100 when loading a NSF
1433 						SetEmulationSpeed(100);
1434 					}
1435 
1436 					if(!this._isNsfPlayerMode) {
1437 						this._nonNsfSize = this.WindowState != FormWindowState.Normal ? this.RestoreBounds.Size : this.Size;
1438 						this._nonNsfMinimumSize = this.MinimumSize;
1439 						this.Size = ctrlNsfPlayer.WindowMinimumSize;
1440 						this.MinimumSize = ctrlNsfPlayer.WindowMinimumSize;
1441 					}
1442 					this._isNsfPlayerMode = true;
1443 					this.ctrlNsfPlayer.UpdateText();
1444 					this.ctrlNsfPlayer.Visible = true;
1445 					this.ctrlNsfPlayer.Focus();
1446 
1447 					NsfHeader header = InteropEmu.NsfGetHeader();
1448 					if(header.HasSongName) {
1449 						_currentGame = header.GetSongName();
1450 					}
1451 				} else if(this._isNsfPlayerMode) {
1452 					this.MinimumSize = this._nonNsfMinimumSize;
1453 					this.Size = this._nonNsfSize.Value;
1454 					this._nonNsfSize = null;
1455 					this._isNsfPlayerMode = false;
1456 					this.ctrlNsfPlayer.Visible = false;
1457 				}
1458 			}
1459 		}
1460 
panelRenderer_MouseLeave(object sender, EventArgs e)1461 		private void panelRenderer_MouseLeave(object sender, EventArgs e)
1462 		{
1463 			CursorManager.OnMouseLeave();
1464 		}
1465 
ctrlRecentGames_OnRecentGameLoaded(Controls.RecentGameInfo gameInfo)1466 		private void ctrlRecentGames_OnRecentGameLoaded(Controls.RecentGameInfo gameInfo)
1467 		{
1468 			_currentRomPath = gameInfo.RomPath;
1469 		}
1470 
ctrlNsfPlayer_MouseMove(object sender, MouseEventArgs e)1471 		private void ctrlNsfPlayer_MouseMove(object sender, MouseEventArgs e)
1472 		{
1473 			if(this.HideMenuStrip && !this.menuStrip.ContainsFocus) {
1474 				Point nsfPlayerPosition = this.ctrlNsfPlayer.PointToClient(((Control)sender).PointToScreen(e.Location));
1475 				this.menuStrip.Visible = nsfPlayerPosition.Y < 30;
1476 			}
1477 		}
1478 
mnu_DropDownOpened(object sender, EventArgs e)1479 		private void mnu_DropDownOpened(object sender, EventArgs e)
1480 		{
1481 			_inMenu++;
1482 		}
1483 
mnu_DropDownClosed(object sender, EventArgs e)1484 		private void mnu_DropDownClosed(object sender, EventArgs e)
1485 		{
1486 			Task.Run(() => {
1487 				Thread.Sleep(100);
1488 				this.BeginInvoke((Action)(() => {
1489 					_inMenu--;
1490 				}));
1491 			});
1492 		}
1493 	}
1494 }
1495