Use GetCharFromConsoleKey on Windows

Due to virtual key codes on Windows, simple chords like Ctrl+] are not
recognized as such. Instead, the ConsoleKey is Oem6, and the KeyChar is
an control code.
This commit is contained in:
Andrew Schwartzmeyer 2016-07-20 11:30:22 -07:00
parent d5b339fb5d
commit 554ef0b780
2 changed files with 36 additions and 3 deletions

View file

@ -6,9 +6,6 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
#if UNIX
using System.Reflection;
#endif
using System.Runtime.InteropServices;
using Microsoft.PowerShell.Internal;
@ -306,6 +303,36 @@ namespace Microsoft.PowerShell
return default(ConsoleKey);
}
#else
internal static char GetCharFromConsoleKey(ConsoleKey key, ConsoleModifiers modifiers)
{
// default for unprintables and unhandled
char keyChar = '\u0000';
// emulate GetKeyboardState bitmap - set high order bit for relevant modifier virtual keys
var state = new byte[256];
state[NativeMethods.VK_SHIFT] = (byte)(((modifiers & ConsoleModifiers.Shift) != 0) ? 0x80 : 0);
state[NativeMethods.VK_CONTROL] = (byte)(((modifiers & ConsoleModifiers.Control) != 0) ? 0x80 : 0);
state[NativeMethods.VK_ALT] = (byte)(((modifiers & ConsoleModifiers.Alt) != 0) ? 0x80 : 0);
// a ConsoleKey enum's value is a virtual key code
uint virtualKey = (uint)key;
// get corresponding scan code
uint scanCode = NativeMethods.MapVirtualKey(virtualKey, NativeMethods.MAPVK_VK_TO_VSC);
// get corresponding character - maybe be 0, 1 or 2 in length (diacriticals)
var chars = new char[2];
int charCount = NativeMethods.ToUnicode(
virtualKey, scanCode, state, chars, chars.Length, NativeMethods.MENU_IS_INACTIVE);
// TODO: support diacriticals (charCount == 2)
if (charCount == 1)
{
keyChar = chars[0];
}
return keyChar;
}
#endif
}
}

View file

@ -386,7 +386,13 @@ namespace Microsoft.PowerShell.Internal
sb.Append("Alt");
}
#if UNIX
char c = key.KeyChar;
#else
// Windows cannot use KeyChar as some chords (like Ctrl+[) show up as control characters.
char c = ConsoleKeyChordConverter.GetCharFromConsoleKey(key.Key,
(mods & ConsoleModifiers.Shift) != 0 ? ConsoleModifiers.Shift : 0);
#endif
if (char.IsControl(c) || char.IsWhiteSpace(c))
{
if (key.Modifiers.HasFlag(ConsoleModifiers.Shift))