ConsoleKeyMapping.cs 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.Linq;
  5. using System.Runtime.InteropServices;
  6. using System.Text;
  7. namespace Terminal.Gui.ConsoleDrivers;
  8. /// <summary>
  9. /// Helper class to handle the scan code and virtual key from a <see cref="ConsoleKey"/>.
  10. /// </summary>
  11. public static class ConsoleKeyMapping {
  12. #if !WT_ISSUE_8871_FIXED // https://github.com/microsoft/terminal/issues/8871
  13. /// <summary>
  14. /// Translates (maps) a virtual-key code into a scan code or character value, or translates a scan code into a virtual-key code.
  15. /// </summary>
  16. /// <param name="vk"></param>
  17. /// <param name="uMapType">
  18. /// If MAPVK_VK_TO_CHAR (2) - The uCode parameter is a virtual-key code and is translated into an un-shifted
  19. /// character value in the low order word of the return value.
  20. /// </param>
  21. /// <param name="dwhkl"></param>
  22. /// <returns>An un-shifted character value in the low order word of the return value. Dead keys (diacritics)
  23. /// are indicated by setting the top bit of the return value. If there is no translation,
  24. /// the function returns 0. See Remarks.</returns>
  25. [DllImport ("user32.dll", EntryPoint = "MapVirtualKeyExW", CharSet = CharSet.Unicode)]
  26. extern static uint MapVirtualKeyEx (VK vk, uint uMapType, IntPtr dwhkl);
  27. /// <summary>
  28. /// Retrieves the active input locale identifier (formerly called the keyboard layout).
  29. /// </summary>
  30. /// <param name="idThread">0 for current thread</param>
  31. /// <returns>The return value is the input locale identifier for the thread.
  32. /// The low word contains a Language Identifier for the input language
  33. /// and the high word contains a device handle to the physical layout of the keyboard.
  34. /// </returns>
  35. [DllImport ("user32.dll", EntryPoint = "GetKeyboardLayout", CharSet = CharSet.Unicode)]
  36. extern static IntPtr GetKeyboardLayout (IntPtr idThread);
  37. //[DllImport ("user32.dll", EntryPoint = "GetKeyboardLayoutNameW", CharSet = CharSet.Unicode)]
  38. //extern static uint GetKeyboardLayoutName (uint idThread);
  39. [DllImport ("user32.dll")]
  40. extern static IntPtr GetForegroundWindow ();
  41. [DllImport ("user32.dll")]
  42. extern static IntPtr GetWindowThreadProcessId (IntPtr hWnd, IntPtr ProcessId);
  43. /// <summary>
  44. /// Translates the specified virtual-key code and keyboard state to the corresponding Unicode character or characters using
  45. /// the Win32 API MapVirtualKey.
  46. /// </summary>
  47. /// <param name="vk"></param>
  48. /// <returns>An un-shifted character value in the low order word of the return value. Dead keys (diacritics)
  49. /// are indicated by setting the top bit of the return value. If there is no translation,
  50. /// the function returns 0.</returns>
  51. public static uint MapVKtoChar (VK vk)
  52. {
  53. if (Environment.OSVersion.Platform != PlatformID.Win32NT) {
  54. return 0;
  55. }
  56. var tid = GetWindowThreadProcessId (GetForegroundWindow (), 0);
  57. var hkl = GetKeyboardLayout (tid);
  58. return MapVirtualKeyEx (vk, 2, hkl);
  59. }
  60. #else
  61. /// <summary>
  62. /// Translates (maps) a virtual-key code into a scan code or character value, or translates a scan code into a virtual-key code.
  63. /// </summary>
  64. /// <param name="vk"></param>
  65. /// <param name="uMapType">
  66. /// If MAPVK_VK_TO_CHAR (2) - The uCode parameter is a virtual-key code and is translated into an unshifted
  67. /// character value in the low order word of the return value.
  68. /// </param>
  69. /// <returns>An unshifted character value in the low order word of the return value. Dead keys (diacritics)
  70. /// are indicated by setting the top bit of the return value. If there is no translation,
  71. /// the function returns 0. See Remarks.</returns>
  72. [DllImport ("user32.dll", EntryPoint = "MapVirtualKeyW", CharSet = CharSet.Unicode)]
  73. extern static uint MapVirtualKey (VK vk, uint uMapType = 2);
  74. uint MapVKtoChar (VK vk) => MapVirtualKeyToCharEx (vk);
  75. #endif
  76. /// <summary>
  77. /// Retrieves the name of the active input locale identifier (formerly called the keyboard layout) for the calling thread.
  78. /// </summary>
  79. /// <param name="pwszKLID"></param>
  80. /// <returns></returns>
  81. [DllImport ("user32.dll")]
  82. extern static bool GetKeyboardLayoutName ([Out] StringBuilder pwszKLID);
  83. public static string GetKeyboardLayoutName ()
  84. {
  85. if (Environment.OSVersion.Platform != PlatformID.Win32NT) {
  86. return "none";
  87. }
  88. StringBuilder klidSB = new StringBuilder ();
  89. GetKeyboardLayoutName (klidSB);
  90. return klidSB.ToString ();
  91. }
  92. class ScanCodeMapping : IEquatable<ScanCodeMapping> {
  93. public uint ScanCode;
  94. public VK VirtualKey;
  95. public ConsoleModifiers Modifiers;
  96. public uint UnicodeChar;
  97. public ScanCodeMapping (uint scanCode, VK virtualKey, ConsoleModifiers modifiers, uint unicodeChar)
  98. {
  99. ScanCode = scanCode;
  100. VirtualKey = virtualKey;
  101. Modifiers = modifiers;
  102. UnicodeChar = unicodeChar;
  103. }
  104. public bool Equals (ScanCodeMapping other)
  105. {
  106. return ScanCode.Equals (other.ScanCode) &&
  107. VirtualKey.Equals (other.VirtualKey) &&
  108. Modifiers.Equals (other.Modifiers) &&
  109. UnicodeChar.Equals (other.UnicodeChar);
  110. }
  111. }
  112. static ConsoleModifiers GetModifiers (ConsoleModifiers modifiers)
  113. {
  114. if (modifiers.HasFlag (ConsoleModifiers.Shift)
  115. && !modifiers.HasFlag (ConsoleModifiers.Alt)
  116. && !modifiers.HasFlag (ConsoleModifiers.Control)) {
  117. return ConsoleModifiers.Shift;
  118. } else if (modifiers == (ConsoleModifiers.Alt | ConsoleModifiers.Control)) {
  119. return modifiers;
  120. }
  121. return 0;
  122. }
  123. static ScanCodeMapping GetScanCode (string propName, uint keyValue, ConsoleModifiers modifiers)
  124. {
  125. switch (propName) {
  126. case "UnicodeChar":
  127. var sCode = _scanCodes.FirstOrDefault ((e) => e.UnicodeChar == keyValue && e.Modifiers == modifiers);
  128. if (sCode == null && modifiers == (ConsoleModifiers.Alt | ConsoleModifiers.Control)) {
  129. return _scanCodes.FirstOrDefault ((e) => e.UnicodeChar == keyValue && e.Modifiers == 0);
  130. }
  131. return sCode;
  132. case "VirtualKey":
  133. sCode = _scanCodes.FirstOrDefault ((e) => e.VirtualKey == (VK)keyValue && e.Modifiers == modifiers);
  134. if (sCode == null && modifiers == (ConsoleModifiers.Alt | ConsoleModifiers.Control)) {
  135. return _scanCodes.FirstOrDefault ((e) => e.VirtualKey == (VK)keyValue && e.Modifiers == 0);
  136. }
  137. return sCode;
  138. }
  139. return null;
  140. }
  141. // BUGBUG: This API is not correct. It is only used by WindowsDriver in VKPacket scenarios
  142. /// <summary>
  143. /// Get the scan code from a <see cref="ConsoleKeyInfo"/>.
  144. /// </summary>
  145. /// <param name="consoleKeyInfo">The console key info.</param>
  146. /// <returns>The value if apply.</returns>
  147. public static uint GetScanCodeFromConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
  148. {
  149. var mod = GetModifiers (consoleKeyInfo.Modifiers);
  150. ScanCodeMapping scode = GetScanCode ("VirtualKey", (uint)consoleKeyInfo.Key, mod);
  151. if (scode != null) {
  152. return scode.ScanCode;
  153. }
  154. return 0;
  155. }
  156. // BUGBUG: This API is not correct. It is only used by FakeDriver and VkeyPacketSimulator
  157. /// <summary>
  158. /// Gets the <see cref="ConsoleKeyInfo"/> from the provided <see cref="KeyCode"/>.
  159. /// </summary>
  160. /// <param name="key">The key code.</param>
  161. /// <returns>The console key info.</returns>
  162. public static ConsoleKeyInfo GetConsoleKeyInfoFromKeyCode (KeyCode key)
  163. {
  164. var modifiers = MapToConsoleModifiers (key);
  165. var keyValue = MapKeyCodeToConsoleKey (key, out bool isConsoleKey);
  166. if (isConsoleKey) {
  167. var mod = GetModifiers (modifiers);
  168. var scode = GetScanCode ("VirtualKey", (uint)keyValue, mod);
  169. if (scode != null) {
  170. return new ConsoleKeyInfo ((char)scode.UnicodeChar, (ConsoleKey)scode.VirtualKey, modifiers.HasFlag (ConsoleModifiers.Shift),
  171. modifiers.HasFlag (ConsoleModifiers.Alt), modifiers.HasFlag (ConsoleModifiers.Control));
  172. }
  173. } else {
  174. var keyChar = GetKeyCharFromUnicodeChar ((uint)keyValue, modifiers, out uint consoleKey, out _, isConsoleKey);
  175. if (consoleKey != 0) {
  176. return new ConsoleKeyInfo ((char)keyChar, (ConsoleKey)consoleKey, modifiers.HasFlag (ConsoleModifiers.Shift),
  177. modifiers.HasFlag (ConsoleModifiers.Alt), modifiers.HasFlag (ConsoleModifiers.Control));
  178. }
  179. }
  180. return new ConsoleKeyInfo ((char)keyValue, ConsoleKey.None, modifiers.HasFlag (ConsoleModifiers.Shift),
  181. modifiers.HasFlag (ConsoleModifiers.Alt), modifiers.HasFlag (ConsoleModifiers.Control));
  182. }
  183. /// <summary>
  184. /// Map existing <see cref="KeyCode"/> modifiers to <see cref="ConsoleModifiers"/>.
  185. /// </summary>
  186. /// <param name="key">The key code.</param>
  187. /// <returns>The console modifiers.</returns>
  188. public static ConsoleModifiers MapToConsoleModifiers (KeyCode key)
  189. {
  190. var modifiers = new ConsoleModifiers ();
  191. if (key.HasFlag (KeyCode.ShiftMask)) {
  192. modifiers |= ConsoleModifiers.Shift;
  193. }
  194. if (key.HasFlag (KeyCode.AltMask)) {
  195. modifiers |= ConsoleModifiers.Alt;
  196. }
  197. if (key.HasFlag (KeyCode.CtrlMask)) {
  198. modifiers |= ConsoleModifiers.Control;
  199. }
  200. return modifiers;
  201. }
  202. /// <summary>
  203. /// Gets <see cref="ConsoleModifiers"/> from <see cref="bool"/> modifiers.
  204. /// </summary>
  205. /// <param name="shift">The shift key.</param>
  206. /// <param name="alt">The alt key.</param>
  207. /// <param name="control">The control key.</param>
  208. /// <returns>The console modifiers.</returns>
  209. public static ConsoleModifiers GetModifiers (bool shift, bool alt, bool control)
  210. {
  211. var modifiers = new ConsoleModifiers ();
  212. if (shift) {
  213. modifiers |= ConsoleModifiers.Shift;
  214. }
  215. if (alt) {
  216. modifiers |= ConsoleModifiers.Alt;
  217. }
  218. if (control) {
  219. modifiers |= ConsoleModifiers.Control;
  220. }
  221. return modifiers;
  222. }
  223. /// <summary>
  224. /// Get the <see cref="ConsoleKeyInfo"/> from a unicode character and modifiers (e.g. (Key)'a' and (Key)Key.CtrlMask).
  225. /// </summary>
  226. /// <param name="keyValue">The key as a unicode codepoint.</param>
  227. /// <param name="modifiers">The modifier keys.</param>
  228. /// <param name="scanCode">The resulting scan code.</param>
  229. /// <returns>The <see cref="ConsoleKeyInfo"/>.</returns>
  230. static ConsoleKeyInfo GetConsoleKeyInfoFromKeyChar (uint keyValue, ConsoleModifiers modifiers, out uint scanCode)
  231. {
  232. scanCode = 0;
  233. if (keyValue == 0) {
  234. return new ConsoleKeyInfo ((char)keyValue, ConsoleKey.None, modifiers.HasFlag (ConsoleModifiers.Shift),
  235. modifiers.HasFlag (ConsoleModifiers.Alt), modifiers.HasFlag (ConsoleModifiers.Control));
  236. }
  237. uint outputChar = keyValue;
  238. uint consoleKey;
  239. if (keyValue > byte.MaxValue) {
  240. var sCode = _scanCodes.FirstOrDefault ((e) => e.UnicodeChar == keyValue);
  241. if (sCode == null) {
  242. consoleKey = (byte)(keyValue & byte.MaxValue);
  243. sCode = _scanCodes.FirstOrDefault ((e) => e.VirtualKey == (VK)consoleKey);
  244. if (sCode == null) {
  245. consoleKey = 0;
  246. outputChar = keyValue;
  247. } else {
  248. outputChar = (char)(keyValue >> 8);
  249. }
  250. } else {
  251. consoleKey = (byte)sCode.VirtualKey;
  252. outputChar = keyValue;
  253. }
  254. } else {
  255. consoleKey = (byte)keyValue;
  256. outputChar = '\0';
  257. }
  258. return new ConsoleKeyInfo ((char)outputChar, (ConsoleKey)consoleKey, modifiers.HasFlag (ConsoleModifiers.Shift),
  259. modifiers.HasFlag (ConsoleModifiers.Alt), modifiers.HasFlag (ConsoleModifiers.Control));
  260. }
  261. // Used only by unit tests
  262. internal static uint GetKeyChar (uint keyValue, ConsoleModifiers modifiers)
  263. {
  264. if (modifiers == ConsoleModifiers.Shift && keyValue - 32 is >= 'A' and <= 'Z') {
  265. return keyValue - 32;
  266. } else if (modifiers == ConsoleModifiers.None && keyValue is >= 'A' and <= 'Z') {
  267. return keyValue + 32;
  268. }
  269. if (modifiers == ConsoleModifiers.Shift && keyValue - 32 is >= 'À' and <= 'Ý') {
  270. return keyValue - 32;
  271. } else if (modifiers == ConsoleModifiers.None && keyValue is >= 'À' and <= 'Ý') {
  272. return keyValue + 32;
  273. }
  274. if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '0') {
  275. return keyValue + 13;
  276. } else if (modifiers == ConsoleModifiers.None && keyValue - 13 is '0') {
  277. return keyValue - 13;
  278. }
  279. if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is >= '1' and <= '9' and not '7') {
  280. return keyValue - 16;
  281. } else if (modifiers == ConsoleModifiers.None && keyValue + 16 is >= '1' and <= '9' and not '7') {
  282. return keyValue + 16;
  283. }
  284. if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '7') {
  285. return keyValue - 8;
  286. } else if (modifiers == ConsoleModifiers.None && keyValue + 8 is '7') {
  287. return keyValue + 8;
  288. }
  289. if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '\'') {
  290. return keyValue + 24;
  291. } else if (modifiers == ConsoleModifiers.None && keyValue - 24 is '\'') {
  292. return keyValue - 24;
  293. }
  294. if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '«') {
  295. return keyValue + 16;
  296. } else if (modifiers == ConsoleModifiers.None && keyValue - 16 is '«') {
  297. return keyValue - 16;
  298. }
  299. if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '\\') {
  300. return keyValue + 32;
  301. } else if (modifiers == ConsoleModifiers.None && keyValue - 32 is '\\') {
  302. return keyValue - 32;
  303. }
  304. if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '+') {
  305. return keyValue - 1;
  306. } else if (modifiers == ConsoleModifiers.None && keyValue + 1 is '+') {
  307. return keyValue + 1;
  308. }
  309. if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '´') {
  310. return keyValue - 84;
  311. } else if (modifiers == ConsoleModifiers.None && keyValue + 84 is '´') {
  312. return keyValue + 84;
  313. }
  314. if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is 'º') {
  315. return keyValue - 16;
  316. } else if (modifiers == ConsoleModifiers.None && keyValue + 16 is 'º') {
  317. return keyValue + 16;
  318. }
  319. if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '~') {
  320. return keyValue - 32;
  321. } else if (modifiers == ConsoleModifiers.None && keyValue + 32 is '~') {
  322. return keyValue + 32;
  323. }
  324. if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '<') {
  325. return keyValue + 2;
  326. } else if (modifiers == ConsoleModifiers.None && keyValue - 2 is '<') {
  327. return keyValue - 2;
  328. }
  329. if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is ',') {
  330. return keyValue + 15;
  331. } else if (modifiers == ConsoleModifiers.None && keyValue - 15 is ',') {
  332. return keyValue - 15;
  333. }
  334. if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '.') {
  335. return keyValue + 12;
  336. } else if (modifiers == ConsoleModifiers.None && keyValue - 12 is '.') {
  337. return keyValue - 12;
  338. }
  339. if (modifiers.HasFlag (ConsoleModifiers.Shift) && keyValue is '-') {
  340. return keyValue + 50;
  341. } else if (modifiers == ConsoleModifiers.None && keyValue - 50 is '-') {
  342. return keyValue - 50;
  343. }
  344. return keyValue;
  345. }
  346. /// <summary>
  347. /// Get the output character from the <see cref="GetConsoleKeyInfoFromKeyCode"/>, with the correct <see cref="ConsoleKey"/>
  348. /// and the scan code used on <see cref="WindowsDriver"/>.
  349. /// </summary>
  350. /// <param name="unicodeChar">The unicode character.</param>
  351. /// <param name="modifiers">The modifiers keys.</param>
  352. /// <param name="consoleKey">The resulting console key.</param>
  353. /// <param name="scanCode">The resulting scan code.</param>
  354. /// <param name="isConsoleKey">Indicates if the <paramref name="unicodeChar"/> is a <see cref="ConsoleKey"/>.</param>
  355. /// <returns>The output character or the <paramref name="consoleKey"/>.</returns>
  356. /// <remarks>This is only used by the <see cref="GetConsoleKeyInfoFromKeyCode"/> and by unit tests.</remarks>
  357. internal static uint GetKeyCharFromUnicodeChar (uint unicodeChar, ConsoleModifiers modifiers, out uint consoleKey, out uint scanCode, bool isConsoleKey = false)
  358. {
  359. uint decodedChar = unicodeChar >> 8 == 0xff ? unicodeChar & 0xff : unicodeChar;
  360. uint keyChar = decodedChar;
  361. consoleKey = 0;
  362. var mod = GetModifiers (modifiers);
  363. scanCode = 0;
  364. ScanCodeMapping scode = null;
  365. if (unicodeChar != 0 && unicodeChar >> 8 != 0xff && isConsoleKey) {
  366. scode = GetScanCode ("VirtualKey", decodedChar, mod);
  367. }
  368. if (isConsoleKey && scode != null) {
  369. consoleKey = (uint)scode.VirtualKey;
  370. keyChar = scode.UnicodeChar;
  371. scanCode = scode.ScanCode;
  372. }
  373. if (scode == null) {
  374. scode = unicodeChar != 0 ? GetScanCode ("UnicodeChar", decodedChar, mod) : null;
  375. if (scode != null) {
  376. consoleKey = (uint)scode.VirtualKey;
  377. keyChar = scode.UnicodeChar;
  378. scanCode = scode.ScanCode;
  379. }
  380. }
  381. if (decodedChar != 0 && scanCode == 0 && char.IsLetter ((char)decodedChar)) {
  382. string stFormD = ((char)decodedChar).ToString ().Normalize (System.Text.NormalizationForm.FormD);
  383. for (int i = 0; i < stFormD.Length; i++) {
  384. var uc = CharUnicodeInfo.GetUnicodeCategory (stFormD [i]);
  385. if (uc != UnicodeCategory.NonSpacingMark && uc != UnicodeCategory.OtherLetter) {
  386. consoleKey = char.ToUpper (stFormD [i]);
  387. scode = GetScanCode ("VirtualKey", char.ToUpper (stFormD [i]), 0);
  388. if (scode != null) {
  389. scanCode = scode.ScanCode;
  390. }
  391. }
  392. }
  393. }
  394. if (keyChar < 255 && consoleKey == 0 && scanCode == 0) {
  395. scode = GetScanCode ("VirtualKey", keyChar, mod);
  396. if (scode != null) {
  397. consoleKey = (uint)scode.VirtualKey;
  398. keyChar = scode.UnicodeChar;
  399. scanCode = scode.ScanCode;
  400. }
  401. }
  402. return keyChar;
  403. }
  404. /// <summary>
  405. /// Maps a unicode character (e.g. (Key)'a') to a uint representing a <see cref="ConsoleKey"/>.
  406. /// </summary>
  407. /// <param name="keyValue">The key value.</param>
  408. /// <param name="isConsoleKey">Indicates if the <paramref name="keyValue"/> is a <see cref="ConsoleKey"/>.
  409. /// <see langword="true"/> means the return value is in the ConsoleKey enum.
  410. /// <see langword="false"/> means the return value can be mapped to a valid unicode character.
  411. /// </param>
  412. /// <returns>The <see cref="ConsoleKey"/> or the <paramref name="keyValue"/>.</returns>
  413. /// <remarks>This is only used by the <see cref="GetConsoleKeyInfoFromKeyCode"/> and by unit tests.</remarks>
  414. internal static uint MapKeyCodeToConsoleKey (KeyCode keyValue, out bool isConsoleKey)
  415. {
  416. isConsoleKey = true;
  417. keyValue = keyValue & ~KeyCode.CtrlMask & ~KeyCode.ShiftMask & ~KeyCode.AltMask;
  418. switch (keyValue) {
  419. case KeyCode.Enter:
  420. return (uint)ConsoleKey.Enter;
  421. case KeyCode.CursorUp:
  422. return (uint)ConsoleKey.UpArrow;
  423. case KeyCode.CursorDown:
  424. return (uint)ConsoleKey.DownArrow;
  425. case KeyCode.CursorLeft:
  426. return (uint)ConsoleKey.LeftArrow;
  427. case KeyCode.CursorRight:
  428. return (uint)ConsoleKey.RightArrow;
  429. case KeyCode.PageUp:
  430. return (uint)ConsoleKey.PageUp;
  431. case KeyCode.PageDown:
  432. return (uint)ConsoleKey.PageDown;
  433. case KeyCode.Home:
  434. return (uint)ConsoleKey.Home;
  435. case KeyCode.End:
  436. return (uint)ConsoleKey.End;
  437. case KeyCode.Insert:
  438. return (uint)ConsoleKey.Insert;
  439. case KeyCode.Delete:
  440. return (uint)ConsoleKey.Delete;
  441. case KeyCode.F1:
  442. return (uint)ConsoleKey.F1;
  443. case KeyCode.F2:
  444. return (uint)ConsoleKey.F2;
  445. case KeyCode.F3:
  446. return (uint)ConsoleKey.F3;
  447. case KeyCode.F4:
  448. return (uint)ConsoleKey.F4;
  449. case KeyCode.F5:
  450. return (uint)ConsoleKey.F5;
  451. case KeyCode.F6:
  452. return (uint)ConsoleKey.F6;
  453. case KeyCode.F7:
  454. return (uint)ConsoleKey.F7;
  455. case KeyCode.F8:
  456. return (uint)ConsoleKey.F8;
  457. case KeyCode.F9:
  458. return (uint)ConsoleKey.F9;
  459. case KeyCode.F10:
  460. return (uint)ConsoleKey.F10;
  461. case KeyCode.F11:
  462. return (uint)ConsoleKey.F11;
  463. case KeyCode.F12:
  464. return (uint)ConsoleKey.F12;
  465. case KeyCode.F13:
  466. return (uint)ConsoleKey.F13;
  467. case KeyCode.F14:
  468. return (uint)ConsoleKey.F14;
  469. case KeyCode.F15:
  470. return (uint)ConsoleKey.F15;
  471. case KeyCode.F16:
  472. return (uint)ConsoleKey.F16;
  473. case KeyCode.F17:
  474. return (uint)ConsoleKey.F17;
  475. case KeyCode.F18:
  476. return (uint)ConsoleKey.F18;
  477. case KeyCode.F19:
  478. return (uint)ConsoleKey.F19;
  479. case KeyCode.F20:
  480. return (uint)ConsoleKey.F20;
  481. case KeyCode.F21:
  482. return (uint)ConsoleKey.F21;
  483. case KeyCode.F22:
  484. return (uint)ConsoleKey.F22;
  485. case KeyCode.F23:
  486. return (uint)ConsoleKey.F23;
  487. case KeyCode.F24:
  488. return (uint)ConsoleKey.F24;
  489. case KeyCode.Tab | KeyCode.ShiftMask:
  490. return (uint)ConsoleKey.Tab;
  491. }
  492. isConsoleKey = false;
  493. return (uint)keyValue;
  494. }
  495. /// <summary>
  496. /// Maps a <see cref="ConsoleKeyInfo"/> to a <see cref="KeyCode"/>.
  497. /// </summary>
  498. /// <param name="consoleKeyInfo">The console key.</param>
  499. /// <returns>The <see cref="KeyCode"/> or the <paramref name="consoleKeyInfo"/>.</returns>
  500. public static KeyCode MapConsoleKeyInfoToKeyCode (ConsoleKeyInfo consoleKeyInfo)
  501. {
  502. KeyCode keyCode;
  503. switch (consoleKeyInfo.Key) {
  504. case ConsoleKey.Enter:
  505. keyCode = KeyCode.Enter;
  506. break;
  507. case ConsoleKey.Delete:
  508. keyCode = KeyCode.Delete;
  509. break;
  510. case ConsoleKey.UpArrow:
  511. keyCode = KeyCode.CursorUp;
  512. break;
  513. case ConsoleKey.DownArrow:
  514. keyCode = KeyCode.CursorDown;
  515. break;
  516. case ConsoleKey.LeftArrow:
  517. keyCode = KeyCode.CursorLeft;
  518. break;
  519. case ConsoleKey.RightArrow:
  520. keyCode = KeyCode.CursorRight;
  521. break;
  522. case ConsoleKey.PageUp:
  523. keyCode = KeyCode.PageUp;
  524. break;
  525. case ConsoleKey.PageDown:
  526. keyCode = KeyCode.PageDown;
  527. break;
  528. case ConsoleKey.Home:
  529. keyCode = KeyCode.Home;
  530. break;
  531. case ConsoleKey.End:
  532. keyCode = KeyCode.End;
  533. break;
  534. case ConsoleKey.Insert:
  535. keyCode = KeyCode.Insert;
  536. break;
  537. case ConsoleKey.F1:
  538. keyCode = KeyCode.F1;
  539. break;
  540. case ConsoleKey.F2:
  541. keyCode = KeyCode.F2;
  542. break;
  543. case ConsoleKey.F3:
  544. keyCode = KeyCode.F3;
  545. break;
  546. case ConsoleKey.F4:
  547. keyCode = KeyCode.F4;
  548. break;
  549. case ConsoleKey.F5:
  550. keyCode = KeyCode.F5;
  551. break;
  552. case ConsoleKey.F6:
  553. keyCode = KeyCode.F6;
  554. break;
  555. case ConsoleKey.F7:
  556. keyCode = KeyCode.F7;
  557. break;
  558. case ConsoleKey.F8:
  559. keyCode = KeyCode.F8;
  560. break;
  561. case ConsoleKey.F9:
  562. keyCode = KeyCode.F9;
  563. break;
  564. case ConsoleKey.F10:
  565. keyCode = KeyCode.F10;
  566. break;
  567. case ConsoleKey.F11:
  568. keyCode = KeyCode.F11;
  569. break;
  570. case ConsoleKey.F12:
  571. keyCode = KeyCode.F12;
  572. break;
  573. case ConsoleKey.F13:
  574. keyCode = KeyCode.F13;
  575. break;
  576. case ConsoleKey.F14:
  577. keyCode = KeyCode.F14;
  578. break;
  579. case ConsoleKey.F15:
  580. keyCode = KeyCode.F15;
  581. break;
  582. case ConsoleKey.F16:
  583. keyCode = KeyCode.F16;
  584. break;
  585. case ConsoleKey.F17:
  586. keyCode = KeyCode.F17;
  587. break;
  588. case ConsoleKey.F18:
  589. keyCode = KeyCode.F18;
  590. break;
  591. case ConsoleKey.F19:
  592. keyCode = KeyCode.F19;
  593. break;
  594. case ConsoleKey.F20:
  595. keyCode = KeyCode.F20;
  596. break;
  597. case ConsoleKey.F21:
  598. keyCode = KeyCode.F21;
  599. break;
  600. case ConsoleKey.F22:
  601. keyCode = KeyCode.F22;
  602. break;
  603. case ConsoleKey.F23:
  604. keyCode = KeyCode.F23;
  605. break;
  606. case ConsoleKey.F24:
  607. keyCode = KeyCode.F24;
  608. break;
  609. case ConsoleKey.Tab:
  610. keyCode = KeyCode.Tab;
  611. break;
  612. default:
  613. keyCode = (KeyCode)consoleKeyInfo.KeyChar;
  614. break;
  615. }
  616. keyCode |= MapToKeyCodeModifiers (consoleKeyInfo.Modifiers, keyCode);
  617. return keyCode;
  618. }
  619. /// <summary>
  620. /// Maps a <see cref="ConsoleKeyInfo"/> to a <see cref="KeyCode"/>.
  621. /// </summary>
  622. /// <param name="modifiers">The console modifiers.</param>
  623. /// <param name="key">The key code.</param>
  624. /// <returns>The <see cref="KeyCode"/> with <see cref="ConsoleModifiers"/> or the <paramref name="key"/></returns>
  625. public static KeyCode MapToKeyCodeModifiers (ConsoleModifiers modifiers, KeyCode key)
  626. {
  627. var keyMod = new KeyCode ();
  628. if ((modifiers & ConsoleModifiers.Shift) != 0) {
  629. keyMod = KeyCode.ShiftMask;
  630. }
  631. if ((modifiers & ConsoleModifiers.Control) != 0) {
  632. keyMod |= KeyCode.CtrlMask;
  633. }
  634. if ((modifiers & ConsoleModifiers.Alt) != 0) {
  635. keyMod |= KeyCode.AltMask;
  636. }
  637. return keyMod != KeyCode.Null ? keyMod | key : key;
  638. }
  639. /// <summary>
  640. /// Generated from winuser.h. See https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
  641. /// </summary>
  642. public enum VK : ushort {
  643. /// <summary>
  644. /// Left mouse button.
  645. /// </summary>
  646. LBUTTON = 0x01,
  647. /// <summary>
  648. /// Right mouse button.
  649. /// </summary>
  650. RBUTTON = 0x02,
  651. /// <summary>
  652. /// Control-break processing.
  653. /// </summary>
  654. CANCEL = 0x03,
  655. /// <summary>
  656. /// Middle mouse button (three-button mouse).
  657. /// </summary>
  658. MBUTTON = 0x04,
  659. /// <summary>
  660. /// X1 mouse button.
  661. /// </summary>
  662. XBUTTON1 = 0x05,
  663. /// <summary>
  664. /// X2 mouse button.
  665. /// </summary>
  666. XBUTTON2 = 0x06,
  667. /// <summary>
  668. /// BACKSPACE key.
  669. /// </summary>
  670. BACK = 0x08,
  671. /// <summary>
  672. /// TAB key.
  673. /// </summary>
  674. TAB = 0x09,
  675. /// <summary>
  676. /// CLEAR key.
  677. /// </summary>
  678. CLEAR = 0x0C,
  679. /// <summary>
  680. /// ENTER key.
  681. /// </summary>
  682. RETURN = 0x0D,
  683. /// <summary>
  684. /// SHIFT key.
  685. /// </summary>
  686. SHIFT = 0x10,
  687. /// <summary>
  688. /// CTRL key.
  689. /// </summary>
  690. CONTROL = 0x11,
  691. /// <summary>
  692. /// ALT key.
  693. /// </summary>
  694. MENU = 0x12,
  695. /// <summary>
  696. /// PAUSE key.
  697. /// </summary>
  698. PAUSE = 0x13,
  699. /// <summary>
  700. /// CAPS LOCK key.
  701. /// </summary>
  702. CAPITAL = 0x14,
  703. /// <summary>
  704. /// IME Kana mode.
  705. /// </summary>
  706. KANA = 0x15,
  707. /// <summary>
  708. /// IME Hangul mode.
  709. /// </summary>
  710. HANGUL = 0x15,
  711. /// <summary>
  712. /// IME Junja mode.
  713. /// </summary>
  714. JUNJA = 0x17,
  715. /// <summary>
  716. /// IME final mode.
  717. /// </summary>
  718. FINAL = 0x18,
  719. /// <summary>
  720. /// IME Hanja mode.
  721. /// </summary>
  722. HANJA = 0x19,
  723. /// <summary>
  724. /// IME Kanji mode.
  725. /// </summary>
  726. KANJI = 0x19,
  727. /// <summary>
  728. /// ESC key.
  729. /// </summary>
  730. ESCAPE = 0x1B,
  731. /// <summary>
  732. /// IME convert.
  733. /// </summary>
  734. CONVERT = 0x1C,
  735. /// <summary>
  736. /// IME nonconvert.
  737. /// </summary>
  738. NONCONVERT = 0x1D,
  739. /// <summary>
  740. /// IME accept.
  741. /// </summary>
  742. ACCEPT = 0x1E,
  743. /// <summary>
  744. /// IME mode change request.
  745. /// </summary>
  746. MODECHANGE = 0x1F,
  747. /// <summary>
  748. /// SPACEBAR.
  749. /// </summary>
  750. SPACE = 0x20,
  751. /// <summary>
  752. /// PAGE UP key.
  753. /// </summary>
  754. PRIOR = 0x21,
  755. /// <summary>
  756. /// PAGE DOWN key.
  757. /// </summary>
  758. NEXT = 0x22,
  759. /// <summary>
  760. /// END key.
  761. /// </summary>
  762. END = 0x23,
  763. /// <summary>
  764. /// HOME key.
  765. /// </summary>
  766. HOME = 0x24,
  767. /// <summary>
  768. /// LEFT ARROW key.
  769. /// </summary>
  770. LEFT = 0x25,
  771. /// <summary>
  772. /// UP ARROW key.
  773. /// </summary>
  774. UP = 0x26,
  775. /// <summary>
  776. /// RIGHT ARROW key.
  777. /// </summary>
  778. RIGHT = 0x27,
  779. /// <summary>
  780. /// DOWN ARROW key.
  781. /// </summary>
  782. DOWN = 0x28,
  783. /// <summary>
  784. /// SELECT key.
  785. /// </summary>
  786. SELECT = 0x29,
  787. /// <summary>
  788. /// PRINT key.
  789. /// </summary>
  790. PRINT = 0x2A,
  791. /// <summary>
  792. /// EXECUTE key
  793. /// </summary>
  794. EXECUTE = 0x2B,
  795. /// <summary>
  796. /// PRINT SCREEN key
  797. /// </summary>
  798. SNAPSHOT = 0x2C,
  799. /// <summary>
  800. /// INS key
  801. /// </summary>
  802. INSERT = 0x2D,
  803. /// <summary>
  804. /// DEL key
  805. /// </summary>
  806. DELETE = 0x2E,
  807. /// <summary>
  808. /// HELP key
  809. /// </summary>
  810. HELP = 0x2F,
  811. /// <summary>
  812. /// Left Windows key (Natural keyboard)
  813. /// </summary>
  814. LWIN = 0x5B,
  815. /// <summary>
  816. /// Right Windows key (Natural keyboard)
  817. /// </summary>
  818. RWIN = 0x5C,
  819. /// <summary>
  820. /// Applications key (Natural keyboard)
  821. /// </summary>
  822. APPS = 0x5D,
  823. /// <summary>
  824. /// Computer Sleep key
  825. /// </summary>
  826. SLEEP = 0x5F,
  827. /// <summary>
  828. /// Numeric keypad 0 key
  829. /// </summary>
  830. NUMPAD0 = 0x60,
  831. /// <summary>
  832. /// Numeric keypad 1 key
  833. /// </summary>
  834. NUMPAD1 = 0x61,
  835. /// <summary>
  836. /// Numeric keypad 2 key
  837. /// </summary>
  838. NUMPAD2 = 0x62,
  839. /// <summary>
  840. /// Numeric keypad 3 key
  841. /// </summary>
  842. NUMPAD3 = 0x63,
  843. /// <summary>
  844. /// Numeric keypad 4 key
  845. /// </summary>
  846. NUMPAD4 = 0x64,
  847. /// <summary>
  848. /// Numeric keypad 5 key
  849. /// </summary>
  850. NUMPAD5 = 0x65,
  851. /// <summary>
  852. /// Numeric keypad 6 key
  853. /// </summary>
  854. NUMPAD6 = 0x66,
  855. /// <summary>
  856. /// Numeric keypad 7 key
  857. /// </summary>
  858. NUMPAD7 = 0x67,
  859. /// <summary>
  860. /// Numeric keypad 8 key
  861. /// </summary>
  862. NUMPAD8 = 0x68,
  863. /// <summary>
  864. /// Numeric keypad 9 key
  865. /// </summary>
  866. NUMPAD9 = 0x69,
  867. /// <summary>
  868. /// Multiply key
  869. /// </summary>
  870. MULTIPLY = 0x6A,
  871. /// <summary>
  872. /// Add key
  873. /// </summary>
  874. ADD = 0x6B,
  875. /// <summary>
  876. /// Separator key
  877. /// </summary>
  878. SEPARATOR = 0x6C,
  879. /// <summary>
  880. /// Subtract key
  881. /// </summary>
  882. SUBTRACT = 0x6D,
  883. /// <summary>
  884. /// Decimal key
  885. /// </summary>
  886. DECIMAL = 0x6E,
  887. /// <summary>
  888. /// Divide key
  889. /// </summary>
  890. DIVIDE = 0x6F,
  891. /// <summary>
  892. /// F1 key
  893. /// </summary>
  894. F1 = 0x70,
  895. /// <summary>
  896. /// F2 key
  897. /// </summary>
  898. F2 = 0x71,
  899. /// <summary>
  900. /// F3 key
  901. /// </summary>
  902. F3 = 0x72,
  903. /// <summary>
  904. /// F4 key
  905. /// </summary>
  906. F4 = 0x73,
  907. /// <summary>
  908. /// F5 key
  909. /// </summary>
  910. F5 = 0x74,
  911. /// <summary>
  912. /// F6 key
  913. /// </summary>
  914. F6 = 0x75,
  915. /// <summary>
  916. /// F7 key
  917. /// </summary>
  918. F7 = 0x76,
  919. /// <summary>
  920. /// F8 key
  921. /// </summary>
  922. F8 = 0x77,
  923. /// <summary>
  924. /// F9 key
  925. /// </summary>
  926. F9 = 0x78,
  927. /// <summary>
  928. /// F10 key
  929. /// </summary>
  930. F10 = 0x79,
  931. /// <summary>
  932. /// F11 key
  933. /// </summary>
  934. F11 = 0x7A,
  935. /// <summary>
  936. /// F12 key
  937. /// </summary>
  938. F12 = 0x7B,
  939. /// <summary>
  940. /// F13 key
  941. /// </summary>
  942. F13 = 0x7C,
  943. /// <summary>
  944. /// F14 key
  945. /// </summary>
  946. F14 = 0x7D,
  947. /// <summary>
  948. /// F15 key
  949. /// </summary>
  950. F15 = 0x7E,
  951. /// <summary>
  952. /// F16 key
  953. /// </summary>
  954. F16 = 0x7F,
  955. /// <summary>
  956. /// F17 key
  957. /// </summary>
  958. F17 = 0x80,
  959. /// <summary>
  960. /// F18 key
  961. /// </summary>
  962. F18 = 0x81,
  963. /// <summary>
  964. /// F19 key
  965. /// </summary>
  966. F19 = 0x82,
  967. /// <summary>
  968. /// F20 key
  969. /// </summary>
  970. F20 = 0x83,
  971. /// <summary>
  972. /// F21 key
  973. /// </summary>
  974. F21 = 0x84,
  975. /// <summary>
  976. /// F22 key
  977. /// </summary>
  978. F22 = 0x85,
  979. /// <summary>
  980. /// F23 key
  981. /// </summary>
  982. F23 = 0x86,
  983. /// <summary>
  984. /// F24 key
  985. /// </summary>
  986. F24 = 0x87,
  987. /// <summary>
  988. /// NUM LOCK key
  989. /// </summary>
  990. NUMLOCK = 0x90,
  991. /// <summary>
  992. /// SCROLL LOCK key
  993. /// </summary>
  994. SCROLL = 0x91,
  995. /// <summary>
  996. /// NEC PC-9800 kbd definition: '=' key on numpad
  997. /// </summary>
  998. OEM_NEC_EQUAL = 0x92,
  999. /// <summary>
  1000. /// Fujitsu/OASYS kbd definition: 'Dictionary' key
  1001. /// </summary>
  1002. OEM_FJ_JISHO = 0x92,
  1003. /// <summary>
  1004. /// Fujitsu/OASYS kbd definition: 'Unregister word' key
  1005. /// </summary>
  1006. OEM_FJ_MASSHOU = 0x93,
  1007. /// <summary>
  1008. /// Fujitsu/OASYS kbd definition: 'Register word' key
  1009. /// </summary>
  1010. OEM_FJ_TOUROKU = 0x94,
  1011. /// <summary>
  1012. /// Fujitsu/OASYS kbd definition: 'Left OYAYUBI' key
  1013. /// </summary>
  1014. OEM_FJ_LOYA = 0x95,
  1015. /// <summary>
  1016. /// Fujitsu/OASYS kbd definition: 'Right OYAYUBI' key
  1017. /// </summary>
  1018. OEM_FJ_ROYA = 0x96,
  1019. /// <summary>
  1020. /// Left SHIFT key
  1021. /// </summary>
  1022. LSHIFT = 0xA0,
  1023. /// <summary>
  1024. /// Right SHIFT key
  1025. /// </summary>
  1026. RSHIFT = 0xA1,
  1027. /// <summary>
  1028. /// Left CONTROL key
  1029. /// </summary>
  1030. LCONTROL = 0xA2,
  1031. /// <summary>
  1032. /// Right CONTROL key
  1033. /// </summary>
  1034. RCONTROL = 0xA3,
  1035. /// <summary>
  1036. /// Left MENU key (Left Alt key)
  1037. /// </summary>
  1038. LMENU = 0xA4,
  1039. /// <summary>
  1040. /// Right MENU key (Right Alt key)
  1041. /// </summary>
  1042. RMENU = 0xA5,
  1043. /// <summary>
  1044. /// Browser Back key
  1045. /// </summary>
  1046. BROWSER_BACK = 0xA6,
  1047. /// <summary>
  1048. /// Browser Forward key
  1049. /// </summary>
  1050. BROWSER_FORWARD = 0xA7,
  1051. /// <summary>
  1052. /// Browser Refresh key
  1053. /// </summary>
  1054. BROWSER_REFRESH = 0xA8,
  1055. /// <summary>
  1056. /// Browser Stop key
  1057. /// </summary>
  1058. BROWSER_STOP = 0xA9,
  1059. /// <summary>
  1060. /// Browser Search key
  1061. /// </summary>
  1062. BROWSER_SEARCH = 0xAA,
  1063. /// <summary>
  1064. /// Browser Favorites key
  1065. /// </summary>
  1066. BROWSER_FAVORITES = 0xAB,
  1067. /// <summary>
  1068. /// Browser Home key
  1069. /// </summary>
  1070. BROWSER_HOME = 0xAC,
  1071. /// <summary>
  1072. /// Volume Mute key
  1073. /// </summary>
  1074. VOLUME_MUTE = 0xAD,
  1075. /// <summary>
  1076. /// Volume Down key
  1077. /// </summary>
  1078. VOLUME_DOWN = 0xAE,
  1079. /// <summary>
  1080. /// Volume Up key
  1081. /// </summary>
  1082. VOLUME_UP = 0xAF,
  1083. /// <summary>
  1084. /// Next Track key
  1085. /// </summary>
  1086. MEDIA_NEXT_TRACK = 0xB0,
  1087. /// <summary>
  1088. /// Previous Track key
  1089. /// </summary>
  1090. MEDIA_PREV_TRACK = 0xB1,
  1091. /// <summary>
  1092. /// Stop Media key
  1093. /// </summary>
  1094. MEDIA_STOP = 0xB2,
  1095. /// <summary>
  1096. /// Play/Pause Media key
  1097. /// </summary>
  1098. MEDIA_PLAY_PAUSE = 0xB3,
  1099. /// <summary>
  1100. /// Start Mail key
  1101. /// </summary>
  1102. LAUNCH_MAIL = 0xB4,
  1103. /// <summary>
  1104. /// Select Media key
  1105. /// </summary>
  1106. LAUNCH_MEDIA_SELECT = 0xB5,
  1107. /// <summary>
  1108. /// Start Application 1 key
  1109. /// </summary>
  1110. LAUNCH_APP1 = 0xB6,
  1111. /// <summary>
  1112. /// Start Application 2 key
  1113. /// </summary>
  1114. LAUNCH_APP2 = 0xB7,
  1115. /// <summary>
  1116. /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ';:' key
  1117. /// </summary>
  1118. OEM_1 = 0xBA,
  1119. /// <summary>
  1120. /// For any country/region, the '+' key
  1121. /// </summary>
  1122. OEM_PLUS = 0xBB,
  1123. /// <summary>
  1124. /// For any country/region, the ',' key
  1125. /// </summary>
  1126. OEM_COMMA = 0xBC,
  1127. /// <summary>
  1128. /// For any country/region, the '-' key
  1129. /// </summary>
  1130. OEM_MINUS = 0xBD,
  1131. /// <summary>
  1132. /// For any country/region, the '.' key
  1133. /// </summary>
  1134. OEM_PERIOD = 0xBE,
  1135. /// <summary>
  1136. /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '/?' key
  1137. /// </summary>
  1138. OEM_2 = 0xBF,
  1139. /// <summary>
  1140. /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '`~' key
  1141. /// </summary>
  1142. OEM_3 = 0xC0,
  1143. /// <summary>
  1144. /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '[{' key
  1145. /// </summary>
  1146. OEM_4 = 0xDB,
  1147. /// <summary>
  1148. /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '\|' key
  1149. /// </summary>
  1150. OEM_5 = 0xDC,
  1151. /// <summary>
  1152. /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ']}' key
  1153. /// </summary>
  1154. OEM_6 = 0xDD,
  1155. /// <summary>
  1156. /// Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the 'single-quote/double-quote' key
  1157. /// </summary>
  1158. OEM_7 = 0xDE,
  1159. /// <summary>
  1160. /// Used for miscellaneous characters; it can vary by keyboard.
  1161. /// </summary>
  1162. OEM_8 = 0xDF,
  1163. /// <summary>
  1164. /// 'AX' key on Japanese AX kbd
  1165. /// </summary>
  1166. OEM_AX = 0xE1,
  1167. /// <summary>
  1168. /// Either the angle bracket key or the backslash key on the RT 102-key keyboard
  1169. /// </summary>
  1170. OEM_102 = 0xE2,
  1171. /// <summary>
  1172. /// Help key on ICO
  1173. /// </summary>
  1174. ICO_HELP = 0xE3,
  1175. /// <summary>
  1176. /// 00 key on ICO
  1177. /// </summary>
  1178. ICO_00 = 0xE4,
  1179. /// <summary>
  1180. /// Process key
  1181. /// </summary>
  1182. PROCESSKEY = 0xE5,
  1183. /// <summary>
  1184. /// Clear key on ICO
  1185. /// </summary>
  1186. ICO_CLEAR = 0xE6,
  1187. /// <summary>
  1188. /// Packet key to be used to pass Unicode characters as if they were keystrokes
  1189. /// </summary>
  1190. PACKET = 0xE7,
  1191. /// <summary>
  1192. /// Reset key
  1193. /// </summary>
  1194. OEM_RESET = 0xE9,
  1195. /// <summary>
  1196. /// Jump key
  1197. /// </summary>
  1198. OEM_JUMP = 0xEA,
  1199. /// <summary>
  1200. /// PA1 key
  1201. /// </summary>
  1202. OEM_PA1 = 0xEB,
  1203. /// <summary>
  1204. /// PA2 key
  1205. /// </summary>
  1206. OEM_PA2 = 0xEC,
  1207. /// <summary>
  1208. /// PA3 key
  1209. /// </summary>
  1210. OEM_PA3 = 0xED,
  1211. /// <summary>
  1212. /// WsCtrl key
  1213. /// </summary>
  1214. OEM_WSCTRL = 0xEE,
  1215. /// <summary>
  1216. /// CuSel key
  1217. /// </summary>
  1218. OEM_CUSEL = 0xEF,
  1219. /// <summary>
  1220. /// Attn key
  1221. /// </summary>
  1222. OEM_ATTN = 0xF0,
  1223. /// <summary>
  1224. /// Finish key
  1225. /// </summary>
  1226. OEM_FINISH = 0xF1,
  1227. /// <summary>
  1228. /// Copy key
  1229. /// </summary>
  1230. OEM_COPY = 0xF2,
  1231. /// <summary>
  1232. /// Auto key
  1233. /// </summary>
  1234. OEM_AUTO = 0xF3,
  1235. /// <summary>
  1236. /// Enlw key
  1237. /// </summary>
  1238. OEM_ENLW = 0xF4,
  1239. /// <summary>
  1240. /// BackTab key
  1241. /// </summary>
  1242. OEM_BACKTAB = 0xF5,
  1243. /// <summary>
  1244. /// Attn key
  1245. /// </summary>
  1246. ATTN = 0xF6,
  1247. /// <summary>
  1248. /// CrSel key
  1249. /// </summary>
  1250. CRSEL = 0xF7,
  1251. /// <summary>
  1252. /// ExSel key
  1253. /// </summary>
  1254. EXSEL = 0xF8,
  1255. /// <summary>
  1256. /// Erase EOF key
  1257. /// </summary>
  1258. EREOF = 0xF9,
  1259. /// <summary>
  1260. /// Play key
  1261. /// </summary>
  1262. PLAY = 0xFA,
  1263. /// <summary>
  1264. /// Zoom key
  1265. /// </summary>
  1266. ZOOM = 0xFB,
  1267. /// <summary>
  1268. /// Reserved
  1269. /// </summary>
  1270. NONAME = 0xFC,
  1271. /// <summary>
  1272. /// PA1 key
  1273. /// </summary>
  1274. PA1 = 0xFD,
  1275. /// <summary>
  1276. /// Clear key
  1277. /// </summary>
  1278. OEM_CLEAR = 0xFE
  1279. }
  1280. // BUGBUG: This database makes no sense. It is not possible to map a VK code to a character without knowing the keyboard layout
  1281. // It should be deleted.
  1282. static HashSet<ScanCodeMapping> _scanCodes = new HashSet<ScanCodeMapping> {
  1283. new (1, VK.ESCAPE, 0, '\u001B'), // Escape
  1284. new (1, VK.ESCAPE, ConsoleModifiers.Shift, '\u001B'),
  1285. new (2, (VK)'1', 0, '1'), // D1
  1286. new (2, (VK)'1', ConsoleModifiers.Shift, '!'),
  1287. new (3, (VK)'2', 0, '2'), // D2
  1288. new (3, (VK)'2', ConsoleModifiers.Shift, '\"'), // BUGBUG: This is true for Portugese keyboard, but not ENG (@) or DEU (")
  1289. new (3, (VK)'2', ConsoleModifiers.Alt | ConsoleModifiers.Control, '@'),
  1290. new (4, (VK)'3', 0, '3'), // D3
  1291. new (4, (VK)'3', ConsoleModifiers.Shift, '#'),
  1292. new (4, (VK)'3', ConsoleModifiers.Alt | ConsoleModifiers.Control, '£'),
  1293. new (5, (VK)'4', 0, '4'), // D4
  1294. new (5, (VK)'4', ConsoleModifiers.Shift, '$'),
  1295. new (5, (VK)'4', ConsoleModifiers.Alt | ConsoleModifiers.Control, '§'),
  1296. new (6, (VK)'5', 0, '5'), // D5
  1297. new (6, (VK)'5', ConsoleModifiers.Shift, '%'),
  1298. new (6, (VK)'5', ConsoleModifiers.Alt | ConsoleModifiers.Control, '€'),
  1299. new (7, (VK)'6', 0, '6'), // D6
  1300. new (7, (VK)'6', ConsoleModifiers.Shift, '&'),
  1301. new (8, (VK)'7', 0, '7'), // D7
  1302. new (8, (VK)'7', ConsoleModifiers.Shift, '/'),
  1303. new (8, (VK)'7', ConsoleModifiers.Alt | ConsoleModifiers.Control, '{'),
  1304. new (9, (VK)'8', 0, '8'), // D8
  1305. new (9, (VK)'8', ConsoleModifiers.Shift, '('),
  1306. new (9, (VK)'8', ConsoleModifiers.Alt | ConsoleModifiers.Control, '['),
  1307. new (10, (VK)'9', 0, '9'), // D9
  1308. new (10, (VK)'9', ConsoleModifiers.Shift, ')'),
  1309. new (10, (VK)'9', ConsoleModifiers.Alt | ConsoleModifiers.Control, ']'),
  1310. new (11, (VK)'0', 0, '0'), // D0
  1311. new (11, (VK)'0', ConsoleModifiers.Shift, '='),
  1312. new (11, (VK)'0', ConsoleModifiers.Alt | ConsoleModifiers.Control, '}'),
  1313. new (12, VK.OEM_4, 0, '\''), // Oem4
  1314. new (12, VK.OEM_4, ConsoleModifiers.Shift, '?'),
  1315. new (13, VK.OEM_6, 0, '+'), // Oem6
  1316. new (13, VK.OEM_6, ConsoleModifiers.Shift, '*'),
  1317. new (14, VK.BACK, 0, '\u0008'), // Backspace
  1318. new (14, VK.BACK, ConsoleModifiers.Shift, '\u0008'),
  1319. new (15, VK.TAB, 0, '\u0009'), // Tab
  1320. new (15, VK.TAB, ConsoleModifiers.Shift, '\u000F'),
  1321. new (16, (VK)'Q', 0, 'q'), // Q
  1322. new (16, (VK)'Q', ConsoleModifiers.Shift, 'Q'),
  1323. new (17, (VK)'W', 0, 'w'), // W
  1324. new (17, (VK)'W', ConsoleModifiers.Shift, 'W'),
  1325. new (18, (VK)'E', 0, 'e'), // E
  1326. new (18, (VK)'E', ConsoleModifiers.Shift, 'E'),
  1327. new (19, (VK)'R', 0, 'r'), // R
  1328. new (19, (VK)'R', ConsoleModifiers.Shift, 'R'),
  1329. new (20, (VK)'T', 0, 't'), // T
  1330. new (20, (VK)'T', ConsoleModifiers.Shift, 'T'),
  1331. new (21, (VK)'Y', 0, 'y'), // Y
  1332. new (21, (VK)'Y', ConsoleModifiers.Shift, 'Y'),
  1333. new (22, (VK)'U', 0, 'u'), // U
  1334. new (22, (VK)'U', ConsoleModifiers.Shift, 'U'),
  1335. new (23, (VK)'I', 0, 'i'), // I
  1336. new (23, (VK)'I', ConsoleModifiers.Shift, 'I'),
  1337. new (24, (VK)'O', 0, 'o'), // O
  1338. new (24, (VK)'O', ConsoleModifiers.Shift, 'O'),
  1339. new (25, (VK)'P', 0, 'p'), // P
  1340. new (25, (VK)'P', ConsoleModifiers.Shift, 'P'),
  1341. new (26, VK.OEM_PLUS, 0, '+'), // OemPlus
  1342. new (26, VK.OEM_PLUS, ConsoleModifiers.Shift, '*'),
  1343. new (26, VK.OEM_PLUS, ConsoleModifiers.Alt | ConsoleModifiers.Control, '¨'),
  1344. new (27, VK.OEM_1, 0, '´'), // Oem1
  1345. new (27, VK.OEM_1, ConsoleModifiers.Shift, '`'),
  1346. new (28, VK.RETURN, 0, '\u000D'), // Enter
  1347. new (28, VK.RETURN, ConsoleModifiers.Shift, '\u000D'),
  1348. new (29, VK.CONTROL, 0, '\0'), // Control
  1349. new (29, VK.CONTROL, ConsoleModifiers.Shift, '\0'),
  1350. new (30, (VK)'A', 0, 'a'), // A
  1351. new (30, (VK)'A', ConsoleModifiers.Shift, 'A'),
  1352. new (31, (VK)'S', 0, 's'), // S
  1353. new (31, (VK)'S', ConsoleModifiers.Shift, 'S'),
  1354. new (32, (VK)'D', 0, 'd'), // D
  1355. new (32, (VK)'D', ConsoleModifiers.Shift, 'D'),
  1356. new (33, (VK)'F', 0, 'f'), // F
  1357. new (33, (VK)'F', ConsoleModifiers.Shift, 'F'),
  1358. new (34, (VK)'G', 0, 'g'), // G
  1359. new (34, (VK)'G', ConsoleModifiers.Shift, 'G'),
  1360. new (35, (VK)'H', 0, 'h'), // H
  1361. new (35, (VK)'H', ConsoleModifiers.Shift, 'H'),
  1362. new (36, (VK)'J', 0, 'j'), // J
  1363. new (36, (VK)'J', ConsoleModifiers.Shift, 'J'),
  1364. new (37, (VK)'K', 0, 'k'), // K
  1365. new (37, (VK)'K', ConsoleModifiers.Shift, 'K'),
  1366. new (38, (VK)'L', 0, 'l'), // L
  1367. new (38, (VK)'L', ConsoleModifiers.Shift, 'L'),
  1368. new (39, VK.OEM_3, 0, '`'), // Oem3 (Backtick/Grave)
  1369. new (39, VK.OEM_3, ConsoleModifiers.Shift, '~'),
  1370. new (40, VK.OEM_7, 0, '\''), // Oem7 (Single Quote)
  1371. new (40, VK.OEM_7, ConsoleModifiers.Shift, '\"'),
  1372. new (41, VK.OEM_5, 0, '\\'), // Oem5 (Backslash)
  1373. new (41, VK.OEM_5, ConsoleModifiers.Shift, '|'),
  1374. new (42, VK.LSHIFT, 0, '\0'), // Left Shift
  1375. new (42, VK.LSHIFT, ConsoleModifiers.Shift, '\0'),
  1376. new (43, VK.OEM_2, 0, '/'), // Oem2 (Forward Slash)
  1377. new (43, VK.OEM_2, ConsoleModifiers.Shift, '?'),
  1378. new (44, (VK)'Z', 0, 'z'), // Z
  1379. new (44, (VK)'Z', ConsoleModifiers.Shift, 'Z'),
  1380. new (45, (VK)'X', 0, 'x'), // X
  1381. new (45, (VK)'X', ConsoleModifiers.Shift, 'X'),
  1382. new (46, (VK)'C', 0, 'c'), // C
  1383. new (46, (VK)'C', ConsoleModifiers.Shift, 'C'),
  1384. new (47, (VK)'V', 0, 'v'), // V
  1385. new (47, (VK)'V', ConsoleModifiers.Shift, 'V'),
  1386. new (48, (VK)'B', 0, 'b'), // B
  1387. new (48, (VK)'B', ConsoleModifiers.Shift, 'B'),
  1388. new (49, (VK)'N', 0, 'n'), // N
  1389. new (49, (VK)'N', ConsoleModifiers.Shift, 'N'),
  1390. new (50, (VK)'M', 0, 'm'), // M
  1391. new (50, (VK)'M', ConsoleModifiers.Shift, 'M'),
  1392. new (51, VK.OEM_COMMA, 0, ','), // OemComma
  1393. new (51, VK.OEM_COMMA, ConsoleModifiers.Shift, '<'),
  1394. new (52, VK.OEM_PERIOD, 0, '.'), // OemPeriod
  1395. new (52, VK.OEM_PERIOD, ConsoleModifiers.Shift, '>'),
  1396. new (53, VK.OEM_MINUS, 0, '-'), // OemMinus
  1397. new (53, VK.OEM_MINUS, ConsoleModifiers.Shift, '_'),
  1398. new (54, VK.RSHIFT, 0, '\0'), // Right Shift
  1399. new (54, VK.RSHIFT, ConsoleModifiers.Shift, '\0'),
  1400. new (55, VK.PRINT, 0, '\0'), // Print Screen
  1401. new (55, VK.PRINT, ConsoleModifiers.Shift, '\0'),
  1402. new (56, VK.LMENU, 0, '\0'), // Alt
  1403. new (56, VK.LMENU, ConsoleModifiers.Shift, '\0'),
  1404. new (57, VK.SPACE, 0, ' '), // Spacebar
  1405. new (57, VK.SPACE, ConsoleModifiers.Shift, ' '),
  1406. new (58, VK.CAPITAL, 0, '\0'), // Caps Lock
  1407. new (58, VK.CAPITAL, ConsoleModifiers.Shift, '\0'),
  1408. new (59, VK.F1, 0, '\0'), // F1
  1409. new (59, VK.F1, ConsoleModifiers.Shift, '\0'),
  1410. new (60, VK.F2, 0, '\0'), // F2
  1411. new (60, VK.F2, ConsoleModifiers.Shift, '\0'),
  1412. new (61, VK.F3, 0, '\0'), // F3
  1413. new (61, VK.F3, ConsoleModifiers.Shift, '\0'),
  1414. new (62, VK.F4, 0, '\0'), // F4
  1415. new (62, VK.F4, ConsoleModifiers.Shift, '\0'),
  1416. new (63, VK.F5, 0, '\0'), // F5
  1417. new (63, VK.F5, ConsoleModifiers.Shift, '\0'),
  1418. new (64, VK.F6, 0, '\0'), // F6
  1419. new (64, VK.F6, ConsoleModifiers.Shift, '\0'),
  1420. new (65, VK.F7, 0, '\0'), // F7
  1421. new (65, VK.F7, ConsoleModifiers.Shift, '\0'),
  1422. new (66, VK.F8, 0, '\0'), // F8
  1423. new (66, VK.F8, ConsoleModifiers.Shift, '\0'),
  1424. new (67, VK.F9, 0, '\0'), // F9
  1425. new (67, VK.F9, ConsoleModifiers.Shift, '\0'),
  1426. new (68, VK.F10, 0, '\0'), // F10
  1427. new (68, VK.F10, ConsoleModifiers.Shift, '\0'),
  1428. new (69, VK.NUMLOCK, 0, '\0'), // Num Lock
  1429. new (69, VK.NUMLOCK, ConsoleModifiers.Shift, '\0'),
  1430. new (70, VK.SCROLL, 0, '\0'), // Scroll Lock
  1431. new (70, VK.SCROLL, ConsoleModifiers.Shift, '\0'),
  1432. new (71, VK.HOME, 0, '\0'), // Home
  1433. new (71, VK.HOME, ConsoleModifiers.Shift, '\0'),
  1434. new (72, VK.UP, 0, '\0'), // Up Arrow
  1435. new (72, VK.UP, ConsoleModifiers.Shift, '\0'),
  1436. new (73, VK.PRIOR, 0, '\0'), // Page Up
  1437. new (73, VK.PRIOR, ConsoleModifiers.Shift, '\0'),
  1438. new (74, VK.SUBTRACT, 0, '-'), // Subtract (Num Pad '-')
  1439. new (74, VK.SUBTRACT, ConsoleModifiers.Shift, '-'),
  1440. new (75, VK.LEFT, 0, '\0'), // Left Arrow
  1441. new (75, VK.LEFT, ConsoleModifiers.Shift, '\0'),
  1442. new (76, VK.CLEAR, 0, '\0'), // Center key (Num Pad 5 with Num Lock off)
  1443. new (76, VK.CLEAR, ConsoleModifiers.Shift, '\0'),
  1444. new (77, VK.RIGHT, 0, '\0'), // Right Arrow
  1445. new (77, VK.RIGHT, ConsoleModifiers.Shift, '\0'),
  1446. new (78, VK.ADD, 0, '+'), // Add (Num Pad '+')
  1447. new (78, VK.ADD, ConsoleModifiers.Shift, '+'),
  1448. new (79, VK.END, 0, '\0'), // End
  1449. new (79, VK.END, ConsoleModifiers.Shift, '\0'),
  1450. new (80, VK.DOWN, 0, '\0'), // Down Arrow
  1451. new (80, VK.DOWN, ConsoleModifiers.Shift, '\0'),
  1452. new (81, VK.NEXT, 0, '\0'), // Page Down
  1453. new (81, VK.NEXT, ConsoleModifiers.Shift, '\0'),
  1454. new (82, VK.INSERT, 0, '\0'), // Insert
  1455. new (82, VK.INSERT, ConsoleModifiers.Shift, '\0'),
  1456. new (83, VK.DELETE, 0, '\0'), // Delete
  1457. new (83, VK.DELETE, ConsoleModifiers.Shift, '\0'),
  1458. new (86, VK.OEM_102, 0, '<'), // OEM 102 (Typically '<' or '|' key next to Left Shift)
  1459. new (86, VK.OEM_102, ConsoleModifiers.Shift, '>'),
  1460. new (87, VK.F11, 0, '\0'), // F11
  1461. new (87, VK.F11, ConsoleModifiers.Shift, '\0'),
  1462. new (88, VK.F12, 0, '\0'), // F12
  1463. new (88, VK.F12, ConsoleModifiers.Shift, '\0')
  1464. };
  1465. /// <summary>
  1466. /// Decode a <see cref="ConsoleKeyInfo"/> that is using <see cref="ConsoleKey.Packet"/>.
  1467. /// </summary>
  1468. /// <param name="consoleKeyInfo">The console key info.</param>
  1469. /// <returns>The decoded <see cref="ConsoleKeyInfo"/> or the <paramref name="consoleKeyInfo"/>.</returns>
  1470. /// <remarks>If it's a <see cref="ConsoleKey.Packet"/> the <see cref="ConsoleKeyInfo.KeyChar"/> may be
  1471. /// a <see cref="ConsoleKeyInfo.Key"/> or a <see cref="ConsoleKeyInfo.KeyChar"/> value.
  1472. /// </remarks>
  1473. public static ConsoleKeyInfo DecodeVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
  1474. {
  1475. if (consoleKeyInfo.Key != ConsoleKey.Packet) {
  1476. return consoleKeyInfo;
  1477. }
  1478. return GetConsoleKeyInfoFromKeyChar (consoleKeyInfo.KeyChar, consoleKeyInfo.Modifiers, out _);
  1479. }
  1480. /// <summary>
  1481. /// Encode the <see cref="ConsoleKeyInfo.KeyChar"/> with the <see cref="ConsoleKeyInfo.Key"/>
  1482. /// if the first a byte length, otherwise only the KeyChar is considered and searched on the database.
  1483. /// </summary>
  1484. /// <param name="consoleKeyInfo">The console key info.</param>
  1485. /// <returns>The encoded KeyChar with the Key if both can be shifted, otherwise only the KeyChar.</returns>
  1486. /// <remarks>This is useful to use with the <see cref="ConsoleKey.Packet"/>.</remarks>
  1487. public static char EncodeKeyCharForVKPacket (ConsoleKeyInfo consoleKeyInfo)
  1488. {
  1489. char keyChar = consoleKeyInfo.KeyChar;
  1490. ConsoleKey consoleKey = consoleKeyInfo.Key;
  1491. if (keyChar != 0 && consoleKeyInfo.KeyChar < byte.MaxValue && consoleKey == ConsoleKey.None) {
  1492. // try to get the ConsoleKey
  1493. var scode = _scanCodes.FirstOrDefault ((e) => e.UnicodeChar == keyChar);
  1494. if (scode != null) {
  1495. consoleKey = (ConsoleKey)scode.VirtualKey;
  1496. }
  1497. }
  1498. if (keyChar < byte.MaxValue && consoleKey != ConsoleKey.None) {
  1499. keyChar = (char)(consoleKeyInfo.KeyChar << 8 | (byte)consoleKey);
  1500. }
  1501. return keyChar;
  1502. }
  1503. }