Página 3 de 3

Re: Ayuda con Winlist()

Publicado: 30 Sep 2009, 12:28
por Ximorro
Una cosa, sigo haciendo pruebas y a mí me va mejor mirando $WS_EX_TOOLWINDOW que $WS_CAPTION.
Si tengo por ejemplo una ventana creada así:
Local $GUI_etq = GUICreate("Recuadro", $tamx, $tamy, $posx, $posy, $WS_POPUP, $WS_EX_TOPMOST)

En ALT+TAB de Windows aparece, y entonces en tu programa hay que mirar $WS_EX_TOOLWINDOW (lo que hacías antes) para que se comporte igual...

Aunque no tenga caption en ALT+TAB aparece... en realidad título sí tiene, "Recuadro", pero al ser tipo $WS_POPUP no se ve.
Pero eso no es importante, resulta que si pongo "" como título sigue saliendo en ALT+TAB (la cajita del nombre está vacío pero me sale el icono de autoit).
Esto es de aspecto como un ToolWindow, pero al no ser realmente un ToolWindow ALT+TAB sí la saca.

¿Qué estilo tenía la ventana que te ha hecho pasar a mirar $WS_CAPTION? A ver si entre la tuya y la mía podemos ver exactamente qué estilo hay que mirar...

Re: Ayuda con Winlist()

Publicado: 01 Oct 2009, 02:12
por Chefito
Pufffff....me gusta tu interes, pero nos estamos pasando :smt005 . Yo encontré una ventana que pertenecía a un programa la cual no era filtrada por la propiedad $WS_EX_TOOLWINDOW y si por la propiedad $WS_CAPTION. Por lo tanto descarté esa propiedad por la otra. Si encuentras una ventana que no es filtrada por el código dilo y lo intentaremos solucionar.
No voy a explicar más cosas de mi código. Creo que ya está toda bastante bien explicado....y si no se entiende, no se explicarlo mejor. Lo siento.
Si alguien puede mejorar el código, que lo haga. Para algo está puesto en el foro.
Dices que ya están definidas algunas funciones en algún udf.....vale....se me habrá pasado. Piensa que este código lo utilizé hace mucho tiempo y puede que esa función no estibiese definida, o simplemente se me pasó (lo siento, no soy perfecto :smt005 :smt005 ). Para eso está el foro. Para incluir opiniones y mejoras. Pero que sepas que una función udf incluida en AutoIt seguro que está definida internamente como la ponemos en el código (o de manera parecida).

Este código para la captura de teclas no te creas que ha sido creado desde 0 por la gente de AutoIt. Yo ya lo conocía de hace muchos años (ya lo utilizé alguna vez) en lenguaje vb6. Lo que han hecho es pasarlo al lenguaje AutoIt.

El próximo post que escriba aquí será para poner un conmutador de tareas personal (anulando el de win). Pero no se cuando lo pondré. Estoy de vacaciones y seguramente me iré al campo sin ningún tipo de tecnología :smt005 :smt005 . Te invito a que tú o alguno lo intente y compararemos funciones.
Ahhh....y gracias por la traducción de la función :smt002 .

Saludos.

Re: Ayuda con Winlist()

Publicado: 01 Oct 2009, 09:23
por Ximorro
Pues esa misma, mirando $WS_CAPTION mi ventana "Recuadro" hace que se líe.

Respecto a las funciones ya definidas en el UDF está más que claro que lo que hacen es EXACTAMENTE lo que haces tú con la llamada a la DLL, simplemente te lo comentaba porque es fácil que se te haya pasado, y aunque la funcionalidad lógicamente es la misma, así es más cómodo escribir la llamada, sólo era por eso.

En realidad aquí hay dos temas diferentes:
a) hacer un intercambiador de tareas tipo ALT+TAB
b) saber exactamente qué ventana tiene seleccionada el ALT+TAB de Windows, que es lo que realmente quiere Jonny

El caso (a) ya lo has solucionado, sólo falta activar la ventana correspondiente. En realidad ya está solucionado porque podemos PASAR de la pesadilla que es la selección de ventanas por ALT+TAB de Windows y usar el orden que nos dé la gana, decidiendo nosotros qué hacemos con las TOPMOST, las TOOLWINDOW y compañía. Siempre que tengamos una ventana seleccionable podemos hacerlo según nuestro criterio, da igual cómo lo haga Windows.

El caso (b) es casi imposible, por dos cosas: primero en cada versión de Windows cambia, por ejemplo he leído que en algunos Vista sólo se comporta como en XP para las 6 ventanas más recientes, las demás las pone alfabéticamente por path o por tipo (por ejemplo todos los explorer juntos). La segunda cosa chunga son los bugs de ALT+TAB, que son los que nos están volviendo locos, porque la caga cuando hay ventanas TOOLWINDOW, que no las muestra pero hace que se equivoque al seleccionar la segunda ventana (por eso a veces se selecciona la primera). Además he leído que a veces no tiene claro el z-order cuando minimizas una aplicación (desapacecen ventanas de la lista que en el siguiente ALT+TAB vuelven a aparecer), y hay aplicaciones "tramposas" que se colocan las segundas aunque las minimices, según he leído pasa bastante con Outlook y a veces con Office (qué casualidad).

