kkm mistrusts SE
kkm mistrusts SE

Reputation: 5548

IVsTextManager::GetActiveView(true, null, ...) returns non-focused view

I am playing with creating a Visual Studio text editing command. I got as far as creating a package, binding the command, placing it into the menu. But what I cannot do in a Microsoft-recommended way is figure out whether there is an active text view to which the command should be applied.

I am following steps in the VSSDK tutorial (scroll down to Using the Menu Command to Add the Comment Adornment). Upon selecting the command from the menu, mt command handler is called all right. however, when the following exact tutorial code is executed, the results I am getting are inconsistent.

IVsTextManager txtMgr = (IVsTextManager)GetService(typeof(SVsTextManager));
IVsTextView vTextView = null;
int mustHaveFocus = 1;
txtMgr.GetActiveView(mustHaveFocus, null, out vTextView);

Now, if there are only text views, everything works as you'd expect: the active text view is returned. But throw another view in the picture (I am using a Bitmap editor), and the view returned by GetActiveView appears to be the last active text view. I. e., if I switch tabs to bring up the bitmap view over previously active view to fileA, the same view for fileA is returned. In other words, I cannot figure out whether the text view is focused or not.

Now, this seems to be insconsistent with (however poor) documentation of IVsTextManager::GetActiveView(). It has to say about the first argument to the function: if true, then the current UI active view is returned. Am I reading that correctly? The behavior that I am observing seemingly corresponds to the other case: if false, then the last active view is returned, regardless of whether this view is currently UI active.

I can figure out another way of binding commands to views, namely by hooking up view creation. What worries me here is that I am apparently unable to process the command in the Microsoft-recommended way.

Upvotes: 1

Views: 429

Answers (3)

Carl Reinke
Carl Reinke

Reputation: 393

GetActiveView(fMustHaveFocus, pBuffer, out ppView) apparently ignores fMustHaveFocus if pBuffer is null. If it is not null, it works as documented.

So you can get the active-and-must-have-focus view by calling GetActiveView a second time with the buffer of the view that it returned the first time.

IVsTextView vsTextView;
IVsTextLines vsTextLines;
// `GetActiveView` apparently ignores `fMustHaveFocus` if `pBuffer` is null, so call
// it a second time with the buffer from the view it returned the first time to find
// out if the view actually has focus.
if (textManager.GetActiveView(1, null, out vsTextView) == VSConstants.S_OK &&
    vsTextView.GetBuffer(out vsTextLines) == VSConstants.S_OK &&
    textManager.GetActiveView(1, vsTextLines, out vsTextView) == VSConstants.S_OK)
{
    // vsTextView has focus.
}

Upvotes: 1

MJW
MJW

Reputation: 387

The answer from the dev on VS editor team to use a different method may work for the person who asked the original question, but for us who want to use GetActiveView for other reasons, the question remains: how does one get only text windows with focus rather than the last text window that had focus? The unreliable documentation (which suggests mustHaveFocus is a boolean even though it's an int) seems to be misleading, since setting the value to either 0 or 1 (or -1) appears to result in the last text window with focus being returned.

Upvotes: 2

Oleg Tkachenko
Oleg Tkachenko

Reputation: 2806

Well, sorry for the confusing documentation, but this walkthrough is not something I would recommend for your case (I'm a dev on VS editor team).

As you pointed out you can handle commands much simpler by hooking up command filter via IVsTextViewCreationListener, this is actually way more common and better way, see Walkthrough: Using a Shortcut Key with an Editor Extension (that is also sort of confusing title :( )

Upvotes: 1

Related Questions