Как я могу контролировать, какое окно в настоящее время имеет фокус клавиатуры - PullRequest
15 голосов
/ 04 сентября 2008

Есть ли способ отследить, какое окно в данный момент имеет фокус клавиатуры. Я мог бы обработать WM_SETFOCUS для каждого окна, но мне интересно, есть ли альтернативный, более простой метод (то есть где-то один обработчик сообщений).

Я мог бы использовать OnIdle () в MFC и вызвать GetFocus (), но это выглядит немного странно.

Ответы [ 7 ]

17 голосов
/ 04 сентября 2008

Итак, из того, как вы сформулировали вопрос, я понимаю, что вы хотите иметь обработчик событий, который вызывается всякий раз, когда фокус переключается между окнами. Вы хотите получать уведомления, а не опрашивать.

На самом деле я не думаю, что вызов GetFocus из OnIdle - это большая часть хака - конечно, это опрос, но это опрос с минимальными издержками без побочных эффектов - но если вы действительно хотите это отслеживать, Windows Hooks вероятно, ваш лучший выбор. В частности, вы можете установить ловушку CBT (WH_CBT) и прослушать уведомление HCBT_SETFOCUS.

Windows вызывает хук WH_CBT с этим кодом хука, когда Windows собирается установить фокус на любое окно. В случае специфических для потока хуков окно должно принадлежать потоку. Если функция фильтра возвращает TRUE, фокус не изменяется.

Вы также можете сделать это с помощью ловушки WH_CALLWNDPROC и прослушать сообщение WM_SETFOCUS.

В зависимости от того, используете ли вы глобальный хук или локально для приложения, вы можете отслеживать фокусировку на всех окнах системы или только на окнах, принадлежащих вашему процессу.

3 голосов
/ 18 сентября 2008

Существует простой способ использования .Net Framework 3.5: библиотека UI Automation предоставляет измененный фокус события, который срабатывает при каждом изменении фокуса на новый элемент управления.

Страница на 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 ...

3 голосов
/ 04 сентября 2008

Как насчет Win32 GetForegroundWindow ?

1 голос
/ 21 мая 2009

Если вы программируете на .net 3.5, пакет, который олорин упоминает, является самым простым, но остерегайтесь использовать его в программе, которая сама имеет пользовательский интерфейс, по крайней мере, если пользовательский интерфейс выполняется в WPF - Хуки отслеживания фокуса запутываются событиями в его собственном приложении и быстро блокируют пользовательский интерфейс. Я послал MS сообщение об ошибке 1002 *. Я не наблюдал такой же проблемы при использовании традиционного интерфейса Windows Forms. Конечно, вы можете поместить код отслеживания в отдельное консольное приложение и использовать какой-нибудь ipc для передачи необходимой вам информации.

Заманчивая альтернатива использования Interop для доступа к хуку Windows WH_CBT из C # не будет работать - единственные глобальные хуки, которые вы можете получить из C # - это мышь и клавиатура .

0 голосов
/ 08 мая 2009

http://msdn.microsoft.com/en-us/library/ms771428.aspx

Имеет образец трекера фокусировки окна.

0 голосов
/ 04 сентября 2008

Ну, это может быть не очень изящно ... но вы можете довольно легко получить текущий фокусированный элемент управления Таким образом, вы можете подумать о настройке таймера, который спрашивает каждые полсекунды или около того: «Где находится текущий фокус? Пример кода 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>
0 голосов
/ 04 сентября 2008

Вы можете отслеживать сообщения для события WM_ACTIVATE .

исх

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...