De todas maneras voy tomar tu "gancho teclado" y voy a hacer una versión de lo que debería ser la selección de ventanas ALT+TAB sin tener en cuenta por ejemplo esos bugs de la ventana minimizada o las tramposas. Intentaré reproducir el de las ventanas TOOLWINDOW pero ya veremos.

Cuento la idea que tengo en la cabeza por si Jonny quiere ponerse, que si no no aprenderá ;-)
Creo que esto se parecerá bastante a lo que hace ALT+TAB, por lo que he estado leyendo por la web, no lo he comprobado todo 100%, eso lo haré cuando me ponga a hacer el programa, pero eso no será ahora mismo...

ALT+TAB en principio simplemente usa el z-orden de las ventanas para ordenarlas, eso lo tomamos de Chefito con lo de tomar ventanas a partir de "Program Manager" (no se me habría ocurrido en la vida).
Las ventanas TOOLWINDOW deben ser ignoradas y no se ponen en la lista de ventanas seleccionables (en realidad tenemos que tenerlas en cuenta para reproducir el bug de la primera ventana seleccionada, de eso hablamos luego)
PERO resulta que las ventanas TOPMOST siempre están primero en la lista.
Así que por un lado se ordenan las TOPMOST y por otro las normales, al final se juntan las dos listas poniendo primero las TOPMOST.

Por ejemplo si el z-orden de las ventanas que denoto por letras es A B C D E F G, pero resulta que C, E y F son TOPMOST, entonces el orden para ALT+TAB es C E F A B D G. Pero si en ese caso, además, resultaba que B y F son TOOLWINDOW, entonces el resultado final sería C E A D G. Ojo porque una TOOLWINDOW puede ser TOPMOST, en ese caso también desaparece de la lista.

Mi idea es no usar la estructura de Chefito que va mirando las ventanas en cada TAB. Si os fijáis las ventanas seleccionables y su orden se hace la primera vez que se pulsa ALT+TAB, a partir de ahí cada TAB va pasando por esas ventanas cíclicamente. Así que mi idea es elaborar esa lista (metiéndola en un array donde cada valor es un hWnd), teniendo en cuenta lo que he puesto en los párrafos anteriores, de golpe y una sóla vez cuando ALT+TAB también la crea. Tomando la fantástica idea de Chefito eso sería cuando la ventana #32771 aún no ha aparecido, donde él iniciaba $auxOnTop, $hwnd y $EmpezarSegundo, yo ahí generaría el vector de los $hwnd ya ordenadito por Z-order, poniendo primero los TOPMOST, e ignorando los TOOLWINDOW (ver al final las consideraciones sobre el bug)

Después, el bucle principal ya no sería un bucle, sería simplemente

Código: Seleccionar todo

Si $codigo=9 Entonces

  coger siguiente hwnd del vector (o volver al primero si ya hemos llegado al final)

  mostrar su icono y texto

FinSi
Con este código mucho más simple (lo complicado estará en el If Not(WinExists("[CLASS:#32771]"))) podemos incluso pensar en hacer el SHIFT+ALT+TAB, que recorre la lista al revés... aunque no sé cómo mirar en KeyProc el SHIFT+TAB... Simplemente sería ir hacia atrás por el vector de los hwnd.

EL BUG:
Esta es la parte que más hay que investigar si queremos emular exactamente ALT+TAB. El orden de las ventanas parece casi seguro que es el que pongo arriba (en XP, ojo), además en principio siempre habría que empezar seleccionando la segunda ventana (la primera será la que tenemos activa, y ALT+TAB pasa primero a la que usamos anteriormente a esa). El problema con los TOOLWINDOW creo que es que sí los tiene en cuenta al seleccionar esa segunda ventana, pero como luego desaparecen de la lista a veces el segundo se convierte en el primero (por ejemplo si la primera era TOOLWINDOW, al desaparecer la segunda, que estaba seleccionada, ahora está la primera).
Esto habrá que mirarlo con más detenimiento, pero adelanto que ponerse a reproducir bugs de otros puede ser muy complicado...

Hala Jonny ya me dirás.

Y si hacemos una selección de ventanas elegante a lo mejor hasta la usa Chefito :smt002

Conmutador de tareas de win.

Publicado: 01 Oct 2009, 13:26
por Chefito
Mmmmmm......como siempre digo, mis códigos son libres y variables (si puede ser a mejor) para lo que querais :smt024 . Que puede haber bugs en este código? Como se ha visto hasta ahora....claro que sí. Las ventanas tienen muchas propiedades y puede que una se cuele, o la combinanción de algunas.....quien sabe. Yo he intentado filtrar lo mejor posible, pero si encontrais otras condiciones mejores decirlo y las probamos.....y si funcionan mejor varío el post donde se encuentra el código (nombrando al que lo ha hecho.....por supuesto).
Pienso igual que tú. Como dije en su momento mi primera opción y más lógica era hacer el último filtro por la propiedad TOOLWINDOW. Hasta como podeis ver en los post de este tema, creía que ya estaba totalmente resuelto. Pero por casualidades de la vida se me coló una ventana de un programa que no debería estar ahí. Y con la propiedad $WS_CAPTION no pasaba.
Por favor, si tienes definida una ventana la cual se salte este filtro, pon el código de esa ventana para ver que solución le podemos dar.

