How can I handle keypresses before Visual Studio does? RRS feed

  • Question

  • In my VS add-in, I need to handle key presses (presumably via PreTranslateAccelerator()) before Visual Studio does. Unfortunately, after digging in Shell.Interop, I can't find the location where I would be able to handle them. Can anyone help?
    - Dmitri Nesteruk, MVP C#, Microsoft Partner
    Saturday, December 24, 2011 2:37 PM

All replies

  • What do you mean by 'in my AddIn'? 

    The only people able to possibly handle keystrokes before the shell are toolwindows.  Arbitrary code can't 'sign up' to handle input before the shell, that would generally result in an unusable system as everyone and their brother would probably do that and then no one could ever rely on getting typed input because anyone in a chain of 50 people could hijack it.

    Perhaps there is another way to do what you are trying to do, so what are really trying to do (i.e. why do you need to 'handle key presses before Visual Studio does')?


    Saturday, December 24, 2011 4:30 PM
  • Well, the idea is that I want to present the results of key presses in a tool window that my addin has, but the focus wouldn't be in a tool window, necessarily. Meaning that I'd like to intercept people pressing down keys like Ctrl and react to this, updating my tool window. Once again, the focus can be in the text editor, object browser, or anywhere else.
    - Dmitri Nesteruk, MVP C#, Microsoft Partner
    Saturday, December 24, 2011 5:14 PM
  • The shell only gives the active toolwindow a chance to pre-translate via IVsWindowPane::TranslateAccelerator.  There are no other hooks in the message loop that would allow anyone else to see the input. 

    You may be able to do this with a Win32 sledgehammer approach like a CBT hook, but that is outside the domain of VS extensibility proper.


    Saturday, December 24, 2011 5:59 PM
  • A keyboard hook doesn't work. It works for while, but misses some messages and then proceeds to ignore 100% of messages while causing massive performance degradation. No idea why.

    Another question, if I may: are things better if we only consider the text editor window for purposes of catching those events?

    - Dmitri Nesteruk, MVP C#, Microsoft Partner
    Saturday, December 24, 2011 6:32 PM
  • Well the shell uses CBT hooks to do focus tracking, so it sounds like the 'works for awhile then ignores messages / causes massive performance degradation' may be something to do with your implementation as opposed to hooking in general.

    >Another question, if I may: are things better if we only consider the text editor window for purposes of catching those events?

    No, the shell really doesn't differentiate between documents and toolwindows in this area, they are all simply window frames that contain window panes.

    edit: Actually, if you are in 2010 look at IKeyProcessorProvoder, it may give you what you want for the editor.


    Saturday, December 24, 2011 6:47 PM
  • Thanks for the advice but I still cannot get it to work. I'm using the 'canonical' keyboard hook implementation, i.e., code that is found all over the internet. And it works, but then VS starts going all slow, and misses some messages. If I then move the focus somewhere or type too quickly, the hook is just 'gone' and no longer fires.

    Can you maybe suggest some reasons as to why this is happening? Could it be some obscure threading issue, or something to do with the CallNextHookEx call (or perhaps VS or some other app failing to call it)?

    - Dmitri Nesteruk, MVP C#, Microsoft Partner
    Wednesday, December 28, 2011 8:37 PM
  • Hooks are called by Windows not VS.  It is impossible to troubleshoot code without seeing it for something as complex as hooks.  I don't know what the 'canonical' code looks like, I have never seen examples of it, I have only ever gone off MSDN and calling SetWindowsHookEx.  If you are doing that, and you are calling from managed code are you properly pinning your hook callback so it isn't being moved by the GC?  I imagine that would cause callbacks to stop happening, or more accurately, it would cause Win32 to invoke into a random memory location thinking it was a hook callback, invoking god knows what.


    Thursday, December 29, 2011 1:27 AM
  • Actually, that's probably what the problem is with. Originally, I tried passing just a delegate, but that didn't work, so I kept the delegate as a field of a class. This works initially and then fails, and I suspect this isn't enough for my purposes.

    Now, what I just tried to do is to use GCHandle.New() to keep the delegate reference for a bit longer. Unfortunately, this doesn't work because I get an ArgumentException which states "Object contains non-primitive or non-blittable data.". However, this discussion suggests that this approach is redundant.

    Any advice?

    - Dmitri Nesteruk, MVP C#, Microsoft Partner
    Thursday, December 29, 2011 5:11 PM
  • Interesting, I had always heard it needed to be done (i.e. the pinning), but if the marhsalling layer is adding indirection and/or JITed code is not movable/relocatable (i.e. the JITed callback method itself) then that would be unecessary. 

    Looking at our CBT hook code we don't explicitly pin it and we simply pass it as a delegate instance over a class (instance) method, so it appears that post is correct (as we have never seen the hook 'stop working' or giving any kind of problems).

    All our hook does is raise an internal .NET event on receipt of HCBT_SETFOCUS and then call CallNextHookEx.

    Further troubleshooting would require repro code, but I suspect the problem is in the hook code and not VS or Windows, since otherwise I would imagine more people would be seeing this.


    Thursday, December 29, 2011 6:27 PM