From b0c96721714c902f6439c134d0037b71acf830b5 Mon Sep 17 00:00:00 2001 From: Ivan Martell Date: Wed, 31 Jul 2024 16:57:57 +0900 Subject: [PATCH] Allow only one instance of the game to be open. Fixed Alt-Tabbing --- LittleWarGameClient/GameForm.cs | 35 +++++++-- LittleWarGameClient/KeyboardHandler.cs | 5 +- LittleWarGameClient/OverlayForm.Designer.cs | 2 +- LittleWarGameClient/OverlayForm.cs | 31 ++++++-- LittleWarGameClient/Program.cs | 80 ++++++++++++++++++--- 5 files changed, 126 insertions(+), 27 deletions(-) diff --git a/LittleWarGameClient/GameForm.cs b/LittleWarGameClient/GameForm.cs index c1c9d2d..3cbb794 100644 --- a/LittleWarGameClient/GameForm.cs +++ b/LittleWarGameClient/GameForm.cs @@ -13,6 +13,7 @@ using CefSharp; using CefSharp.Handler; using CefSharp.WinForms; +using CefSharp.DevTools.Debugger; namespace LittleWarGameClient { @@ -42,6 +43,7 @@ internal static GameForm Instance internal GameForm() { + PreInitWeb(); InitializeComponent(); settings = new Settings(); audioMngr = new AudioManager(Text); @@ -51,9 +53,8 @@ internal GameForm() InitWebView(); } - private void InitWebView() + private void PreInitWeb() { - webBrowser.JavascriptMessageReceived += ElementMessage.JSMessageReceived; var path = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); var cefSettings = new CefSettings(); cefSettings.CefCommandLineArgs.Add("no-proxy-server", "1"); @@ -61,6 +62,11 @@ private void InitWebView() cefSettings.CefCommandLineArgs.Add("disable-extensions", "1"); cefSettings.RootCachePath = Path.Join(path, "data"); Cef.Initialize(cefSettings); + } + + private void InitWebView() + { + webBrowser.JavascriptMessageReceived += ElementMessage.JSMessageReceived; webBrowser.KeyboardHandler = kbHandler; webBrowser.RequestHandler = new RequestInterceptor(); webBrowser.DownloadHandler = new DownloadInterceptor(); @@ -205,8 +211,15 @@ private void webView_LoadingStateChanged(object sender, LoadingStateChangedEvent internal void InvokeUI(Action a) { - if (formInstance != null) - formInstance.BeginInvoke(new MethodInvoker(a)); + if (formInstance != null && formInstance.InvokeRequired) + { + if (formInstance.IsHandleCreated) + formInstance.BeginInvoke(new MethodInvoker(a)); + } + else + { + a.Invoke(); + } } private void GameForm_Deactivate(object sender, EventArgs e) @@ -221,12 +234,22 @@ private void GameForm_Activated(object sender, EventArgs e) ResizeGameWindows(); if (!OverlayForm.Instance.IsDisposed) OverlayForm.Instance.Visible = true; + SendKeys.Send("%{F16}"); //Alt-Tab fix for game } private void GameForm_FormClosing(object sender, FormClosingEventArgs e) { - audioMngr.DestroySession(); - Application.Exit(); + switch (e.CloseReason) + { + case CloseReason.None: + e.Cancel = true; + break; + case CloseReason.UserClosing: + audioMngr.DestroySession(); + webBrowser.Dispose(); + Application.Exit(); + break; + } } private void GameForm_Resize(object sender, EventArgs e) diff --git a/LittleWarGameClient/KeyboardHandler.cs b/LittleWarGameClient/KeyboardHandler.cs index 38185f9..5542545 100644 --- a/LittleWarGameClient/KeyboardHandler.cs +++ b/LittleWarGameClient/KeyboardHandler.cs @@ -80,10 +80,9 @@ private void FriendsHotkeyFunc(ChromiumWebBrowser sender) public bool OnPreKeyEvent(IWebBrowser webView, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut) { - if (OverlayForm.Instance.IsActivated) - { + if (OverlayForm.Instance.IsActivated) return true; - } + var key = (Keys)windowsKeyCode; if (type == KeyType.RawKeyDown) { diff --git a/LittleWarGameClient/OverlayForm.Designer.cs b/LittleWarGameClient/OverlayForm.Designer.cs index ed00a98..37ef301 100644 --- a/LittleWarGameClient/OverlayForm.Designer.cs +++ b/LittleWarGameClient/OverlayForm.Designer.cs @@ -46,7 +46,6 @@ private void InitializeComponent() ClientSize = new Size(1445, 681); DoubleBuffered = true; EscapeKeyToClose = false; - Font = new Font(Program.LWG_FONT, 21.75F, FontStyle.Regular, GraphicsUnit.Point); ForeColor = Color.White; FormBorderStyle = FormBorderStyle.None; Location = new Point(0, 0); @@ -58,6 +57,7 @@ private void InitializeComponent() Text = "OverlayForm"; TopMost = true; TransparencyKey = Color.Black; + FormClosing += OverlayForm_FormClosing; Load += OverlayForm_Load; ResumeLayout(false); } diff --git a/LittleWarGameClient/OverlayForm.cs b/LittleWarGameClient/OverlayForm.cs index bf57c54..840b238 100644 --- a/LittleWarGameClient/OverlayForm.cs +++ b/LittleWarGameClient/OverlayForm.cs @@ -30,6 +30,7 @@ internal static OverlayForm Instance } } + private bool IsGameFormLoaded = false; private BDictionary overlayMessages; internal void AddOverlayMessage(string name, Notification notification) { @@ -43,6 +44,9 @@ internal OverlayForm() overlayMessages = new BDictionary(); IsActivated = false; InitializeComponent(); + if (Program.LWG_FONT != null) + Font = new Font(Program.LWG_FONT, 21.75F, FontStyle.Regular, GraphicsUnit.Point); + try { SteamClient.Init(480); @@ -58,7 +62,7 @@ protected override void OnRender(D2DGraphics g) for (int i = 0; i < overlayMessages.Count; i++) { var notification = overlayMessages[i].Value.message; - g.DrawText($" >{notification}", D2DColor.Yellow, Font, 0, (i+1)*30); + g.DrawText($" >{notification}", D2DColor.Yellow, Font, 0, (i + 1) * 30); } } @@ -77,19 +81,18 @@ private void OnGameOverlayActivated(bool overlayActivated) { InvokeUI(() => { - TransparencyKey = Color.Fuchsia; IsActivated = true; - KeyPreview = true; - Activate(); + GameForm.Instance.Visible = false; + TransparencyKey = Color.Fuchsia; }); } else { InvokeUI(() => { - TransparencyKey = Color.Black; IsActivated = false; - KeyPreview = false; + GameForm.Instance.Visible = true; + TransparencyKey = Color.Black; }); } } @@ -114,7 +117,21 @@ internal void InvokeUI(Action a) private void OverlayForm_Load(object sender, EventArgs e) { - GameForm.Instance.ShowDialog(); + if (!IsGameFormLoaded) + { + IsGameFormLoaded = true; + GameForm.Instance.Show(); + } + } + + private void OverlayForm_FormClosing(object sender, FormClosingEventArgs e) + { + switch (e.CloseReason) + { + case CloseReason.None: + e.Cancel = true; + break; + } } } } diff --git a/LittleWarGameClient/Program.cs b/LittleWarGameClient/Program.cs index 4393fb1..9cecdf9 100644 --- a/LittleWarGameClient/Program.cs +++ b/LittleWarGameClient/Program.cs @@ -1,15 +1,34 @@ +using CefSharp; using CefSharp.DevTools.Overlay; using LittleWarGameClient.Properties; using Loyc.Syntax; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing.Text; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; namespace LittleWarGameClient { internal static class Program { + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool SetForegroundWindow(IntPtr hWnd); + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); + + [DllImport("User32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool EnumWindows(CallBackPtr lpEnumFunc, IntPtr lParam); + + private delegate bool CallBackPtr(IntPtr hwnd, int lParam); + + private static CallBackPtr callBackPtr = Callback; + private static List _WinStructList = new List(); + internal static FontFamily? LWG_FONT; /// /// The main entry point for the application. @@ -17,16 +36,57 @@ internal static class Program [STAThread] static void Main() { - // To customize application configuration such as set high DPI settings or default font, - // see https://aka.ms/applicationconfiguration. - ApplicationConfiguration.Initialize(); - string font_filename = "lwgFont.ttf"; - if (!File.Exists(font_filename)) - File.WriteAllBytes(font_filename, Resources.LcdSolidFont); - PrivateFontCollection pfc = new PrivateFontCollection(); - pfc.AddFontFile(font_filename); - LWG_FONT = pfc.Families[0]; - Application.Run(OverlayForm.Instance); + bool createdNew = true; + using (Mutex mutex = new Mutex(true, "Global\\LittleWarGameClient", out createdNew)) + { + if (createdNew) + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + string font_filename = "lwgFont.ttf"; + if (!File.Exists(font_filename)) + File.WriteAllBytes(font_filename, Resources.LcdSolidFont); + PrivateFontCollection pfc = new PrivateFontCollection(); + pfc.AddFontFile(font_filename); + LWG_FONT = pfc.Families[0]; + Application.Run(OverlayForm.Instance); + } + else + { + Process current = Process.GetCurrentProcess(); + foreach (Process process in Process.GetProcessesByName(current.ProcessName)) + { + if (process.Id != current.Id) + { + var clientMainWindow = GetWindows(process.Handle).Where(window => window.WinTitle == "Littlewargame").First(); + SetForegroundWindow(clientMainWindow.MainWindowHandle); + break; + } + } + } + } + } + + private static bool Callback(IntPtr hWnd, int lparam) + { + StringBuilder sb = new StringBuilder(256); + int res = GetWindowText(hWnd, sb, 256); + _WinStructList.Add(new WinStruct { MainWindowHandle = hWnd, WinTitle = sb.ToString() }); + return true; } + + private static List GetWindows(IntPtr pHandle) + { + _WinStructList = new List(); + EnumWindows(callBackPtr, pHandle); + return _WinStructList; + } + } + + internal struct WinStruct + { + internal string? WinTitle; + internal IntPtr MainWindowHandle; } } \ No newline at end of file