Igualmente, no se si te habrás fijado, pero en el código dejé en comentarios varios filtros válidos por si fallaba $WS_CAPTION (estaba casi seguro que con alguna iba a fallar, por eso dejé las alternativa :smt005 ).
Una muy buena es sustituir bitand(_WinAPI_GetWindowLong($hWnd, $GWL_STYLE),$WS_CAPTION)=$WS_CAPTION por bitand(_WinAPI_GetWindowLong($hWnd, $GWL_EXSTYLE),$WS_EX_TOOLWINDOW)<>$WS_EX_TOOLWINDOW And _WinAPI_GetWindowHeight($hwnd)>0 And _WinAPI_GetWindowWidth($hwnd)>0.
O quien sabe, seguramente funcione bien un doble filtro, bitand(_WinAPI_GetWindowLong($hWnd, $GWL_STYLE),$WS_CAPTION)=$WS_CAPTION And bitand(_WinAPI_GetWindowLong($hWnd, $GWL_EXSTYLE),$WS_EX_TOOLWINDOW)<>$WS_EX_TOOLWINDOW. O incluir también las condiciones de que no tienen ningún tamaño a lo anterior..........hay muchas posibilidades.
Lo que pasa que yo siempre intento buscar la velocidad y no poner las comparaciones innecesarias, por eso cuando vi que con $WS_CAPTION iba bien, quité las otras. Pero prueba algo de lo que te he dicho arriba y ya me contarás si funcionó o no con tu ventana :smt002 .

Respecto al orden de las ventanas, no te comas la cabeza. La api GetWindow ya te las ordena como tiene que hacerlo (Z-orden). Olvidate de rollo y envolados :smt002 .

Y lo de que no irá en win vista....ni idea, yo no lo tengo ni creo que lo tenga nunca, no me gusta. Debería ir, lo malo es que como tu dices se pueda cambiar el orden de alguna forma (agrupando o no). No se si la api lo reconocería. Alguien lo tendría que probar.
Ximorro escribió:Así que mi idea es elaborar esa lista (metiéndola en un array donde cada valor es un hWnd)
Lo de hacer un array con las ventanas siempre que pulses alt+tab yo ya lo había pensado :smt047 . Al principio estube a punto de hacerlo así. Seguramente es algo más facil de hacer. Lo que pasa que es que como ya he dicho antes busco la velocidad. Y pensé.....como por casualidad haya un montón de programas abiertos van a ver un montón de ventanas y a lo mejor retrasan las pulsaciones. Y si hay mucho retraso _KeyProc puede hacer cosas raras :smt005 . Pero dudo que pase esto. Películas que me monté en la cabeza!!!! :smt005 . Así que montar un array de ventanas válidas es muy buena opción (incluso va a ser necesario por lo que voy a poner más abajo).
Ximorro escribió:podemos incluso pensar en hacer el SHIFT+ALT+TAB, que recorre la lista al revés
Jajajaja.....no sabía ese comportamiento del conmutador :smt005 . Todos los días se aprende algo nuevo :smt016 . Seguramente se podría tratar, no tengas duda. Piensa que también se pueden recorrer las ventanas previas además de las siguientes. También se puede coger la última ventana del Program Manager. En definitiva....más código más código jajajaja. Puede que a causa de esto sí fuese mejor idea hacer un array.

Respecto a mi forma de buscar la ventana........la hice para que fuese bastante rápida. Su funcionamiento es el siguiente: coge la primera ventana y se sale de la función (así no recorro todas las ventanas). Si pulsas de nuevo, coger la posición de la ventana activa y busca la siguiente ventana válida. Cuando la encuentra se sale de la función. Y así continuamente. Vamos, que cada vez que se pulsa el recorrido es de ventana en ventana válida. (1 a 1), que no recorro siempre todas las ventanas.
Pensé que este sistema evitaría el posible retraso que sería el tener que hacer un array de las ventanas válidas la primera vez que pulsas alt+tab, sobre todo si había muchas ventanas. Pero como ya dije antes.....creo que me monté una película, ya que este retraso será ínfimo :smt036 .
Para mostrar el nombre de la ventana próxima (que es lo que quería Jonny) mi forma sirve, pero si quisieras hacer un conmutador de tareas como el de win (que te mostrase todas las ventanas y te dijese cual es la activa) tendrías que hacerlo con un array. Por eso seguramente, tendré que modificar el código para bloquear el conmutador de win y mostrar el mío propio. Ya veremos.
Además, con lo que me has dicho del comportamiento al pulsar SHIFT+ALT+TAB......habrá que tratarlo también!!! jajajaja. Respecto a tratar esa combinación, en un principio se me ocurre que se tendrá que poner una condición viendo el estado de shift (GetKeyState). Puede que haya más opciones, ya lo miraré.
Ximorro escribió:Y si hacemos una selección de ventanas elegante a lo mejor hasta la usa Chefito
Jajajaja.....por supuesto que la usaré. Animaros. A ver que sale :smt003 .

