/// <summary> /// This handler is necessary to intercept keyboard input which maps to Vim /// commands but doesn't map to text input. Any combination which can be /// translated into actual text input will be done so much more accurately by /// WPF and will end up in the TextInput event. /// /// An example of why this handler is needed is for key combinations like /// Shift+Escape. This combination won't translate to an actual character in most /// (possibly all) keyboard layouts. This means it won't ever make it to the /// TextInput event. But it can translate to a Vim command or mapped keyboard /// combination that we do want to handle. Hence we override here specifically /// to capture those circumstances /// </summary> public override void KeyDown(KeyEventArgs e) { VimTrace.TraceInfo("VimKeyProcessor::KeyDown {0} {1}", e.Characters, e.CharactersIgnoringModifiers); bool handled = false; if (ShouldBeProcessedByVim(e)) { var oldMode = VimBuffer.Mode.ModeKind; VimTrace.TraceDebug(oldMode.ToString()); // Attempt to map the key information into a KeyInput value which can be processed // by Vim. If this works and the key is processed then the input is considered // to be handled if (_keyUtil.TryConvertSpecialToKeyInput(e.Event, out KeyInput keyInput)) { handled = TryProcess(keyInput); } } VimTrace.TraceInfo("VimKeyProcessor::KeyDown Handled = {0}", handled); var status = Mac.StatusBar.GetStatus(VimBuffer); var text = status.Text; if (VimBuffer.ModeKind == ModeKind.Command) { // Add a fake 'caret' text = text.Insert(status.CaretPosition, "|"); } IdeApp.Workbench.StatusBar.ShowMessage(text); e.Handled = handled; }
/// <summary> /// This handler is necessary to intercept keyboard input which maps to Vim /// commands but doesn't map to text input. Any combination which can be /// translated into actual text input will be done so much more accurately by /// WPF and will end up in the TextInput event. /// /// An example of why this handler is needed is for key combinations like /// Shift+Escape. This combination won't translate to an actual character in most /// (possibly all) keyboard layouts. This means it won't ever make it to the /// TextInput event. But it can translate to a Vim command or mapped keyboard /// combination that we do want to handle. Hence we override here specifically /// to capture those circumstances /// </summary> public override void KeyDown(KeyEventArgs e) { VimTrace.TraceInfo("VimKeyProcessor::KeyDown {0} {1}", e.Characters, e.CharactersIgnoringModifiers); bool handled; if (KeyEventIsDeadChar(e)) { // When a dead key combination is pressed we will get the key down events in // sequence after the combination is complete. The dead keys will come first // and be followed the final key which produces the char. That final key // is marked as DeadCharProcessed. // // All of these should be ignored. They will produce a TextInput value which // we can process in the TextInput event handled = false; } else if (_completionBroker.IsCompletionActive(TextView) && !IsEscapeKey(e)) { handled = false; } else if (_signatureHelpBroker.IsSignatureHelpActive(TextView)) { handled = false; } else if (_inlineRenameListenerFactory.InRename) { handled = false; } else { var oldMode = VimBuffer.Mode.ModeKind; VimTrace.TraceDebug(oldMode.ToString()); // Attempt to map the key information into a KeyInput value which can be processed // by Vim. If this works and the key is processed then the input is considered // to be handled if (_keyUtil.TryConvertSpecialToKeyInput(e.Event, out KeyInput keyInput)) { handled = TryProcess(keyInput); } else { handled = false; } } VimTrace.TraceInfo("VimKeyProcessor::KeyDown Handled = {0}", handled); var status = Mac.StatusBar.GetStatus(VimBuffer); var text = status.Text; if (VimBuffer.ModeKind == ModeKind.Command) { // Add a fake 'caret' text = text.Insert(status.CaretPosition, "|"); } IdeApp.Workbench.StatusBar.ShowMessage(text); e.Handled = handled; }
/// <summary> /// The PreviewKeyDown event is raised before Visual Assist handles a key stroke and they respect the /// Handled property of the KeyEventArgs structure. This is our chance to intercept any keys that /// they will process in a way that conflicts with VsVim /// </summary> public override void PreviewKeyDown(KeyEventArgs args) { VimTrace.TraceInfo("VisualAssistKeyProcessor::PreviewKeyDown {0} {1}", args.Key, args.KeyboardDevice.Modifiers); if (IsTextViewFocused && _vimBuffer.ModeKind == ModeKind.Normal && args.Key == Key.OemPeriod && args.KeyboardDevice.Modifiers == ModifierKeys.None) { // Visual Assist in general won't process any keys when we are in normal mode because we have // the caret hidden. However it appears they check for the caret hidden on a timer or some // form of delay. This is provable by editting some text in insert mode then quickly hitting // Escape followed by '.'. If this happens fast enough they will process the '.' directly // instead of letting the key stroke go through. This will cause a '.' to appear in the code // instead of a repeat action. // // Experimentation shows that they only do this processing for a subset of keys including // '.'. Letter keys and the like don't have this behavior so we let them go through // normal processing. In the future though we may find more keys that need this exception _vimBuffer.Process(KeyInputUtil.CharToKeyInput('.')); args.Handled = true; } VimTrace.TraceInfo("VisualAssistKeyProcessor::KeyDown Handled = {0}", args.Handled); base.PreviewKeyDown(args); }
private void CachePairs() { _glyphPairs.Clear(); if (_activeMarks == 0) { return; } var pairs = _lineNumberMap .Where(pair => pair.Value != -1) .GroupBy(pair => pair.Value) .Select(grouping => Tuple.Create( String.Concat( grouping .Select(pair => pair.Key.Char) .OrderBy(key => key)), grouping.Key ) ); _glyphPairs.AddRange(pairs); VimTrace.TraceInfo($"MarkGlyphTagger: Glyph Pairs"); foreach (var pair in _glyphPairs) { VimTrace.TraceInfo($"MarkGlyphTagger: {pair.Item2} -> {pair.Item1}"); } }
private ReadOnlyCollection <ITagSpan <MarkGlyphTag> > GetTags(SnapshotSpan span) { if (_glyphPairs.Count == 0) { return(s_emptyTagList); } var snapshot = span.Snapshot; var list = new List <ITagSpan <MarkGlyphTag> >(); VimTrace.TraceInfo($"MarkGlyphTagger::GetTags: starting..."); foreach (var pair in _glyphPairs) { var chars = pair.Item1; var lineNumber = pair.Item2; if (lineNumber < snapshot.LineCount) { var line = snapshot.GetLineFromLineNumber(lineNumber); var startSpan = new SnapshotSpan(line.Start, 0); if (span.Contains(startSpan)) { VimTrace.TraceInfo($"MarkGlyphTagger::GetTags: tag {lineNumber} {chars}"); var tag = new MarkGlyphTag(chars); var tagSpan = new TagSpan <MarkGlyphTag>(startSpan, tag); list.Add(tagSpan); } } } return(list.ToReadOnlyCollectionShallow()); }
/// <summary> /// Try to process this KeyInput /// </summary> internal bool TryProcess(KeyInput keyInput) { // If this processor is associated with a IVimBuffer then don't fall back to VS commands // unless vim is currently disabled if (_vimBuffer != null && _vimBuffer.ModeKind != ModeKind.Disabled) { return(false); } // When a modal dialog is active don't turn key strokes into commands. This happens when // the editor is hosted as a control in a modal window. No command routing should // take place in this scenario if (_vsShell.IsInModalState()) { return(false); } // Check for any applicable fallback bindings, in order VimTrace.TraceInfo("FallbackKeyProcessor::TryProcess {0}", keyInput); foreach (var fallbackCommand in _fallbackCommandList) { if (fallbackCommand.KeyInput == keyInput) { return(SafeExecuteCommand(fallbackCommand.Command)); } } return(false); }
internal bool Exec(EditCommand editCommand, out Action preAction, out Action postAction) { VimTrace.TraceInfo("VsCommandTarget::Exec {0}", editCommand); preAction = null; postAction = null; // If the KeyInput was already handled then pretend we handled it here if (editCommand.HasKeyInput && _vimBufferCoordinator.IsDiscarded(editCommand.KeyInput)) { return(true); } var result = false; foreach (var commandTarget in _commandTargets) { if (commandTarget.Exec(editCommand, out preAction, out postAction)) { result = true; break; } } return(result); }
//.> internal bool Exec(EditCommand editCommand, out Action preAction, out Action postAction) { //.<如果是ESCAPE键,无论处于何种状态,都关闭CAPSLOCK和IM。 if (editCommand.EditCommandKind == EditCommandKind.UserInput) { if (editCommand.KeyInput.Key == VimKey.Escape) { CloseCapsLock(); System.Windows.Input.InputMethod.Current.ImeState = System.Windows.Input.InputMethodState.Off; } } //.> VimTrace.TraceInfo("VsCommandTarget::Exec {0}", editCommand); preAction = null; postAction = null; // If the KeyInput was already handled then pretend we handled it here if (editCommand.HasKeyInput && _vimBufferCoordinator.IsDiscarded(editCommand.KeyInput)) { return(true); } var result = false; foreach (var commandTarget in _commandTargets) { if (commandTarget.Exec(editCommand, out preAction, out postAction)) { result = true; break; } } return(result); }
private void SetImeState(InputMethodState state) { if (InputMethod.Current.ImeState != state) { VimTrace.TraceInfo($"ImeCoordinator: in mode = {_inputMode} turning IME {state}"); } InputMethod.Current.ImeState = state; }
private void OnSearchStopped(string searchText) { VimTrace.TraceInfo("NavigateTo Stop: {0}", searchText); if (_inSearch) { _inSearch = false; _unwantedSelectionHandler.PostAction(); } }
/// <summary> /// This handler is necessary to intercept keyboard input which maps to Vim /// commands but doesn't map to text input. Any combination which can be /// translated into actual text input will be done so much more accurately by /// WPF and will end up in the TextInput event. /// /// An example of why this handler is needed is for key combinations like /// Shift+Escape. This combination won't translate to an actual character in most /// (possibly all) keyboard layouts. This means it won't ever make it to the /// TextInput event. But it can translate to a Vim command or mapped keyboard /// combination that we do want to handle. Hence we override here specifically /// to capture those circumstances /// </summary> public override void KeyDown(KeyEventArgs e) { VimTrace.TraceInfo("VimKeyProcessor::KeyDown {0} {1}", e.Characters, e.CharactersIgnoringModifiers); bool handled = false; if (ShouldBeProcessedByVim(e)) { var oldMode = VimBuffer.Mode.ModeKind; VimTrace.TraceDebug(oldMode.ToString()); // Attempt to map the key information into a KeyInput value which can be processed // by Vim. If this works and the key is processed then the input is considered // to be handled if (_keyUtil.TryConvertSpecialToKeyInput(e.Event, out KeyInput keyInput)) { var bufferedKeyInputsWasEmpty = VimBuffer.BufferedKeyInputs.IsEmpty; handled = TryProcess(keyInput); if (handled && BufferedKeysWasEmptyAndIsEmpty() && oldMode == ModeKind.Insert && CharTriggersCompletion(keyInput.Char) && !_completionBroker.IsCompletionActive(VimBuffer.TextView)) { // Because VsVim handled the key press for us in insert mode, // we need to trigger the completion window to open. _completionBroker.TriggerCompletion(VimBuffer.TextView); } bool BufferedKeysWasEmptyAndIsEmpty() { // We don't want the completion window to appear if we // have something like `inoremap fd <esc>` // and we just typed the first 'f' or the 'd' return(bufferedKeyInputsWasEmpty && VimBuffer.BufferedKeyInputs.IsEmpty); } } } VimTrace.TraceInfo("VimKeyProcessor::KeyDown Handled = {0}", handled); var status = Mac.StatusBar.GetStatus(VimBuffer); var text = status.Text; if (VimBuffer.ModeKind == ModeKind.Command) { // Add a fake 'caret' text = text.Insert(status.CaretPosition, "|"); } IdeApp.Workbench.StatusBar.ShowMessage(text); e.Handled = handled; }
private bool GetCharFromKey(Key key, ModifierKeys modifierKeys, out char unicodeChar) { // From the documentation for GetKeyboardState: // - If the high-order bit is 1, the key is down; otherwise, it is up. const byte keyIsDown = 0x80; const byte keyIsUp = 0x00; // Use interop and pinvoke to get the scan code and keyboard layout. var virtualKey = (uint)KeyInterop.VirtualKeyFromKey(key); var scanCode = NativeMethods.MapVirtualKey(virtualKey, NativeMethods.MAPVK_VK_TO_VSC); StringBuilder stringBuilder = new StringBuilder(1); var keyboardLayout = NativeMethods.GetKeyboardLayout(0); // Fail if the AltGr modifier is set and the key produces a character // when AltGr is pressed. We want to disambiguate Ctrl+Alt from AltGr. if (IsAltGr(modifierKeys)) { // Mark control and alt (and their merged virtual keys) as pressed. // This is conceptually equivalent to passing in the modifier // keys control and alt. _keyboardState[NativeMethods.VK_LCONTROL] = keyIsDown; _keyboardState[NativeMethods.VK_LMENU] = keyIsDown; _keyboardState[NativeMethods.VK_CONTROL] = keyIsDown; _keyboardState[NativeMethods.VK_MENU] = keyIsDown; int altGrResult = NativeMethods.ToUnicodeEx(virtualKey, scanCode, _keyboardState, stringBuilder, stringBuilder.Capacity, 0, keyboardLayout); if (altGrResult == 1) { VimTrace.TraceInfo("AlternateKeyUtil::GetCharFromKey AltGr {0} -> {1}", key, stringBuilder[0]); unicodeChar = default(char); return(false); } } // Return the "base" key (or AltGr level 1) for the scan code. // This is the unicode character that would be produced if the // the key were pressed with no modifiers. // This is conceptually equivalent to passing in modifier keys none. _keyboardState[NativeMethods.VK_LCONTROL] = keyIsUp; _keyboardState[NativeMethods.VK_LMENU] = keyIsUp; _keyboardState[NativeMethods.VK_CONTROL] = keyIsUp; _keyboardState[NativeMethods.VK_MENU] = keyIsUp; int result = NativeMethods.ToUnicodeEx(virtualKey, scanCode, _keyboardState, stringBuilder, stringBuilder.Capacity, 0, keyboardLayout); if (result == 1) { unicodeChar = stringBuilder[0]; return(true); } unicodeChar = default(char); return(false); }
private void OnSearchStarted(string searchText) { // Cautiously record which buffers have pre-existing selections. _selected = _textManager .GetDocumentTextViews(DocumentLoad.RespectLazy) .Where(x => !x.Selection.IsEmpty) .Select(x => new WeakReference <ITextView>(x)) .ToList(); _inSearch = true; VimTrace.TraceInfo("NavigateTo Start: {0}", searchText); }
/// <summary> /// This method is called to process KeyInput in any fashion by the IVimBuffer. There are /// several cases where we want to defer to Visual Studio and IOleCommandTarget for processing /// of a command. In particular we don't want to process any text input here /// </summary> protected override bool TryProcess(KeyInput keyInput) { // If the ITextView doesn't have aggregate focus then this event needs to be discarded. This will // happen when a peek definition window is active. The peek window is a child and if it fails to // process a key event it will bubble up to the parent window. If the peek window has focus the // parent window shouldn't be handling the key if (!_vimHost.IsFocused(TextView)) { return(false); } // Check to see if we should be discarding this KeyInput value. If it is discarded and // made it back to us then we need to pretend that it was handled here if (_bufferCoordinator.IsDiscarded(keyInput)) { return(true); } // Don't handle input when incremental search is active. Let Visual Studio handle it if (_adapter.IsIncrementalSearchActive(TextView)) { VimTrace.TraceInfo("VsKeyProcessor::TryProcess Incremental search active"); return(false); } // In insert mode we don't want text input going directly to VsVim. Text input must // be routed through Visual Studio and IOleCommandTarget in order to get intellisense // properly hooked up. Not handling it in this KeyProcessor will eventually cause // it to be routed through IOleCommandTarget if it's input // // The Visual Studio KeyProcessor won't pass along control characters that are less than // or equal to 0x1f so we have to handle them here if (VimBuffer.ModeKind.IsAnyInsert() && !VimBuffer.CanProcessAsCommand(keyInput) && (int)keyInput.Char > 0x1f) { return(false); } // The report designer will process certain key strokes both through IOleCommandTarget and // then back through the KeyProcessor interface. This happens because they call into IOleCommandTarget // from Control.PreProcessMessage and if the execution succeeds they return false. This // causes it to continue to be processed as a normal message and hence leads to this // interface. Don't process any of these keys twice if (_reportDesignerUtil.IsExpressionView(TextView) && _reportDesignerUtil.IsSpecialHandled(keyInput)) { return(false); } return(base.TryProcess(keyInput)); }
/// <summary> /// Last chance at custom handling of user input. At this point we have the /// advantage that WPF has properly converted the user input into a char which /// can be effeciently mapped to a KeyInput value. /// </summary> public override void TextInput(TextCompositionEventArgs args) { VimTrace.TraceInfo("VimKeyProcessor::TextInput Text={0} ControlText={1} SystemText={2}", StringUtil.GetDisplayString(args.Text), StringUtil.GetDisplayString(args.ControlText), StringUtil.GetDisplayString(args.SystemText)); var handled = false; var text = args.Text; if (string.IsNullOrEmpty(text)) { text = args.ControlText; } if (!string.IsNullOrEmpty(text)) { // In the case of a failed dead key mapping (pressing the accent key twice for // example) we will recieve a multi-length string here. One character for every // one of the mappings. Make sure to handle each of them for (var i = 0; i < text.Length; i++) { var keyInput = KeyInputUtil.CharToKeyInput(text[i]); handled = TryProcess(keyInput); } } else if (!string.IsNullOrEmpty(args.SystemText)) { // The system text needs to be processed differently than normal text. When 'a' // is pressed with control it will come in as control text as the proper control // character. When 'a' is pressed with Alt it will come in as simply 'a' and we // have to rely on the currently pressed key modifiers to determine the appropriate // character var keyboardDevice = args.Device as KeyboardDevice; var keyModifiers = keyboardDevice != null ? _keyUtil.GetKeyModifiers(keyboardDevice.Modifiers) : VimKeyModifiers.Alt; text = args.SystemText; for (var i = 0; i < text.Length; i++) { var keyInput = KeyInputUtil.ApplyKeyModifiers(KeyInputUtil.CharToKeyInput(text[i]), keyModifiers); handled = TryProcess(keyInput); } } VimTrace.TraceInfo("VimKeyProcessor::TextInput Handled={0}", handled); args.Handled = handled; base.TextInput(args); }
private void OnSearchStopped(string searchText) { VimTrace.TraceInfo("NavigateTo Stop: {0}", searchText); if (_inSearch) { // Once the search is stopped clear out all of the selections in active buffers. Leaving the // selection puts us into Visual Mode. Don't force any document loads here. If the document // isn't loaded then it can't have a selection which will interfere with this _inSearch = false; _textManager.GetDocumentTextViews(DocumentLoad.RespectLazy) .Where(x => !x.Selection.IsEmpty) .ForEach(x => x.Selection.Clear()); } }
public override void PreviewKeyUp(KeyEventArgs args) { if (args.Key == Key.Escape) { // The Escape key was pressed and we are still inside of Insert mode. This means that R# // handled the key stroke to dismiss intellisense. Leave insert mode now to complete the operation if (_vimBuffer.ModeKind == ModeKind.Insert) { VimTrace.TraceInfo("ReSharperKeyUtil::PreviewKeyUp handled escape swallowed by ReSharper"); _vimBuffer.Process(KeyInputUtil.EscapeKey); } } base.PreviewKeyUp(args); }
/// <summary> /// Safely execute a Visual Studio command /// </summary> private bool SafeExecuteCommand(CommandId command) { try { VimTrace.TraceInfo("FallbackKeyProcessor::SafeExecuteCommand {0}", command); object customIn = null; object customOut = null; _dte.Commands.Raise(command.Group.ToString(), (int)command.Id, ref customIn, ref customOut); return(true); } catch { return(false); } }
internal bool ExecCore(EditCommand editCommand) { VimTrace.TraceInfo("VsCommandTarget::Exec {0}", editCommand); switch (editCommand.EditCommandKind) { case EditCommandKind.Undo: // The user hit the undo button. Don't attempt to map anything here and instead just // run a single Vim undo operation _vimBuffer.UndoRedoOperations.Undo(1); return(true); case EditCommandKind.Redo: // The user hit the redo button. Don't attempt to map anything here and instead just // run a single Vim redo operation _vimBuffer.UndoRedoOperations.Redo(1); return(true); case EditCommandKind.GoToDefinition: // Let Visual Studio process this command return(false); case EditCommandKind.UserInput: case EditCommandKind.VisualStudioCommand: if (editCommand.HasKeyInput) { var keyInput = editCommand.KeyInput; // Discard the input if it's been flagged by a previous QueryStatus if (_bufferCoordinator.DiscardedKeyInput.IsSome(keyInput)) { return(true); } // Try and process the command with the IVimBuffer if (TryProcessWithBuffer(keyInput)) { return(true); } } return(false); default: Debug.Assert(false); return(false); } }
/// <summary> /// The escape key was pressed. If we are currently in insert mode we need to leave it because it /// means that Visual Assist swallowed the key stroke to perform an operation like escaping /// </summary> public override void PreviewKeyUp(KeyEventArgs args) { VimTrace.TraceInfo("VisualAssistKeyProcessor::PreviewKeyUp {0} {1}", args.Key, args.KeyboardDevice.Modifiers); if (args.Key == Key.Escape || (args.Key == Key.OemOpenBrackets && args.KeyboardDevice.Modifiers == ModifierKeys.Control)) { // The Escape key was pressed and we are still inside of Insert mode. This means that Visual Assit // handled the key stroke to dismiss intellisense. Leave insert mode now to complete the operation if (_vimBuffer.ModeKind == ModeKind.Insert) { VimTrace.TraceInfo("VisualAssistKeyProcessor::PreviewKeyUp handled escape swallowed by Visual Assist"); _vimBuffer.Process(KeyInputUtil.EscapeKey); } } base.KeyDown(args); }
/// <summary> /// This handler is necessary to intercept keyboard input which maps to Vim /// commands but doesn't map to text input. Any combination which can be /// translated into actual text input will be done so much more accurately by /// WPF and will end up in the TextInput event. /// /// An example of why this handler is needed is for key combinations like /// Shift+Escape. This combination won't translate to an actual character in most /// (possibly all) keyboard layouts. This means it won't ever make it to the /// TextInput event. But it can translate to a Vim command or mapped keyboard /// combination that we do want to handle. Hence we override here specifically /// to capture those circumstances /// </summary> public override void KeyDown(KeyEventArgs args) { VimTrace.TraceInfo("VimKeyProcessor::KeyDown {0} {1}", args.Key, args.KeyboardDevice.Modifiers); bool handled; if (args.Key == Key.DeadCharProcessed) { // When a dead key combination is pressed we will get the key down events in // sequence after the combination is complete. The dead keys will come first // and be followed by the final key which produces the char. That final key // is marked as DeadCharProcessed. // // All of these should be ignored. They will produce a TextInput value which // we can process in the TextInput event handled = false; } else if (_keyUtil.IsAltGr(args.KeyboardDevice.Modifiers)) { // AltGr greatly confuses things becuase it's realized in WPF as Control | Alt. So // while it's possible to use Control to further modify a key which used AltGr // originally the result is indistinguishable here (and in gVim). Don't attempt // to process it handled = false; } else { // Attempt to map the key information into a KeyInput value which can be processed // by Vim. If this worksa nd the key is processed then the input is considered // to be handled KeyInput keyInput; if (_keyUtil.TryConvertSpecialToKeyInput(args.Key, args.KeyboardDevice.Modifiers, out keyInput)) { handled = TryProcess(keyInput); } else { handled = false; } } VimTrace.TraceInfo("VimKeyProcessor::KeyDown Handled = {0}", handled); args.Handled = handled; base.KeyDown(args); }
private CommandStatus QueryStatus(EditCommand editCommand) { VimTrace.TraceInfo("VsCommandTarget::QueryStatus {0}", editCommand); var action = CommandStatus.PassOn; foreach (var commandTarget in _commandTargets) { action = commandTarget.QueryStatus(editCommand); if (action != CommandStatus.PassOn) { break; } } VimTrace.TraceInfo("VsCommandTarget::QueryStatus ", action); return(action); }
private void Dispose() { VimTrace.TraceInfo("NavigateTo Disposed"); // In some configurations the C++ editor will not set focus to the ITextView which is displayed // as a result of completing a NavigateTo operation. Instead focus will be on the navigation // bar. This is not a function of VsVim but does mess up the general keyboard usage and // hence we force the focus to be correct // // Note: The exact scenarios under which this happens is not well understood. It does repro under // a clean machine and Windows 8.1 but doesn't always repro under other configurations. Either way // need to fix if (_textManager.ActiveTextViewOptional is IWpfTextView wpfTextView && !wpfTextView.HasAggregateFocus && wpfTextView.TextSnapshot.ContentType.IsCPlusPlus()) { VimTrace.TraceInfo("NavigateTo adjust C++ focus"); Keyboard.Focus(wpfTextView.VisualElement); } }
int IOleCommandTarget.QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) { EditCommand editCommand; if (1 == cCmds && TryConvert(pguidCmdGroup, prgCmds[0].cmdID, pCmdText, out editCommand)) { VimTrace.TraceInfo("VsCommandTarget::QueryStatus {0}", editCommand); _bufferCoordinator.DiscardedKeyInput = FSharpOption <KeyInput> .None; var action = CommandStatus.PassOn; if (editCommand.IsUndo || editCommand.IsRedo) { action = CommandStatus.Enable; } else if (editCommand.HasKeyInput && _vimBuffer.CanProcess(editCommand.KeyInput)) { action = CommandStatus.Enable; if (_resharperUtil.IsInstalled) { action = QueryStatusInResharper(editCommand.KeyInput) ?? CommandStatus.Enable; } } switch (action) { case CommandStatus.Enable: prgCmds[0].cmdf = (uint)(OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_SUPPORTED); return(NativeMethods.S_OK); case CommandStatus.Disable: prgCmds[0].cmdf = (uint)OLECMDF.OLECMDF_SUPPORTED; return(NativeMethods.S_OK); case CommandStatus.PassOn: return(_nextTarget.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText)); } VimTrace.TraceInfo("VsCommandTarget::QueryStatus ", action); } return(_nextTarget.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText)); }
private void OnSearchStopped(string searchText) { VimTrace.TraceInfo("NavigateTo Stop: {0}", searchText); if (_inSearch) { // Once the search is stopped clear out all of the selections in active buffers. Leaving the // selection puts us into Visual Mode. Don't force any document loads here. If the document // isn't loaded then it can't have a selection which will interfere with this _inSearch = false; _textManager.GetDocumentTextViews(DocumentLoad.RespectLazy) .Where(x => !x.Selection.IsEmpty && !_selected.Where(y => y.TryGetTarget(out ITextView target) && target == x).Any()) .ForEach(x => { var startPoint = x.Selection.Start; x.Selection.Clear(); x.Caret.MoveTo(startPoint); }); } }
/// <summary> /// Try to process this KeyInput /// </summary> internal bool TryProcess(KeyInput keyInput) { // If this processor is associated with a IVimBuffer then don't fall back to VS commands // unless vim is currently disabled if (_vimBuffer != null && _vimBuffer.ModeKind != ModeKind.Disabled) { return(false); } // Check for any applicable fallback bindings, in order VimTrace.TraceInfo("FallbackKeyProcessor::TryProcess {0}", keyInput); foreach (var fallbackCommand in _fallbackCommandList) { if (fallbackCommand.KeyInput == keyInput) { return(SafeExecuteCommand(fallbackCommand.Command)); } } return(false); }
/// <summary> /// This method is called to process KeyInput in any fashion by the IVimBuffer. There are /// several cases where we want to defer to Visual Studio and IOleCommandTarget for processing /// of a command. In particular we don't want to process any text input here /// </summary> protected override bool TryProcess(KeyInput keyInput) { if (IsDiscardedKeyInput(keyInput)) { return(true); } // Don't handle input when incremental search is active. Let Visual Studio handle it if (_adapter.IsIncrementalSearchActive(TextView)) { VimTrace.TraceInfo("VsKeyProcessor::TryProcess Incremental search active"); return(false); } // In insert mode we don't want text input going directly to VsVim. Text input must // be routed through Visual Studio and IOleCommandTarget in order to get intellisense // properly hooked up. Not handling it in this KeyProcessor will eventually cause // it to be routed through IOleCommandTarget if it's input // // The Visual Studio KeyProcessor won't pass along control characters that are less than // or equal to 0x1f so we have to handle them here if (VimBuffer.ModeKind.IsAnyInsert() && !VimBuffer.CanProcessAsCommand(keyInput) && (int)keyInput.Char > 0x1f) { return(false); } // The report designer will process certain key strokes both through IOleCommandTarget and // then back through the KeyProcessor interface. This happens because they call into IOleCommandTarget // from Control.PreProcessMessage and if the execution succeeds they return false. This // causes it to continue to be processed as a normal message and hence leads to this // interface. Don't process any of these keys twice if (_reportDesignerUtil.IsExpressionView(TextView) && _reportDesignerUtil.IsSpecialHandled(keyInput)) { return(false); } return(base.TryProcess(keyInput)); }
/// <summary> /// This handler is necessary to intercept keyboard input which maps to Vim /// commands but doesn't map to text input. Any combination which can be /// translated into actual text input will be done so much more accurately by /// WPF and will end up in the TextInput event. /// /// An example of why this handler is needed is for key combinations like /// Shift+Escape. This combination won't translate to an actual character in most /// (possibly all) keyboard layouts. This means it won't ever make it to the /// TextInput event. But it can translate to a Vim command or mapped keyboard /// combination that we do want to handle. Hence we override here specifically /// to capture those circumstances /// </summary> public override void KeyDown(KeyEventArgs args) { VimTrace.TraceInfo("VimKeyProcessor::KeyDown {0} {1} {2}", args.Key, args.SystemKey, args.KeyboardDevice.Modifiers); var key = args.Key == Key.System ? args.SystemKey : args.Key; bool handled; if (key == Key.DeadCharProcessed) { // When a dead key combination is pressed we will get the key down events in // sequence after the combination is complete. The dead keys will come first // and be followed by the final key which produces the char. That final key // is marked as DeadCharProcessed. // // All of these should be ignored. They will produce a TextInput value which // we can process in the TextInput event handled = false; } else { // Attempt to map the key information into a KeyInput value which can be processed // by Vim. If this worksa nd the key is processed then the input is considered // to be handled if (_keyUtil.TryConvertSpecialToKeyInput(key, args.KeyboardDevice.Modifiers, out KeyInput keyInput)) { handled = TryProcess(keyInput); } else { handled = false; } } VimTrace.TraceInfo("VimKeyProcessor::KeyDown Handled = {0}", handled); args.Handled = handled; base.KeyDown(args); }
private bool Exec(EditCommand editCommand) { VimTrace.TraceInfo("VsCommandTarget::Exec {0}", editCommand); if (editCommand.IsUndo) { // The user hit the undo button. Don't attempt to map anything here and instead just // run a single Vim undo operation _vimBuffer.UndoRedoOperations.Undo(1); return(true); } else if (editCommand.IsRedo) { // The user hit the redo button. Don't attempt to map anything here and instead just // run a single Vim redo operation _vimBuffer.UndoRedoOperations.Redo(1); return(true); } else if (editCommand.HasKeyInput) { var keyInput = editCommand.KeyInput; // Discard the input if it's been flagged by a previous QueryStatus if (_bufferCoordinator.DiscardedKeyInput.IsSome(keyInput)) { return(true); } // Try and process the command with the IVimBuffer if (TryProcessWithBuffer(keyInput)) { return(true); } } return(false); }
private CommandStatus QueryStatusCore(EditCommand editCommand) { VimTrace.TraceInfo("VsCommandTarget::QueryStatus {0}", editCommand); _bufferCoordinator.DiscardedKeyInput = FSharpOption <KeyInput> .None; var action = CommandStatus.PassOn; switch (editCommand.EditCommandKind) { case EditCommandKind.Undo: case EditCommandKind.Redo: action = CommandStatus.Enable; break; case EditCommandKind.Paste: action = _vimBuffer.ModeKind == ModeKind.Command ? CommandStatus.Enable : CommandStatus.PassOn; break; default: if (editCommand.HasKeyInput && _vimBuffer.CanProcess(editCommand.KeyInput)) { action = CommandStatus.Enable; if (_resharperUtil.IsInstalled) { action = QueryStatusInResharper(editCommand.KeyInput) ?? CommandStatus.Enable; } } break; } VimTrace.TraceInfo("VsCommandTarget::QueryStatus ", action); return(action); }