Página 1 de 1

Conmutador de ventanas con alt-shift-tab

Publicado: 24 Feb 2011, 22:13
por Jonny
Hola

Estoy intentando capturar el conmutador de ventanas tanto con Alt-tab como con Alt-shift-tab.

La captura con Alt-tab, está solucionada gracias a Chefito y Ximorro en este post que puse hace ya un tiempo, que lo suyo les costó dar con la mejor forma de filtrar ventanas, etc etc:

http://www.emesn.com/autoitforum/viewto ... f=3&t=1757

La cosa está ahora, en hacer lo mismo, pero a la inversa; cuando se pulsa Alt-shift-tab, que el desplazamiento por el conmutador de ventanas es en el sentido contrario.

Imaginé, que no sería muy complicado, pero la verdad es que no acaba de funcionarme.

Creí, que básicamente para cambiar el sentido del desplazamiento por el conmutador, tendría que tocar únicamente la llamada a la función _WinAPI_GetWindow(), cambiando el segundo parámetro.

Por ejemplo, - $GW_HWNDNEXT por $GW_HWNDPREV o $GW_HWNDFIRST por $GW_HWNDLAST, como he hecho en el siguiente código.

(El código es el de Chefito, solo con las modificaciones que creí que bastarían):

Código: Seleccionar todo


#include <GUIConstantsEx.au3>
#Include <WinAPI.au3>
#include<Constants.au3>
#include <WindowsConstants.au3>

Global $Codigo=0
Global $NumWin
Global $ProgramManager
Global $Hwnd
Global $EmpezarSegundo
Global $AuxOnTop
Global $ProgramManager=WinGetHandle("Program Manager")
Global $Dll=DllOpen("user32.dll")
Global $HStub_KeyProc=DllCallbackRegister("_KeyProc", "long", "int;wparam;lparam")
Global $Hmod=DllCall("kernel32.dll", "hwnd", "GetModuleHandle", "ptr", 0)
Global $HHook=DllCall("user32.dll", "hwnd", "SetWindowsHookEx", "int", $WH_KEYBOARD_LL, "ptr", DllCallbackGetPtr($HStub_KeyProc), "hwnd", $Hmod[0], "dword", 0)
Global $Gui=GuiCreate("My GUI Button", 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
Sleep(10)
$Msg=GuiGetMsg()
Select
Case $Msg=$GUI_EVENT_CLOSE
ExitLoop
EndSelect
WEnd

Func _KeyProc($NCode, $WParam, $LParam)
If $Wparam=260 Then ;entra al pulsar la tecla alt.
$KEYHOOKSTRUCT=DllStructCreate("dword;dword;dword;dword;ptr", $LParam)
$Codigo=DllStructGetData($KEYHOOKSTRUCT, 1)
If Not (WinExists("[CLASS:#32771]")) Then
$NumWin=1 ;un contador que te indica el número de la ventana señalada.
;con esto comprobamos al principio si la ventana activa es topmost o no para seleccionar la buena.
If _WinIsOnTop(WinGetHandle("[active]")) Then
$AuxOnTop=False
Else
$AuxOnTop=True
EndIf
$Hwnd=_WinAPI_GetWindow($ProgramManager, $GW_HWNDLAST) ;cogo el handle de la primera ventana a partir de la "Program Manager"
$EmpezarSegundo=False ;Con esta variable hago que se salte la primera ventana buena que encuentra y que señale la 2º.
EndIf
If $Codigo=9 Then ;entra al pulsar la tecla tab.
While 1
$TituloWin=_WinAPI_GetWindowText($HWnd) ;capturo el título de la ventana.
;pongo todas estas condiciones para encontrar las ventanas válidas.
;Digo que el título no puede ser vacio, que la ventana tiene que ser visible, que tiene que tener un handle, y que tiene que tener alguna médida.
;condiciones alternativas válidas:
;bitand(_WinAPI_GetWindowLong($hWnd, $GWL_STYLE),$WS_CAPTION)=$ws_caption
;bitand(_WinAPI_GetWindowLong($HWnd, $GWL_EXSTYLE), $WS_EX_TOOLWINDOW)<>$WS_EX_TOOLWINDOW And _WinAPI_GetWindowHeight($Hwnd)>0 And _WinAPI_GetWindowWidth($Hwnd)>0
If _WinAPI_IsWindowVisible($Hwnd) And $Hwnd<>0 Then
If Bitand(_WinAPI_GetWindowLong($HWnd, $GWL_EXSTYLE), $WS_EX_TOOLWINDOW)<>$WS_EX_TOOLWINDOW Then
$WinOnTop=_WinIsOnTop($Hwnd)
If $WinOnTop And $AuxOnTop Then
$NumWin-=1
$Hwnd=_WinAPI_GetWindow($Hwnd, $GW_HWNDPREV)
Else
$AuxOnTop=False
If $EmpezarSegundo Then
$NumWin-=1
;ConsoleWrite($NumWin" - "$TituloWin@CR)
$HwndAnterior=$Hwnd
GuiCtrlSetData($Label, $NumWin&" - "&$TituloWin)
$Proceso=WinGetProcess($Hwnd) ;averiguo el proceso de la ventana.
$Pathfile=_WinAPI_GetModuleFileNameEx($Proceso)
;con el proceso, averiguo el camino completo más el nombre del archivo del programa que ha cargado la ventana.
GuiCtrlSetImage($Icon, $Pathfile, 0) ;inserto la imagen del icono del programa.
$Hwnd=_WinAPI_GetWindow($Hwnd, $GW_HWNDPREV)
;doy el handle de la siguiente ventana.
ExitLoop
Else
$EmpezarSegundo=True
$Hwnd=_WinAPI_GetWindow($Hwnd, $GW_HWNDPREV)
EndIf
EndIf
ElseIf $Hwnd=$ProgramManager Then
$NumWin=0
$Hwnd=_WinAPI_GetWindow($ProgramManager, $GW_HWNDLAST)
Else
$Hwnd=_WinAPI_GetWindow($Hwnd, $GW_HWNDPREV)
EndIf
Else
$Hwnd=_WinAPI_GetWindow($Hwnd, $GW_HWNDPREV)
EndIf
WEnd
EndIf
EndIf
Return _WinAPI_CallNextHookEx($hHook, $NCode, $WParam, $LParam)
EndFunc

Func OnAutoItExit()
DllClose($Dll)
DllCall("user32.dll", "int", "UnhookWindowsHookEx", "hwnd", $hHook[0])
DllCallbackFree($HStub_KeyProc)
EndFunc

Func _WinAPI_GetModuleFileNameEx($PID=0)
If $PID=0 Then
$PID=_WinAPI_GetCurrentProcessID()
EndIf
Local $HProc=DllCall("kernel32.dll", "ptr", "OpenProcess", "dword", 0x00000410, "int", 0, "dword", $PID)
If (@error) Or ($HProc[0]=0) Then
Return SetError(1, 0, "")
EndIf
$HProc=$HProc[0]
Local $TPath=DllStructCreate("wchar[1024]")
Local $Ret=DllCall("psapi.dll", "int", "GetModuleFileNameExW", "ptr", $HProc, "ptr", 0, "ptr", DllStructGetPtr($TPath), "int", 1024)
If (@Error) Or ($Ret[0]=0) Then
$Ret=0
EndIf
_WinAPI_FreeHandle($HProc)
If Not IsArray($Ret) Then
Return SetError(1, 0, "")
EndIf
Return SetError(0, 0, DllStructGetData($TPath, 1))
EndFunc

Func _WinAPI_FreeHandle($HObject)
Local $Ret=DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $HObject)
If (@Error) Or ($Ret[0]=0) Then
Return SetError(1, 0, 0)
EndIf
Return 1
EndFunc

