|  | 
| 1 | 1 | 
 | 
| 2 | 2 | using System; | 
| 3 |  | -using System.Collections.Generic; | 
| 4 |  | -using System.Globalization; | 
| 5 |  | -using System.Runtime.InteropServices; | 
| 6 |  | -using System.Threading; | 
| 7 |  | -using Xunit; | 
| 8 | 3 | 
 | 
| 9 | 4 | namespace Test | 
| 10 | 5 | { | 
| 11 |  | -    public class WindowsConsoleFixtureHelper | 
| 12 |  | -    { | 
| 13 |  | -        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] | 
| 14 |  | -        static extern IntPtr LoadKeyboardLayout(string pwszKLID, uint Flags); | 
| 15 |  | - | 
| 16 |  | -        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] | 
| 17 |  | -        static extern IntPtr GetKeyboardLayout(uint idThread); | 
| 18 |  | - | 
| 19 |  | -        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] | 
| 20 |  | -        static extern int GetKeyboardLayoutList(int nBuff, [Out] IntPtr[] lpList); | 
| 21 |  | - | 
| 22 |  | -        // For set: | 
| 23 |  | -        [DllImport("user32.dll", CharSet = CharSet.Auto)] | 
| 24 |  | -        public static extern bool PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam); | 
| 25 |  | - | 
| 26 |  | -        // For get: | 
| 27 |  | -        [DllImport("user32.dll", SetLastError = true)] | 
| 28 |  | -        static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId); | 
| 29 |  | - | 
| 30 |  | -        [DllImport("user32.dll", SetLastError = true)] | 
| 31 |  | -        static extern IntPtr GetForegroundWindow(); | 
| 32 |  | - | 
| 33 |  | -        const int WM_INPUTLANGCHANGEREQUEST = 0x0050; | 
| 34 |  | - | 
| 35 |  | -        private static string GetLayoutNameFromHKL(IntPtr hkl) | 
| 36 |  | -        { | 
| 37 |  | -            var lcid = (int)((uint)hkl & 0xffff); | 
| 38 |  | -            return (new CultureInfo(lcid)).Name; | 
| 39 |  | -        } | 
| 40 |  | - | 
| 41 |  | -        public static IEnumerable<string> GetKeyboardLayoutList() | 
| 42 |  | -        { | 
| 43 |  | -            int cnt = GetKeyboardLayoutList(0, null); | 
| 44 |  | -            var list = new IntPtr[cnt]; | 
| 45 |  | -            GetKeyboardLayoutList(list.Length, list); | 
| 46 |  | - | 
| 47 |  | -            foreach (var layout in list) | 
| 48 |  | -            { | 
| 49 |  | -                yield return GetLayoutNameFromHKL(layout); | 
| 50 |  | -            } | 
| 51 |  | -        } | 
| 52 |  | - | 
| 53 |  | -        public static string GetKeyboardLayout() | 
| 54 |  | -        { | 
| 55 |  | -            // In CI environments like GitHub Actions, keyboard layout detection can fail | 
| 56 |  | -            // or return incorrect results. Default to en-US in these cases. | 
| 57 |  | -            if (Environment.GetEnvironmentVariable("GITHUB_ACTIONS") == "true" || | 
| 58 |  | -                Environment.GetEnvironmentVariable("TF_BUILD") == "true" || | 
| 59 |  | -                !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) | 
| 60 |  | -            { | 
| 61 |  | -                return "en-US"; | 
| 62 |  | -            } | 
| 63 |  | - | 
| 64 |  | -            var layout = GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow(), out var processId)); | 
| 65 |  | -            return GetLayoutNameFromHKL(layout); | 
| 66 |  | -        } | 
| 67 |  | - | 
| 68 |  | -        public static IntPtr SetKeyboardLayout(string lang) | 
| 69 |  | -        { | 
| 70 |  | -            var layoutId = (new CultureInfo(lang)).KeyboardLayoutId; | 
| 71 |  | -            var layout = LoadKeyboardLayout(layoutId.ToString("x8"), 0x80); | 
| 72 |  | -            // Hacky, but tests are probably running in a console app and the layout change | 
| 73 |  | -            // is ignored, so post the layout change to the foreground window. | 
| 74 |  | -            PostMessage(GetForegroundWindow(), WM_INPUTLANGCHANGEREQUEST, 0, layoutId); | 
| 75 |  | -            Thread.Sleep(500); | 
| 76 |  | -            return layout; | 
| 77 |  | -        } | 
| 78 |  | -    } | 
| 79 |  | - | 
| 80 | 6 |     public class ConsoleFixture : IDisposable | 
| 81 | 7 |     { | 
| 82 | 8 |         public KeyboardLayout KbLayout { get; private set; } | 
| 83 |  | -        public string Lang { get; private set; } | 
| 84 |  | -        public string Os { get; private set; } | 
| 85 | 9 | 
 | 
| 86 | 10 |         public ConsoleFixture() | 
| 87 | 11 |         { | 
| 88 |  | -            Lang = ""; | 
| 89 |  | -            Os = ""; | 
| 90 | 12 |         } | 
| 91 | 13 | 
 | 
| 92 |  | -        public void Initialize(string lang, string os) | 
|  | 14 | +        public void Initialize() | 
| 93 | 15 |         { | 
| 94 |  | -            if (!string.Equals(lang, Lang) || !string.Equals(os, Os)) | 
| 95 |  | -            { | 
| 96 |  | -                Lang = lang; | 
| 97 |  | -                Os = os; | 
| 98 |  | -                KbLayout = new KeyboardLayout(lang, "windows"); | 
| 99 |  | -            } | 
|  | 16 | +            KbLayout = new KeyboardLayout(); | 
| 100 | 17 |         } | 
| 101 | 18 | 
 | 
| 102 | 19 |         public void Dispose() | 
| 103 | 20 |         { | 
| 104 | 21 |         } | 
| 105 |  | - | 
| 106 |  | -        public override string ToString() | 
| 107 |  | -        { | 
| 108 |  | -            return Lang + "-" + Os; | 
| 109 |  | -        } | 
| 110 | 22 |     } | 
| 111 | 23 | } | 
0 commit comments