From a160a781902409d0520cdf5acd154651bbff2538 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 21 Mar 2025 14:46:39 +0800 Subject: [PATCH 01/29] Fix result update interface issue --- Flow.Launcher/App.xaml.cs | 1 + Flow.Launcher/ViewModel/MainViewModel.cs | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 23c77618f..6649a8110 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -131,6 +131,7 @@ namespace Flow.Launcher Ioc.Default.GetRequiredService().ChangeLanguage(_settings.Language); PluginManager.LoadPlugins(_settings.PluginSettings); + Ioc.Default.GetRequiredService().RegisterResultsUpdatedEvent(); Http.Proxy = _settings.Proxy; diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 46970a6a1..452222d93 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -168,7 +168,6 @@ namespace Flow.Launcher.ViewModel }; RegisterViewUpdate(); - RegisterResultsUpdatedEvent(); _ = RegisterClockAndDateUpdateAsync(); } @@ -213,7 +212,7 @@ namespace Flow.Launcher.ViewModel } } - private void RegisterResultsUpdatedEvent() + public void RegisterResultsUpdatedEvent() { foreach (var pair in PluginManager.GetPluginsForInterface()) { From b75066f52ceb0b2a140b041aa133454ee56e21a1 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 21 Mar 2025 15:23:13 +0800 Subject: [PATCH 02/29] Fix change plugin language issue --- Flow.Launcher/App.xaml.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 6649a8110..377d36c48 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -127,12 +127,15 @@ namespace Flow.Launcher AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate(_settings); + PluginManager.LoadPlugins(_settings.PluginSettings); + + // Register ResultsUpdated event after all plugins are loaded + Ioc.Default.GetRequiredService().RegisterResultsUpdatedEvent(); + + // Change language after all plugins are initialized // TODO: Clean InternationalizationManager.Instance and InternationalizationManager.Instance.GetTranslation in future Ioc.Default.GetRequiredService().ChangeLanguage(_settings.Language); - PluginManager.LoadPlugins(_settings.PluginSettings); - Ioc.Default.GetRequiredService().RegisterResultsUpdatedEvent(); - Http.Proxy = _settings.Proxy; await PluginManager.InitializePluginsAsync(); From 81a46327223596a9cff55bd8ad4e1b332237d997 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sat, 22 Mar 2025 00:27:03 +0600 Subject: [PATCH 03/29] Implement auto-switching to English when the option is enabled --- Flow.Launcher/Helper/KeyboardLayoutHelper.cs | 95 ++++++++++++++++++++ Flow.Launcher/ViewModel/MainViewModel.cs | 13 ++- 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 Flow.Launcher/Helper/KeyboardLayoutHelper.cs diff --git a/Flow.Launcher/Helper/KeyboardLayoutHelper.cs b/Flow.Launcher/Helper/KeyboardLayoutHelper.cs new file mode 100644 index 000000000..db62ef783 --- /dev/null +++ b/Flow.Launcher/Helper/KeyboardLayoutHelper.cs @@ -0,0 +1,95 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Flow.Launcher.Helper; + +public static class KeyboardLayoutHelper +{ + #region Windows API + + [DllImport("user32.dll")] + private static extern IntPtr GetKeyboardLayout(uint idThread); + + [DllImport("user32.dll")] + private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId); + + [DllImport("user32.dll")] + private static extern IntPtr ActivateKeyboardLayout(IntPtr hkl, uint flags); + + [DllImport("user32.dll")] + private static extern int GetKeyboardLayoutList(int nBuff, [Out] IntPtr[] lpList); + + [DllImport("kernel32.dll")] + private static extern int GetLocaleInfoA(uint Locale, uint LCType, StringBuilder lpLCData, int cchData); + + [DllImport("user32.dll")] + private static extern IntPtr GetForegroundWindow(); + + // Used to get the language name of the keyboard layout + private const uint LOCALE_SLANGUAGE = 0x00000002; + + // The string to search for in the language name of a keyboard layout + private const string LAYOUT_ENGLISH_SEARCH = "english"; + + private static IntPtr FindEnglishKeyboardLayout() + { + // Get the number of keyboard layouts + var count = GetKeyboardLayoutList(0, null); + if (count <= 0) return IntPtr.Zero; + + // Get all keyboard layouts + var keyboardLayouts = new IntPtr[count]; + GetKeyboardLayoutList(count, keyboardLayouts); + + // Look for any English keyboard layout + foreach (var layout in keyboardLayouts) + { + // The lower word contains the language identifier + var langId = (uint)layout.ToInt32() & 0xFFFF; + + // Get language name for the layout + var sb = new StringBuilder(256); + GetLocaleInfoA(langId, LOCALE_SLANGUAGE, sb, sb.Capacity); + var langName = sb.ToString().ToLowerInvariant(); + + // Check if it's an English layout + if (langName.Contains(LAYOUT_ENGLISH_SEARCH)) + { + return layout; + } + } + + return IntPtr.Zero; + } + + #endregion + + // Query textbox keyboard layout + private static IntPtr _previousLayout; + + public static void SetEnglishKeyboardLayout() + { + // Find an installed English layout + var englishLayout = FindEnglishKeyboardLayout(); + + // No installed English layout found + if (englishLayout == IntPtr.Zero) return; + + var hwnd = GetForegroundWindow(); + var threadId = GetWindowThreadProcessId(hwnd, IntPtr.Zero); + + // Store current keyboard layout + _previousLayout = GetKeyboardLayout(threadId) & 0xFFFF; + + // Switch to English layout + ActivateKeyboardLayout(englishLayout, 0); + } + + public static void SetPreviousKeyboardLayout() + { + if (_previousLayout == IntPtr.Zero) return; + ActivateKeyboardLayout(_previousLayout, 0); + _previousLayout = IntPtr.Zero; + } +} diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 46970a6a1..641825ec6 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -14,6 +14,7 @@ using System.Windows.Threading; using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Input; using Flow.Launcher.Core.Plugin; +using Flow.Launcher.Helper; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.Image; @@ -1373,6 +1374,11 @@ namespace Flow.Launcher.ViewModel MainWindowOpacity = 1; MainWindowVisibilityStatus = true; VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = true }); + + if (StartWithEnglishMode) + { + KeyboardLayoutHelper.SetEnglishKeyboardLayout(); + } }); } @@ -1441,7 +1447,12 @@ namespace Flow.Launcher.ViewModel // 📌 Apply DWM Cloak (Completely hide the window) Win32Helper.DWMSetCloakForWindow(mainWindow, true); } - + + if (StartWithEnglishMode) + { + KeyboardLayoutHelper.SetPreviousKeyboardLayout(); + } + await Task.Delay(50); // Update WPF properties From aa3ad10044396092a7e6779542d389e2d76716a5 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sat, 22 Mar 2025 08:32:35 +0600 Subject: [PATCH 04/29] When looking for English keyboard layout, use pre-defined IDs instead of relying on layout name as a string --- Flow.Launcher/Helper/KeyboardLayoutHelper.cs | 23 +++++++------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/Flow.Launcher/Helper/KeyboardLayoutHelper.cs b/Flow.Launcher/Helper/KeyboardLayoutHelper.cs index db62ef783..e5458f6cd 100644 --- a/Flow.Launcher/Helper/KeyboardLayoutHelper.cs +++ b/Flow.Launcher/Helper/KeyboardLayoutHelper.cs @@ -1,6 +1,6 @@ using System; +using System.Linq; using System.Runtime.InteropServices; -using System.Text; namespace Flow.Launcher.Helper; @@ -20,17 +20,15 @@ public static class KeyboardLayoutHelper [DllImport("user32.dll")] private static extern int GetKeyboardLayoutList(int nBuff, [Out] IntPtr[] lpList); - [DllImport("kernel32.dll")] - private static extern int GetLocaleInfoA(uint Locale, uint LCType, StringBuilder lpLCData, int cchData); - [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); - // Used to get the language name of the keyboard layout - private const uint LOCALE_SLANGUAGE = 0x00000002; - - // The string to search for in the language name of a keyboard layout - private const string LAYOUT_ENGLISH_SEARCH = "english"; + // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f + private static readonly uint[] EnglishLanguageIds = + { + 0x0009, 0x0409, 0x0809, 0x0C09, 0x1000, 0x1009, 0x1409, 0x1809, 0x1C09, 0x2009, 0x2409, 0x2809, 0x2C09, + 0x3009, 0x3409, 0x3C09, 0x4009, 0x4409, 0x4809, 0x4C09, + }; private static IntPtr FindEnglishKeyboardLayout() { @@ -48,13 +46,8 @@ public static class KeyboardLayoutHelper // The lower word contains the language identifier var langId = (uint)layout.ToInt32() & 0xFFFF; - // Get language name for the layout - var sb = new StringBuilder(256); - GetLocaleInfoA(langId, LOCALE_SLANGUAGE, sb, sb.Capacity); - var langName = sb.ToString().ToLowerInvariant(); - // Check if it's an English layout - if (langName.Contains(LAYOUT_ENGLISH_SEARCH)) + if (EnglishLanguageIds.Contains(langId)) { return layout; } From 4e5584b70920a4269080219dccf55838478d68ce Mon Sep 17 00:00:00 2001 From: DB p Date: Sat, 22 Mar 2025 12:25:02 +0900 Subject: [PATCH 05/29] Enable acrylic effect on first launch if running on Windows 11 --- Flow.Launcher/MainWindow.xaml.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 2ce3d1e95..d2e9dade9 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -98,6 +98,9 @@ namespace Flow.Launcher { _settings.FirstLaunch = false; App.API.SaveAppAllSettings(); + /* Set Backdrop Type to Acrylic for Windows 11 when First Launch. Default is None. */ + if (OperatingSystem.IsWindowsVersionAtLeast(10, 0, 22000)) + _settings.BackdropType = BackdropTypes.Acrylic; var WelcomeWindow = new WelcomeWindow(); WelcomeWindow.Show(); } From 023ab45022fab28b9969ea1df1521c8d2c3912e1 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 22 Mar 2025 12:06:44 +0800 Subject: [PATCH 06/29] Use PInvoke instead of DllImport & Several adjustments --- .../NativeMethods.txt | 7 +- Flow.Launcher.Infrastructure/Win32Helper.cs | 79 +++++++++++++++++ Flow.Launcher/Helper/KeyboardLayoutHelper.cs | 88 ------------------- Flow.Launcher/ViewModel/MainViewModel.cs | 5 +- 4 files changed, 87 insertions(+), 92 deletions(-) delete mode 100644 Flow.Launcher/Helper/KeyboardLayoutHelper.cs diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt index f080f24de..d26478bbe 100644 --- a/Flow.Launcher.Infrastructure/NativeMethods.txt +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -46,4 +46,9 @@ GetMonitorInfo MONITORINFOEXW WM_ENTERSIZEMOVE -WM_EXITSIZEMOVE \ No newline at end of file +WM_EXITSIZEMOVE + +GetKeyboardLayout +GetWindowThreadProcessId +ActivateKeyboardLayout +GetKeyboardLayoutList \ No newline at end of file diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 8dbe3f7e9..664f428ec 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel; +using System.Linq; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; @@ -7,8 +8,10 @@ using System.Windows.Media; using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.Graphics.Dwm; +using Windows.Win32.UI.Input.KeyboardAndMouse; using Windows.Win32.UI.WindowsAndMessaging; using Flow.Launcher.Infrastructure.UserSettings; +using Point = System.Windows.Point; namespace Flow.Launcher.Infrastructure { @@ -317,5 +320,81 @@ namespace Flow.Launcher.Infrastructure } #endregion + + #region Keyboard Layout + + // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f + private static readonly uint[] EnglishLanguageIds = + { + 0x0009, 0x0409, 0x0809, 0x0C09, 0x1000, 0x1009, 0x1409, 0x1809, 0x1C09, 0x2009, 0x2409, 0x2809, 0x2C09, + 0x3009, 0x3409, 0x3C09, 0x4009, 0x4409, 0x4809, 0x4C09, + }; + + // Store the previous keyboard layout + private static HKL _previousLayout; + + private static unsafe HKL FindEnglishKeyboardLayout() + { + // Get the number of keyboard layouts + int count = PInvoke.GetKeyboardLayoutList(0, null); + if (count <= 0) return HKL.Null; + + // Get all keyboard layouts + var handles = new HKL[count]; + fixed (HKL* h = handles) + { + _ = PInvoke.GetKeyboardLayoutList(count, h); + } + + // Look for any English keyboard layout + foreach (var hkl in handles) + { + // The lower word contains the language identifier + var langId = (uint)hkl.Value & 0xFFFF; + + // Check if it's an English layout + if (EnglishLanguageIds.Contains(langId)) + { + return hkl; + } + } + + return HKL.Null; + } + + public static unsafe void SetEnglishKeyboardLayout(bool backupPrevious) + { + // Find an installed English layout + var enHKL = FindEnglishKeyboardLayout(); + + // No installed English layout found + if (enHKL == HKL.Null) return; + + // Get the current window thread ID + uint threadId = 0; + var result = PInvoke.GetWindowThreadProcessId(PInvoke.GetForegroundWindow(), &threadId); + if (result == 0 || threadId == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); + + // Backup current keyboard layout + if (backupPrevious) + { + _previousLayout = PInvoke.GetKeyboardLayout(threadId); + } + + // Switch to English layout + PInvoke.ActivateKeyboardLayout(enHKL, 0); + } + + public static void SetPreviousKeyboardLayout() + { + if (_previousLayout != HKL.Null) + { + PInvoke.ActivateKeyboardLayout(_previousLayout, 0); + + _previousLayout = HKL.Null; + } + } + + #endregion } } diff --git a/Flow.Launcher/Helper/KeyboardLayoutHelper.cs b/Flow.Launcher/Helper/KeyboardLayoutHelper.cs deleted file mode 100644 index e5458f6cd..000000000 --- a/Flow.Launcher/Helper/KeyboardLayoutHelper.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.Linq; -using System.Runtime.InteropServices; - -namespace Flow.Launcher.Helper; - -public static class KeyboardLayoutHelper -{ - #region Windows API - - [DllImport("user32.dll")] - private static extern IntPtr GetKeyboardLayout(uint idThread); - - [DllImport("user32.dll")] - private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId); - - [DllImport("user32.dll")] - private static extern IntPtr ActivateKeyboardLayout(IntPtr hkl, uint flags); - - [DllImport("user32.dll")] - private static extern int GetKeyboardLayoutList(int nBuff, [Out] IntPtr[] lpList); - - [DllImport("user32.dll")] - private static extern IntPtr GetForegroundWindow(); - - // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f - private static readonly uint[] EnglishLanguageIds = - { - 0x0009, 0x0409, 0x0809, 0x0C09, 0x1000, 0x1009, 0x1409, 0x1809, 0x1C09, 0x2009, 0x2409, 0x2809, 0x2C09, - 0x3009, 0x3409, 0x3C09, 0x4009, 0x4409, 0x4809, 0x4C09, - }; - - private static IntPtr FindEnglishKeyboardLayout() - { - // Get the number of keyboard layouts - var count = GetKeyboardLayoutList(0, null); - if (count <= 0) return IntPtr.Zero; - - // Get all keyboard layouts - var keyboardLayouts = new IntPtr[count]; - GetKeyboardLayoutList(count, keyboardLayouts); - - // Look for any English keyboard layout - foreach (var layout in keyboardLayouts) - { - // The lower word contains the language identifier - var langId = (uint)layout.ToInt32() & 0xFFFF; - - // Check if it's an English layout - if (EnglishLanguageIds.Contains(langId)) - { - return layout; - } - } - - return IntPtr.Zero; - } - - #endregion - - // Query textbox keyboard layout - private static IntPtr _previousLayout; - - public static void SetEnglishKeyboardLayout() - { - // Find an installed English layout - var englishLayout = FindEnglishKeyboardLayout(); - - // No installed English layout found - if (englishLayout == IntPtr.Zero) return; - - var hwnd = GetForegroundWindow(); - var threadId = GetWindowThreadProcessId(hwnd, IntPtr.Zero); - - // Store current keyboard layout - _previousLayout = GetKeyboardLayout(threadId) & 0xFFFF; - - // Switch to English layout - ActivateKeyboardLayout(englishLayout, 0); - } - - public static void SetPreviousKeyboardLayout() - { - if (_previousLayout == IntPtr.Zero) return; - ActivateKeyboardLayout(_previousLayout, 0); - _previousLayout = IntPtr.Zero; - } -} diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 641825ec6..0f355a80f 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -14,7 +14,6 @@ using System.Windows.Threading; using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Input; using Flow.Launcher.Core.Plugin; -using Flow.Launcher.Helper; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.Image; @@ -1377,7 +1376,7 @@ namespace Flow.Launcher.ViewModel if (StartWithEnglishMode) { - KeyboardLayoutHelper.SetEnglishKeyboardLayout(); + Win32Helper.SetEnglishKeyboardLayout(true); } }); } @@ -1450,7 +1449,7 @@ namespace Flow.Launcher.ViewModel if (StartWithEnglishMode) { - KeyboardLayoutHelper.SetPreviousKeyboardLayout(); + Win32Helper.SetPreviousKeyboardLayout(); } await Task.Delay(50); From 465108a9d487a0aee8d7bdb253a5e983bbfa715a Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 22 Mar 2025 13:58:53 +0800 Subject: [PATCH 07/29] Fix keyboard layout fetch issue --- Flow.Launcher.Infrastructure/Win32Helper.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 664f428ec..2248fadd6 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -371,9 +371,8 @@ namespace Flow.Launcher.Infrastructure if (enHKL == HKL.Null) return; // Get the current window thread ID - uint threadId = 0; - var result = PInvoke.GetWindowThreadProcessId(PInvoke.GetForegroundWindow(), &threadId); - if (result == 0 || threadId == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); + var threadId = PInvoke.GetWindowThreadProcessId(PInvoke.GetForegroundWindow()); + if (threadId == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); // Backup current keyboard layout if (backupPrevious) From 67be335600d96d1a8077b340c5848819208b0a9e Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sat, 22 Mar 2025 14:58:42 +0600 Subject: [PATCH 08/29] Rename methods to make their purpose more obvious; slight code style changes --- Flow.Launcher.Infrastructure/Win32Helper.cs | 14 ++++++-------- Flow.Launcher/ViewModel/MainViewModel.cs | 12 ++++++------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 2248fadd6..3d8821fca 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -66,7 +66,7 @@ namespace Flow.Launcher.Infrastructure } /// - /// + /// /// /// /// DoNotRound, Round, RoundSmall, Default @@ -362,7 +362,7 @@ namespace Flow.Launcher.Infrastructure return HKL.Null; } - public static unsafe void SetEnglishKeyboardLayout(bool backupPrevious) + public static unsafe void SwitchToEnglishKeyboardLayout(bool backupPrevious) { // Find an installed English layout var enHKL = FindEnglishKeyboardLayout(); @@ -384,14 +384,12 @@ namespace Flow.Launcher.Infrastructure PInvoke.ActivateKeyboardLayout(enHKL, 0); } - public static void SetPreviousKeyboardLayout() + public static void RestorePreviousKeyboardLayout() { - if (_previousLayout != HKL.Null) - { - PInvoke.ActivateKeyboardLayout(_previousLayout, 0); + if (_previousLayout == HKL.Null) return; - _previousLayout = HKL.Null; - } + PInvoke.ActivateKeyboardLayout(_previousLayout, 0); + _previousLayout = HKL.Null; } #endregion diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 0f355a80f..5ebed0369 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1376,7 +1376,7 @@ namespace Flow.Launcher.ViewModel if (StartWithEnglishMode) { - Win32Helper.SetEnglishKeyboardLayout(true); + Win32Helper.SwitchToEnglishKeyboardLayout(true); } }); } @@ -1385,6 +1385,11 @@ namespace Flow.Launcher.ViewModel public async void Hide() { + + if (StartWithEnglishMode) + { + Win32Helper.RestorePreviousKeyboardLayout(); + } lastHistoryIndex = 1; if (ExternalPreviewVisible) @@ -1447,11 +1452,6 @@ namespace Flow.Launcher.ViewModel Win32Helper.DWMSetCloakForWindow(mainWindow, true); } - if (StartWithEnglishMode) - { - Win32Helper.SetPreviousKeyboardLayout(); - } - await Task.Delay(50); // Update WPF properties From c39079badc789a05bea0d23fbd37ab1c22641ecb Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sat, 22 Mar 2025 15:35:34 +0600 Subject: [PATCH 09/29] Revert accidental change --- Flow.Launcher/ViewModel/MainViewModel.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 5ebed0369..59af95da5 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1385,11 +1385,6 @@ namespace Flow.Launcher.ViewModel public async void Hide() { - - if (StartWithEnglishMode) - { - Win32Helper.RestorePreviousKeyboardLayout(); - } lastHistoryIndex = 1; if (ExternalPreviewVisible) @@ -1452,6 +1447,11 @@ namespace Flow.Launcher.ViewModel Win32Helper.DWMSetCloakForWindow(mainWindow, true); } + if (StartWithEnglishMode) + { + Win32Helper.RestorePreviousKeyboardLayout(); + } + await Task.Delay(50); // Update WPF properties From 4146f4d3096cd44b5e81435d50d8df1711cd3a3d Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 22 Mar 2025 18:03:41 +0800 Subject: [PATCH 10/29] Use focus events to trigger --- Flow.Launcher/MainWindow.xaml | 2 ++ Flow.Launcher/MainWindow.xaml.cs | 16 ++++++++++++++++ Flow.Launcher/ViewModel/MainViewModel.cs | 10 ---------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 5b63303ac..2440e89fa 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -242,6 +242,8 @@ InputMethod.PreferredImeState="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEStateConverter}}" PreviewDragOver="QueryTextBox_OnPreviewDragOver" PreviewKeyUp="QueryTextBox_KeyUp" + GotKeyboardFocus="QueryTextBox_OnGotKeyboardFocus" + PreviewLostKeyboardFocus="QueryTextBox_OnPreviewLostKeyboardFocus" Style="{DynamicResource QueryBoxStyle}" Text="{Binding QueryText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Visibility="Visible" diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 2ce3d1e95..bf560e621 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -989,6 +989,22 @@ namespace Flow.Launcher e.Handled = true; } + private void QueryTextBox_OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) + { + if (_viewModel.StartWithEnglishMode) + { + Win32Helper.SwitchToEnglishKeyboardLayout(true); + } + } + + private void QueryTextBox_OnPreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) + { + if (_viewModel.StartWithEnglishMode) + { + Win32Helper.RestorePreviousKeyboardLayout(); + } + } + #endregion } } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 59af95da5..97ed422c5 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1373,11 +1373,6 @@ namespace Flow.Launcher.ViewModel MainWindowOpacity = 1; MainWindowVisibilityStatus = true; VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = true }); - - if (StartWithEnglishMode) - { - Win32Helper.SwitchToEnglishKeyboardLayout(true); - } }); } @@ -1447,11 +1442,6 @@ namespace Flow.Launcher.ViewModel Win32Helper.DWMSetCloakForWindow(mainWindow, true); } - if (StartWithEnglishMode) - { - Win32Helper.RestorePreviousKeyboardLayout(); - } - await Task.Delay(50); // Update WPF properties From f83e8eddb6aad1ed6cbec06620db6f1b1e6dab74 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sat, 22 Mar 2025 16:23:34 +0600 Subject: [PATCH 11/29] Revert "Use focus events to trigger" This reverts commit 4146f4d3096cd44b5e81435d50d8df1711cd3a3d. --- Flow.Launcher/MainWindow.xaml | 2 -- Flow.Launcher/MainWindow.xaml.cs | 16 ---------------- Flow.Launcher/ViewModel/MainViewModel.cs | 10 ++++++++++ 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 2440e89fa..5b63303ac 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -242,8 +242,6 @@ InputMethod.PreferredImeState="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEStateConverter}}" PreviewDragOver="QueryTextBox_OnPreviewDragOver" PreviewKeyUp="QueryTextBox_KeyUp" - GotKeyboardFocus="QueryTextBox_OnGotKeyboardFocus" - PreviewLostKeyboardFocus="QueryTextBox_OnPreviewLostKeyboardFocus" Style="{DynamicResource QueryBoxStyle}" Text="{Binding QueryText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Visibility="Visible" diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index bf560e621..2ce3d1e95 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -989,22 +989,6 @@ namespace Flow.Launcher e.Handled = true; } - private void QueryTextBox_OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) - { - if (_viewModel.StartWithEnglishMode) - { - Win32Helper.SwitchToEnglishKeyboardLayout(true); - } - } - - private void QueryTextBox_OnPreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) - { - if (_viewModel.StartWithEnglishMode) - { - Win32Helper.RestorePreviousKeyboardLayout(); - } - } - #endregion } } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 97ed422c5..59af95da5 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1373,6 +1373,11 @@ namespace Flow.Launcher.ViewModel MainWindowOpacity = 1; MainWindowVisibilityStatus = true; VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = true }); + + if (StartWithEnglishMode) + { + Win32Helper.SwitchToEnglishKeyboardLayout(true); + } }); } @@ -1442,6 +1447,11 @@ namespace Flow.Launcher.ViewModel Win32Helper.DWMSetCloakForWindow(mainWindow, true); } + if (StartWithEnglishMode) + { + Win32Helper.RestorePreviousKeyboardLayout(); + } + await Task.Delay(50); // Update WPF properties From 6ad4b2355ed23a4df7693f3b12221908893acfad Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sat, 22 Mar 2025 17:08:09 +0600 Subject: [PATCH 12/29] Don't switch to English when IME can be disabled instead --- Flow.Launcher.Infrastructure/Win32Helper.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 3d8821fca..76d469414 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -330,6 +330,13 @@ namespace Flow.Launcher.Infrastructure 0x3009, 0x3409, 0x3C09, 0x4009, 0x4409, 0x4809, 0x4C09, }; + private static readonly uint[] ImeLanguageIds = + { + 0x0004, 0x7804, 0x0804, 0x1004, 0x7C04, 0x0C04, 0x1404, 0x0404, 0x0011, 0x0411, 0x0012, 0x0412, + }; + + private const uint KeyboardLayoutLoWord = 0xFFFF; + // Store the previous keyboard layout private static HKL _previousLayout; @@ -350,7 +357,7 @@ namespace Flow.Launcher.Infrastructure foreach (var hkl in handles) { // The lower word contains the language identifier - var langId = (uint)hkl.Value & 0xFFFF; + var langId = (uint)hkl.Value & KeyboardLayoutLoWord; // Check if it's an English layout if (EnglishLanguageIds.Contains(langId)) @@ -374,10 +381,18 @@ namespace Flow.Launcher.Infrastructure var threadId = PInvoke.GetWindowThreadProcessId(PInvoke.GetForegroundWindow()); if (threadId == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); + // If the current layout has an IME mode, disable it without switching to another layout + var currentLayout = PInvoke.GetKeyboardLayout(threadId); + var currentLayoutCode = (uint)currentLayout.Value & KeyboardLayoutLoWord; + if (ImeLanguageIds.Contains(currentLayoutCode)) + { + return; + } + // Backup current keyboard layout if (backupPrevious) { - _previousLayout = PInvoke.GetKeyboardLayout(threadId); + _previousLayout = currentLayout; } // Switch to English layout From ca04823dd77be4ba24d5a7dee69275049dd78eb8 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sat, 22 Mar 2025 19:40:26 +0600 Subject: [PATCH 13/29] Remove generic language code --- Flow.Launcher.Infrastructure/Win32Helper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 76d469414..f23f02447 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -326,8 +326,8 @@ namespace Flow.Launcher.Infrastructure // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f private static readonly uint[] EnglishLanguageIds = { - 0x0009, 0x0409, 0x0809, 0x0C09, 0x1000, 0x1009, 0x1409, 0x1809, 0x1C09, 0x2009, 0x2409, 0x2809, 0x2C09, - 0x3009, 0x3409, 0x3C09, 0x4009, 0x4409, 0x4809, 0x4C09, + 0x0009, 0x0409, 0x0809, 0x0C09, 0x1009, 0x1409, 0x1809, 0x1C09, 0x2009, 0x2409, 0x2809, 0x2C09, 0x3009, + 0x3409, 0x3C09, 0x4009, 0x4409, 0x4809, 0x4C09, }; private static readonly uint[] ImeLanguageIds = From 3e64a341bc08ff75bea37817900b1cad80f1551b Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Sat, 22 Mar 2025 19:41:26 +0100 Subject: [PATCH 14/29] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6611f55dc..cbb553bd1 100644 --- a/README.md +++ b/README.md @@ -219,7 +219,7 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea ## 📦 Plugins -- Support wide range of plugins. Visit [here](https://flowlauncher.com/docs/#/plugins) for our plugin portfolio. +- Support wide range of plugins. Visit [here](https://www.flowlauncher.com/plugins/) for our plugin portfolio. - Publish your own plugin to flow! Create plugins in:

From 0ef4b0580881df69a2e396ce570d488ef9ba4108 Mon Sep 17 00:00:00 2001 From: DB p Date: Sun, 23 Mar 2025 17:21:03 +0900 Subject: [PATCH 15/29] Add Initial state for QueryTextBoxCursorMovedToEnd --- Flow.Launcher/MainWindow.xaml.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index d2e9dade9..ec8649efc 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -143,7 +143,9 @@ namespace Flow.Launcher // Since the default main window visibility is visible, so we need set focus during startup QueryTextBox.Focus(); - + // Set the initial state of the QueryTextBoxCursorMovedToEnd property + // Without this part, when shown for the first time, switching the context menu does not move the cursor to the end. + _viewModel.QueryTextCursorMovedToEnd = false; _viewModel.PropertyChanged += (o, e) => { switch (e.PropertyName) From 747f9582c3673a72eaf707e765f3badfc5af6674 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 23 Mar 2025 19:27:40 +0800 Subject: [PATCH 16/29] Fix keyboard restore issue when window is deactivated --- Flow.Launcher/MainWindow.xaml.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 2ce3d1e95..de15f30e8 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -250,11 +250,21 @@ namespace Flow.Launcher private async void OnDeactivated(object sender, EventArgs e) { + // When window is deactivated, FL cannot set keyboard correctly + // This is a workaround to restore the keyboard layout + if (_settings.HideWhenDeactivated && _viewModel.StartWithEnglishMode) + { + Activate(); + QueryTextBox.Focus(); + Win32Helper.RestorePreviousKeyboardLayout(); + } + _settings.WindowLeft = Left; _settings.WindowTop = Top; ClockPanel.Opacity = 0; SearchIcon.Opacity = 0; - //This condition stops extra hide call when animator is on, + + // This condition stops extra hide call when animator is on, // which causes the toggling to occasional hide instead of show. if (_viewModel.MainWindowVisibilityStatus) { @@ -262,8 +272,9 @@ namespace Flow.Launcher // This also stops the mainwindow from flickering occasionally after Settings window is opened // and always after Settings window is closed. if (_settings.UseAnimation) - + { await Task.Delay(100); + } if (_settings.HideWhenDeactivated && !_viewModel.ExternalPreviewVisible) { From cd28c09c09b3a30a78571a9448db07fba2303e72 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sun, 23 Mar 2025 17:56:52 +0600 Subject: [PATCH 17/29] Fix the issue with not being able to switch back to the original keyboard layout in OnDeactivated --- Flow.Launcher.Infrastructure/NativeMethods.txt | 7 ++++++- Flow.Launcher.Infrastructure/Win32Helper.cs | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt index d26478bbe..54ae099f8 100644 --- a/Flow.Launcher.Infrastructure/NativeMethods.txt +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -51,4 +51,9 @@ WM_EXITSIZEMOVE GetKeyboardLayout GetWindowThreadProcessId ActivateKeyboardLayout -GetKeyboardLayoutList \ No newline at end of file +GetKeyboardLayoutList + +PostMessage +HWND_BROADCAST +WM_INPUTLANGCHANGEREQUEST +INPUTLANGCHANGE_FORWARD diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index f23f02447..197a5a556 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -403,7 +403,11 @@ namespace Flow.Launcher.Infrastructure { if (_previousLayout == HKL.Null) return; - PInvoke.ActivateKeyboardLayout(_previousLayout, 0); + PInvoke.PostMessage(HWND.HWND_BROADCAST, + PInvoke.WM_INPUTLANGCHANGEREQUEST, + PInvoke.INPUTLANGCHANGE_FORWARD, + _previousLayout.Value + ); _previousLayout = HKL.Null; } From bf011f11dbac1b28e7cbfc15e1e60157a1c0bc84 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sun, 23 Mar 2025 17:57:24 +0600 Subject: [PATCH 18/29] Revert "Fix keyboard restore issue when window is deactivated" This reverts commit 747f9582c3673a72eaf707e765f3badfc5af6674. --- Flow.Launcher/MainWindow.xaml.cs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index de15f30e8..2ce3d1e95 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -250,21 +250,11 @@ namespace Flow.Launcher private async void OnDeactivated(object sender, EventArgs e) { - // When window is deactivated, FL cannot set keyboard correctly - // This is a workaround to restore the keyboard layout - if (_settings.HideWhenDeactivated && _viewModel.StartWithEnglishMode) - { - Activate(); - QueryTextBox.Focus(); - Win32Helper.RestorePreviousKeyboardLayout(); - } - _settings.WindowLeft = Left; _settings.WindowTop = Top; ClockPanel.Opacity = 0; SearchIcon.Opacity = 0; - - // This condition stops extra hide call when animator is on, + //This condition stops extra hide call when animator is on, // which causes the toggling to occasional hide instead of show. if (_viewModel.MainWindowVisibilityStatus) { @@ -272,9 +262,8 @@ namespace Flow.Launcher // This also stops the mainwindow from flickering occasionally after Settings window is opened // and always after Settings window is closed. if (_settings.UseAnimation) - { + await Task.Delay(100); - } if (_settings.HideWhenDeactivated && !_viewModel.ExternalPreviewVisible) { From 382d0c2bfe85416185d9ffcebfc0d9ab68065f31 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sun, 23 Mar 2025 18:26:11 +0600 Subject: [PATCH 19/29] Don't broadcast language change --- Flow.Launcher.Infrastructure/NativeMethods.txt | 1 - Flow.Launcher.Infrastructure/Win32Helper.cs | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt index 54ae099f8..833c6682b 100644 --- a/Flow.Launcher.Infrastructure/NativeMethods.txt +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -54,6 +54,5 @@ ActivateKeyboardLayout GetKeyboardLayoutList PostMessage -HWND_BROADCAST WM_INPUTLANGCHANGEREQUEST INPUTLANGCHANGE_FORWARD diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 197a5a556..7bb9df2e7 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -403,7 +403,9 @@ namespace Flow.Launcher.Infrastructure { if (_previousLayout == HKL.Null) return; - PInvoke.PostMessage(HWND.HWND_BROADCAST, + var hwnd = PInvoke.GetForegroundWindow(); + PInvoke.PostMessage( + hwnd, PInvoke.WM_INPUTLANGCHANGEREQUEST, PInvoke.INPUTLANGCHANGE_FORWARD, _previousLayout.Value From 48aff32f1b9a699204766c1284bc1373a37fb218 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sun, 23 Mar 2025 18:28:19 +0600 Subject: [PATCH 20/29] Clarify why not switch keyboard layout for languages that have IME mode --- Flow.Launcher.Infrastructure/Win32Helper.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 7bb9df2e7..f874c7006 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -381,7 +381,9 @@ namespace Flow.Launcher.Infrastructure var threadId = PInvoke.GetWindowThreadProcessId(PInvoke.GetForegroundWindow()); if (threadId == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); - // If the current layout has an IME mode, disable it without switching to another layout + // If the current layout has an IME mode, disable it without switching to another layout. + // This is needed because for languages with IME mode, Flow Launcher just temporarily disables + // the IME mode instead of switching to another layout. var currentLayout = PInvoke.GetKeyboardLayout(threadId); var currentLayoutCode = (uint)currentLayout.Value & KeyboardLayoutLoWord; if (ImeLanguageIds.Contains(currentLayoutCode)) From 4df42a0f638ea0dc2a4be6999606cc1ea1141e63 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sun, 23 Mar 2025 18:40:41 +0600 Subject: [PATCH 21/29] Add doc comments and additional error handling in keyboard layout switch logic --- Flow.Launcher.Infrastructure/Win32Helper.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index f874c7006..7cebedfdc 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -350,7 +350,11 @@ namespace Flow.Launcher.Infrastructure var handles = new HKL[count]; fixed (HKL* h = handles) { - _ = PInvoke.GetKeyboardLayoutList(count, h); + var result = PInvoke.GetKeyboardLayoutList(count, h); + if (result != 0) + { + throw new Win32Exception(Marshal.GetLastWin32Error()); + } } // Look for any English keyboard layout @@ -369,6 +373,11 @@ namespace Flow.Launcher.Infrastructure return HKL.Null; } + ///

+ /// Switches the keyboard layout to English if available. + /// + /// If true, the current keyboard layout will be stored for later restoration. + /// Thrown when there's an error getting the window thread process ID. public static unsafe void SwitchToEnglishKeyboardLayout(bool backupPrevious) { // Find an installed English layout @@ -401,11 +410,17 @@ namespace Flow.Launcher.Infrastructure PInvoke.ActivateKeyboardLayout(enHKL, 0); } + /// + /// Restores the previously backed-up keyboard layout. + /// If it wasn't backed up or has already been restored, this method does nothing. + /// public static void RestorePreviousKeyboardLayout() { if (_previousLayout == HKL.Null) return; var hwnd = PInvoke.GetForegroundWindow(); + if (hwnd == HWND.Null) return; + PInvoke.PostMessage( hwnd, PInvoke.WM_INPUTLANGCHANGEREQUEST, From 1bf573344ae676adb2d22198e0d10e7b9a3cb5ff Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sun, 23 Mar 2025 18:53:01 +0600 Subject: [PATCH 22/29] Fix incorrect error handling logic in keyboard layout change --- Flow.Launcher.Infrastructure/Win32Helper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 7cebedfdc..108f51fd4 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -351,7 +351,7 @@ namespace Flow.Launcher.Infrastructure fixed (HKL* h = handles) { var result = PInvoke.GetKeyboardLayoutList(count, h); - if (result != 0) + if (result == 0) { throw new Win32Exception(Marshal.GetLastWin32Error()); } From 5be88dd38613bc1f110b8d0437611ff396502c9c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 23 Mar 2025 20:57:12 +0800 Subject: [PATCH 23/29] Remove blank line --- Flow.Launcher.Infrastructure/NativeMethods.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt index 833c6682b..de74eb7f9 100644 --- a/Flow.Launcher.Infrastructure/NativeMethods.txt +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -52,7 +52,6 @@ GetKeyboardLayout GetWindowThreadProcessId ActivateKeyboardLayout GetKeyboardLayoutList - PostMessage WM_INPUTLANGCHANGEREQUEST INPUTLANGCHANGE_FORWARD From c63debe296ec40bda08a8083bd667aec7a549f32 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 23 Mar 2025 20:57:25 +0800 Subject: [PATCH 24/29] Add foreground window check --- Flow.Launcher.Infrastructure/Win32Helper.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 108f51fd4..226d7b76c 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -386,8 +386,12 @@ namespace Flow.Launcher.Infrastructure // No installed English layout found if (enHKL == HKL.Null) return; - // Get the current window thread ID - var threadId = PInvoke.GetWindowThreadProcessId(PInvoke.GetForegroundWindow()); + // Get the current foreground window + var hwnd = PInvoke.GetForegroundWindow(); + if (hwnd == HWND.Null) return; + + // Get the current foreground window thread ID + var threadId = PInvoke.GetWindowThreadProcessId(hwnd); if (threadId == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); // If the current layout has an IME mode, disable it without switching to another layout. From 4fc7f70d18b4b284f1814f44addceda457f87f52 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 23 Mar 2025 21:05:14 +0800 Subject: [PATCH 25/29] Adjust formats --- Flow.Launcher.Infrastructure/Win32Helper.cs | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 226d7b76c..8c32899ec 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -351,10 +351,7 @@ namespace Flow.Launcher.Infrastructure fixed (HKL* h = handles) { var result = PInvoke.GetKeyboardLayoutList(count, h); - if (result == 0) - { - throw new Win32Exception(Marshal.GetLastWin32Error()); - } + if (result == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); } // Look for any English keyboard layout @@ -364,10 +361,7 @@ namespace Flow.Launcher.Infrastructure var langId = (uint)hkl.Value & KeyboardLayoutLoWord; // Check if it's an English layout - if (EnglishLanguageIds.Contains(langId)) - { - return hkl; - } + if (EnglishLanguageIds.Contains(langId)) return hkl; } return HKL.Null; @@ -399,16 +393,10 @@ namespace Flow.Launcher.Infrastructure // the IME mode instead of switching to another layout. var currentLayout = PInvoke.GetKeyboardLayout(threadId); var currentLayoutCode = (uint)currentLayout.Value & KeyboardLayoutLoWord; - if (ImeLanguageIds.Contains(currentLayoutCode)) - { - return; - } + if (ImeLanguageIds.Contains(currentLayoutCode)) return; // Backup current keyboard layout - if (backupPrevious) - { - _previousLayout = currentLayout; - } + if (backupPrevious) _previousLayout = currentLayout; // Switch to English layout PInvoke.ActivateKeyboardLayout(enHKL, 0); @@ -431,6 +419,7 @@ namespace Flow.Launcher.Infrastructure PInvoke.INPUTLANGCHANGE_FORWARD, _previousLayout.Value ); + _previousLayout = HKL.Null; } From d827d0ac9f42f88556476731c700c6ad8806e8fc Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 23 Mar 2025 22:22:08 +0800 Subject: [PATCH 26/29] Use language tag instead of language id --- .../NativeMethods.txt | 4 + Flow.Launcher.Infrastructure/Win32Helper.cs | 143 +++++++++++++----- 2 files changed, 108 insertions(+), 39 deletions(-) diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt index de74eb7f9..363ecb9d0 100644 --- a/Flow.Launcher.Infrastructure/NativeMethods.txt +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -55,3 +55,7 @@ GetKeyboardLayoutList PostMessage WM_INPUTLANGCHANGEREQUEST INPUTLANGCHANGE_FORWARD +LOCALE_TRANSIENT_KEYBOARD1 +LOCALE_TRANSIENT_KEYBOARD2 +LOCALE_TRANSIENT_KEYBOARD3 +LOCALE_TRANSIENT_KEYBOARD4 \ No newline at end of file diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 8c32899ec..c84c2e3a8 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -1,16 +1,17 @@ using System; using System.ComponentModel; -using System.Linq; +using System.Globalization; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; using System.Windows.Media; +using Flow.Launcher.Infrastructure.UserSettings; +using Microsoft.Win32; using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.Graphics.Dwm; using Windows.Win32.UI.Input.KeyboardAndMouse; using Windows.Win32.UI.WindowsAndMessaging; -using Flow.Launcher.Infrastructure.UserSettings; using Point = System.Windows.Point; namespace Flow.Launcher.Infrastructure @@ -323,16 +324,16 @@ namespace Flow.Launcher.Infrastructure #region Keyboard Layout - // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f - private static readonly uint[] EnglishLanguageIds = - { - 0x0009, 0x0409, 0x0809, 0x0C09, 0x1009, 0x1409, 0x1809, 0x1C09, 0x2009, 0x2409, 0x2809, 0x2C09, 0x3009, - 0x3409, 0x3C09, 0x4009, 0x4409, 0x4809, 0x4C09, - }; + private const string UserProfileRegistryPath = @"Control Panel\International\User Profile"; - private static readonly uint[] ImeLanguageIds = + // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f + private const string EnglishLanguageTag = "en"; + + private static readonly string[] ImeLanguageTags = { - 0x0004, 0x7804, 0x0804, 0x1004, 0x7C04, 0x0C04, 0x1404, 0x0404, 0x0011, 0x0411, 0x0012, 0x0412, + "zh", // Chinese + "ja", // Japanese + "ko", // Korean }; private const uint KeyboardLayoutLoWord = 0xFFFF; @@ -340,33 +341,6 @@ namespace Flow.Launcher.Infrastructure // Store the previous keyboard layout private static HKL _previousLayout; - private static unsafe HKL FindEnglishKeyboardLayout() - { - // Get the number of keyboard layouts - int count = PInvoke.GetKeyboardLayoutList(0, null); - if (count <= 0) return HKL.Null; - - // Get all keyboard layouts - var handles = new HKL[count]; - fixed (HKL* h = handles) - { - var result = PInvoke.GetKeyboardLayoutList(count, h); - if (result == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); - } - - // Look for any English keyboard layout - foreach (var hkl in handles) - { - // The lower word contains the language identifier - var langId = (uint)hkl.Value & KeyboardLayoutLoWord; - - // Check if it's an English layout - if (EnglishLanguageIds.Contains(langId)) return hkl; - } - - return HKL.Null; - } - /// /// Switches the keyboard layout to English if available. /// @@ -392,8 +366,14 @@ namespace Flow.Launcher.Infrastructure // This is needed because for languages with IME mode, Flow Launcher just temporarily disables // the IME mode instead of switching to another layout. var currentLayout = PInvoke.GetKeyboardLayout(threadId); - var currentLayoutCode = (uint)currentLayout.Value & KeyboardLayoutLoWord; - if (ImeLanguageIds.Contains(currentLayoutCode)) return; + var currentLangId = (uint)currentLayout.Value & KeyboardLayoutLoWord; + foreach (var langTag in ImeLanguageTags) + { + if (GetLanguageTag(currentLangId).StartsWith(langTag, StringComparison.OrdinalIgnoreCase)) + { + return; + } + } // Backup current keyboard layout if (backupPrevious) _previousLayout = currentLayout; @@ -423,6 +403,91 @@ namespace Flow.Launcher.Infrastructure _previousLayout = HKL.Null; } + /// + /// Finds an installed English keyboard layout. + /// + /// + /// + private static unsafe HKL FindEnglishKeyboardLayout() + { + // Get the number of keyboard layouts + int count = PInvoke.GetKeyboardLayoutList(0, null); + if (count <= 0) return HKL.Null; + + // Get all keyboard layouts + var handles = new HKL[count]; + fixed (HKL* h = handles) + { + var result = PInvoke.GetKeyboardLayoutList(count, h); + if (result == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); + } + + // Look for any English keyboard layout + foreach (var hkl in handles) + { + // The lower word contains the language identifier + var langId = (uint)hkl.Value & KeyboardLayoutLoWord; + var langTag = GetLanguageTag(langId); + + // Check if it's an English layout + if (langTag.StartsWith(EnglishLanguageTag, StringComparison.OrdinalIgnoreCase)) + { + return hkl; + } + } + + return HKL.Null; + } + + /// + /// Returns the + /// + /// BCP 47 language tag + /// + /// of the current input language. + /// + /// + /// Edited from: https://github.com/dotnet/winforms + /// + private static string GetLanguageTag(uint langId) + { + // We need to convert the language identifier to a language tag, because they are deprecated and may have a + // transient value. + // https://learn.microsoft.com/globalization/locale/other-locale-names#lcid + // https://learn.microsoft.com/windows/win32/winmsg/wm-inputlangchange#remarks + // + // It turns out that the LCIDToLocaleName API, which is used inside CultureInfo, may return incorrect + // language tags for transient language identifiers. For example, it returns "nqo-GN" and "jv-Java-ID" + // instead of the "nqo" and "jv-Java" (as seen in the Get-WinUserLanguageList PowerShell cmdlet). + // + // Try to extract proper language tag from registry as a workaround approved by a Windows team. + // https://github.com/dotnet/winforms/pull/8573#issuecomment-1542600949 + // + // NOTE: this logic may break in future versions of Windows since it is not documented. + if (langId is (int)PInvoke.LOCALE_TRANSIENT_KEYBOARD1 + or (int)PInvoke.LOCALE_TRANSIENT_KEYBOARD2 + or (int)PInvoke.LOCALE_TRANSIENT_KEYBOARD3 + or (int)PInvoke.LOCALE_TRANSIENT_KEYBOARD4) + { + using RegistryKey key = Registry.CurrentUser.OpenSubKey(UserProfileRegistryPath); + if (key is not null && key.GetValue("Languages") is string[] languages) + { + foreach (string language in languages) + { + using RegistryKey subKey = key.OpenSubKey(language); + if (subKey is not null + && subKey.GetValue("TransientLangId") is int transientLangId + && transientLangId == langId) + { + return language; + } + } + } + } + + return CultureInfo.GetCultureInfo((int)langId).Name; + } + #endregion } } From 4f2a951adfe2d1d5d96770f1470184f9dce6d091 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sun, 23 Mar 2025 20:41:28 +0600 Subject: [PATCH 27/29] Small code style changes in keyboard change logic --- Flow.Launcher.Infrastructure/Win32Helper.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index c84c2e3a8..7a3a0c36e 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -464,19 +464,18 @@ namespace Flow.Launcher.Infrastructure // https://github.com/dotnet/winforms/pull/8573#issuecomment-1542600949 // // NOTE: this logic may break in future versions of Windows since it is not documented. - if (langId is (int)PInvoke.LOCALE_TRANSIENT_KEYBOARD1 - or (int)PInvoke.LOCALE_TRANSIENT_KEYBOARD2 - or (int)PInvoke.LOCALE_TRANSIENT_KEYBOARD3 - or (int)PInvoke.LOCALE_TRANSIENT_KEYBOARD4) + if (langId is PInvoke.LOCALE_TRANSIENT_KEYBOARD1 + or PInvoke.LOCALE_TRANSIENT_KEYBOARD2 + or PInvoke.LOCALE_TRANSIENT_KEYBOARD3 + or PInvoke.LOCALE_TRANSIENT_KEYBOARD4) { - using RegistryKey key = Registry.CurrentUser.OpenSubKey(UserProfileRegistryPath); - if (key is not null && key.GetValue("Languages") is string[] languages) + using var key = Registry.CurrentUser.OpenSubKey(UserProfileRegistryPath); + if (key?.GetValue("Languages") is string[] languages) { foreach (string language in languages) { - using RegistryKey subKey = key.OpenSubKey(language); - if (subKey is not null - && subKey.GetValue("TransientLangId") is int transientLangId + using var subKey = key.OpenSubKey(language); + if (subKey?.GetValue("TransientLangId") is int transientLangId && transientLangId == langId) { return language; From dfad11cbed8880c17248a2a3a689616ecc7a02a4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 24 Mar 2025 13:22:15 +0800 Subject: [PATCH 28/29] Fix language change issue --- Flow.Launcher.Core/Plugin/PluginManager.cs | 3 - .../Resource/Internationalization.cs | 79 +++++++++++++------ Flow.Launcher/App.xaml.cs | 9 ++- 3 files changed, 58 insertions(+), 33 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index b1396e207..aab3caa40 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -205,9 +205,6 @@ namespace Flow.Launcher.Core.Plugin } } - InternationalizationManager.Instance.AddPluginLanguageDirectories(GetPluginsForInterface()); - InternationalizationManager.Instance.ChangeLanguage(Ioc.Default.GetRequiredService().Language); - if (failedPlugins.Any()) { var failed = string.Join(",", failedPlugins.Select(x => x.Metadata.Name)); diff --git a/Flow.Launcher.Core/Resource/Internationalization.cs b/Flow.Launcher.Core/Resource/Internationalization.cs index e2a66656a..baf602096 100644 --- a/Flow.Launcher.Core/Resource/Internationalization.cs +++ b/Flow.Launcher.Core/Resource/Internationalization.cs @@ -67,9 +67,9 @@ namespace Flow.Launcher.Core.Resource return DefaultLanguageCode; } - internal void AddPluginLanguageDirectories(IEnumerable plugins) + private void AddPluginLanguageDirectories() { - foreach (var plugin in plugins) + foreach (var plugin in PluginManager.GetPluginsForInterface()) { var location = Assembly.GetAssembly(plugin.Plugin.GetType()).Location; var dir = Path.GetDirectoryName(location); @@ -96,6 +96,32 @@ namespace Flow.Launcher.Core.Resource _oldResources.Clear(); } + /// + /// Initialize language. Will change app language and plugin language based on settings. + /// + public async Task InitializeLanguageAsync() + { + // Get actual language + var languageCode = _settings.Language; + if (languageCode == Constant.SystemLanguageCode) + { + languageCode = SystemLanguageCode; + } + + // Get language by language code and change language + var language = GetLanguageByLanguageCode(languageCode); + + // Add plugin language directories first so that we can load language files from plugins + AddPluginLanguageDirectories(); + + // Change language + await ChangeLanguageAsync(language); + } + + /// + /// Change language during runtime. Will change app language and plugin language & save settings. + /// + /// public void ChangeLanguage(string languageCode) { languageCode = languageCode.NonNull(); @@ -110,10 +136,33 @@ namespace Flow.Launcher.Core.Resource // Get language by language code and change language var language = GetLanguageByLanguageCode(languageCode); - ChangeLanguage(language, isSystem); + + // Change language + _ = ChangeLanguageAsync(language); + + // Save settings + _settings.Language = isSystem ? Constant.SystemLanguageCode : language.LanguageCode; } - private Language GetLanguageByLanguageCode(string languageCode) + private async Task ChangeLanguageAsync(Language language) + { + // Remove old language files and load language + RemoveOldLanguageFiles(); + if (language != AvailableLanguages.English) + { + LoadLanguage(language); + } + + // Culture of main thread + // Use CreateSpecificCulture to preserve possible user-override settings in Windows, if Flow's language culture is the same as Windows's + CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture(language.LanguageCode); + CultureInfo.CurrentUICulture = CultureInfo.CurrentCulture; + + // Raise event for plugins after culture is set + await Task.Run(UpdatePluginMetadataTranslations); + } + + private static Language GetLanguageByLanguageCode(string languageCode) { var lowercase = languageCode.ToLower(); var language = AvailableLanguages.GetAvailableLanguages().FirstOrDefault(o => o.LanguageCode.ToLower() == lowercase); @@ -128,28 +177,6 @@ namespace Flow.Launcher.Core.Resource } } - private void ChangeLanguage(Language language, bool isSystem) - { - language = language.NonNull(); - - RemoveOldLanguageFiles(); - if (language != AvailableLanguages.English) - { - LoadLanguage(language); - } - // Culture of main thread - // Use CreateSpecificCulture to preserve possible user-override settings in Windows, if Flow's language culture is the same as Windows's - CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture(language.LanguageCode); - CultureInfo.CurrentUICulture = CultureInfo.CurrentCulture; - - // Raise event after culture is set - _settings.Language = isSystem ? Constant.SystemLanguageCode : language.LanguageCode; - _ = Task.Run(() => - { - UpdatePluginMetadataTranslations(); - }); - } - public bool PromptShouldUsePinyin(string languageCodeToSet) { var languageToSet = GetLanguageByLanguageCode(languageCodeToSet); diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 377d36c48..b102e384e 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -132,13 +132,14 @@ namespace Flow.Launcher // Register ResultsUpdated event after all plugins are loaded Ioc.Default.GetRequiredService().RegisterResultsUpdatedEvent(); - // Change language after all plugins are initialized - // TODO: Clean InternationalizationManager.Instance and InternationalizationManager.Instance.GetTranslation in future - Ioc.Default.GetRequiredService().ChangeLanguage(_settings.Language); - Http.Proxy = _settings.Proxy; await PluginManager.InitializePluginsAsync(); + + // Change language after all plugins are initialized because we need to update plugin title based on their api + // TODO: Clean InternationalizationManager.Instance and InternationalizationManager.Instance.GetTranslation in future + await Ioc.Default.GetRequiredService().InitializeLanguageAsync(); + await imageLoadertask; var window = new MainWindow(); From a3193cf525c3a487bbe690e67f9b07fe05624802 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 24 Mar 2025 13:24:05 +0800 Subject: [PATCH 29/29] Move function position --- .../Resource/Internationalization.cs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Flow.Launcher.Core/Resource/Internationalization.cs b/Flow.Launcher.Core/Resource/Internationalization.cs index baf602096..ffa17ab4d 100644 --- a/Flow.Launcher.Core/Resource/Internationalization.cs +++ b/Flow.Launcher.Core/Resource/Internationalization.cs @@ -144,6 +144,21 @@ namespace Flow.Launcher.Core.Resource _settings.Language = isSystem ? Constant.SystemLanguageCode : language.LanguageCode; } + private Language GetLanguageByLanguageCode(string languageCode) + { + var lowercase = languageCode.ToLower(); + var language = AvailableLanguages.GetAvailableLanguages().FirstOrDefault(o => o.LanguageCode.ToLower() == lowercase); + if (language == null) + { + Log.Error($"|Internationalization.GetLanguageByLanguageCode|Language code can't be found <{languageCode}>"); + return AvailableLanguages.English; + } + else + { + return language; + } + } + private async Task ChangeLanguageAsync(Language language) { // Remove old language files and load language @@ -162,21 +177,6 @@ namespace Flow.Launcher.Core.Resource await Task.Run(UpdatePluginMetadataTranslations); } - private static Language GetLanguageByLanguageCode(string languageCode) - { - var lowercase = languageCode.ToLower(); - var language = AvailableLanguages.GetAvailableLanguages().FirstOrDefault(o => o.LanguageCode.ToLower() == lowercase); - if (language == null) - { - Log.Error($"|Internationalization.GetLanguageByLanguageCode|Language code can't be found <{languageCode}>"); - return AvailableLanguages.English; - } - else - { - return language; - } - } - public bool PromptShouldUsePinyin(string languageCodeToSet) { var languageToSet = GetLanguageByLanguageCode(languageCodeToSet);