Example #1
0
        /// <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;
        }
Example #2
0
        /// <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;
        }
Example #3
0
        /// <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);
        }
Example #4
0
        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}");
            }
        }
Example #5
0
        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());
        }
Example #6
0
        /// <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);
        }
Example #7
0
        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);
        }
Example #8
0
        //.>
        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);
        }
Example #9
0
 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();
     }
 }
Example #11
0
        /// <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;
        }
Example #12
0
        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);
        }
Example #13
0
 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);
 }
Example #14
0
        /// <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));
        }
Example #15
0
        /// <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);
        }
Example #16
0
 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());
     }
 }
Example #17
0
 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);
 }
Example #18
0
 /// <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);
     }
 }
Example #19
0
        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);
            }
        }
Example #20
0
        /// <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);
        }
Example #21
0
        /// <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);
        }
Example #22
0
        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);
        }
Example #23
0
        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);
            }
        }
Example #24
0
        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));
        }
Example #25
0
 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);
         });
     }
 }
Example #26
0
        /// <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);
        }
Example #27
0
        /// <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));
        }
Example #28
0
        /// <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);
        }
Example #29
0
        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);
        }
Example #30
0
        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);
        }