Saludos.

Re: Ayuda con Winlist()

Publicado: 01 Oct 2009, 13:27
por Ximorro
Bien, a ver qué os parece este código que pongo abajo, he implementado lo que cuento arriba así que eso no lo vuelvo a explicar. Cuento algunos detalles:

Los comentarios al principio que explican las variables explican cosas importantes para entender el código de dentro de KeyProc.

Uso la estructura de Chefito, principalmente su GUI y el hook, pero como veis ha quedado considerablemente simplificado, creo.
En el bucle principal del GUI quito el Sleep, pues GUIGetMsg es bloqueante y no consume CPU, además lo he cambiado a un Switch, queda más compacto.

La función _Seleccionable mira si una ventana es del tipo de las que salen en ALT+TAB, si no salen las ventanas que toca habrá que modificar sólo ésta función.

La variable $InicializarLista es importante porque mientras se está pulsando ALT, antes de pulsar TAB, se entra en KeyProc y se ejecutaría varias veces la parte que hay en If (Not WinExists("[CLASS:#32771]")). En el código de Chefito pasaba pero ahí ejecutaba pocas cosas y era un código muy rápido así que daba lo mismo, aquí he preferido hacer el proceso sólo una vez.

He dejado por medio algunos ConsoleWrite que van explicando lo que va pasando, en una versión final se quitarían, claro. Hay que dejar KeyProc lo más simple posible.

Podéis ver en qué ha quedado el proceso de la tecla TAB, ahora son sólo 5 líneas :smt004 . En _ProcesaVentana he sacado el proceso de la ventana, para cambiarlo a lo que se quiera hacer con ella (en este caso es básicamente el código de Chefito mostrando título e icono).
Pero el while y la complicación de pasar a la ventana siguiente ha desaparecido, gracias al preproceso que se guarda en $aHWnd.


Por lo que veo no es tan complicado ver qué ventana va a ser la primera en ser seleccionada por ALT+TAB: simplemente es la siguiente a la actual activa. No hay problema con las TOPMOST, creo. :smt002

El problema está con el bug de las TOOLWINDOW (en realidad con cualquier ventana no seleccionable con ALT+TAB), en ese caso se seleccionaba la primera de la lista y es lo que hago. Si no se selecciona la ventana que toca probablemente el problema está aquí, si os pasa y sabéis qué tipo de ventanas están dando problemas lo decís y lo estudiaremos, pero ya digo que tener en cuenta los bugs de los demás es complicadito.

No copio los códigos de _WinAPI_GetModuleFileNameEx y _WinAPI_FreeHandle porque son las mismas que puso Chefito.

En cambio he quitado _WinIsOnTop porque ya no lo uso, ¡resulta que no he tenido que mirar las TOPMOST! En realidad al ir mirando el z-orden sí que tiene en cuenta las topmost y me las da tal cual las tiene ALT+TAB, el problema era al pillar la primera seleccionada, pero mirando la activa no hay que estar fijándose en las topmost.

No se me ocurre nada más por ahora. Por supuesto puedo haberme equivocado y que la cosa no funcione bien. Para eso está el foro, para ayudarnos entre todos. Si no va bien la culpa es mía, que el código de Chefito que he usado iba de lujo. Pero creo que este código es algo más fácil de modificar y mantener, reconozco que yo el otro muy bien no lo entendía. ¿Cómo lo veis?

Chefito (o quien sepa), ¿cómo se miraría en KeyProc el ALT+SHIFT+TAB? Aquí debería ser bastante fácil recorrer la lista al revés, como hace el Windows...

He aquí la criatura:

Editado:
Límite de vector a 100 y parametrizado
Aceleración del bucle crítico sacando el cálculo de WinGetHandle("[active]") fuera de él

Código: Seleccionar todo

#include <GUIConstantsEx.au3>

#include <WinAPI.au3>

#include<Constants.au3>

#include <WindowsConstants.au3>



Opt("MustDeclareVars", 1)



;$aHWnd es el array de manejadores de ventana que se van mirando en cada pulsación de TAB en un mismo ciclo de ALT+TAB

;Fijo el máximo de ventanas, se pone un número acetablemente grande, mejor no estar redimensionando dentro de KeyProc

;que aquéllo debe ejecutarse lo más rápido posible

Global Const $MAXVENTANAS = 100 ; máximo tamaño del vector

Global $aHWnd[$MAXVENTANAS ]

Global $maxHwnd = 0 ;indicará el índice máximo ocupado en $aHWnd

Global $iHWnd ;índice de ventana seleccionada en cada momento

Global $InicializarLista = True ; Para que mientras se está pulsando ALT, antes del primer TAB, no esté actualizando

    ;constantemente, sólo la primera vez.



Global $ProgramManager = WinGetHandle("Program Manager")



Global $hStub_KeyProc = DllCallbackRegister("_KeyProc", "long", "int;wparam;lparam")

Global $hmod = _WinAPI_GetModuleHandle(0)

Global $hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hStub_KeyProc), $hmod)



