protected override bool PreProcessMessage(ref System.Windows.Forms.Message m) { ThreadHelper.ThrowIfNotOnUIThread(); if (m.Msg >= WM_KEYFIRST && m.Msg <= WM_KEYLAST) { var oleMsg = new MSG { hwnd = m.HWnd, lParam = m.LParam, wParam = m.WParam, message = (uint)m.Msg }; if (_filterKeys == null) { _filterKeys = this.GetService <IVsFilterKeys2, SVsFilterKeys>(); } return(_filterKeys.TranslateAcceleratorEx( new[] { oleMsg }, (uint)__VSTRANSACCELEXFLAGS.VSTAEXF_UseTextEditorKBScope, 0, Array.Empty <Guid>(), out var _, out var _, out var _, out var _) == VSConstants.S_OK); } return(base.PreProcessMessage(ref m)); }
/// <summary> /// Preprocess input (keyboard) messages in order to translate them to editor commands if they map. Since our tool window is NOT an /// editor the shell won't consider the editor keybindings when doing its usual input pre-translation. We could either set our /// window frames InheritKeyBindings property to point to the std editor factory GUID OR we can do this. I chose this method as /// it allows us to have the editor keybindings active ONLY when the focus is in the editor, that way we won't have editor /// keybindings active in our window UNLESS the editor has focus, which is what we want. /// </summary> protected override bool PreProcessMessage(ref System.Windows.Forms.Message m) { //Only try and pre-process keyboard input messages, all others are not interesting to us. if (m.Msg >= WM_KEYFIRST && m.Msg <= WM_KEYLAST) { //Only attempt to do the input -> command mapping if focus is inside our hosted editor. if (this.control.IsKeyboardFocusWithin) { IVsFilterKeys2 filterKeys = (IVsFilterKeys2)GetService(typeof(SVsFilterKeys)); MSG oleMSG = new MSG() { hwnd = m.HWnd, lParam = m.LParam, wParam = m.WParam, message = (uint)m.Msg }; //Ask the shell to do the command mapping for us and fire off the command if it succeeds with that mapping. We pass no 'custom' scopes //(third and fourth argument) because we pass VSTAEXF_UseTextEditorKBScope to indicate we want the shell to apply the text editor //command scope to this call. Guid cmdGuid; uint cmdId; int fTranslated; int fStartsMultiKeyChord; int res = filterKeys.TranslateAcceleratorEx(new MSG[] { oleMSG }, (uint)(__VSTRANSACCELEXFLAGS.VSTAEXF_UseTextEditorKBScope), 0 /*scope count*/, new Guid[0] /*scopes*/, out cmdGuid, out cmdId, out fTranslated, out fStartsMultiKeyChord); if (fStartsMultiKeyChord == 0) { //HACK: Work around a bug in TranslateAcceleratorEx that will report it DIDN'T do the command mapping //when in fact it did :( Problem has been fixed (since I found it while writing this code), but in the //mean time we need to successfully eat keystrokes that have been mapped to commands and dispatched, //we DON'T want them to continue on to Translate/Dispatch. "Luckily" asking TranslateAcceleratorEx to //do the mapping WITHOUT firing the command will give us the right result code to indicate if the command //mapped or not, unfortunately we can't always do this as it would break key-chords as it causes the shell //to not remember the first input match of a multi-part chord, hence the reason we ONLY hit this block if //it didn't tell us the input IS part of key-chord. res = filterKeys.TranslateAcceleratorEx(new MSG[] { oleMSG }, (uint)(__VSTRANSACCELEXFLAGS.VSTAEXF_NoFireCommand | __VSTRANSACCELEXFLAGS.VSTAEXF_UseTextEditorKBScope), 0, new Guid[0], out cmdGuid, out cmdId, out fTranslated, out fStartsMultiKeyChord); return(res == VSConstants.S_OK); } //We return true (that we handled the input message) if we managed to map it to a command OR it was the //beginning of a multi-key chord, anything else should continue on with normal processing. return((res == VSConstants.S_OK) || (fStartsMultiKeyChord != 0)); } } return(base.PreProcessMessage(ref m)); }
/// <summary> /// Filters out a message before it is dispatched /// </summary> /// <param name="m">The message to be dispatched. You cannot modify this message.</param> /// <returns>True to filter the message and stop it from being dispatched; false to allow the message to continue to the next filter or control.</returns> public bool PreFilterMessage(ref Message m) { //IVsFilterKeys2 performs advanced keyboard message translation IVsFilterKeys2 filterKeys2 = services.VsFilterKeys2; MSG[] messages = new MSG[1]; messages[0].hwnd = m.HWnd; messages[0].lParam = m.LParam; messages[0].wParam = m.WParam; messages[0].message = (uint)m.Msg; Guid cmdGuid; uint cmdCode; int cmdTranslated; int keyComboStarts; int hr = filterKeys2.TranslateAcceleratorEx(messages, (uint)__VSTRANSACCELEXFLAGS.VSTAEXF_UseTextEditorKBScope //Translates keys using TextEditor key bindings. Equivalent to passing CMDUIGUID_TextEditor, CMDSETID_StandardCommandSet97, and guidKeyDupe for scopes and the VSTAEXF_IgnoreActiveKBScopes flag. | (uint)__VSTRANSACCELEXFLAGS.VSTAEXF_AllowModalState, //By default this function cannot be called when the shell is in a modal state, since command routing is inherently dangerous. However if you must access this in a modal state, specify this flag, but keep in mind that many commands will cause unpredictable behavior if fired. 0, null, out cmdGuid, out cmdCode, out cmdTranslated, out keyComboStarts); if (hr != VSConstants.S_OK) { return(false); } return(cmdTranslated != 0); }
public override bool PreProcessMessage(ref Message msg) { if (msg.Msg >= _wm_KEYFIRST && msg.Msg <= _wm_KEYLAST) { IVsFilterKeys2 filterKeys = (IVsFilterKeys2)ServiceProvider.GlobalProvider.GetService(typeof(SVsFilterKeys)); Microsoft.VisualStudio.OLE.Interop.MSG oleMSG = new Microsoft.VisualStudio.OLE.Interop.MSG() { hwnd = msg.HWnd, lParam = msg.LParam, wParam = msg.WParam, message = (uint)msg.Msg }; //Ask the shell to do the command mapping for us and without firing off the command. We need to check if this command is one of the //supported commands first before actually firing the command. filterKeys.TranslateAcceleratorEx(new Microsoft.VisualStudio.OLE.Interop.MSG[] { oleMSG }, (uint)(__VSTRANSACCELEXFLAGS.VSTAEXF_NoFireCommand | __VSTRANSACCELEXFLAGS.VSTAEXF_UseGlobalKBScope | __VSTRANSACCELEXFLAGS.VSTAEXF_AllowModalState), 0 /*scope count*/, new Guid[0] /*scopes*/, out Guid cmdGuid, out uint cmdId, out int fTranslated, out int fStartsMultiKeyChord); if (ShouldRouteCommandBackToVS(cmdGuid, cmdId, fTranslated == 1, fStartsMultiKeyChord == 1)) { return(false); } } return(base.PreProcessMessage(ref msg)); }
void OnLoad(object sender, EventArgs e) { if (_fKeys == null) { _fKeys = GetService <IVsFilterKeys2>(typeof(SVsFilterKeys)); } if (_form.ToolBar != 0) { System.ComponentModel.Design.CommandID tbId = new System.ComponentModel.Design.CommandID(AnkhId.CommandSetGuid, (int)_form.ToolBar); if (_tbHost == null) { IVsUIShell uiShell = GetService <IVsUIShell>(typeof(SVsUIShell)); Marshal.ThrowExceptionForHR(uiShell.SetupToolbar(_form.Handle, (IVsToolWindowToolbar)this, out _tbHost)); } Guid toolbarCommandSet = tbId.Guid; Marshal.ThrowExceptionForHR( _tbHost.AddToolbar(VSTWT_LOCATION.VSTWT_TOP, ref toolbarCommandSet, (uint)tbId.ID)); Marshal.ThrowExceptionForHR(_tbHost.Show(0)); Marshal.ThrowExceptionForHR(_tbHost.ForceUpdateUI()); } }
/// <summary> /// Preprocess input (keyboard) messages in order to translate them to editor commands if they map. Since we are in a modal dialog /// we need to tell the shell to allow pre-translate during a modal loop as well as instructing it to use the editor keyboard scope /// even though, as far as the shell knows, there is no editor active (in a document or tool window, the shell knows nothing about /// random modal dialogs such as this one). /// </summary> private void FilterThreadMessage(ref System.Windows.Interop.MSG msg, ref bool handled) { if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST) { IVsFilterKeys2 filterKeys = (IVsFilterKeys2)ServiceProvider.GlobalProvider.GetService(typeof(SVsFilterKeys)); Microsoft.VisualStudio.OLE.Interop.MSG oleMSG = new Microsoft.VisualStudio.OLE.Interop.MSG() { hwnd = msg.hwnd, lParam = msg.lParam, wParam = msg.wParam, message = (uint)msg.message }; //Ask the shell to do the command mapping for us and fire off the command if it succeeds with that mapping. We pass no 'custom' scopes //(third and fourth argument) because we pass VSTAEXF_UseTextEditorKBScope to indicate we want the shell to apply the text editor //command scope to this call. Guid cmdGuid; uint cmdId; int fTranslated; int fStartsMultiKeyChord; int res = filterKeys.TranslateAcceleratorEx(new Microsoft.VisualStudio.OLE.Interop.MSG[] { oleMSG }, (uint)(__VSTRANSACCELEXFLAGS.VSTAEXF_UseTextEditorKBScope | __VSTRANSACCELEXFLAGS.VSTAEXF_AllowModalState), 0 /*scope count*/, new Guid[0] /*scopes*/, out cmdGuid, out cmdId, out fTranslated, out fStartsMultiKeyChord); if (fStartsMultiKeyChord == 0) { //HACK: Work around a bug in TranslateAcceleratorEx that will report it DIDN'T do the command mapping //when in fact it did :( Problem has been fixed (since I found it while writing this code), but in the //mean time we need to successfully eat keystrokes that have been mapped to commands and dispatched, //we DON'T want them to continue on to Translate/Dispatch. "Luckily" asking TranslateAcceleratorEx to //do the mapping WITHOUT firing the command will give us the right result code to indicate if the command //mapped or not, unfortunately we can't always do this as it would break key-chords as it causes the shell //to not remember the first input match of a multi-part chord, hence the reason we ONLY hit this block if //it didn't tell us the input IS part of key-chord. res = filterKeys.TranslateAcceleratorEx(new Microsoft.VisualStudio.OLE.Interop.MSG[] { oleMSG }, (uint)(__VSTRANSACCELEXFLAGS.VSTAEXF_NoFireCommand | __VSTRANSACCELEXFLAGS.VSTAEXF_UseTextEditorKBScope | __VSTRANSACCELEXFLAGS.VSTAEXF_AllowModalState), 0, new Guid[0], out cmdGuid, out cmdId, out fTranslated, out fStartsMultiKeyChord); handled = (res == VSConstants.S_OK); return; } //We return true (that we handled the input message) if we managed to map it to a command OR it was the //beginning of a multi-key chord, anything else should continue on with normal processing. handled = ((res == VSConstants.S_OK) || (fStartsMultiKeyChord != 0)); } }
void OnLoad(object sender, EventArgs e) { if (_fKeys == null) _fKeys = GetService<IVsFilterKeys2>(typeof(SVsFilterKeys)); if (_form.ToolBar != 0) { System.ComponentModel.Design.CommandID tbId = new System.ComponentModel.Design.CommandID(AnkhId.CommandSetGuid, (int)_form.ToolBar); if (_tbHost == null) { IVsUIShell uiShell = GetService<IVsUIShell>(typeof(SVsUIShell)); Marshal.ThrowExceptionForHR(uiShell.SetupToolbar(_form.Handle, (IVsToolWindowToolbar)this, out _tbHost)); } Guid toolbarCommandSet = tbId.Guid; Marshal.ThrowExceptionForHR( _tbHost.AddToolbar(VSTWT_LOCATION.VSTWT_TOP, ref toolbarCommandSet, (uint)tbId.ID)); Marshal.ThrowExceptionForHR(_tbHost.Show(0)); Marshal.ThrowExceptionForHR(_tbHost.ForceUpdateUI()); } }