winapi - usar - ¿Cómo puedo monitorear qué ventana tiene actualmente foco de teclado?
winapi tutorial (7)
¿Hay alguna manera de rastrear qué ventana tiene actualmente el foco del teclado? Podría manejar WM_SETFOCUS para cada ventana pero me pregunto si hay un método alternativo, más simple (es decir, un manejador de mensajes único en alguna parte).
Podría usar OnIdle () en MFC y llamar a GetFocus (), pero eso parece un poco hacky.
¿Qué tal el Win32 GetForegroundWindow ?
Bueno, esto puede no ser muy elegante ... pero puedes recuperar el control enfocado actual con bastante facilidad. Entonces, podría considerar configurar un temporizador que pregunte cada 1/2 segundo más o menos "¿Dónde está el foco actual?" ... Entonces puede observar los cambios. Ejemplo de código Delphi está abajo; debería ser bastante fácil de adaptar, ya que el trabajo real está en las llamadas a la API de Windows.
<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>
Entonces, por la forma en que redactó la pregunta, infiero que desea tener un controlador de eventos que se invoca cada vez que se cambia de foco entre ventanas. Desea que lo notifiquen, en lugar de tener que sondear.
De hecho, no creo que llamar a GetFocus desde OnIdle es mucho más un hack, seguro que es un sondeo, pero es un sondeo bajo sin efectos secundarios, pero si realmente quieres hacer un seguimiento de esto, Windows Hooks es probablemente tu mejor opción. Específicamente, puede instalar un gancho CBT (WH_CBT) y escuchar la notificación HCBT_SETFOCUS.
Windows llama al enlace WH_CBT con este código de enlace cuando Windows está a punto de establecer el foco en cualquier ventana. En el caso de ganchos específicos de subprocesos, la ventana debe pertenecer al subproceso. Si la función de filtro devuelve TRUE, el enfoque no cambia.
También podría hacerlo con un enlace WH_CALLWNDPROC y escuchar el mensaje WM_SETFOCUS.
Dependiendo de si lo convierte en un gancho global o local de aplicación, puede rastrear el enfoque en todas las ventanas del sistema, o solo en las ventanas que pertenecen a su proceso.
Existe una manera sencilla de utilizar .Net Framework 3.5: la UI de la biblioteca Automatización proporciona un enfoque de evento modificado que se activa cada vez que el foco cambia a un nuevo control.
Muestra:
public void SubscribeToFocusChange()
{
AutomationFocusChangedEventHandler focusHandler
= new AutomationFocusChangedEventHandler(OnFocusChanged);
Automation.AddAutomationFocusChangedEventHandler(focusHandler);
}
private void OnFocusChanged(object src, AutomationFocusChangedEventArgs e)
{
AutomationElement focusedElement = sender as AutomationElement;
//...
}
De hecho, esta api utiliza Windows hook detrás de las escenas para hacer eso. Sin embargo, debe usar .Net Framework ...
Puede supervisar mensajes para el evento WM_ACTIVATE .
Si está programando en .net 3.5, el paquete de automatización que menciona olorin es de lejos el más fácil, pero tenga cuidado de usarlo en un programa que tenga una IU, al menos si la interfaz de usuario está hecha en WPF: los enganches de seguimiento de foco confundirse con los eventos en su propia aplicación y bloquear rápidamente la interfaz de usuario. Le envié a MS un informe de error . No he observado el mismo problema usando una interfaz de usuario de Windows Forms tradicional. Por supuesto, podría poner el código de seguimiento en una aplicación de consola separada y usar algún tipo de ipc para transmitir la información que necesita.
La tentadora alternativa de utilizar Interop para acceder al WH_CBT Windows Hook desde C # no funcionará: los únicos ganchos globales que puede obtener desde C # son el mouse y el teclado .
http://msdn.microsoft.com/en-us/library/ms771428.aspx
Tiene una muestra de rastreador de foco de ventana.