using System.Runtime.InteropServices; namespace Terminal.Gui.Drivers; /// /// Windows-specific keyboard layout information using P/Invoke. /// This class encapsulates all Windows API calls for keyboard layout operations. /// internal static class WindowsKeyboardLayout { #if !WT_ISSUE_8871_FIXED // https://github.com/microsoft/terminal/issues/8871 /// /// Translates (maps) a virtual-key code into a scan code or character value, or translates a scan code into a /// virtual-key code. /// /// /// /// If MAPVK_VK_TO_CHAR (2) - The uCode parameter is a virtual-key code and is translated into an /// un-shifted character value in the low order word of the return value. /// /// /// /// An un-shifted character value in the low order word of the return value. Dead keys (diacritics) are indicated /// by setting the top bit of the return value. If there is no translation, the function returns 0. See Remarks. /// [DllImport ("user32.dll", EntryPoint = "MapVirtualKeyExW", CharSet = CharSet.Unicode)] private static extern uint MapVirtualKeyEx (VK vk, uint uMapType, nint dwhkl); /// Retrieves the active input locale identifier (formerly called the keyboard layout). /// 0 for current thread /// /// The return value is the input locale identifier for the thread. The low word contains a Language Identifier /// for the input language and the high word contains a device handle to the physical layout of the keyboard. /// [DllImport ("user32.dll", EntryPoint = "GetKeyboardLayout", CharSet = CharSet.Unicode)] private static extern nint GetKeyboardLayout (nint idThread); [DllImport ("user32.dll")] private static extern nint GetForegroundWindow (); [DllImport ("user32.dll")] private static extern nint GetWindowThreadProcessId (nint hWnd, nint ProcessId); /// /// Translates the specified virtual-key code and keyboard state to the corresponding Unicode character or /// characters using the Win32 API MapVirtualKey. /// /// /// /// An un-shifted character value in the low order word of the return value. Dead keys (diacritics) are indicated /// by setting the top bit of the return value. If there is no translation, the function returns 0. /// public static uint MapVKtoChar (VK vk) { if (Environment.OSVersion.Platform != PlatformID.Win32NT) { return 0; } nint tid = GetWindowThreadProcessId (GetForegroundWindow (), 0); nint hkl = GetKeyboardLayout (tid); return MapVirtualKeyEx (vk, 2, hkl); } #else /// /// Translates (maps) a virtual-key code into a scan code or character value, or translates a scan code into a virtual-key code. /// /// /// /// If MAPVK_VK_TO_CHAR (2) - The uCode parameter is a virtual-key code and is translated into an unshifted /// character value in the low order word of the return value. /// /// An unshifted character value in the low order word of the return value. Dead keys (diacritics) /// are indicated by setting the top bit of the return value. If there is no translation, /// the function returns 0. See Remarks. [DllImport ("user32.dll", EntryPoint = "MapVirtualKeyW", CharSet = CharSet.Unicode)] private static extern uint MapVirtualKey (VK vk, uint uMapType = 2); public static uint MapVKtoChar (VK vk) => MapVirtualKey (vk, 2); #endif /// /// Retrieves the name of the active input locale identifier (formerly called the keyboard layout) for the calling /// thread. /// /// /// [DllImport ("user32.dll")] private static extern bool GetKeyboardLayoutName ([Out] StringBuilder pwszKLID); /// /// Retrieves the name of the active input locale identifier (formerly called the keyboard layout) for the calling /// thread. /// /// public static string GetKeyboardLayoutName () { if (Environment.OSVersion.Platform != PlatformID.Win32NT) { return "none"; } var klidSB = new StringBuilder (); GetKeyboardLayoutName (klidSB); return klidSB.ToString (); } }