Global $gui = GUICreate("Capturador ALT+TAB", 400, 100, 10, 10, -1, $WS_EX_TOPMOST)

Global $label = GUICtrlCreateLabel("", 10, 60, 380, 30)

Global $icon = GUICtrlCreateIcon("", 0, 40, 10) ;necesario que haya al menos un control antes que él, sino no aparece (no refresca bien).

GUISetState()



While 1

    Switch GUIGetMsg()

        Case $GUI_EVENT_CLOSE

            ExitLoop

    EndSwitch

WEnd



Func _KeyProc($nCode, $wParam, $lParam)

    Local $hwnd

    If $wParam = 260 Then ;entra al pulsar la tecla alt

        If (Not WinExists("[CLASS:#32771]")) And $InicializarLista Then

            $InicializarLista = False

            $iHWnd = -1

            $hwnd = _WinAPI_GetWindow($ProgramManager, $GW_HWNDFIRST) ;Primera ventana, es la siguiente a "Program Manager"

            Local $aux_iHWnd = -1 ;índice de la ventana activa, la primera del ALT+TAB es la siguiente a ésta

            Local $hwndActiva = WinGetHandle("[active]") ;para ahorrar cálculo en el bucle

            ConsoleWrite("REINICIANDO LISTA" & @LF)

            While $hwnd <> $ProgramManager ; acabamos cuando volvamos a llegar a "Program Manager"

                If $iHWnd = $MAXVENTANAS Then ExitLoop ;jonny, aquí haz el redim en vez de salir del bucle...

                If _Seleccionable($hwnd) Then

                    $iHWnd+=1

                    $aHWnd[$iHWnd] = $hwnd

                    If $hwnd = $hwndActiva Then

                        ConsoleWrite("ACTIVA --> ")

                        $aux_iHWnd = $iHWnd

                    EndIf

                    ConsoleWrite("#" & _WinAPI_GetWindowText($hwnd) &"#" & @LF)

                EndIf

                $hwnd = _WinAPI_GetWindow($hwnd, $GW_HWNDNEXT)

            WEnd

            ConsoleWrite("FIN LISTA" & @LF)

            $maxHwnd = $iHWnd



            ;Primera ventana seleccionada en ALT+TAB: en principio es la siguiente a la activa, pero si la activa era

            ;una TOOLWINDOW entonces $aux_iHWnd=-1 y se selecciona la primera (tal como hace ALT+TAB de Windows)

            $iHWnd = $aux_iHWnd + 1

            If $iHWnd > $maxHwnd Then $iHWnd = 0 ; ¡Por si son todas TOPMOST y la activa está al final!

        EndIf

        Local $KEYHOOKSTRUCT = DllStructCreate("dword;dword;dword;dword;ptr", $lParam)

        Local $codigo = DllStructGetData($KEYHOOKSTRUCT, 1)

        If $codigo = 9 Then ;entra al pulsar la tecla tab

            $InicializarLista = True

            $hwnd = $aHWnd[$iHWnd]

            _ProcesaVentana($hwnd)

            $iHWnd+=1

            If $iHWnd > $maxHwnd Then $iHWnd = 0 ;da la vuelta

        EndIf

    EndIf

    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)

EndFunc   ;==>_KeyProc



Func _Seleccionable($hW)

    Return $hW <> 0 AND _WinAPI_IsWindowVisible($hW) AND _

        BitAND(_WinAPI_GetWindowLong($hW, $GWL_EXSTYLE), $WS_EX_TOOLWINDOW) <> $WS_EX_TOOLWINDOW

EndFunc



Func _ProcesaVentana($hW)

    Local $tituloWin = _WinAPI_GetWindowText($hW) ;título de la ventana

    GUICtrlSetData($label, $tituloWin)

    Local $proceso = WinGetProcess($hW) ;proceso de la ventana

    Local $pathfile = _WinAPI_GetModuleFileNameEx($proceso) ;nombre completo del archivo del programa que ha cargado la ventana

    GUICtrlSetImage($icon, $pathfile, 0) ;inserto la imagen del icono del programa

EndFunc   ;==>_ProcesaVentana



Func OnAutoItExit()

    ConsoleWrite("Saliendo normalmente..." & @CRLF)

    _WinAPI_UnhookWindowsHookEx($hHook)

    DllCallbackFree($hStub_KeyProc)

EndFunc   ;==>OnAutoItExit

 

Re: Ayuda con Winlist()

Publicado: 01 Oct 2009, 13:28
por Ximorro
Vaya Chefito, otra vez estábamos escribiendo a la vez, :smt005 voy a leerte con tranquilidad...

Re: Ayuda con Winlist()

Publicado: 01 Oct 2009, 14:17
por Ximorro
Bueno ya te he leído...

Respecto a lo que comentas en rojo vuelvo a comprobar tranquilamente y te digo mañana, a ver si no lo vi bien. Bien no iba pero a lo mejor resulta que el filtro estaba bien y lo que no hacía bien era seleccionar la primera ventana. Desde luego con ALT+TAB de windows se sincronizaba con TOOLWINDOWpero no con CAPTION.


