Skip to content

Commit 64ff1b8

Browse files
committed
Reset console mode for calls to external code
For an unknown reason - SetConsoleMode calls fail when setting certain modes. One such case is when PowerShell calls SetConsoleMode in it's implementation of PSHostRawUserInterface.ReadKey. PowerTab calls this method - and it's possible that other custom key handlers might want to use that api, so I will reset the console mode to what it was before calling PSReadline for the duration of the external code (tab completion or custom handlers) and reset it when the external code completes. Fixes #125.
1 parent 0643245 commit 64ff1b8

File tree

3 files changed

+37
-8
lines changed

3 files changed

+37
-8
lines changed

PSReadLine/Completion.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ public partial class PSConsoleReadLine
2222
[ExcludeFromCodeCoverage]
2323
CommandCompletion IPSConsoleReadLineMockableMethods.CompleteInput(string input, int cursorIndex, Hashtable options, PowerShell powershell)
2424
{
25-
return CommandCompletion.CompleteInput(input, cursorIndex, options, powershell);
25+
return CalloutUsingDefaultConsoleMode(
26+
() => CommandCompletion.CompleteInput(input, cursorIndex, options, powershell));
2627
}
2728

2829
/// <summary>

PSReadLine/Options.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ private void SetKeyHandlerInternal(string[] keys, Action<ConsoleKeyInfo?, object
163163
var chord = ConsoleKeyChordConverter.Convert(key);
164164
if (chord.Length == 1)
165165
{
166-
_dispatchTable[chord[0]] = MakeKeyHandler(handler, briefDescription, longDescription);
166+
_dispatchTable[chord[0]] = MakeKeyHandler(handler, briefDescription, longDescription, scriptBlock);
167167
}
168168
else
169169
{
@@ -174,7 +174,7 @@ private void SetKeyHandlerInternal(string[] keys, Action<ConsoleKeyInfo?, object
174174
secondDispatchTable = new Dictionary<ConsoleKeyInfo, KeyHandler>();
175175
_chordDispatchTable[chord[0]] = secondDispatchTable;
176176
}
177-
secondDispatchTable[chord[1]] = MakeKeyHandler(handler, briefDescription, longDescription);
177+
secondDispatchTable[chord[1]] = MakeKeyHandler(handler, briefDescription, longDescription, scriptBlock);
178178
}
179179
}
180180
}

PSReadLine/ReadLine.cs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public partial class PSConsoleReadLine : IPSConsoleReadLineMockableMethods
2828
private WaitHandle[] _waitHandles;
2929
private bool _captureKeys;
3030
private readonly Queue<ConsoleKeyInfo> _savedKeys;
31+
private uint _prePSReadlineConsoleMode;
3132

3233
private readonly StringBuilder _buffer;
3334
private readonly StringBuilder _statusBuffer;
@@ -211,16 +212,15 @@ private bool BreakHandler(ConsoleBreakSignal signal)
211212
/// <returns>The complete command line.</returns>
212213
public static string ReadLine(Runspace remoteRunspace = null)
213214
{
214-
uint dwConsoleMode;
215215
var handle = NativeMethods.GetStdHandle((uint) StandardHandleId.Input);
216-
NativeMethods.GetConsoleMode(handle, out dwConsoleMode);
216+
NativeMethods.GetConsoleMode(handle, out _singleton._prePSReadlineConsoleMode);
217217
try
218218
{
219219
// Clear a couple flags so we can actually receive certain keys:
220220
// ENABLE_PROCESSED_INPUT - enables Ctrl+C
221221
// ENABLE_LINE_INPUT - enables Ctrl+S
222222
NativeMethods.SetConsoleMode(handle,
223-
dwConsoleMode & ~(NativeMethods.ENABLE_PROCESSED_INPUT | NativeMethods.ENABLE_LINE_INPUT));
223+
_singleton._prePSReadlineConsoleMode & ~(NativeMethods.ENABLE_PROCESSED_INPUT | NativeMethods.ENABLE_LINE_INPUT));
224224

225225
_singleton.Initialize(remoteRunspace);
226226
return _singleton.InputLoop();
@@ -265,7 +265,7 @@ public static string ReadLine(Runspace remoteRunspace = null)
265265
}
266266
finally
267267
{
268-
NativeMethods.SetConsoleMode(handle, dwConsoleMode);
268+
NativeMethods.SetConsoleMode(handle, _singleton._prePSReadlineConsoleMode);
269269
}
270270
}
271271

@@ -343,6 +343,27 @@ private string InputLoop()
343343
}
344344
}
345345

346+
T CalloutUsingDefaultConsoleMode<T>(Func<T> func)
347+
{
348+
var handle = NativeMethods.GetStdHandle((uint) StandardHandleId.Input);
349+
uint psReadlineConsoleMode;
350+
NativeMethods.GetConsoleMode(handle, out psReadlineConsoleMode);
351+
try
352+
{
353+
NativeMethods.SetConsoleMode(handle, _prePSReadlineConsoleMode);
354+
return func();
355+
}
356+
finally
357+
{
358+
NativeMethods.SetConsoleMode(handle, psReadlineConsoleMode);
359+
}
360+
}
361+
362+
void CalloutUsingDefaultConsoleMode(Action action)
363+
{
364+
CalloutUsingDefaultConsoleMode<object>(() => { action(); return null; });
365+
}
366+
346367
void ProcessOneKey(ConsoleKeyInfo key, Dictionary<ConsoleKeyInfo, KeyHandler> dispatchTable, bool ignoreIfNoAction, object arg)
347368
{
348369
KeyHandler handler;
@@ -360,7 +381,14 @@ void ProcessOneKey(ConsoleKeyInfo key, Dictionary<ConsoleKeyInfo, KeyHandler> di
360381
{
361382
_renderForDemoNeeded = _demoMode;
362383

363-
handler.Action(key, arg);
384+
if (handler.ScriptBlock != null)
385+
{
386+
CalloutUsingDefaultConsoleMode(() => handler.Action(key, arg));
387+
}
388+
else
389+
{
390+
handler.Action(key, arg);
391+
}
364392

365393
if (_renderForDemoNeeded)
366394
{

0 commit comments

Comments
 (0)