Página 1 de 1
Capturar eventos de foco globales
Publicado: 02 Mar 2010, 14:36
por Ximorro
En esta entrada
http://www.emesn.com/autoitforum/viewto ... f=3&t=1809
me resolvió Chefito cómo controlar el foco de mi GUI hecho en AutoIt.
Ahora la consulta es parecida pero más complicada: ¿cómo controlar el foco de todas las ventanas de Windows?
Es decir, por ejemplo que el siguiente código me mostrara qué ventana obtiene y pierde el foco.
Código: Seleccionar todo
#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
GuiCreate("Mi GUI de AutoIt")
GuiSetState()
GUIRegisterMsg($WM_SETFOCUS, "WM_SETFOCUS")
GUIRegisterMsg($WM_KILLFOCUS, "WM_KILLFOCUS")
While GUIGetMsg() <> $GUI_EVENT_CLOSE
WEnd
Func WM_SETFOCUS($hWnd, $iMsg, $iwParam, $ilParam)
ConsoleWrite("WM_SETFOCUS: " & WinGetTitle($hWnd) & @LF)
Return $GUI_RUNDEFMSG
EndFunc
Func WM_KILLFOCUS($hWnd, $iMsg, $iwParam, $ilParam)
ConsoleWrite("WM_KILLFOCUS: " & WinGetTitle($hWnd) & @LF)
Return $GUI_RUNDEFMSG
EndFunc
Pero sólo me muestra los mensajes de mi propio GUI.
En realidad ni siquiera quiero usar un GUI, quiero ver qué ventanas se van activando y desactivando en Windows...
Una manera cutre que se me ocurre es ir haciendo WinGetHandle([active]) continuamente, y si cambia respecto a una llamada anterior pues la anterior ha perdido el foco y la actual lo ha ganado. Pero no mola porque además de usar mucha CPU se puede saltar fácilmente activaciones de ventanas si se producen varias entre llamada y llamada.
¿Hay alguna manera de hacerlo por eventos o similar?, sería genial algo parecido a los WM_xxxFOCUS pero que me notifique todas las ventanas...
Graciaaaaas
Re: Capturar eventos de foco globales
Publicado: 03 Mar 2010, 00:25
por Chefito
Yo no lo veo tan chapucero lo que dices. Yo utilizaría la función AdlibRegister, la cual ha sustituído a AdlibEnable. Ahora puedes ejecutar varias funciones al mismo tiempo de forma asíncrona.
Otra forma es como siempre con apis a saco
. Tenemos que utilizar hooks para enguanchar los mensajes de windows. Esto es bastante complicado.
He intentado una forma pero no me ha salido. Por alguna razón se desenguancha.
En el foro ingles he visto esto:
http://www.autoitscript.com/forum/index ... ntry545125
He adaptado la función un poquito:
Código: Seleccionar todo
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>
Global Const $HSHELL_WINDOWACTIVATED = 4
$hGUI = GUICreate("My Ownerdrawn Created Button", 300, 200)
GUIRegisterMsg(_WinAPI_RegisterWindowMessage("SHELLHOOK"), "FocoDeVentana")
ShellHookWindow($hGui, 1)
GUISetState(0)
$focoWinAnt=WinGetTitle("[active]")
ConsoleWrite("Tiene el foco la ventana: " & $focoWinAnt & @LF&@LF)
While 1
Sleep(10)
WEnd
Func FocoDeVentana($hWnd, $Msg, $wParam, $lParam)
ConsoleWrite($wparam)
If $hshell_windowactivated=$wparam Then ConsoleWrite("Abandonó el foro: " & $focoWinAnt & @LF &"Tiene el foco la ventana: " & WinGetTitle("[active]") & @LF & @LF)
$focoWinAnt=WinGetTitle("[active]")
Return $GUI_RUNDEFMSG
EndFunc
Func ShellHookWindow($hWnd, $bFlag)
Local $sFunc = 'DeregisterShellHookWindow'
If $bFlag Then $sFunc = 'RegisterShellHookWindow'
Local $aRet = DllCall('user32.dll', 'int', $sFunc, 'hwnd', $hWnd)
Return $aRet[0]
EndFunc
Espero que te sirva de algo.
Saludos.
Re: Capturar eventos de foco globales
Publicado: 03 Mar 2010, 10:19
por Ximorro
Jo, ya lo creo que sirve, como la seda. ¡GRACIAS!
Esto de los hooks como no lo conozco no se me ocurre a mí ni de coña. Sí lo prefiero porque los Adlib tienen que estar continuamente mirando, cuando así te notifica el mensaje y sólo actúas en ese momento.
Je je, en vez de "Abandonó el foco" has puesto "Abandonó el
foro". Nooooooooooooo, no abandones el foroooooooooooo.
Una cosa que no entiendo, ¿es necesario tener un GUI para enganchar el Hook? ¿no se puede simplemente asociar al proceso?
Desde luego si quito el
ShellHookWindow no va. ¿Por qué no es suficiente el
GUIRegisterMsg?
Evidentemente no es vital, se puede tener un GUI oculto, pero me parece una restricción tonta cuando no te hace falta para nada dicho GUI...
Re: Capturar eventos de foco globales
Publicado: 01 Sep 2011, 20:37
por melvinhn
En una busqueda encontres este scrip
pero la ayuda que necesito es, cuando el titulo no es el mismo y se pierde podria recibir un nuevo foco
me explico estoy en mi pc, entro a la unidad C: ya la ventana tiene un nuevo titulo, o bien en la unidad c: entro a archivo de programa ya cambia el titulo
hay alguna manera que se actualize, cada vez que vas entrando a una carpeta.
Re: Capturar eventos de foco globales
Publicado: 01 Sep 2011, 21:00
por Jonny
Efectivamente, lo suyo es hacerlo con hooks. Yo se algo de estos, pero no los domino al cien por cien si no es mirando la documentación de las apis que los gestionan.
No he probado el código de Chefito, si funciona bien nada. Pero sino, quizá también podrías hacerlo capturando los mensajes del sistema (hooks globales). En autoit en principio no sería posible, pero posteé una dll para poder hacerlo...
El tema de los hooks es bastante complicado pero una vez se domina, da un juego impresionante en los programas.
Salu2!
Saber titulo de cualquier ventana activa y si cambia éste.
Publicado: 02 Sep 2011, 00:07
por Chefito
Dios!!! Escribí yo esto? Ni me acordaba
.
Mmmmmm.....programar con apis es algo complicado. Ya ni te cuento manejar hooks
. Se necesita saber bastante de apis de windows y autoit. Es un nivel bastante avanzado.
Supongo que si hubieses analizado el código y entendido (creo que no lo entiendes), hubieses visto que dejé ConsoleWrite($wparam) dentro de la función que recoge los mensajes de las ventanas. Analizando estos mensajes devueltos, hubieses visto que cuando cambias el título de la ventana salta varias veces el 6 en hexadecimal. Pues ya tienes el mensaje que necesitas
.
Vale, lo vamos a hacer bien. Vamos a esta página del msdn de microsoft para ver los valores de los códigos hook que nos puede mandar una ventana. Se trata del primer parámetro de la función ShellProc:
http://msdn.microsoft.com/en-us/library ... S.85).aspx
Bueno, pues leyendo un poquito y traduciendo mal y pronto, vemos esto que es lo que nos interesa:
HSHELL_REDRAW
6
The title of a window in the task bar has been redrawn.
Dios!!! Sorpresa!!! Coincide con el número 6 del principio!!
.
Pues con esto y un bizcocho ya tenemos la constante que necesitamos.
Un código que te dice cual es el título de la ventana activa y si ha cambiado podría ser algo así:
Código: Seleccionar todo
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>
Global Const $HSHELL_WINDOWACTIVATED = 4
Global Const $HSHELL_REDRAW = 6
Global $tituloAnterior
$hGUI = GUICreate("My Ownerdrawn Created Button", 300, 200)
GUIRegisterMsg(_WinAPI_RegisterWindowMessage("SHELLHOOK"), "FocoDeVentana")
ShellHookWindow($hGui, 1)
GUISetState(0)
$tituloAnterior=WinGetTitle("[active]")
ConsoleWrite(">>La ventana activa es: " & $tituloAnterior & @LF&@LF)
While 1
Sleep(10)
WEnd
Func FocoDeVentana($hWnd, $Msg, $wParam, $lParam)
;~ ConsoleWrite($wparam)
Switch $wParam
Case $HSHELL_REDRAW=$wparam
$tituloVentana=WinGetTitle("[active]")
If $tituloVentana<>$tituloAnterior Then
$tituloAnterior=$tituloVentana ;con esto evitamos que se repita varias veces el consolewrite, ya que el mismo mensaje se lanza varias veces.
ConsoleWrite("<<El título de la ventana ha cambiado. Ahora es: " & $tituloVentana & @LF & @LF)
EndIf
Case $HSHELL_WINDOWACTIVATED
ConsoleWrite(">>La ventana activa es: " & WinGetTitle("[active]") & @LF&@LF)
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc
Func ShellHookWindow($hWnd, $bFlag)
Local $sFunc = 'DeregisterShellHookWindow'
If $bFlag Then $sFunc = 'RegisterShellHookWindow'
Local $aRet = DllCall('user32.dll', 'int', $sFunc, 'hwnd', $hWnd)
Return $aRet[0]
EndFunc
Como habrás comprobado dispones de varios mensajes que envían las ventanas en la página del mdsn que te pasé antes. Puedes capturarlos y hacer que haga lo que quieras añadiendolos al switch.
Un dato curioso que se me acaba de ocurrir ahora mismo. Por ejemplo, sabiendo el handle de una ventana específica a la cual le quisieses capturar cualquier tipo de mensajes, podrías utilizar la api getmessage. Tendrías que implementarla (y sus estructuras) y hacer alguna otra cosilla que seguro que es complicada
.
Tiene que haber muchas más formas de hacer cosas de estas. Las apis de win son un mundo. Te puedes volver loco
.
Saludos.
Re: Capturar eventos de foco globales
Publicado: 02 Sep 2011, 07:53
por Ximorro
melvinhn, otra manera de no tener problemas con los cambios de título de ventana es usar su identificador único de Windows, en vez del título. Es lo que llamamos "handler" o manejador.
Así en vez de $titu=WinGetTitle("[active]"), que te da directamente el título, puedes hacer $hWnd=WinGetHandle("[active]").
Lo bueno de este método es que aunque cambie el título de una ventana ¡su manejador sigue siendo el mismo!
Así que puedes usar el esquema de Chefito pero mirando si cambia el manejador, en vez del título, de esa manera cuando una ventana cambie de título pero no de foco lo detectarás.
Además en cualquier momento puedes saber el título de esa ventana con WinGetTitle($hWnd).
De la misma manera, si tienes un título puedes obtener su manejador con WinGetHandle($titu)
Re: Capturar eventos de foco globales
Publicado: 02 Sep 2011, 09:08
por ms999
Y otra manera de conseguir el handle es usando la clase
$WinHandle = WinGetHandle("[CLASS:CabinetWClass]")
Yo suelo usar este metodo, casi nunca uso el titulo de la ventana, quiza si se que habran varias ventantas abiertas de lo mismo.
Re: Capturar eventos de foco globales
Publicado: 02 Sep 2011, 11:00
por Ximorro
Bueno, es la misma, la función
WinGetHandle
Pero no entiendo lo que quieres decir. Esto era para tomar la ventana con el foco, por eso usamos
"[active]", si pones una clase específica pues sólo sirve para esa, que además puede no tener el foco...
Re: Capturar eventos de foco globales
Publicado: 02 Sep 2011, 11:13
por Chefito
Mmmmm....ahora que lo pienso y leo a los compañeros....puede que te haya entendido mal y tu hayas buscado un mal código para hacer algo. Si lo que quieres es trabajar con una ventana, y la estás identificando por su título, y éste cambia perdiendo la posibilidad de seguir trabajando con la ventana, haz caso a los compas e inicialmente saca su handle (identificador de ventana) con wingethandle. Este nunca cambia. Ya te explican los compañeros como hacerlo. Si es esto, olvida mi código que no tiene nada que ver.
Como te referiste a este post, yo pensaba que necesitabas saber de manera asíncrona cuando cambiaba el título de cualquier ventana
.
Saludos.
Re: Capturar eventos de foco globales
Publicado: 02 Sep 2011, 20:45
por melvinhn
Pues mira en lo que cabe me ha ayudado el codigo
pero ahora me presenta la siguiente inquietud
Código: Seleccionar todo
While(1)
HotKeySet("^!v", "TituloVentana")
Sleep(100)
WEnd
Func TituloVentana()
Switch $TituloVentana = "("&@UserName&") "&WinGetTitle("[active]")
If $TituloVentana < > $TituloAnterior Then
$TituloAnterior = $TituloVentana ;con esto evitamos que se repita varias veces el consolewrite, ya que el mismo mensaje se lanza varias veces.
ConsoleWrite(@CRLF&$TituloVentana&@CRLF)
EndIf
EndSwitch
EndFunc
Quiero captuara el titulo de la ventana al precinar la combinacion de teclas Control + Alt + V
pero no quiero que el titulo se repita... si yo aprieto la combinacion de teclas dos veces no quiero que se repita el titulo.
bueno de antemano gracias...
Re: Capturar eventos de foco globales
Publicado: 03 Sep 2011, 00:35
por ms999
A ese codigo le falta bastante para ser de AutoIt... xD solo un poco
Empezando que no entiendo bien que es lo que queres. Escribir el nombre de la ventana activa cuando presionas CTRL + ALT + V y que si el nombre de la ventana es el mismo que no lo escriba?
bueno suponiendo que es eso lo que queres empezemos con esto
No es necesario poner HotKeySet() dentro de un bucle porque no es necesario Declarar esa funcion tantas veces, solo haciendolo una vez ya esta bien
El bucle no se escribe asi While(1) como posiste, sino que se pone While 1 o While true o While 2 = 2 o la condicion que quieras.
No se que intentaste hacer con Swithc pero no funciona de esa manera y tampoco lo veo tan necesario para este caso, mira como ejemplo de Switch los codigos que te tira el KodaForm.
Las Variables que queres que sobrevivan cuando termine la funcion las debes guardar en una variable Global, ya que todas las variables que creas dentro de una funcion sin especificar si es Local, Global, son por defecto tomadas como locales, por lo tanto dejan de existir una vez que terminó la función.
La convinación de teclas que elegiste no me parece la mejor, ya que se confunde con la acción PASTE de windows.. (esto es a elección, yo eleji SHIFT + F2)
Y por ultimo agregué una función y una hotkey para terminar el script de manera sencilla.
Código: Seleccionar todo
HotKeySet("{ESC}", "_exit")
HotKeySet("+{F2}", "TituloVentana")
Global $TituloAnterior
While True
Sleep(100)
WEnd
Func TituloVentana()
Local $TituloVentana = WinGetTitle("[active]")
If $TituloVentana <> $TituloAnterior Then
$TituloAnterior = $TituloVentana
ConsoleWrite(@CRLF & $TituloVentana & @CRLF)
EndIf
EndFunc ;==>TituloVentana
Func _exit()
Exit
EndFunc
Espero que esto te sirva y pregunta cuanto quieras! disculpa si aveces
mucho!
Re: Capturar eventos de foco globales
Publicado: 03 Sep 2011, 03:37
por melvinhn
Por eso les pregunto a los experto, tu sabes uno que apenas empieza
tiene que ir aprendiento cada dia.
justo lo que queria me sirvio de mucho el codigo