Por lo que he podido ver el proceso de meter los handles en el array es super-rápido. Y más si tenemos en cuenta que probablemente la llamada a WinGetHandle("[active]") se puede sacar a una variable local fuera del bucle (no creo que cambie la ventana activa mientras se está ejecutando eso). Además la llamada a _WinAPI_GetWindowText será eliminada en una versión final porque sólo se usa en un ConsoleWrite para ver cómo iba la cosa.
Lo más costoso de ese proceso será _WinAPI_GetWindow($hwnd, $GW_HWNDNEXT), pero tampoco se ejecuta tantas veces.

Ese es el punto débil de mi implementación, eso lo he dejado un poco en el aire, me refiero al número de ventanas seleccionables. He puesto a piñón fijo 50, si hay más no cascará, ya he puesto una condición de control, pero sólo recorrerá las primeras 50 ventanas. ¿¿Alguien ha tenido alguna vez más de 50 ventanas en ALT+TAB?? Bueno, si creéis que es un límite pequeño pues se pone 100, creo que es mejor tener ese límite duro en vez de estar haciendo ReDim dentro de ese bucle crítico, eso sí podría relentizar KeyProc. Ojo, repito que ese límite es el del número de ventanas que salen en ALT+TAB, no el número total de ventanas del sistema que por supuesto pasan fácilmente de 50.

Por cierto, que ese proceso "gordo" sólo se realiza una vez, al pulsar ALT antes de pulsar TAB, ignorando las repeticiones de ALT (repeticiones por Windows, que el usuario no la suelta). Ahora el proceso de TAB es MEGAsimple y encima facilita mucho recorrer la lista al revés para ALT+SHIFT+TAB.

Ale, ya me diréis si lo veis bien o volvemos al original.

Re: Ayuda con Winlist()

Publicado: 01 Oct 2009, 16:42
por Jonny
Hola

Puffffffff.... Me habeis dejado fuera de combate hace muchos post jejeje.

Así para empezar. ¿Donde veis las propiedades de las ventanas?
(En autoit me refiero). ¿En la ayuda de GuiCreate?

Sabiendo eso y entendiendo el código de chefito supongo que estaré en condiciones de intentar escribir algo de código.
Yo tengo Windows XP también, no quiero el Vista, pero intentaré ejecutar el código en uno, a ver como se porta.

No creo que haya mucha gente con 50 ventanas abiertas (5 es para volverse loco) pero siempre he oido eso, de que en la programación hay que contemplar todas las posibilidades jajaja.

Salu2!

Re: Ayuda con Winlist()

Publicado: 02 Oct 2009, 08:31
por Ximorro
Bueno, en mi código se podría contemplar hacer un ReDim si hace falta, poniendo la base de 50 (o 100) no se ejecutará muchas veces, pero la verdad, no creo que sea muy necesario.
Ponle un 100 y ponlo a prueba, ¿¡pero de verdad crees que alguien puede tener 100 ventanas abiertas!? ¡si lo haces hazle un Print-Screen y nos lo mandas :smt003

¿Las propiedades de las ventanas te refieres a las posibilidades que hay? Pues son los estilos que les puedes poner, efectivamente en la ayuda de GUICreate, cuando explica los parámetros, tienes enlaces que te mandan a los estilos normales (parámetro style, enlace GUI Control Styles Appendix), y a los extendidos (parámetro exStyle, explicados más abajo en la misma ayuda). De todas maneras es un poco lio, hay algunos que ni los entiendo. Esto ya no es saber AutoIt, sino Windows...

Para ver qué estilos tiene se puede usar GUIGetStyle que te devuelve un array de dos elementos (estilos normales y extendidos) o _WinAPI_GetWindowLong con el segundo parámetro como $GWL_STYLE (estilos normales) o $GWL_EXSTYLE (estilos extendidos). Hay que usar máscaras para buscar uno concreto, como puedes ver en nuestros códigos.

Por ejemplo para ver si una ventana es TOPMOST, de las que siempre están delante incluso cuando no están activas, se hace:
If BitAND(_WinAPI_GetWindowLong($hVentana, $GWL_EXSTYLE), $WS_EX_TOPMOST) = $WS_EX_TOPMOST Then...

Ya sé que es un poco raro pero intenta ver la estructura y úsala así. El caso es que los estilos no son variables independientes, sino que son bits dentro de una variable única que es el estilo (bueno para ser precisos hay dos números, uno para el estilo normal y otro para el extendido). Para ver el valor de esos bits hay que hacer los BitAnd, que ponen a cero los demás y dejan a uno el que buscas, si en ese bit que buscas se ha quedado un 1 es que había un 1 (1 AND 1 = 1), si queda un cero es que había un cero (0 AND 1 = 0).
Si no entiendes mucho el rollo este no te calientes demasiado la cabeza, la cosa es recordar que se mira con la estructura esa que te he puesto, cambiando $WS_EX_TOPMOST con el estilo que te interese.

Re: Ayuda con Winlist()

Publicado: 02 Oct 2009, 08:35
por Ximorro
Por cierto, si usas mi código recuerda quitar o comentar los ConsoleWrite de la parte de creación del vector, y el comando WinGetHandle("[active]") yo lo precalcularía fuera del While a una variable y dentro usaría la variable.

