diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs
index 8dbf99f24..2c8b6c090 100644
--- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs
+++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs
@@ -251,6 +251,10 @@ namespace Microsoft.PowerShell
/// It also manages the cursor as keys are entered and "backspaced". However, it is possible that
/// while this method is running, the console buffer contents could change. Then, its cursor mgmt
/// will likely be messed up.
+ ///
+ /// Secondary implementation for Unix based on Console.ReadKey(), where
+ /// the advantage is portability through abstraction. Does not support
+ /// arrow key movement, but supports backspace.
///
///
///
@@ -285,9 +289,6 @@ namespace Microsoft.PowerShell
private object ReadLineSafe(bool isSecureString, char? printToken)
{
-#if LINUX
- throw new PlatformNotSupportedException("Cannot read secure strings!");
-#else
// Don't lock (instanceLock) in here -- the caller needs to do that...
PreRead();
@@ -296,13 +297,21 @@ namespace Microsoft.PowerShell
null;
SecureString secureResult = new SecureString();
StringBuilder result = new StringBuilder();
+#if LINUX
+ bool treatControlCAsInput = Console.TreatControlCAsInput;
+#endif
ConsoleHandle handle = ConsoleControl.GetConioDeviceHandle();
ConsoleControl.ConsoleModes originalMode = ConsoleControl.GetMode(handle);
bool isModeChanged = true; // assume ConsoleMode is changed so that if ReadLineSetMode
// fails to return the value correctly, the original mode is
// restored.
+#endif
+
try
{
+#if LINUX
+ Console.TreatControlCAsInput = true;
+#else
// Ensure that we're in the proper line-input mode.
ConsoleControl.ConsoleModes desiredMode =
@@ -329,6 +338,7 @@ namespace Microsoft.PowerShell
isModeChanged = false;
}
rawui.ClearKeyCache();
+#endif
Coordinates originalCursorPos = rawui.CursorPosition;
@@ -339,22 +349,40 @@ namespace Microsoft.PowerShell
// end up having a immutable string holding the
// secret in memory.
//
+#if LINUX
+ ConsoleKeyInfo keyInfo = Console.ReadKey(true);
+#else
uint unused = 0;
string key = ConsoleControl.ReadConsole(handle, string.Empty, 1, false, out unused);
+#endif
+#if LINUX
+ // Handle Ctrl-C and Ctrl-D ending input
+ if ((keyInfo.Key == ConsoleKey.C || keyInfo.Key == ConsoleKey.D)
+ && keyInfo.Modifiers.HasFlag(ConsoleModifiers.Control))
+#else
if (string.IsNullOrEmpty(key) || (char)3 == key[0])
+#endif
{
PipelineStoppedException e = new PipelineStoppedException();
throw e;
}
+#if LINUX
+ if (keyInfo.Key == ConsoleKey.Enter)
+#else
if ((char)13 == key[0])
+#endif
{
//
// we are done if user presses ENTER key
//
break;
}
+#if LINUX
+ if (keyInfo.Key == ConsoleKey.Backspace)
+#else
if ((char)8 == key[0])
+#endif
{
//
// for backspace, remove last char appended
@@ -377,11 +405,19 @@ namespace Microsoft.PowerShell
//
if (isSecureString)
{
+#if LINUX
+ secureResult.AppendChar(keyInfo.KeyChar);
+#else
secureResult.AppendChar(key[0]);
+#endif
}
else
{
+#if LINUX
+ result.Append(keyInfo.KeyChar);
+#else
result.Append(key);
+#endif
}
if (!string.IsNullOrEmpty(printTokenString))
{
@@ -391,12 +427,23 @@ namespace Microsoft.PowerShell
}
while (true);
}
+#if LINUX
+ catch (InvalidOperationException)
+ {
+ // ReadKey() failed so we stop
+ throw new PipelineStoppedException();
+ }
+#endif
finally
{
+#if LINUX
+ Console.TreatControlCAsInput = treatControlCAsInput;
+#else
if (isModeChanged)
{
ConsoleControl.SetMode(handle, originalMode);
}
+#endif
}
WriteLineToConsole();
PostRead(result.ToString());
@@ -408,10 +455,8 @@ namespace Microsoft.PowerShell
{
return result;
}
-#endif
}
-#if !LINUX
///
///
@@ -522,7 +567,7 @@ namespace Microsoft.PowerShell
}
-
+#if !LINUX
///
///
/// If is set on , unset it and return true;