mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-28 16:58:01 +01:00
* Replace all 342 `== null` with `is null`
* Replace 354 `!= null` with `is { }`
* Wrap these in conditionals since they break tests against Release configuration
The members they depend on do not exist in Release configuration
* Split these up and dispose properly
This test needs to be revisited for several reasons at some point.
* Fix release configuration tests
* Declare interface these already support
* Annotate constructor properly and use throw helper
* Move class to its own file
* Rename these files so they nest in the solution explorer
* Make this a record type and remove now-redundant/illegal members
* Reference passing to avoid some struct copies
* Simplify this
* Carry reference passing through as appropriate
* Turn this into a record struct
* Remove unused internal constructor and its test
It was only used by that test.
* Simplify this constructor
* This should be a property
* Simplify constructor
* Simplify GetHashCode
* Mark this ignored just in case
* Missed a couple of opportunities for reference passing
* record struct already does this by value
* Remove unused class
* Simplify the type initializer and Reset method
* Implement INotifyCollectionChanged and IDictionary by delegating to ColorSchemes
* Fix for reflection-based configuration
* Make CI build happy by disambiguiating this attribute
2537 lines
83 KiB
C#
2537 lines
83 KiB
C#
using System.Globalization;
|
||
using System.Runtime.InteropServices;
|
||
|
||
namespace Terminal.Gui.ConsoleDrivers;
|
||
|
||
/// <summary>Helper class to handle the scan code and virtual key from a <see cref="ConsoleKey"/>.</summary>
|
||
public static class ConsoleKeyMapping
|
||
{
|
||
#if !WT_ISSUE_8871_FIXED // https://github.com/microsoft/terminal/issues/8871
|
||
/// <summary>
|
||
/// Translates (maps) a virtual-key code into a scan code or character value, or translates a scan code into a
|
||
/// virtual-key code.
|
||
/// </summary>
|
||
/// <param name="vk"></param>
|
||
/// <param name="uMapType">
|
||
/// 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.
|
||
/// </param>
|
||
/// <param name="dwhkl"></param>
|
||
/// <returns>
|
||
/// 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.
|
||
/// </returns>
|
||
[DllImport ("user32.dll", EntryPoint = "MapVirtualKeyExW", CharSet = CharSet.Unicode)]
|
||
private static extern uint MapVirtualKeyEx (VK vk, uint uMapType, nint dwhkl);
|
||
|
||
/// <summary>Retrieves the active input locale identifier (formerly called the keyboard layout).</summary>
|
||
/// <param name="idThread">0 for current thread</param>
|
||
/// <returns>
|
||
/// 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.
|
||
/// </returns>
|
||
[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);
|
||
|
||
/// <summary>
|
||
/// Translates the specified virtual-key code and keyboard state to the corresponding Unicode character or
|
||
/// characters using the Win32 API MapVirtualKey.
|
||
/// </summary>
|
||
/// <param name="vk"></param>
|
||
/// <returns>
|
||
/// 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.
|
||
/// </returns>
|
||
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
|
||
/// <summary>
|
||
/// Translates (maps) a virtual-key code into a scan code or character value, or translates a scan code into a virtual-key code.
|
||
/// </summary>
|
||
/// <param name="vk"></param>
|
||
/// <param name="uMapType">
|
||
/// 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.
|
||
/// </param>
|
||
/// <returns>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.</returns>
|
||
[DllImport ("user32.dll", EntryPoint = "MapVirtualKeyW", CharSet = CharSet.Unicode)]
|
||
extern static uint MapVirtualKey (VK vk, uint uMapType = 2);
|
||
|
||
uint MapVKtoChar (VK vk) => MapVirtualKeyToCharEx (vk);
|
||
#endif
|
||
/// <summary>
|
||
/// Retrieves the name of the active input locale identifier (formerly called the keyboard layout) for the calling
|
||
/// thread.
|
||
/// </summary>
|
||
/// <param name="pwszKLID"></param>
|
||
/// <returns></returns>
|
||
[DllImport ("user32.dll")]
|
||
private static extern bool GetKeyboardLayoutName ([Out] StringBuilder pwszKLID);
|
||
|
||
/// <summary>
|
||
/// Retrieves the name of the active input locale identifier (formerly called the keyboard layout) for the calling
|
||
/// thread.
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
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<ScanCodeMapping>
|
||
{
|
||
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
|
||
/// <summary>Get the scan code from a <see cref="ConsoleKeyInfo"/>.</summary>
|
||
/// <param name="consoleKeyInfo">The console key info.</param>
|
||
/// <returns>The value if apply.</returns>
|
||
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
|
||
/// <summary>Gets the <see cref="ConsoleKeyInfo"/> from the provided <see cref="KeyCode"/>.</summary>
|
||
/// <param name="key">The key code.</param>
|
||
/// <returns>The console key info.</returns>
|
||
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)
|
||
);
|
||
}
|
||
|
||
/// <summary>Map existing <see cref="KeyCode"/> modifiers to <see cref="ConsoleModifiers"/>.</summary>
|
||
/// <param name="key">The key code.</param>
|
||
/// <returns>The console modifiers.</returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>Gets <see cref="ConsoleModifiers"/> from <see cref="bool"/> modifiers.</summary>
|
||
/// <param name="shift">The shift key.</param>
|
||
/// <param name="alt">The alt key.</param>
|
||
/// <param name="control">The control key.</param>
|
||
/// <returns>The console modifiers.</returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get the <see cref="ConsoleKeyInfo"/> from a unicode character and modifiers (e.g. (Key)'a' and
|
||
/// (Key)Key.CtrlMask).
|
||
/// </summary>
|
||
/// <param name="keyValue">The key as a unicode codepoint.</param>
|
||
/// <param name="modifiers">The modifier keys.</param>
|
||
/// <param name="scanCode">The resulting scan code.</param>
|
||
/// <returns>The <see cref="ConsoleKeyInfo"/>.</returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get the output character from the <see cref="GetConsoleKeyInfoFromKeyCode"/>, with the correct
|
||
/// <see cref="ConsoleKey"/> and the scan code used on <see cref="WindowsDriver"/>.
|
||
/// </summary>
|
||
/// <param name="unicodeChar">The unicode character.</param>
|
||
/// <param name="modifiers">The modifiers keys.</param>
|
||
/// <param name="consoleKey">The resulting console key.</param>
|
||
/// <param name="scanCode">The resulting scan code.</param>
|
||
/// <param name="isConsoleKey">Indicates if the <paramref name="unicodeChar"/> is a <see cref="ConsoleKey"/>.</param>
|
||
/// <returns>The output character or the <paramref name="consoleKey"/>.</returns>
|
||
/// <remarks>This is only used by the <see cref="GetConsoleKeyInfoFromKeyCode"/> and by unit tests.</remarks>
|
||
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;
|
||
}
|
||
|
||
/// <summary>Maps a unicode character (e.g. (Key)'a') to a uint representing a <see cref="ConsoleKey"/>.</summary>
|
||
/// <param name="keyValue">The key value.</param>
|
||
/// <param name="isConsoleKey">
|
||
/// Indicates if the <paramref name="keyValue"/> is a <see cref="ConsoleKey"/>.
|
||
/// <see langword="true"/> means the return value is in the ConsoleKey enum. <see langword="false"/> means the return
|
||
/// value can be mapped to a valid unicode character.
|
||
/// </param>
|
||
/// <returns>The <see cref="ConsoleKey"/> or the <paramref name="keyValue"/>.</returns>
|
||
/// <remarks>This is only used by the <see cref="GetConsoleKeyInfoFromKeyCode"/> and by unit tests.</remarks>
|
||
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;
|
||
}
|
||
|
||
/// <summary>Maps a <see cref="ConsoleKeyInfo"/> to a <see cref="KeyCode"/>.</summary>
|
||
/// <param name="consoleKeyInfo">The console key.</param>
|
||
/// <returns>The <see cref="KeyCode"/> or the <paramref name="consoleKeyInfo"/>.</returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>Maps a <see cref="ConsoleKeyInfo"/> to a <see cref="KeyCode"/>.</summary>
|
||
/// <param name="modifiers">The console modifiers.</param>
|
||
/// <param name="key">The key code.</param>
|
||
/// <returns>The <see cref="KeyCode"/> with <see cref="ConsoleModifiers"/> or the <paramref name="key"/></returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>Generated from winuser.h. See https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes</summary>
|
||
public enum VK : ushort
|
||
{
|
||
/// <summary>Left mouse button.</summary>
|
||
LBUTTON = 0x01,
|
||
|
||
/// <summary>Right mouse button.</summary>
|
||
RBUTTON = 0x02,
|
||
|
||
/// <summary>Control-break processing.</summary>
|
||
CANCEL = 0x03,
|
||
|
||
/// <summary>Middle mouse button (three-button mouse).</summary>
|
||
MBUTTON = 0x04,
|
||
|
||
/// <summary>X1 mouse button.</summary>
|
||
XBUTTON1 = 0x05,
|
||
|
||
/// <summary>X2 mouse button.</summary>
|
||
XBUTTON2 = 0x06,
|
||
|
||
/// <summary>BACKSPACE key.</summary>
|
||
BACK = 0x08,
|
||
|
||
/// <summary>TAB key.</summary>
|
||
TAB = 0x09,
|
||
|
||
/// <summary>CLEAR key.</summary>
|
||
CLEAR = 0x0C,
|
||
|
||
/// <summary>ENTER key.</summary>
|
||
RETURN = 0x0D,
|
||
|
||
/// <summary>SHIFT key.</summary>
|
||
SHIFT = 0x10,
|
||
|
||
/// <summary>CTRL key.</summary>
|
||
CONTROL = 0x11,
|
||
|
||
/// <summary>ALT key.</summary>
|
||
MENU = 0x12,
|
||
|
||
/// <summary>PAUSE key.</summary>
|
||
PAUSE = 0x13,
|
||
|
||
/// <summary>CAPS LOCK key.</summary>
|
||
CAPITAL = 0x14,
|
||
|
||
/// <summary>IME Kana mode.</summary>
|
||
KANA = 0x15,
|
||
|
||
/// <summary>IME Hangul mode.</summary>
|
||
HANGUL = 0x15,
|
||
|
||
/// <summary>IME Junja mode.</summary>
|
||
JUNJA = 0x17,
|
||
|
||
/// <summary>IME final mode.</summary>
|
||
FINAL = 0x18,
|
||
|
||
/// <summary>IME Hanja mode.</summary>
|
||
HANJA = 0x19,
|
||
|
||
/// <summary>IME Kanji mode.</summary>
|
||
KANJI = 0x19,
|
||
|
||
/// <summary>ESC key.</summary>
|
||
ESCAPE = 0x1B,
|
||
|
||
/// <summary>IME convert.</summary>
|
||
CONVERT = 0x1C,
|
||
|
||
/// <summary>IME nonconvert.</summary>
|
||
NONCONVERT = 0x1D,
|
||
|
||
/// <summary>IME accept.</summary>
|
||
ACCEPT = 0x1E,
|
||
|
||
/// <summary>IME mode change request.</summary>
|
||
MODECHANGE = 0x1F,
|
||
|
||
/// <summary>SPACEBAR.</summary>
|
||
SPACE = 0x20,
|
||
|
||
/// <summary>PAGE UP key.</summary>
|
||
PRIOR = 0x21,
|
||
|
||
/// <summary>PAGE DOWN key.</summary>
|
||
NEXT = 0x22,
|
||
|
||
/// <summary>END key.</summary>
|
||
END = 0x23,
|
||
|
||
/// <summary>HOME key.</summary>
|
||
HOME = 0x24,
|
||
|
||
/// <summary>LEFT ARROW key.</summary>
|
||
LEFT = 0x25,
|
||
|
||
/// <summary>UP ARROW key.</summary>
|
||
UP = 0x26,
|
||
|
||
/// <summary>RIGHT ARROW key.</summary>
|
||
RIGHT = 0x27,
|
||
|
||
/// <summary>DOWN ARROW key.</summary>
|
||
DOWN = 0x28,
|
||
|
||
/// <summary>SELECT key.</summary>
|
||
SELECT = 0x29,
|
||
|
||
/// <summary>PRINT key.</summary>
|
||
PRINT = 0x2A,
|
||
|
||
/// <summary>EXECUTE key</summary>
|
||
EXECUTE = 0x2B,
|
||
|
||
/// <summary>PRINT SCREEN key</summary>
|
||
SNAPSHOT = 0x2C,
|
||
|
||
/// <summary>INS key</summary>
|
||
INSERT = 0x2D,
|
||
|
||
/// <summary>DEL key</summary>
|
||
DELETE = 0x2E,
|
||
|
||
/// <summary>HELP key</summary>
|
||
HELP = 0x2F,
|
||
|
||
/// <summary>Left Windows key (Natural keyboard)</summary>
|
||
LWIN = 0x5B,
|
||
|
||
/// <summary>Right Windows key (Natural keyboard)</summary>
|
||
RWIN = 0x5C,
|
||
|
||
/// <summary>Applications key (Natural keyboard)</summary>
|
||
APPS = 0x5D,
|
||
|
||
/// <summary>Computer Sleep key</summary>
|
||
SLEEP = 0x5F,
|
||
|
||
/// <summary>Numeric keypad 0 key</summary>
|
||
NUMPAD0 = 0x60,
|
||
|
||
/// <summary>Numeric keypad 1 key</summary>
|
||
NUMPAD1 = 0x61,
|
||
|
||
/// <summary>Numeric keypad 2 key</summary>
|
||
NUMPAD2 = 0x62,
|
||
|
||
/// <summary>Numeric keypad 3 key</summary>
|
||
NUMPAD3 = 0x63,
|
||
|
||
/// <summary>Numeric keypad 4 key</summary>
|
||
NUMPAD4 = 0x64,
|
||
|
||
/// <summary>Numeric keypad 5 key</summary>
|
||
NUMPAD5 = 0x65,
|
||
|
||
/// <summary>Numeric keypad 6 key</summary>
|
||
NUMPAD6 = 0x66,
|
||
|
||
/// <summary>Numeric keypad 7 key</summary>
|
||
NUMPAD7 = 0x67,
|
||
|
||
/// <summary>Numeric keypad 8 key</summary>
|
||
NUMPAD8 = 0x68,
|
||
|
||
/// <summary>Numeric keypad 9 key</summary>
|
||
NUMPAD9 = 0x69,
|
||
|
||
/// <summary>Multiply key</summary>
|
||
MULTIPLY = 0x6A,
|
||
|
||
/// <summary>Add key</summary>
|
||
ADD = 0x6B,
|
||
|
||
/// <summary>Separator key</summary>
|
||
SEPARATOR = 0x6C,
|
||
|
||
/// <summary>Subtract key</summary>
|
||
SUBTRACT = 0x6D,
|
||
|
||
/// <summary>Decimal key</summary>
|
||
DECIMAL = 0x6E,
|
||
|
||
/// <summary>Divide key</summary>
|
||
DIVIDE = 0x6F,
|
||
|
||
/// <summary>F1 key</summary>
|
||
F1 = 0x70,
|
||
|
||
/// <summary>F2 key</summary>
|
||
F2 = 0x71,
|
||
|
||
/// <summary>F3 key</summary>
|
||
F3 = 0x72,
|
||
|
||
/// <summary>F4 key</summary>
|
||
F4 = 0x73,
|
||
|
||
/// <summary>F5 key</summary>
|
||
F5 = 0x74,
|
||
|
||
/// <summary>F6 key</summary>
|
||
F6 = 0x75,
|
||
|
||
/// <summary>F7 key</summary>
|
||
F7 = 0x76,
|
||
|
||
/// <summary>F8 key</summary>
|
||
F8 = 0x77,
|
||
|
||
/// <summary>F9 key</summary>
|
||
F9 = 0x78,
|
||
|
||
/// <summary>F10 key</summary>
|
||
F10 = 0x79,
|
||
|
||
/// <summary>F11 key</summary>
|
||
F11 = 0x7A,
|
||
|
||
/// <summary>F12 key</summary>
|
||
F12 = 0x7B,
|
||
|
||
/// <summary>F13 key</summary>
|
||
F13 = 0x7C,
|
||
|
||
/// <summary>F14 key</summary>
|
||
F14 = 0x7D,
|
||
|
||
/// <summary>F15 key</summary>
|
||
F15 = 0x7E,
|
||
|
||
/// <summary>F16 key</summary>
|
||
F16 = 0x7F,
|
||
|
||
/// <summary>F17 key</summary>
|
||
F17 = 0x80,
|
||
|
||
/// <summary>F18 key</summary>
|
||
F18 = 0x81,
|
||
|
||
/// <summary>F19 key</summary>
|
||
F19 = 0x82,
|
||
|
||
/// <summary>F20 key</summary>
|
||
F20 = 0x83,
|
||
|
||
/// <summary>F21 key</summary>
|
||
F21 = 0x84,
|
||
|
||
/// <summary>F22 key</summary>
|
||
F22 = 0x85,
|
||
|
||
/// <summary>F23 key</summary>
|
||
F23 = 0x86,
|
||
|
||
/// <summary>F24 key</summary>
|
||
F24 = 0x87,
|
||
|
||
/// <summary>NUM LOCK key</summary>
|
||
NUMLOCK = 0x90,
|
||
|
||
/// <summary>SCROLL LOCK key</summary>
|
||
SCROLL = 0x91,
|
||
|
||
/// <summary>NEC PC-9800 kbd definition: '=' key on numpad</summary>
|
||
OEM_NEC_EQUAL = 0x92,
|
||
|
||
/// <summary>Fujitsu/OASYS kbd definition: 'Dictionary' key</summary>
|
||
OEM_FJ_JISHO = 0x92,
|
||
|
||
/// <summary>Fujitsu/OASYS kbd definition: 'Unregister word' key</summary>
|
||
OEM_FJ_MASSHOU = 0x93,
|
||
|
||
/// <summary>Fujitsu/OASYS kbd definition: 'Register word' key</summary>
|
||
OEM_FJ_TOUROKU = 0x94,
|
||
|
||
/// <summary>Fujitsu/OASYS kbd definition: 'Left OYAYUBI' key</summary>
|
||
OEM_FJ_LOYA = 0x95,
|
||
|
||
/// <summary>Fujitsu/OASYS kbd definition: 'Right OYAYUBI' key</summary>
|
||
OEM_FJ_ROYA = 0x96,
|
||
|
||
/// <summary>Left SHIFT key</summary>
|
||
LSHIFT = 0xA0,
|
||
|
||
/// <summary>Right SHIFT key</summary>
|
||
RSHIFT = 0xA1,
|
||
|
||
/// <summary>Left CONTROL key</summary>
|
||
LCONTROL = 0xA2,
|
||
|
||
/// <summary>Right CONTROL key</summary>
|
||
RCONTROL = 0xA3,
|
||
|
||
/// <summary>Left MENU key (Left Alt key)</summary>
|
||
LMENU = 0xA4,
|
||
|
||
/// <summary>Right MENU key (Right Alt key)</summary>
|
||
RMENU = 0xA5,
|
||
|
||
/// <summary>Browser Back key</summary>
|
||
BROWSER_BACK = 0xA6,
|
||
|
||
/// <summary>Browser Forward key</summary>
|
||
BROWSER_FORWARD = 0xA7,
|
||
|
||
/// <summary>Browser Refresh key</summary>
|
||
BROWSER_REFRESH = 0xA8,
|
||
|
||
/// <summary>Browser Stop key</summary>
|
||
BROWSER_STOP = 0xA9,
|
||
|
||
/// <summary>Browser Search key</summary>
|
||
BROWSER_SEARCH = 0xAA,
|
||
|
||
/// <summary>Browser Favorites key</summary>
|
||
BROWSER_FAVORITES = 0xAB,
|
||
|
||
/// <summary>Browser Home key</summary>
|
||
BROWSER_HOME = 0xAC,
|
||
|
||
/// <summary>Volume Mute key</summary>
|
||
VOLUME_MUTE = 0xAD,
|
||
|
||
/// <summary>Volume Down key</summary>
|
||
VOLUME_DOWN = 0xAE,
|
||
|
||
/// <summary>Volume Up key</summary>
|
||
VOLUME_UP = 0xAF,
|
||
|
||
/// <summary>Next Track key</summary>
|
||
MEDIA_NEXT_TRACK = 0xB0,
|
||
|
||
/// <summary>Previous Track key</summary>
|
||
MEDIA_PREV_TRACK = 0xB1,
|
||
|
||
/// <summary>Stop Media key</summary>
|
||
MEDIA_STOP = 0xB2,
|
||
|
||
/// <summary>Play/Pause Media key</summary>
|
||
MEDIA_PLAY_PAUSE = 0xB3,
|
||
|
||
/// <summary>Start Mail key</summary>
|
||
LAUNCH_MAIL = 0xB4,
|
||
|
||
/// <summary>Select Media key</summary>
|
||
LAUNCH_MEDIA_SELECT = 0xB5,
|
||
|
||
/// <summary>Start Application 1 key</summary>
|
||
LAUNCH_APP1 = 0xB6,
|
||
|
||
/// <summary>Start Application 2 key</summary>
|
||
LAUNCH_APP2 = 0xB7,
|
||
|
||
/// <summary>Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ';:' key</summary>
|
||
OEM_1 = 0xBA,
|
||
|
||
/// <summary>For any country/region, the '+' key</summary>
|
||
OEM_PLUS = 0xBB,
|
||
|
||
/// <summary>For any country/region, the ',' key</summary>
|
||
OEM_COMMA = 0xBC,
|
||
|
||
/// <summary>For any country/region, the '-' key</summary>
|
||
OEM_MINUS = 0xBD,
|
||
|
||
/// <summary>For any country/region, the '.' key</summary>
|
||
OEM_PERIOD = 0xBE,
|
||
|
||
/// <summary>Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '/?' key</summary>
|
||
OEM_2 = 0xBF,
|
||
|
||
/// <summary>Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '`~' key</summary>
|
||
OEM_3 = 0xC0,
|
||
|
||
/// <summary>Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '[{' key</summary>
|
||
OEM_4 = 0xDB,
|
||
|
||
/// <summary>Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '\|' key</summary>
|
||
OEM_5 = 0xDC,
|
||
|
||
/// <summary>Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ']}' key</summary>
|
||
OEM_6 = 0xDD,
|
||
|
||
/// <summary>
|
||
/// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the
|
||
/// 'single-quote/double-quote' key
|
||
/// </summary>
|
||
OEM_7 = 0xDE,
|
||
|
||
/// <summary>Used for miscellaneous characters; it can vary by keyboard.</summary>
|
||
OEM_8 = 0xDF,
|
||
|
||
/// <summary>'AX' key on Japanese AX kbd</summary>
|
||
OEM_AX = 0xE1,
|
||
|
||
/// <summary>Either the angle bracket key or the backslash key on the RT 102-key keyboard</summary>
|
||
OEM_102 = 0xE2,
|
||
|
||
/// <summary>Help key on ICO</summary>
|
||
ICO_HELP = 0xE3,
|
||
|
||
/// <summary>00 key on ICO</summary>
|
||
ICO_00 = 0xE4,
|
||
|
||
/// <summary>Process key</summary>
|
||
PROCESSKEY = 0xE5,
|
||
|
||
/// <summary>Clear key on ICO</summary>
|
||
ICO_CLEAR = 0xE6,
|
||
|
||
/// <summary>Packet key to be used to pass Unicode characters as if they were keystrokes</summary>
|
||
PACKET = 0xE7,
|
||
|
||
/// <summary>Reset key</summary>
|
||
OEM_RESET = 0xE9,
|
||
|
||
/// <summary>Jump key</summary>
|
||
OEM_JUMP = 0xEA,
|
||
|
||
/// <summary>PA1 key</summary>
|
||
OEM_PA1 = 0xEB,
|
||
|
||
/// <summary>PA2 key</summary>
|
||
OEM_PA2 = 0xEC,
|
||
|
||
/// <summary>PA3 key</summary>
|
||
OEM_PA3 = 0xED,
|
||
|
||
/// <summary>WsCtrl key</summary>
|
||
OEM_WSCTRL = 0xEE,
|
||
|
||
/// <summary>CuSel key</summary>
|
||
OEM_CUSEL = 0xEF,
|
||
|
||
/// <summary>Attn key</summary>
|
||
OEM_ATTN = 0xF0,
|
||
|
||
/// <summary>Finish key</summary>
|
||
OEM_FINISH = 0xF1,
|
||
|
||
/// <summary>Copy key</summary>
|
||
OEM_COPY = 0xF2,
|
||
|
||
/// <summary>Auto key</summary>
|
||
OEM_AUTO = 0xF3,
|
||
|
||
/// <summary>Enlw key</summary>
|
||
OEM_ENLW = 0xF4,
|
||
|
||
/// <summary>BackTab key</summary>
|
||
OEM_BACKTAB = 0xF5,
|
||
|
||
/// <summary>Attn key</summary>
|
||
ATTN = 0xF6,
|
||
|
||
/// <summary>CrSel key</summary>
|
||
CRSEL = 0xF7,
|
||
|
||
/// <summary>ExSel key</summary>
|
||
EXSEL = 0xF8,
|
||
|
||
/// <summary>Erase EOF key</summary>
|
||
EREOF = 0xF9,
|
||
|
||
/// <summary>Play key</summary>
|
||
PLAY = 0xFA,
|
||
|
||
/// <summary>Zoom key</summary>
|
||
ZOOM = 0xFB,
|
||
|
||
/// <summary>Reserved</summary>
|
||
NONAME = 0xFC,
|
||
|
||
/// <summary>PA1 key</summary>
|
||
PA1 = 0xFD,
|
||
|
||
/// <summary>Clear key</summary>
|
||
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<ScanCodeMapping> _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'
|
||
)
|
||
};
|
||
|
||
/// <summary>Decode a <see cref="ConsoleKeyInfo"/> that is using <see cref="ConsoleKey.Packet"/>.</summary>
|
||
/// <param name="consoleKeyInfo">The console key info.</param>
|
||
/// <returns>The decoded <see cref="ConsoleKeyInfo"/> or the <paramref name="consoleKeyInfo"/>.</returns>
|
||
/// <remarks>
|
||
/// If it's a <see cref="ConsoleKey.Packet"/> the <see cref="ConsoleKeyInfo.KeyChar"/> may be a
|
||
/// <see cref="ConsoleKeyInfo.Key"/> or a <see cref="ConsoleKeyInfo.KeyChar"/> value.
|
||
/// </remarks>
|
||
public static ConsoleKeyInfo DecodeVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
|
||
{
|
||
if (consoleKeyInfo.Key != ConsoleKey.Packet)
|
||
{
|
||
return consoleKeyInfo;
|
||
}
|
||
|
||
return GetConsoleKeyInfoFromKeyChar (consoleKeyInfo.KeyChar, consoleKeyInfo.Modifiers, out _);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Encode the <see cref="ConsoleKeyInfo.KeyChar"/> with the <see cref="ConsoleKeyInfo.Key"/> if the first a byte
|
||
/// length, otherwise only the KeyChar is considered and searched on the database.
|
||
/// </summary>
|
||
/// <param name="consoleKeyInfo">The console key info.</param>
|
||
/// <returns>The encoded KeyChar with the Key if both can be shifted, otherwise only the KeyChar.</returns>
|
||
/// <remarks>This is useful to use with the <see cref="ConsoleKey.Packet"/>.</remarks>
|
||
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;
|
||
}
|
||
}
|