También puedes poner el límite del vector a 100... fallo importante no haber puesto ese número en una variable, porque está en dos sitios. Y de paso en vez de salir del bucle cuando llega al límite, pues haces un Redim y así ya no hay límite.

Mira, los dos primeros cambios voy a hacerlos y edito el comentario anterior, lo del ReDim te lo dejo como ejercício :smt003

Re: Ayuda con Winlist()

Publicado: 07 Oct 2009, 01:18
por Chefito
Me gusta mucho como has hecho el código Ximorro :smt023 .
Pero parece que vamos a tener que filtrar más. Se sigue colando la ventana que te dije. Además, prueba a tener el Administrador de tareas y verás que el filtrado falla :smt009 .
Pon como filtro $hW <> 0 AND _WinAPI_IsWindowVisible($hW) AND BitAND(_WinAPI_GetWindowLong($hW, $GWL_EXSTYLE), $WS_EX_TOOLWINDOW) <> $WS_EX_TOOLWINDOW and bitand(_WinAPI_GetWindowLong($hWnd, $GWL_STYLE),$WS_CAPTION)=$WS_CAPTION y así nos aseguramos con un buen filtro.

Ahhhh...y ya que te has puesto, yo creo que deberías redimensionar el array, ya que no creo que tampoco se pierda tanto tiempo y se ve más correcto. Además, piensa que se ejecutaría al dar la tecla alt, justo antes de dar el tab. Por eso supongo que el tiempo no sea muy importante.

Saludos.

Re: Ayuda con Winlist()

Publicado: 07 Oct 2009, 10:01
por Ximorro
¡Gracias!

Estooo, no sé cómo será esa ventana tuya pero a mí con el administrador de tareas me funciona perfectamente, es una Topmost que se pone al principio, y me selecciona perfectamente las ventanas exactamente igual que ALT+TAB.
Por ejemplo me hace (si ya sabía yo que los consolewrite me iban a ser útiles ;-) ):
REINICIANDO LISTA
#Capturador ALT+TAB#
#Administrador de tareas de Windows#
ACTIVA --> #D:\Programacion\AutoIt\Teclado\AltTabXimo.au3 - SciTE [2 of 2]#
#Autoit en Español (http://www.Autoit.es) • Publicar una respuesta - Mozilla Firefox#
#D:\Programacion\AutoIt\Teclado#
#D:\#
#Bandeja de entrada para [email protected] - Thunderbird#
FIN LISTA
(ejem, he cambiando el correo que aparecía en el Thunderbird, pero a parte de eso esta es la salida exacta del programa)

La propia ventana del Capturador ALT+TAB y el Administrador son TOPMOST, por eso aparecen al principio, tenía el Scite activo cuando lo ejecuté (el F5 :smt003 ), así que la primera ventana seleccionada por ALT+TAB, así como por mi rutina, es la del Firefox (que está justo en esta página ;-) )
Me salen todas las ventanas tal cual como la ventana ALT+TAB de Windows y va pasando de una a otra en el mismo orden...

Así que no será el admin de tareas lo que lo fastidia, sino otra ¿Qué estilo tiene esa ventana que te falla?

Miraré con lo de $WS_CAPTION, pero recuerdo que cuando probé con tu código original, cuando cambiaste $WS_EX_TOOLWINDOW por $WS_CAPTION, me fallaba en algún sitio.


Lo del Redim se lo había dejado a Jonny como colaboración, incluso he comentado en el código dónde debe tocarlo ;-) Bueno si no vuelve por aquí lo haré yo. Quizás no sea muy lento pero sospecho que crea un array nuevo donde copia todos los valores que ya tiene, así que trivial tampoco es.

Re: Ayuda con Winlist()

Publicado: 07 Oct 2009, 11:02
por Ximorro
Pues mira, filtrar las de CAPTION no me va bien, porque puede haber ventanas sin caption que sí son seleccionables por ALT+TAB, por ejemplo si haces un GUI así:
$GUI1 = GUICreate("Gui1", 100, 100, 500, 600, $WS_POPUP, $WS_EX_TOPMOST)

Al ser Popup no tiene título (da igual que sea topmost, eso lo hago para tenerla delante y poderla seleccionar bien), pero como no es ToolWindow en ALT+TAB de Windows aparece. Si obligamos que tenga título con el filtro del CAPTION desaparece de nuestra lista y no es correcto.

No es un caso tan raro, por ejemplo tengo un programita que se llama EzPop, que es un avisador de correo, que es así. En ALT+TAB de Windows sale, y con el filtro original sin CAPTION también, pero con lo de CAPTION nos desaparece con lo que ya no es igual que ALT+TAB...

También pasará con ventanas de interfaz "chula", donde quitan el título de Windows y lo dibujan todo a pelo. Se me ocurría el Winamp o el KMLPlayer pero no los tengo aquí instalados, pero he probado con otros y efectivamente pasa (como FLVPlayer y QuickTime Player). Esos aparecen en ALT+TAB de Windows, pero no tienen $WS_CAPTION porque se dibujan sus propios títulos, con lo que si filtras $WS_CAPTION no salen, y deben salir...

