using System.Globalization;
using System.Runtime.InteropServices;
namespace Terminal.Gui.ConsoleDrivers;
/// Helper class to handle the scan code and virtual key from a .
public static class ConsoleKeyMapping
{
#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", EntryPoint = "GetKeyboardLayoutNameW", CharSet = CharSet.Unicode)]
//extern static uint GetKeyboardLayoutName (uint 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)]
extern static uint MapVirtualKey (VK vk, uint uMapType = 2);
uint MapVKtoChar (VK vk) => MapVirtualKeyToCharEx (vk);
#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 ();
}
private class ScanCodeMapping : IEquatable
{
public readonly ConsoleModifiers Modifiers;
public readonly uint ScanCode;
public readonly uint UnicodeChar;
public readonly VK VirtualKey;
public ScanCodeMapping (uint scanCode, VK virtualKey, ConsoleModifiers modifiers, uint unicodeChar)
{
ScanCode = scanCode;
VirtualKey = virtualKey;
Modifiers = modifiers;
UnicodeChar = unicodeChar;
}
public bool Equals (ScanCodeMapping other)
{
return ScanCode.Equals (other.ScanCode)
&& VirtualKey.Equals (other.VirtualKey)
&& Modifiers.Equals (other.Modifiers)
&& UnicodeChar.Equals (other.UnicodeChar);
}
}
private static ConsoleModifiers GetModifiers (ConsoleModifiers modifiers)
{
if (modifiers.HasFlag (ConsoleModifiers.Shift)
&& !modifiers.HasFlag (ConsoleModifiers.Alt)
&& !modifiers.HasFlag (ConsoleModifiers.Control))
{
return ConsoleModifiers.Shift;
}
if (modifiers == (ConsoleModifiers.Alt | ConsoleModifiers.Control))
{
return modifiers;
}
return 0;
}
private static ScanCodeMapping GetScanCode (string propName, uint keyValue, ConsoleModifiers modifiers)
{
switch (propName)
{
case "UnicodeChar":
ScanCodeMapping sCode =
_scanCodes.FirstOrDefault (e => e.UnicodeChar == keyValue && e.Modifiers == modifiers);
if (sCode is null && modifiers == (ConsoleModifiers.Alt | ConsoleModifiers.Control))
{
return _scanCodes.FirstOrDefault (e => e.UnicodeChar == keyValue && e.Modifiers == 0);
}
return sCode;
case "VirtualKey":
sCode = _scanCodes.FirstOrDefault (e => e.VirtualKey == (VK)keyValue && e.Modifiers == modifiers);
if (sCode is null && modifiers == (ConsoleModifiers.Alt | ConsoleModifiers.Control))
{
return _scanCodes.FirstOrDefault (e => e.VirtualKey == (VK)keyValue && e.Modifiers == 0);
}
return sCode;
}
return null;
}
// BUGBUG: This API is not correct. It is only used by WindowsDriver in VKPacket scenarios
/// Get the scan code from a .
/// The console key info.
/// The value if apply.
public static uint GetScanCodeFromConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
{
ConsoleModifiers mod = GetModifiers (consoleKeyInfo.Modifiers);
ScanCodeMapping scode = GetScanCode ("VirtualKey", (uint)consoleKeyInfo.Key, mod);
if (scode is { })
{
return scode.ScanCode;
}
return 0;
}
// BUGBUG: This API is not correct. It is only used by FakeDriver and VkeyPacketSimulator
/// Gets the from the provided .
/// The key code.
/// The console key info.
public static ConsoleKeyInfo GetConsoleKeyInfoFromKeyCode (KeyCode key)
{
ConsoleModifiers modifiers = MapToConsoleModifiers (key);
uint keyValue = MapKeyCodeToConsoleKey (key, out bool isConsoleKey);
if (isConsoleKey)
{
ConsoleModifiers mod = GetModifiers (modifiers);
ScanCodeMapping scode = GetScanCode ("VirtualKey", keyValue, mod);
if (scode is { })
{
return new ConsoleKeyInfo (
(char)scode.UnicodeChar,
(ConsoleKey)scode.VirtualKey,
modifiers.HasFlag (ConsoleModifiers.Shift),
modifiers.HasFlag (ConsoleModifiers.Alt),
modifiers.HasFlag (ConsoleModifiers.Control)
);
}
}
else
{
uint keyChar = GetKeyCharFromUnicodeChar (keyValue, modifiers, out uint consoleKey, out _, isConsoleKey);
if (consoleKey != 0)
{
return new ConsoleKeyInfo (
(char)keyChar,
(ConsoleKey)consoleKey,
modifiers.HasFlag (ConsoleModifiers.Shift),
modifiers.HasFlag (ConsoleModifiers.Alt),
modifiers.HasFlag (ConsoleModifiers.Control)
);
}
}
return new ConsoleKeyInfo (
(char)keyValue,
ConsoleKey.None,
modifiers.HasFlag (ConsoleModifiers.Shift),
modifiers.HasFlag (ConsoleModifiers.Alt),
modifiers.HasFlag (ConsoleModifiers.Control)
);
}
/// Map existing modifiers to .
/// The key code.
/// The console modifiers.
public static ConsoleModifiers MapToConsoleModifiers (KeyCode key)
{
var modifiers = new ConsoleModifiers ();
if (key.HasFlag (KeyCode.ShiftMask))
{
modifiers |= ConsoleModifiers.Shift;
}
if (key.HasFlag (KeyCode.AltMask))
{
modifiers |= ConsoleModifiers.Alt;
}
if (key.HasFlag (KeyCode.CtrlMask))
{
modifiers |= ConsoleModifiers.Control;
}
return modifiers;
}
/// Gets from modifiers.
/// The shift key.
/// The alt key.
/// The control key.
/// The console modifiers.
public static ConsoleModifiers GetModifiers (bool shift, bool alt, bool control)
{
var modifiers = new ConsoleModifiers ();
if (shift)
{
modifiers |= ConsoleModifiers.Shift;
}
if (alt)
{
modifiers |= ConsoleModifiers.Alt;
}
if (control)
{
modifiers |= ConsoleModifiers.Control;
}
return modifiers;
}
///
/// Get the from a unicode character and modifiers (e.g. (Key)'a' and
/// (Key)Key.CtrlMask).
///
/// The key as a unicode codepoint.
/// The modifier keys.
/// The resulting scan code.
/// The .
private static ConsoleKeyInfo GetConsoleKeyInfoFromKeyChar (
uint keyValue,
ConsoleModifiers modifiers,
out uint scanCode
)
{
scanCode = 0;
if (keyValue == 0)
{
return new ConsoleKeyInfo (
(char)keyValue,
ConsoleKey.None,
modifiers.HasFlag (ConsoleModifiers.Shift),
modifiers.HasFlag (ConsoleModifiers.Alt),
modifiers.HasFlag (ConsoleModifiers.Control)
);
}
uint outputChar = keyValue;
uint consoleKey;
if (keyValue > byte.MaxValue)
{
ScanCodeMapping sCode = _scanCodes.FirstOrDefault (e => e.UnicodeChar == keyValue);
if (sCode is null)
{
consoleKey = (byte)(keyValue & byte.MaxValue);
sCode = _scanCodes.FirstOrDefault (e => e.VirtualKey == (VK)consoleKey);
if (sCode is null)
{
consoleKey = 0;
outputChar = keyValue;
}
else
{
outputChar = (char)(keyValue >> 8);
}
}
else
{
consoleKey = (byte)sCode.VirtualKey;
outputChar = keyValue;
}
}
else
{
consoleKey = (byte)keyValue;
outputChar = '\0';
}
return new ConsoleKeyInfo (
(char)outputChar,
(ConsoleKey)consoleKey,
modifiers.HasFlag (ConsoleModifiers.Shift),
modifiers.HasFlag (ConsoleModifiers.Alt),
modifiers.HasFlag (ConsoleModifiers.Control)
);
}
// Used only by unit tests
internal static uint GetKeyChar (uint keyValue, ConsoleModifiers modifiers)
{
if (modifiers == ConsoleModifiers.Shift && keyValue - 32 is >= 'A' and <= 'Z')
{
return keyValue - 32;
}
if (modifiers == ConsoleModifiers.None && keyValue is >= 'A' and <= 'Z')
{
return keyValue + 32;
}
if (modifiers == ConsoleModifiers.Shift && keyValue - 32 is >= 'À' and <= 'Ý')
{
return keyValue - 32;
}
if (modifiers == ConsoleModifiers.None && keyValue is >= 'À' and <= 'Ý')
{
return keyValue + 32;
}
if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '0')
{
return keyValue + 13;
}
if (modifiers == ConsoleModifiers.None && keyValue - 13 is '0')
{
return keyValue - 13;
}
if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is >= '1' and <= '9' and not '7')
{
return keyValue - 16;
}
if (modifiers == ConsoleModifiers.None && keyValue + 16 is >= '1' and <= '9' and not '7')
{
return keyValue + 16;
}
if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '7')
{
return keyValue - 8;
}
if (modifiers == ConsoleModifiers.None && keyValue + 8 is '7')
{
return keyValue + 8;
}
if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '\'')
{
return keyValue + 24;
}
if (modifiers == ConsoleModifiers.None && keyValue - 24 is '\'')
{
return keyValue - 24;
}
if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '«')
{
return keyValue + 16;
}
if (modifiers == ConsoleModifiers.None && keyValue - 16 is '«')
{
return keyValue - 16;
}
if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '\\')
{
return keyValue + 32;
}
if (modifiers == ConsoleModifiers.None && keyValue - 32 is '\\')
{
return keyValue - 32;
}
if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '+')
{
return keyValue - 1;
}
if (modifiers == ConsoleModifiers.None && keyValue + 1 is '+')
{
return keyValue + 1;
}
if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '´')
{
return keyValue - 84;
}
if (modifiers == ConsoleModifiers.None && keyValue + 84 is '´')
{
return keyValue + 84;
}
if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is 'º')
{
return keyValue - 16;
}
if (modifiers == ConsoleModifiers.None && keyValue + 16 is 'º')
{
return keyValue + 16;
}
if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '~')
{
return keyValue - 32;
}
if (modifiers == ConsoleModifiers.None && keyValue + 32 is '~')
{
return keyValue + 32;
}
if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '<')
{
return keyValue + 2;
}
if (modifiers == ConsoleModifiers.None && keyValue - 2 is '<')
{
return keyValue - 2;
}
if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is ',')
{
return keyValue + 15;
}
if (modifiers == ConsoleModifiers.None && keyValue - 15 is ',')
{
return keyValue - 15;
}
if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '.')
{
return keyValue + 12;
}
if (modifiers == ConsoleModifiers.None && keyValue - 12 is '.')
{
return keyValue - 12;
}
if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '-')
{
return keyValue + 50;
}
if (modifiers == ConsoleModifiers.None && keyValue - 50 is '-')
{
return keyValue - 50;
}
return keyValue;
}
///
/// Get the output character from the , with the correct
/// and the scan code used on .
///
/// The unicode character.
/// The modifiers keys.
/// The resulting console key.
/// The resulting scan code.
/// Indicates if the is a .
/// The output character or the .
/// This is only used by the and by unit tests.
internal static uint GetKeyCharFromUnicodeChar (
uint unicodeChar,
ConsoleModifiers modifiers,
out uint consoleKey,
out uint scanCode,
bool isConsoleKey = false
)
{
uint decodedChar = unicodeChar >> 8 == 0xff ? unicodeChar & 0xff : unicodeChar;
uint keyChar = decodedChar;
consoleKey = 0;
ConsoleModifiers mod = GetModifiers (modifiers);
scanCode = 0;
ScanCodeMapping scode = null;
if (unicodeChar != 0 && unicodeChar >> 8 != 0xff && isConsoleKey)
{
scode = GetScanCode ("VirtualKey", decodedChar, mod);
}
if (isConsoleKey && scode is { })
{
consoleKey = (uint)scode.VirtualKey;
keyChar = scode.UnicodeChar;
scanCode = scode.ScanCode;
}
if (scode is null)
{
scode = unicodeChar != 0 ? GetScanCode ("UnicodeChar", decodedChar, mod) : null;
if (scode is { })
{
consoleKey = (uint)scode.VirtualKey;
keyChar = scode.UnicodeChar;
scanCode = scode.ScanCode;
}
}
if (decodedChar != 0 && scanCode == 0 && char.IsLetter ((char)decodedChar))
{
string stFormD = ((char)decodedChar).ToString ().Normalize (NormalizationForm.FormD);
for (var i = 0; i < stFormD.Length; i++)
{
UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory (stFormD [i]);
if (uc != UnicodeCategory.NonSpacingMark && uc != UnicodeCategory.OtherLetter)
{
consoleKey = char.ToUpper (stFormD [i]);
scode = GetScanCode ("VirtualKey", char.ToUpper (stFormD [i]), 0);
if (scode is { })
{
scanCode = scode.ScanCode;
}
}
}
}
if (keyChar < 255 && consoleKey == 0 && scanCode == 0)
{
scode = GetScanCode ("VirtualKey", keyChar, mod);
if (scode is { })
{
consoleKey = (uint)scode.VirtualKey;
keyChar = scode.UnicodeChar;
scanCode = scode.ScanCode;
}
}
return keyChar;
}
/// Maps a unicode character (e.g. (Key)'a') to a uint representing a .
/// The key value.
///
/// Indicates if the is a .
/// means the return value is in the ConsoleKey enum. means the return
/// value can be mapped to a valid unicode character.
///
/// The or the .
/// This is only used by the and by unit tests.
internal static uint MapKeyCodeToConsoleKey (KeyCode keyValue, out bool isConsoleKey)
{
isConsoleKey = true;
keyValue = keyValue & ~KeyCode.CtrlMask & ~KeyCode.ShiftMask & ~KeyCode.AltMask;
switch (keyValue)
{
case KeyCode.Enter:
return (uint)ConsoleKey.Enter;
case KeyCode.CursorUp:
return (uint)ConsoleKey.UpArrow;
case KeyCode.CursorDown:
return (uint)ConsoleKey.DownArrow;
case KeyCode.CursorLeft:
return (uint)ConsoleKey.LeftArrow;
case KeyCode.CursorRight:
return (uint)ConsoleKey.RightArrow;
case KeyCode.PageUp:
return (uint)ConsoleKey.PageUp;
case KeyCode.PageDown:
return (uint)ConsoleKey.PageDown;
case KeyCode.Home:
return (uint)ConsoleKey.Home;
case KeyCode.End:
return (uint)ConsoleKey.End;
case KeyCode.Insert:
return (uint)ConsoleKey.Insert;
case KeyCode.Delete:
return (uint)ConsoleKey.Delete;
case KeyCode.F1:
return (uint)ConsoleKey.F1;
case KeyCode.F2:
return (uint)ConsoleKey.F2;
case KeyCode.F3:
return (uint)ConsoleKey.F3;
case KeyCode.F4:
return (uint)ConsoleKey.F4;
case KeyCode.F5:
return (uint)ConsoleKey.F5;
case KeyCode.F6:
return (uint)ConsoleKey.F6;
case KeyCode.F7:
return (uint)ConsoleKey.F7;
case KeyCode.F8:
return (uint)ConsoleKey.F8;
case KeyCode.F9:
return (uint)ConsoleKey.F9;
case KeyCode.F10:
return (uint)ConsoleKey.F10;
case KeyCode.F11:
return (uint)ConsoleKey.F11;
case KeyCode.F12:
return (uint)ConsoleKey.F12;
case KeyCode.F13:
return (uint)ConsoleKey.F13;
case KeyCode.F14:
return (uint)ConsoleKey.F14;
case KeyCode.F15:
return (uint)ConsoleKey.F15;
case KeyCode.F16:
return (uint)ConsoleKey.F16;
case KeyCode.F17:
return (uint)ConsoleKey.F17;
case KeyCode.F18:
return (uint)ConsoleKey.F18;
case KeyCode.F19:
return (uint)ConsoleKey.F19;
case KeyCode.F20:
return (uint)ConsoleKey.F20;
case KeyCode.F21:
return (uint)ConsoleKey.F21;
case KeyCode.F22:
return (uint)ConsoleKey.F22;
case KeyCode.F23:
return (uint)ConsoleKey.F23;
case KeyCode.F24:
return (uint)ConsoleKey.F24;
case KeyCode.Tab | KeyCode.ShiftMask:
return (uint)ConsoleKey.Tab;
}
isConsoleKey = false;
return (uint)keyValue;
}
/// Maps a to a .
/// The console key.
/// The or the .
public static KeyCode MapConsoleKeyInfoToKeyCode (ConsoleKeyInfo consoleKeyInfo)
{
KeyCode keyCode;
switch (consoleKeyInfo.Key)
{
case ConsoleKey.Enter:
keyCode = KeyCode.Enter;
break;
case ConsoleKey.Delete:
keyCode = KeyCode.Delete;
break;
case ConsoleKey.UpArrow:
keyCode = KeyCode.CursorUp;
break;
case ConsoleKey.DownArrow:
keyCode = KeyCode.CursorDown;
break;
case ConsoleKey.LeftArrow:
keyCode = KeyCode.CursorLeft;
break;
case ConsoleKey.RightArrow:
keyCode = KeyCode.CursorRight;
break;
case ConsoleKey.PageUp:
keyCode = KeyCode.PageUp;
break;
case ConsoleKey.PageDown:
keyCode = KeyCode.PageDown;
break;
case ConsoleKey.Home:
keyCode = KeyCode.Home;
break;
case ConsoleKey.End:
keyCode = KeyCode.End;
break;
case ConsoleKey.Insert:
keyCode = KeyCode.Insert;
break;
case ConsoleKey.F1:
keyCode = KeyCode.F1;
break;
case ConsoleKey.F2:
keyCode = KeyCode.F2;
break;
case ConsoleKey.F3:
keyCode = KeyCode.F3;
break;
case ConsoleKey.F4:
keyCode = KeyCode.F4;
break;
case ConsoleKey.F5:
keyCode = KeyCode.F5;
break;
case ConsoleKey.F6:
keyCode = KeyCode.F6;
break;
case ConsoleKey.F7:
keyCode = KeyCode.F7;
break;
case ConsoleKey.F8:
keyCode = KeyCode.F8;
break;
case ConsoleKey.F9:
keyCode = KeyCode.F9;
break;
case ConsoleKey.F10:
keyCode = KeyCode.F10;
break;
case ConsoleKey.F11:
keyCode = KeyCode.F11;
break;
case ConsoleKey.F12:
keyCode = KeyCode.F12;
break;
case ConsoleKey.F13:
keyCode = KeyCode.F13;
break;
case ConsoleKey.F14:
keyCode = KeyCode.F14;
break;
case ConsoleKey.F15:
keyCode = KeyCode.F15;
break;
case ConsoleKey.F16:
keyCode = KeyCode.F16;
break;
case ConsoleKey.F17:
keyCode = KeyCode.F17;
break;
case ConsoleKey.F18:
keyCode = KeyCode.F18;
break;
case ConsoleKey.F19:
keyCode = KeyCode.F19;
break;
case ConsoleKey.F20:
keyCode = KeyCode.F20;
break;
case ConsoleKey.F21:
keyCode = KeyCode.F21;
break;
case ConsoleKey.F22:
keyCode = KeyCode.F22;
break;
case ConsoleKey.F23:
keyCode = KeyCode.F23;
break;
case ConsoleKey.F24:
keyCode = KeyCode.F24;
break;
case ConsoleKey.Tab:
keyCode = KeyCode.Tab;
break;
default:
keyCode = (KeyCode)consoleKeyInfo.KeyChar;
break;
}
keyCode |= MapToKeyCodeModifiers (consoleKeyInfo.Modifiers, keyCode);
return keyCode;
}
/// Maps a to a .
/// The console modifiers.
/// The key code.
/// The with or the
public static KeyCode MapToKeyCodeModifiers (ConsoleModifiers modifiers, KeyCode key)
{
var keyMod = new KeyCode ();
if ((modifiers & ConsoleModifiers.Shift) != 0)
{
keyMod = KeyCode.ShiftMask;
}
if ((modifiers & ConsoleModifiers.Control) != 0)
{
keyMod |= KeyCode.CtrlMask;
}
if ((modifiers & ConsoleModifiers.Alt) != 0)
{
keyMod |= KeyCode.AltMask;
}
return keyMod != KeyCode.Null ? keyMod | key : key;
}
/// Generated from winuser.h. See https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
public enum VK : ushort
{
/// Left mouse button.
LBUTTON = 0x01,
/// Right mouse button.
RBUTTON = 0x02,
/// Control-break processing.
CANCEL = 0x03,
/// Middle mouse button (three-button mouse).
MBUTTON = 0x04,
/// X1 mouse button.
XBUTTON1 = 0x05,
/// X2 mouse button.
XBUTTON2 = 0x06,
/// BACKSPACE key.
BACK = 0x08,
/// TAB key.
TAB = 0x09,
/// CLEAR key.
CLEAR = 0x0C,
/// ENTER key.
RETURN = 0x0D,
/// SHIFT key.
SHIFT = 0x10,
/// CTRL key.
CONTROL = 0x11,
/// ALT key.
MENU = 0x12,
/// PAUSE key.
PAUSE = 0x13,
/// CAPS LOCK key.
CAPITAL = 0x14,
/// IME Kana mode.
KANA = 0x15,
/// IME Hangul mode.
HANGUL = 0x15,
/// IME Junja mode.
JUNJA = 0x17,
/// IME final mode.
FINAL = 0x18,
/// IME Hanja mode.
HANJA = 0x19,
/// IME Kanji mode.
KANJI = 0x19,
/// ESC key.
ESCAPE = 0x1B,
/// IME convert.
CONVERT = 0x1C,
/// IME nonconvert.
NONCONVERT = 0x1D,
/// IME accept.
ACCEPT = 0x1E,
/// IME mode change request.
MODECHANGE = 0x1F,
/// SPACEBAR.
SPACE = 0x20,
/// PAGE UP key.
PRIOR = 0x21,
/// PAGE DOWN key.
NEXT = 0x22,
/// END key.
END = 0x23,
/// HOME key.
HOME = 0x24,
/// LEFT ARROW key.
LEFT = 0x25,
/// UP ARROW key.
UP = 0x26,
/// RIGHT ARROW key.
RIGHT = 0x27,
/// DOWN ARROW key.
DOWN = 0x28,
/// SELECT key.
SELECT = 0x29,
/// PRINT key.
PRINT = 0x2A,
/// EXECUTE key
EXECUTE = 0x2B,
/// PRINT SCREEN key
SNAPSHOT = 0x2C,
/// INS key
INSERT = 0x2D,
/// DEL key
DELETE = 0x2E,
/// HELP key
HELP = 0x2F,
/// Left Windows key (Natural keyboard)
LWIN = 0x5B,
/// Right Windows key (Natural keyboard)
RWIN = 0x5C,
/// Applications key (Natural keyboard)
APPS = 0x5D,
/// Computer Sleep key
SLEEP = 0x5F,
/// Numeric keypad 0 key
NUMPAD0 = 0x60,
/// Numeric keypad 1 key
NUMPAD1 = 0x61,
/// Numeric keypad 2 key
NUMPAD2 = 0x62,
/// Numeric keypad 3 key
NUMPAD3 = 0x63,
/// Numeric keypad 4 key
NUMPAD4 = 0x64,
/// Numeric keypad 5 key
NUMPAD5 = 0x65,
/// Numeric keypad 6 key
NUMPAD6 = 0x66,
/// Numeric keypad 7 key
NUMPAD7 = 0x67,
/// Numeric keypad 8 key
NUMPAD8 = 0x68,
/// Numeric keypad 9 key
NUMPAD9 = 0x69,
/// Multiply key
MULTIPLY = 0x6A,
/// Add key
ADD = 0x6B,
/// Separator key
SEPARATOR = 0x6C,
/// Subtract key
SUBTRACT = 0x6D,
/// Decimal key
DECIMAL = 0x6E,
/// Divide key
DIVIDE = 0x6F,
/// F1 key
F1 = 0x70,
/// F2 key
F2 = 0x71,
/// F3 key
F3 = 0x72,
/// F4 key
F4 = 0x73,
/// F5 key
F5 = 0x74,
/// F6 key
F6 = 0x75,
/// F7 key
F7 = 0x76,
/// F8 key
F8 = 0x77,
/// F9 key
F9 = 0x78,
/// F10 key
F10 = 0x79,
/// F11 key
F11 = 0x7A,
/// F12 key
F12 = 0x7B,
/// F13 key
F13 = 0x7C,
/// F14 key
F14 = 0x7D,
/// F15 key
F15 = 0x7E,
/// F16 key
F16 = 0x7F,
/// F17 key
F17 = 0x80,
/// F18 key
F18 = 0x81,
/// F19 key
F19 = 0x82,
/// F20 key
F20 = 0x83,
/// F21 key
F21 = 0x84,
/// F22 key
F22 = 0x85,
/// F23 key
F23 = 0x86,
/// F24 key
F24 = 0x87,
/// NUM LOCK key
NUMLOCK = 0x90,
/// SCROLL LOCK key
SCROLL = 0x91,
/// NEC PC-9800 kbd definition: '=' key on numpad
OEM_NEC_EQUAL = 0x92,
/// Fujitsu/OASYS kbd definition: 'Dictionary' key
OEM_FJ_JISHO = 0x92,
/// Fujitsu/OASYS kbd definition: 'Unregister word' key
OEM_FJ_MASSHOU = 0x93,
/// Fujitsu/OASYS kbd definition: 'Register word' key
OEM_FJ_TOUROKU = 0x94,
/// Fujitsu/OASYS kbd definition: 'Left OYAYUBI' key
OEM_FJ_LOYA = 0x95,
/// Fujitsu/OASYS kbd definition: 'Right OYAYUBI' key
OEM_FJ_ROYA = 0x96,
/// Left SHIFT key
LSHIFT = 0xA0,
/// Right SHIFT key
RSHIFT = 0xA1,
/// Left CONTROL key
LCONTROL = 0xA2,
/// Right CONTROL key
RCONTROL = 0xA3,
/// Left MENU key (Left Alt key)
LMENU = 0xA4,
/// Right MENU key (Right Alt key)
RMENU = 0xA5,
/// Browser Back key
BROWSER_BACK = 0xA6,
/// Browser Forward key
BROWSER_FORWARD = 0xA7,
/// Browser Refresh key
BROWSER_REFRESH = 0xA8,
/// Browser Stop key
BROWSER_STOP = 0xA9,
/// Browser Search key
BROWSER_SEARCH = 0xAA,
/// Browser Favorites key
BROWSER_FAVORITES = 0xAB,
/// Browser Home key
BROWSER_HOME = 0xAC,
/// Volume Mute key
VOLUME_MUTE = 0xAD,
/// Volume Down key
VOLUME_DOWN = 0xAE,
/// Volume Up key
VOLUME_UP = 0xAF,
/// Next Track key
MEDIA_NEXT_TRACK = 0xB0,
/// Previous Track key
MEDIA_PREV_TRACK = 0xB1,
/// Stop Media key
MEDIA_STOP = 0xB2,
/// Play/Pause Media key
MEDIA_PLAY_PAUSE = 0xB3,
/// Start Mail key
LAUNCH_MAIL = 0xB4,
/// Select Media key
LAUNCH_MEDIA_SELECT = 0xB5,
/// Start Application 1 key
LAUNCH_APP1 = 0xB6,
/// Start Application 2 key
LAUNCH_APP2 = 0xB7,
/// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ';:' key
OEM_1 = 0xBA,
/// For any country/region, the '+' key
OEM_PLUS = 0xBB,
/// For any country/region, the ',' key
OEM_COMMA = 0xBC,
/// For any country/region, the '-' key
OEM_MINUS = 0xBD,
/// For any country/region, the '.' key
OEM_PERIOD = 0xBE,
/// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '/?' key
OEM_2 = 0xBF,
/// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '`~' key
OEM_3 = 0xC0,
/// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '[{' key
OEM_4 = 0xDB,
/// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '\|' key
OEM_5 = 0xDC,
/// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ']}' key
OEM_6 = 0xDD,
///
/// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the
/// 'single-quote/double-quote' key
///
OEM_7 = 0xDE,
/// Used for miscellaneous characters; it can vary by keyboard.
OEM_8 = 0xDF,
/// 'AX' key on Japanese AX kbd
OEM_AX = 0xE1,
/// Either the angle bracket key or the backslash key on the RT 102-key keyboard
OEM_102 = 0xE2,
/// Help key on ICO
ICO_HELP = 0xE3,
/// 00 key on ICO
ICO_00 = 0xE4,
/// Process key
PROCESSKEY = 0xE5,
/// Clear key on ICO
ICO_CLEAR = 0xE6,
/// Packet key to be used to pass Unicode characters as if they were keystrokes
PACKET = 0xE7,
/// Reset key
OEM_RESET = 0xE9,
/// Jump key
OEM_JUMP = 0xEA,
/// PA1 key
OEM_PA1 = 0xEB,
/// PA2 key
OEM_PA2 = 0xEC,
/// PA3 key
OEM_PA3 = 0xED,
/// WsCtrl key
OEM_WSCTRL = 0xEE,
/// CuSel key
OEM_CUSEL = 0xEF,
/// Attn key
OEM_ATTN = 0xF0,
/// Finish key
OEM_FINISH = 0xF1,
/// Copy key
OEM_COPY = 0xF2,
/// Auto key
OEM_AUTO = 0xF3,
/// Enlw key
OEM_ENLW = 0xF4,
/// BackTab key
OEM_BACKTAB = 0xF5,
/// Attn key
ATTN = 0xF6,
/// CrSel key
CRSEL = 0xF7,
/// ExSel key
EXSEL = 0xF8,
/// Erase EOF key
EREOF = 0xF9,
/// Play key
PLAY = 0xFA,
/// Zoom key
ZOOM = 0xFB,
/// Reserved
NONAME = 0xFC,
/// PA1 key
PA1 = 0xFD,
/// Clear key
OEM_CLEAR = 0xFE
}
// BUGBUG: This database makes no sense. It is not possible to map a VK code to a character without knowing the keyboard layout
// It should be deleted.
private static readonly HashSet _scanCodes = new ()
{
new ScanCodeMapping (
1,
VK.ESCAPE,
0,
'\u001B'
), // Escape
new ScanCodeMapping (
1,
VK.ESCAPE,
ConsoleModifiers.Shift,
'\u001B'
),
new ScanCodeMapping (
2,
(VK)'1',
0,
'1'
), // D1
new ScanCodeMapping (
2,
(VK)'1',
ConsoleModifiers.Shift,
'!'
),
new ScanCodeMapping (
3,
(VK)'2',
0,
'2'
), // D2
new ScanCodeMapping (
3,
(VK)'2',
ConsoleModifiers.Shift,
'\"'
), // BUGBUG: This is true for Portugese keyboard, but not ENG (@) or DEU (")
new ScanCodeMapping (
3,
(VK)'2',
ConsoleModifiers.Alt
| ConsoleModifiers.Control,
'@'
),
new ScanCodeMapping (
4,
(VK)'3',
0,
'3'
), // D3
new ScanCodeMapping (
4,
(VK)'3',
ConsoleModifiers.Shift,
'#'
),
new ScanCodeMapping (
4,
(VK)'3',
ConsoleModifiers.Alt
| ConsoleModifiers.Control,
'£'
),
new ScanCodeMapping (
5,
(VK)'4',
0,
'4'
), // D4
new ScanCodeMapping (
5,
(VK)'4',
ConsoleModifiers.Shift,
'$'
),
new ScanCodeMapping (
5,
(VK)'4',
ConsoleModifiers.Alt
| ConsoleModifiers.Control,
'§'
),
new ScanCodeMapping (
6,
(VK)'5',
0,
'5'
), // D5
new ScanCodeMapping (
6,
(VK)'5',
ConsoleModifiers.Shift,
'%'
),
new ScanCodeMapping (
6,
(VK)'5',
ConsoleModifiers.Alt
| ConsoleModifiers.Control,
'€'
),
new ScanCodeMapping (
7,
(VK)'6',
0,
'6'
), // D6
new ScanCodeMapping (
7,
(VK)'6',
ConsoleModifiers.Shift,
'&'
),
new ScanCodeMapping (
8,
(VK)'7',
0,
'7'
), // D7
new ScanCodeMapping (
8,
(VK)'7',
ConsoleModifiers.Shift,
'/'
),
new ScanCodeMapping (
8,
(VK)'7',
ConsoleModifiers.Alt
| ConsoleModifiers.Control,
'{'
),
new ScanCodeMapping (
9,
(VK)'8',
0,
'8'
), // D8
new ScanCodeMapping (
9,
(VK)'8',
ConsoleModifiers.Shift,
'('
),
new ScanCodeMapping (
9,
(VK)'8',
ConsoleModifiers.Alt
| ConsoleModifiers.Control,
'['
),
new ScanCodeMapping (
10,
(VK)'9',
0,
'9'
), // D9
new ScanCodeMapping (
10,
(VK)'9',
ConsoleModifiers.Shift,
')'
),
new ScanCodeMapping (
10,
(VK)'9',
ConsoleModifiers.Alt
| ConsoleModifiers.Control,
']'
),
new ScanCodeMapping (
11,
(VK)'0',
0,
'0'
), // D0
new ScanCodeMapping (
11,
(VK)'0',
ConsoleModifiers.Shift,
'='
),
new ScanCodeMapping (
11,
(VK)'0',
ConsoleModifiers.Alt
| ConsoleModifiers.Control,
'}'
),
new ScanCodeMapping (
12,
VK.OEM_4,
0,
'\''
), // Oem4
new ScanCodeMapping (
12,
VK.OEM_4,
ConsoleModifiers.Shift,
'?'
),
new ScanCodeMapping (
13,
VK.OEM_6,
0,
'+'
), // Oem6
new ScanCodeMapping (
13,
VK.OEM_6,
ConsoleModifiers.Shift,
'*'
),
new ScanCodeMapping (
14,
VK.BACK,
0,
'\u0008'
), // Backspace
new ScanCodeMapping (
14,
VK.BACK,
ConsoleModifiers.Shift,
'\u0008'
),
new ScanCodeMapping (
15,
VK.TAB,
0,
'\u0009'
), // Tab
new ScanCodeMapping (
15,
VK.TAB,
ConsoleModifiers.Shift,
'\u000F'
),
new ScanCodeMapping (
16,
(VK)'Q',
0,
'q'
), // Q
new ScanCodeMapping (
16,
(VK)'Q',
ConsoleModifiers.Shift,
'Q'
),
new ScanCodeMapping (
17,
(VK)'W',
0,
'w'
), // W
new ScanCodeMapping (
17,
(VK)'W',
ConsoleModifiers.Shift,
'W'
),
new ScanCodeMapping (
18,
(VK)'E',
0,
'e'
), // E
new ScanCodeMapping (
18,
(VK)'E',
ConsoleModifiers.Shift,
'E'
),
new ScanCodeMapping (
19,
(VK)'R',
0,
'r'
), // R
new ScanCodeMapping (
19,
(VK)'R',
ConsoleModifiers.Shift,
'R'
),
new ScanCodeMapping (
20,
(VK)'T',
0,
't'
), // T
new ScanCodeMapping (
20,
(VK)'T',
ConsoleModifiers.Shift,
'T'
),
new ScanCodeMapping (
21,
(VK)'Y',
0,
'y'
), // Y
new ScanCodeMapping (
21,
(VK)'Y',
ConsoleModifiers.Shift,
'Y'
),
new ScanCodeMapping (
22,
(VK)'U',
0,
'u'
), // U
new ScanCodeMapping (
22,
(VK)'U',
ConsoleModifiers.Shift,
'U'
),
new ScanCodeMapping (
23,
(VK)'I',
0,
'i'
), // I
new ScanCodeMapping (
23,
(VK)'I',
ConsoleModifiers.Shift,
'I'
),
new ScanCodeMapping (
24,
(VK)'O',
0,
'o'
), // O
new ScanCodeMapping (
24,
(VK)'O',
ConsoleModifiers.Shift,
'O'
),
new ScanCodeMapping (
25,
(VK)'P',
0,
'p'
), // P
new ScanCodeMapping (
25,
(VK)'P',
ConsoleModifiers.Shift,
'P'
),
new ScanCodeMapping (
26,
VK.OEM_PLUS,
0,
'+'
), // OemPlus
new ScanCodeMapping (
26,
VK.OEM_PLUS,
ConsoleModifiers.Shift,
'*'
),
new ScanCodeMapping (
26,
VK.OEM_PLUS,
ConsoleModifiers.Alt
| ConsoleModifiers.Control,
'¨'
),
new ScanCodeMapping (
27,
VK.OEM_1,
0,
'´'
), // Oem1
new ScanCodeMapping (
27,
VK.OEM_1,
ConsoleModifiers.Shift,
'`'
),
new ScanCodeMapping (
28,
VK.RETURN,
0,
'\u000D'
), // Enter
new ScanCodeMapping (
28,
VK.RETURN,
ConsoleModifiers.Shift,
'\u000D'
),
new ScanCodeMapping (
29,
VK.CONTROL,
0,
'\0'
), // Control
new ScanCodeMapping (
29,
VK.CONTROL,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
30,
(VK)'A',
0,
'a'
), // A
new ScanCodeMapping (
30,
(VK)'A',
ConsoleModifiers.Shift,
'A'
),
new ScanCodeMapping (
31,
(VK)'S',
0,
's'
), // S
new ScanCodeMapping (
31,
(VK)'S',
ConsoleModifiers.Shift,
'S'
),
new ScanCodeMapping (
32,
(VK)'D',
0,
'd'
), // D
new ScanCodeMapping (
32,
(VK)'D',
ConsoleModifiers.Shift,
'D'
),
new ScanCodeMapping (
33,
(VK)'F',
0,
'f'
), // F
new ScanCodeMapping (
33,
(VK)'F',
ConsoleModifiers.Shift,
'F'
),
new ScanCodeMapping (
34,
(VK)'G',
0,
'g'
), // G
new ScanCodeMapping (
34,
(VK)'G',
ConsoleModifiers.Shift,
'G'
),
new ScanCodeMapping (
35,
(VK)'H',
0,
'h'
), // H
new ScanCodeMapping (
35,
(VK)'H',
ConsoleModifiers.Shift,
'H'
),
new ScanCodeMapping (
36,
(VK)'J',
0,
'j'
), // J
new ScanCodeMapping (
36,
(VK)'J',
ConsoleModifiers.Shift,
'J'
),
new ScanCodeMapping (
37,
(VK)'K',
0,
'k'
), // K
new ScanCodeMapping (
37,
(VK)'K',
ConsoleModifiers.Shift,
'K'
),
new ScanCodeMapping (
38,
(VK)'L',
0,
'l'
), // L
new ScanCodeMapping (
38,
(VK)'L',
ConsoleModifiers.Shift,
'L'
),
new ScanCodeMapping (
39,
VK.OEM_3,
0,
'`'
), // Oem3 (Backtick/Grave)
new ScanCodeMapping (
39,
VK.OEM_3,
ConsoleModifiers.Shift,
'~'
),
new ScanCodeMapping (
40,
VK.OEM_7,
0,
'\''
), // Oem7 (Single Quote)
new ScanCodeMapping (
40,
VK.OEM_7,
ConsoleModifiers.Shift,
'\"'
),
new ScanCodeMapping (
41,
VK.OEM_5,
0,
'\\'
), // Oem5 (Backslash)
new ScanCodeMapping (
41,
VK.OEM_5,
ConsoleModifiers.Shift,
'|'
),
new ScanCodeMapping (
42,
VK.LSHIFT,
0,
'\0'
), // Left Shift
new ScanCodeMapping (
42,
VK.LSHIFT,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
43,
VK.OEM_2,
0,
'/'
), // Oem2 (Forward Slash)
new ScanCodeMapping (
43,
VK.OEM_2,
ConsoleModifiers.Shift,
'?'
),
new ScanCodeMapping (
44,
(VK)'Z',
0,
'z'
), // Z
new ScanCodeMapping (
44,
(VK)'Z',
ConsoleModifiers.Shift,
'Z'
),
new ScanCodeMapping (
45,
(VK)'X',
0,
'x'
), // X
new ScanCodeMapping (
45,
(VK)'X',
ConsoleModifiers.Shift,
'X'
),
new ScanCodeMapping (
46,
(VK)'C',
0,
'c'
), // C
new ScanCodeMapping (
46,
(VK)'C',
ConsoleModifiers.Shift,
'C'
),
new ScanCodeMapping (
47,
(VK)'V',
0,
'v'
), // V
new ScanCodeMapping (
47,
(VK)'V',
ConsoleModifiers.Shift,
'V'
),
new ScanCodeMapping (
48,
(VK)'B',
0,
'b'
), // B
new ScanCodeMapping (
48,
(VK)'B',
ConsoleModifiers.Shift,
'B'
),
new ScanCodeMapping (
49,
(VK)'N',
0,
'n'
), // N
new ScanCodeMapping (
49,
(VK)'N',
ConsoleModifiers.Shift,
'N'
),
new ScanCodeMapping (
50,
(VK)'M',
0,
'm'
), // M
new ScanCodeMapping (
50,
(VK)'M',
ConsoleModifiers.Shift,
'M'
),
new ScanCodeMapping (
51,
VK.OEM_COMMA,
0,
','
), // OemComma
new ScanCodeMapping (
51,
VK.OEM_COMMA,
ConsoleModifiers.Shift,
'<'
),
new ScanCodeMapping (
52,
VK.OEM_PERIOD,
0,
'.'
), // OemPeriod
new ScanCodeMapping (
52,
VK.OEM_PERIOD,
ConsoleModifiers.Shift,
'>'
),
new ScanCodeMapping (
53,
VK.OEM_MINUS,
0,
'-'
), // OemMinus
new ScanCodeMapping (
53,
VK.OEM_MINUS,
ConsoleModifiers.Shift,
'_'
),
new ScanCodeMapping (
54,
VK.RSHIFT,
0,
'\0'
), // Right Shift
new ScanCodeMapping (
54,
VK.RSHIFT,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
55,
VK.PRINT,
0,
'\0'
), // Print Screen
new ScanCodeMapping (
55,
VK.PRINT,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
56,
VK.LMENU,
0,
'\0'
), // Alt
new ScanCodeMapping (
56,
VK.LMENU,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
57,
VK.SPACE,
0,
' '
), // Spacebar
new ScanCodeMapping (
57,
VK.SPACE,
ConsoleModifiers.Shift,
' '
),
new ScanCodeMapping (
58,
VK.CAPITAL,
0,
'\0'
), // Caps Lock
new ScanCodeMapping (
58,
VK.CAPITAL,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
59,
VK.F1,
0,
'\0'
), // F1
new ScanCodeMapping (
59,
VK.F1,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
60,
VK.F2,
0,
'\0'
), // F2
new ScanCodeMapping (
60,
VK.F2,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
61,
VK.F3,
0,
'\0'
), // F3
new ScanCodeMapping (
61,
VK.F3,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
62,
VK.F4,
0,
'\0'
), // F4
new ScanCodeMapping (
62,
VK.F4,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
63,
VK.F5,
0,
'\0'
), // F5
new ScanCodeMapping (
63,
VK.F5,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
64,
VK.F6,
0,
'\0'
), // F6
new ScanCodeMapping (
64,
VK.F6,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
65,
VK.F7,
0,
'\0'
), // F7
new ScanCodeMapping (
65,
VK.F7,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
66,
VK.F8,
0,
'\0'
), // F8
new ScanCodeMapping (
66,
VK.F8,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
67,
VK.F9,
0,
'\0'
), // F9
new ScanCodeMapping (
67,
VK.F9,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
68,
VK.F10,
0,
'\0'
), // F10
new ScanCodeMapping (
68,
VK.F10,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
69,
VK.NUMLOCK,
0,
'\0'
), // Num Lock
new ScanCodeMapping (
69,
VK.NUMLOCK,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
70,
VK.SCROLL,
0,
'\0'
), // Scroll Lock
new ScanCodeMapping (
70,
VK.SCROLL,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
71,
VK.HOME,
0,
'\0'
), // Home
new ScanCodeMapping (
71,
VK.HOME,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
72,
VK.UP,
0,
'\0'
), // Up Arrow
new ScanCodeMapping (
72,
VK.UP,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
73,
VK.PRIOR,
0,
'\0'
), // Page Up
new ScanCodeMapping (
73,
VK.PRIOR,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
74,
VK.SUBTRACT,
0,
'-'
), // Subtract (Num Pad '-')
new ScanCodeMapping (
74,
VK.SUBTRACT,
ConsoleModifiers.Shift,
'-'
),
new ScanCodeMapping (
75,
VK.LEFT,
0,
'\0'
), // Left Arrow
new ScanCodeMapping (
75,
VK.LEFT,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
76,
VK.CLEAR,
0,
'\0'
), // Center key (Num Pad 5 with Num Lock off)
new ScanCodeMapping (
76,
VK.CLEAR,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
77,
VK.RIGHT,
0,
'\0'
), // Right Arrow
new ScanCodeMapping (
77,
VK.RIGHT,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
78,
VK.ADD,
0,
'+'
), // Add (Num Pad '+')
new ScanCodeMapping (
78,
VK.ADD,
ConsoleModifiers.Shift,
'+'
),
new ScanCodeMapping (
79,
VK.END,
0,
'\0'
), // End
new ScanCodeMapping (
79,
VK.END,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
80,
VK.DOWN,
0,
'\0'
), // Down Arrow
new ScanCodeMapping (
80,
VK.DOWN,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
81,
VK.NEXT,
0,
'\0'
), // Page Down
new ScanCodeMapping (
81,
VK.NEXT,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
82,
VK.INSERT,
0,
'\0'
), // Insert
new ScanCodeMapping (
82,
VK.INSERT,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
83,
VK.DELETE,
0,
'\0'
), // Delete
new ScanCodeMapping (
83,
VK.DELETE,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
86,
VK.OEM_102,
0,
'<'
), // OEM 102 (Typically '<' or '|' key next to Left Shift)
new ScanCodeMapping (
86,
VK.OEM_102,
ConsoleModifiers.Shift,
'>'
),
new ScanCodeMapping (
87,
VK.F11,
0,
'\0'
), // F11
new ScanCodeMapping (
87,
VK.F11,
ConsoleModifiers.Shift,
'\0'
),
new ScanCodeMapping (
88,
VK.F12,
0,
'\0'
), // F12
new ScanCodeMapping (
88,
VK.F12,
ConsoleModifiers.Shift,
'\0'
)
};
/// Decode a that is using .
/// The console key info.
/// The decoded or the .
///
/// If it's a the may be a
/// or a value.
///
public static ConsoleKeyInfo DecodeVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
{
if (consoleKeyInfo.Key != ConsoleKey.Packet)
{
return consoleKeyInfo;
}
return GetConsoleKeyInfoFromKeyChar (consoleKeyInfo.KeyChar, consoleKeyInfo.Modifiers, out _);
}
///
/// Encode the with the if the first a byte
/// length, otherwise only the KeyChar is considered and searched on the database.
///
/// The console key info.
/// The encoded KeyChar with the Key if both can be shifted, otherwise only the KeyChar.
/// This is useful to use with the .
public static char EncodeKeyCharForVKPacket (ConsoleKeyInfo consoleKeyInfo)
{
char keyChar = consoleKeyInfo.KeyChar;
ConsoleKey consoleKey = consoleKeyInfo.Key;
if (keyChar != 0 && consoleKeyInfo.KeyChar < byte.MaxValue && consoleKey == ConsoleKey.None)
{
// try to get the ConsoleKey
ScanCodeMapping scode = _scanCodes.FirstOrDefault (e => e.UnicodeChar == keyChar);
if (scode is { })
{
consoleKey = (ConsoleKey)scode.VirtualKey;
}
}
if (keyChar < byte.MaxValue && consoleKey != ConsoleKey.None)
{
keyChar = (char)((consoleKeyInfo.KeyChar << 8) | (byte)consoleKey);
}
return keyChar;
}
}