Enable PSReadline to work on NanoServer (#3815)

NanoServer is missing some console APIs that PSReadline uses which causes PSReadline to not be usable on NanoServer docker images.

For the missing font/display APIs, the fix is to assume all characters use 1 cell which is not always correct for some languages.

For the missing keymap APIs - there is no workaround in this change and a small number of key bindings don't work, there is an open issue to track those.

Fixes #3463
This commit is contained in:
Steve Lee 2017-05-31 10:26:41 -07:00 committed by Jason Shirk
parent 51d4a45e3c
commit ee45650660
2 changed files with 42 additions and 11 deletions

View file

@ -1,4 +1,4 @@
/********************************************************************++
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
@ -231,7 +231,6 @@ namespace Microsoft.PowerShell
return valid;
}
#if UNIX
// this is borrowed from the CoreFX internal System.IO.StdInReader class
// https://github.com/dotnet/corefx/blob/5b2ae6aa485773cd5569f56f446698633c9ad945/src/System.Console/src/System/IO/StdInReader.cs#L222
private static ConsoleKey GetKeyFromCharValue(char x, out bool isShift, out bool isCtrl)
@ -303,7 +302,8 @@ namespace Microsoft.PowerShell
return default(ConsoleKey);
}
#else
#if !UNIX
internal static char GetCharFromConsoleKey(ConsoleKey key, ConsoleModifiers modifiers)
{
// default for unprintables and unhandled

View file

@ -1,4 +1,4 @@
/********************************************************************++
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
@ -370,6 +370,23 @@ namespace Microsoft.PowerShell.Internal
internal static class ConsoleKeyInfoExtension
{
#if !UNIX
private static bool _toUnicodeApiAvailable = true;
static ConsoleKeyInfoExtension()
{
try
{
var chars = new char[2];
NativeMethods.ToUnicode(13, 28, null, chars, chars.Length, 0);
}
catch (System.EntryPointNotFoundException)
{
_toUnicodeApiAvailable = false; // api not available on NanoServer
}
}
#endif
public static string ToGestureString(this ConsoleKeyInfo key)
{
var mods = key.Modifiers;
@ -386,13 +403,16 @@ 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);
#if !UNIX
if (_toUnicodeApiAvailable)
{
// Windows cannot use KeyChar as some chords (like Ctrl+[) show up as control characters.
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))
@ -426,6 +446,7 @@ namespace Microsoft.PowerShell.Internal
private bool _istmInitialized = false;
private TEXTMETRIC _tm = new TEXTMETRIC();
private bool _trueTypeInUse = false;
private static bool _getCurrentConsoleFontExApiAvailable = true;
private readonly Lazy<SafeFileHandle> _outputHandle = new Lazy<SafeFileHandle>(() =>
{
@ -691,7 +712,18 @@ namespace Microsoft.PowerShell.Internal
CONSOLE_FONT_INFO_EX fontInfo = new CONSOLE_FONT_INFO_EX();
fontInfo.cbSize = Marshal.SizeOf(fontInfo);
bool result = NativeMethods.GetCurrentConsoleFontEx(consoleHandle.DangerousGetHandle(), false, ref fontInfo);
bool result = true;
if (_getCurrentConsoleFontExApiAvailable)
{
try
{
result = NativeMethods.GetCurrentConsoleFontEx(consoleHandle.DangerousGetHandle(), false, ref fontInfo);
}
catch (System.EntryPointNotFoundException)
{
_getCurrentConsoleFontExApiAvailable = false; // api not available on NanoServer
}
}
if (result == false)
{
@ -865,7 +897,6 @@ namespace Microsoft.PowerShell.Internal
CONSOLE_FONT_INFO_EX fontInfo = ConhostConsole.GetConsoleFontInfo(consoleHandle);
int fontType = fontInfo.FontFamily & NativeMethods.FontTypeMask;
_trueTypeInUse = (fontType & NativeMethods.TrueTypeFont) == NativeMethods.TrueTypeFont;
}
public void EndRender()