Tiene que ser otro atributo lo que te está fastidiando...

Re: Ayuda con Winlist()

Publicado: 08 Oct 2009, 01:27
por Chefito
Sí, tienes razón y yo estoy equivocado. Lo siento.
Como estuve toqueteando tu código, debí hacer algo que lo desvariase un poco y por eso no me aparecía el Administrador de tareas. Mea Culpa :smt021 . El código va bien menos la ventana que te dije.
La verdad es que la filtrar con la propiedad $WS_CAPTION no es buena idea. Ya veo que puede fallar si no tiene barra de título.
Pero tendremos que intentar solucionar lo de esa ventana, no? :smt002 . He sacado el número en decimal de las propiedades de esa ventana e intentar reproducirla en AutoIt, pero no lo he conseguido :smt017 .
Lo próximo que haré será un pequeño script que te diga las propiedades de esa ventana, a ver si así me entero de que hay que filtrar. Cuando lo haga, lo colgaré y pondré esa o esas propiedades.

Saludos.

Re: Ayuda con Winlist()

Publicado: 08 Oct 2009, 10:41
por Ximorro
Ok, a ver qué tendrá esa ventana, ya me tiene mosqueado :smt002
A todo esto, ¿qué es lo que pasa? que sale en nuestro programa pero no en Windows, ¿es eso?
¿Es una ventana visible que puedes activar o está oculta?

¿Es algún programa de acceso libre que podamos investigar?

¿Has encontrado otras que fallen? es por intentar buscar cosas comunes.

Por cierto que lo probé en Vista y no va ni de cerca. Al final es lo que decía, que emular el ALT+TAB con la funcionalidad exacta será imposible (y más si tiene que ir en los diferentes Windows), otra cosa es pasar de ese ALTTAB y hacerse uno propio, ahí ya da igual con lo que tenemos hasta ahora sería suficiente.

Otra cosa es que alguien que sepa ensamblador se desemsamble la dll donde está el código de la dichosa ventana ALTTAB y mire qué demonios filtra el Windows... :smt003

Re: Ayuda con Winlist()

Publicado: 26 Oct 2009, 19:39
por Chefito
Después de un tiempo, este finde me he animado y como no he salido, he hecho el script para ver las propiedades de las ventanas (ahora lo cuelgo en la sección de scripts).
Pues he intentado reproducir la ventana y no he podido!!! :smt013 . Me da que puede que puede que sea hija de la principal y tenga algo que ver con esto o que se yo :smt017 . O que a lo mejor tiene alguna propiedad la cual se me escapa (y al AutoIt también). No he mirado las propiedades según microsoft por si falta alguna (yo ya paso :smt012 ).
Puede que tengamos que reproducir algún estado :smt017 . No se no se.
Mira, te dejo el link del programa para que investigues (si te apetece).
Además, recomiendo a todo el mundo que se baje este programa. Es una guía (algo antigua pero muy util) de las apis de windows (por supuesto no están todas, pero es una buenísima colección). Para los que programábamos en vb6 era una guía imprescindible :smt002 . Los ejemplos están en vb6, pero con un poco de esfuerzo se pueden medio entender.
Si os fijais, vereís que muchos de estos ejemplos han sido pasados posteriormente a AutoIt :smt002 .

El programa lo podeís descargar de aquí: http://allapi.mentalis.org/agnet/appdown.shtml
Se llama Api-guide 3.7.

Saludos.

Re: Ayuda con Winlist()

Publicado: 27 Oct 2009, 07:50
por Jonny
Hola

Interesante programa ¡gracias!
Lo descargaré, seguro que es de mucha utilidad.

Salu2!

Re: Ayuda con Winlist()

Publicado: 27 Oct 2009, 09:27
por Ximorro
Lo de la ventana es que emular exactamente el Windows los veo imposible, porque cuando lo tengas saldrán más cosas, y si alguna vez es perfecto entonces sólo tienes que pasarte al Vista o al Windows7 y ya no va ni de cerca...

Otra cosa es hacer esto para programar un ALTTAB personalizado, en ese caso con lo que tenemos ya va bien. Otra cosa es que aparezcan ventanas a las que no se puede conmutar, pero si es visible se podrá...

La API GUIDE ES IMPRESIONANTE. ¡¡Gracias por el enlace!!

Re: Ayuda con Winlist()

Publicado: 21 Feb 2011, 22:07
por Jonny
Hola

Resulta, que estoy intentando adaptar el código del conmutador de ventanas de Chefito, para qué al pulsar Alt+Shift+tab, haga el mismo efecto pero a la inversa (recorra hacia atrás las ventanas del conmutador de ventanas de windows.

El problema está, al capturar las teclas Alt+shift+tab; que no se por qué, con los malditos hooks se queda el tabulador o la mayúscula temporal como bloqueada; cada vez que se pulsa cualquier tecla, sale el código virtual del tabulador o shift (a veces ambas) y la tecla pulsada. Hasta que no se pulsa la tecla que aparece constantemente (tab o shift), no deja de salir el código virtual. Como si se hubiera quedado pulsada...

¿Como puedo arreglar esto? ¡ya he probado de todo!.

Salu2!