2008-09-04 82 views
15

有没有方法可以跟踪哪个窗口当前具有键盘焦点。我可以为每个窗口处理WM_SETFOCUS,但我想知道是否有另一种更简单的方法(即某个单独的消息处理程序)。如何监视当前哪个窗口具有键盘焦点

我可以在MFC中使用OnIdle()并调用GetFocus(),但这看起来有点乱。

+0

焦点跟踪器似乎已移动到这里: https://github.com/Microsoft/WPF-Samples/tree/master/Accessibility/FocusTracker(道歉,我没有足够的声望将其添加为评论到上面的相关答案)。 – greiginsydney 2017-06-10 06:46:23

回答

3

Win32 GetForegroundWindow怎么样?

+0

我知道如何让焦点聚焦于窗口,我正在寻找一种方式,在焦点发生变化时通知您一个位置。 – jmatthias 2008-09-04 17:57:19

16

因此,从你提出这个问题的方式,我推断你想要一个事件处理程序,无论何时在窗口之间进行焦点切换时都会调用它。您希望得到通知,而不必轮询。

我实际上并不认为从OnIdle调用GetFocus是一件骇人听闻的事 - 确保它是轮询的,但它的低开销轮询没有副作用 - 但如果你真的想跟踪这个,Windows Hooks可能是你最好的选择。具体而言,您可以安装CBT挂钩(WH_CBT)并监听HCBT_SETFOCUS通知。

当Windows将焦点设置到任何窗口时,Windows使用此挂接代码调用WH_CBT挂钩。在线程特定的钩子的情况下,该窗口必须属于该线程。如果过滤器函数返回TRUE,则焦点不会更改。

你也可以使用WH_CALLWNDPROC钩子来监听WM_SETFOCUS消息。

根据您是否使其成为全局挂钩或本地应用程序,您可以跟踪系统上所有窗口的焦点,还是只跟踪流程拥有的窗口。

+0

这是正确的答案。 – 2014-05-02 01:56:27

0

那么,这可能不是很优雅......但是你可以很容易地检索当前集中控制。所以你可以考虑设置一个计时器,每隔1/2秒问一次“当前焦点在哪里?”......然后你可以观察到变化。示例Delphi代码如下所示;它应该很容易适应,因为真正的工作是在Windows API调用中。

<snip> 

function TForm1.GetCurrentHandle: integer; 
var 
    activeWinHandle: HWND; 
    focusedThreadID : DWORD; 
begin 
    //return the Windows handle of the currently focused control 
    Result := 0; 
    activeWinHandle := GetForegroundWindow; 
    focusedThreadID := GetWindowThreadProcessID(activeWinHandle,nil); 
    if AttachThreadInput(GetCurrentThreadID,focusedThreadID,true) then begin 
    try 
     Result := GetFocus; 
    finally 
     AttachThreadInput(GetCurrentThreadID, focusedThreadID, false); 
    end; 
    end; //if attached 
end; 

procedure TForm1.Timer1Timer(Sender: TObject); 
begin 
    //give notification if the handle changed 
    //(this code gets fired by a timer) 
    CurrentHandle := GetCurrentHandle; 
    if CurrentHandle <> PreviousHandle then begin 
    Label1.Caption := 'Last focus change occurred @ ' + DateTimeToStr(Now); 
    end; 
    PreviousHandle := CurrentHandle; 
end; 

<snip> 
3

有使用.NET Framework 3.5的简单方法:图书馆UI自动化提供了一个事件的焦点改变了火灾每次对焦变化到一个新的控制。

Page on MSDN

样品:

public void SubscribeToFocusChange() 
{ 
    AutomationFocusChangedEventHandler focusHandler 
     = new AutomationFocusChangedEventHandler(OnFocusChanged); 
    Automation.AddAutomationFocusChangedEventHandler(focusHandler); 
} 

private void OnFocusChanged(object src, AutomationFocusChangedEventArgs e) 
{ 
    AutomationElement focusedElement = sender as AutomationElement; 
    //... 
} 

这个API实际上是使用Windows钩子在幕后做。但是,你必须使用.NET Framework ...

1

如果您使用.net 3进行编程。5,自动化包olorin提到目前为止最简单,但要小心在一个本身具有UI的程序中使用它,至少如果UI是在WPF中完成的 - 焦点跟踪挂钩会被自己的应用中的事件弄糊涂,并快速锁定用户界面。我给MS发了一个bug report就可以了。我没有使用传统的Windows Forms UI观察到同样的问题。当然,您可以将跟踪代码放在单独的控制台应用程序中,并使用某种ipc来传输所需的信息。

使用Interop从C#访问WH_CBT Windows Hook的诱惑性替代方法将不起作用 - the only global hooks you can get at from C# are the mouse and keyboard