in src/NuGet.Clients/NuGet.Console/WpfConsole/WpfConsoleKeyProcessor.cs [155:398]
protected override int InternalExec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
{
ThreadHelper.ThrowIfNotOnUIThread();
int hr = OLECMDERR_E_NOTSUPPORTED;
if (WpfConsole == null
|| WpfConsole.Host == null
|| WpfConsole.Dispatcher == null)
{
return hr;
}
if (!WpfConsole.Host.IsCommandEnabled)
{
return hr;
}
if (!WpfConsole.Dispatcher.IsExecutingReadKey)
{
// if the console has not been successfully started, do not accept any key inputs, unless
// we are in the middle of a ReadKey call. This happens when the execution group policy setting
// is set to AllSigned, and PS is asking user to trust the certificate.
if (!WpfConsole.Dispatcher.IsStartCompleted)
{
return hr;
}
// if the console is in the middle of executing a command, do not accept any key inputs unless
// we are in the middle of a ReadKey call.
if (WpfConsole.Dispatcher.IsExecutingCommand)
{
return hr;
}
}
if (pguidCmdGroup == VSConstants.GUID_VSStandardCommandSet97)
{
//Debug.Print("Exec: GUID_VSStandardCommandSet97: {0}", (VSConstants.VSStd97CmdID)nCmdID);
switch ((VSConstants.VSStd97CmdID)nCmdID)
{
case VSConstants.VSStd97CmdID.Paste:
if (IsCaretInReadOnlyRegion || IsSelectionReadonly)
{
hr = VSConstants.S_OK; // eat it
}
else
{
PasteText(ref hr);
}
break;
}
}
else if (pguidCmdGroup == VSConstants.VSStd2K)
{
//Debug.Print("Exec: VSStd2K: {0}", (VSConstants.VSStd2KCmdID)nCmdID);
var commandID = (VSConstants.VSStd2KCmdID)nCmdID;
if (WpfConsole.Dispatcher.IsExecutingReadKey)
{
switch (commandID)
{
case VSConstants.VSStd2KCmdID.TYPECHAR:
case VSConstants.VSStd2KCmdID.BACKSPACE:
case VSConstants.VSStd2KCmdID.RETURN:
var keyInfo = GetVsKeyInfo(pvaIn, commandID);
WpfConsole.Dispatcher.PostKey(keyInfo);
break;
case VSConstants.VSStd2KCmdID.CANCEL: // Handle ESC
WpfConsole.Dispatcher.CancelWaitKey();
break;
}
hr = VSConstants.S_OK; // eat everything
}
else
{
switch (commandID)
{
case VSConstants.VSStd2KCmdID.TYPECHAR:
if (IsCompletionSessionActive)
{
char ch = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn);
if (IsCommitChar(ch))
{
if (_completionSession.SelectedCompletionSet.SelectionStatus.IsSelected)
{
_completionSession.Commit();
}
else
{
_completionSession.Dismiss();
}
}
}
else
{
if (IsSelectionReadonly)
{
WpfTextView.Selection.Clear();
}
if (IsCaretInReadOnlyRegion)
{
WpfTextView.Caret.MoveTo(WpfConsole.InputLineExtent.End);
}
}
break;
case VSConstants.VSStd2KCmdID.LEFT:
case VSConstants.VSStd2KCmdID.LEFT_EXT:
case VSConstants.VSStd2KCmdID.LEFT_EXT_COL:
case VSConstants.VSStd2KCmdID.WORDPREV:
case VSConstants.VSStd2KCmdID.WORDPREV_EXT:
case VSConstants.VSStd2KCmdID.WORDPREV_EXT_COL:
if (IsCaretAtInputLineStart)
{
//
// Note: This simple implementation depends on Prompt containing a trailing space.
// When caret is on the right of InputLineStart, editor will handle it correctly,
// and caret won't move left to InputLineStart because of the trailing space.
//
hr = VSConstants.S_OK; // eat it
}
break;
case VSConstants.VSStd2KCmdID.BOL:
case VSConstants.VSStd2KCmdID.BOL_EXT:
case VSConstants.VSStd2KCmdID.BOL_EXT_COL:
if (IsCaretOnInputLine)
{
VirtualSnapshotPoint oldCaretPoint = WpfTextView.Caret.Position.VirtualBufferPosition;
WpfTextView.Caret.MoveTo(WpfConsole.InputLineStart.Value);
WpfTextView.Caret.EnsureVisible();
if ((VSConstants.VSStd2KCmdID)nCmdID == VSConstants.VSStd2KCmdID.BOL)
{
WpfTextView.Selection.Clear();
}
else if ((VSConstants.VSStd2KCmdID)nCmdID != VSConstants.VSStd2KCmdID.BOL)
// extend selection
{
VirtualSnapshotPoint anchorPoint = WpfTextView.Selection.IsEmpty
? oldCaretPoint.TranslateTo(
WpfTextView.TextSnapshot)
: WpfTextView.Selection.AnchorPoint;
WpfTextView.Selection.Select(anchorPoint,
WpfTextView.Caret.Position.VirtualBufferPosition);
}
hr = VSConstants.S_OK;
}
break;
case VSConstants.VSStd2KCmdID.UP:
if (!IsCompletionSessionActive)
{
if (IsCaretInReadOnlyRegion)
{
ExecuteCommand(VSConstants.VSStd2KCmdID.END);
}
WpfConsole.NavigateHistory(-1);
hr = VSConstants.S_OK;
}
break;
case VSConstants.VSStd2KCmdID.DOWN:
if (!IsCompletionSessionActive)
{
if (IsCaretInReadOnlyRegion)
{
ExecuteCommand(VSConstants.VSStd2KCmdID.END);
}
WpfConsole.NavigateHistory(+1);
hr = VSConstants.S_OK;
}
break;
case VSConstants.VSStd2KCmdID.RETURN:
if (IsCompletionSessionActive)
{
if (_completionSession.SelectedCompletionSet.SelectionStatus.IsSelected)
{
_completionSession.Commit();
}
else
{
_completionSession.Dismiss();
}
}
else if (IsCaretOnInputLine || !IsCaretInReadOnlyRegion)
{
ExecuteCommand(VSConstants.VSStd2KCmdID.END);
ExecuteCommand(VSConstants.VSStd2KCmdID.RETURN);
NuGetUIThreadHelper.JoinableTaskFactory
.RunAsync(() => EndInputLineAsync(WpfConsole))
.PostOnFailure(nameof(WpfConsoleKeyProcessor));
}
hr = VSConstants.S_OK;
break;
case VSConstants.VSStd2KCmdID.TAB:
if (!IsCaretInReadOnlyRegion)
{
if (IsCompletionSessionActive)
{
_completionSession.Commit();
}
else
{
NuGetUIThreadHelper.JoinableTaskFactory.RunAsync(async delegate { await TriggerCompletionAsync(); })
.PostOnFailure(nameof(WpfConsoleKeyProcessor));
}
}
hr = VSConstants.S_OK;
break;
case VSConstants.VSStd2KCmdID.CANCEL:
if (IsCompletionSessionActive)
{
_completionSession.Dismiss();
hr = VSConstants.S_OK;
}
else if (!IsCaretInReadOnlyRegion)
{
// Delete all text after InputLineStart
WpfTextView.TextBuffer.Delete(WpfConsole.AllInputExtent);
hr = VSConstants.S_OK;
}
break;
case VSConstants.VSStd2KCmdID.CUTLINE:
// clears the console when CutLine shortcut key is pressed,
// usually it is Ctrl + L
WpfConsole.ClearConsole();
hr = VSConstants.S_OK;
break;
}
}
}
return hr;
}