Func _WinIsOnTop($WindowHandle)
Local $Long=DllCall("User32.dll", "int", "GetWindowLong", "hwnd", WinGetHandle($WindowHandle), "int", -20)
Return BitAND($Long[0], 8)=8 ; $WS_EX_TOPMOST=8
EndFunc

Lo capturo con Alt-tab. Eso es lo de menos, pues lo importante es conseguir desplazarme hacia atrás por el conmutador de ventanas; la captura de alt-shift-tab sí se hacerla.

¿Se os ocurre donde está el fallo?.

Acias,
Salu2!

Re: Conmutador de ventanas con alt-shift-tab

Publicado: 25 Feb 2011, 11:01
por Ximorro
Yo el código de Chefito no lo entendí mucho por eso hice el mío propio (derivado del suyo, claro, pero no son tan iguales).
En el mío no hay que cambiar eso, pues lo uso para rellenar la matriz inicial que luego reutilizo.
En mi código simplemente cambiando
$iHWnd+=1
If $iHWnd > $maxHwnd Then $iHWnd = 0 ;da la vuelta
por
$iHWnd-=1
If $iHWnd =-1 Then $iHWnd = $maxHwnd ;da la vuelta

ya va correctamente hacia atrás, es decir, simplemente recorro el array de ventanas al revés.

Hay que hacer otro cambio a la hora de recoger la primera ventana, es lo que se hace aquí:
;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 = 1 ; ¡Por si son todas TOPMOST y la activa está al final!

Simplemente en vez de coger la siguiente activa no Toolwindow o topmost a la actual habrá que coger la anterior, pero no tengo ganas de pensarlo. Quizás haya que cambiar algo en la creación del vector (para colocar $aux_iHWnd donde toca). Pero eso ya me dio bastantes dolores de cabeza. Si no se arregla eso la primera ventana seleccionada puede que no sea la adecuada, pero el recorrido hacia atrás lo hace perfectamente.

Para modificar los códigos, ya sea el de Chefito o el mío, primero tienes que entenderlos bien. Si no los entiendes perfectamente, como si los hubieras escrito tú, estúdiate aquélla entrada, que escribimos la tira. Y si no haz como yo, que no entendía la lógica de Chefito y programé la mía, después de aprender de él cosas muy importantes como lo de acceder a las ventanas a partir de Program Manager y cosas así.