2008-09-04 16 views
15

¿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).¿Cómo puedo controlar qué ventana tiene actualmente foco en el teclado?

Podría usar OnIdle() en MFC y llamar a GetFocus() pero parece un poco hacky.

+0

El rastreador de enfoque parece haberse movido aquí: https://github.com/Microsoft/WPF-Samples/tree/master/Accessibility/FocusTracker (Disculpas, no tengo suficiente reputación para agregar esto como comentario a la respuesta relevante anterior). – greiginsydney

Respuesta

3

¿Qué tal el Win32 GetForegroundWindow?

+0

Sé cómo enfocar la ventana, estoy buscando una forma de recibir notificaciones cuando cambia el foco, en una sola ubicación. – jmatthias

16

Así que por la forma en que redactó la pregunta inferir que desea tener un controlador de eventos que se invoca cada vez que el foco cambia de una ventana a otra. Desea que lo notifiquen, en lugar de tener que sondear.

En realidad, no creo que llamar a GetFocus desde OnIdle es mucho más complicado, seguro que es un sondeo, pero es una encuesta baja sin efectos secundarios, pero si realmente quieres rastrear 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 enganche WH_CBT con este código de gancho 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 gancho 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.

+0

Esta es la respuesta correcta. –

0

Bueno, esto no puede ser muy gracioso ... pero se puede recuperar el control de centrado 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> 
3

hay una manera más fácil usando .Net Framework 3.5: la biblioteca UI Automation proporciona un enfoque acontecimiento cambió incendios que cada vez que el cambio de enfoque a un nuevo control.

Page on MSDN

muestra:

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

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

esta API, de hecho, las ventanas de uso enganchan detrás de las escenas para hacer eso. Sin embargo, usted tiene que utilizar el .Net Framework ...

1

Si está programando en .net 3.5, el paquete de automatización que menciona olorin es de lejos el más fácil, pero ten 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 se confunden con eventos en su propia aplicación y bloquea rápidamente la IU. Envié MS un bug report en él. No he observado el mismo problema usando una interfaz de usuario de Windows Forms tradicional. Podría, por supuesto, 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 usar Interop para acceder al WH_CBT Windows Hook desde C# no funcionará - the only global hooks you can get at from C# are the mouse and keyboard.

Cuestiones relacionadas