WinNav - Fenster mit der Tastatur wechseln

    • Offizieller Beitrag

    Hi,

    Ein kleines Projekt, um Fenster etwas komfortabler mit der Tastatur wechseln zu können.

    Features:
    - Zunächst Auswahl nach Prozess
    - Dann Auswahl des Fensters dazu (falls mehere existieren)
    - Aufruf über Strg+Shift+a, Auswahl mit F1-F9
    - Übersichtsfenster zur Orientierung

    Code:

    Spoiler anzeigen
    [autoit]

    #cs ----------------------------------------------------------------------------

    [/autoit] [autoit][/autoit] [autoit]

    AutoIt Version: 3.3.6.1
    Author: Johannes Mitlmeier

    [/autoit] [autoit][/autoit] [autoit]

    Script Function:
    Window navigation via keyboard.

    [/autoit] [autoit][/autoit] [autoit]

    #ce ----------------------------------------------------------------------------

    [/autoit] [autoit][/autoit] [autoit]

    ; Vorbereitungen
    Global $sHotkey = "^+a"
    Global $aFilter[2][2] = [["Start", "explorer.exe"],["Program Manager", "explorer.exe"]]
    Global $aFixOrder[3] = ["firefox.exe", "explorer.exe", "scite.exe"]

    [/autoit] [autoit][/autoit] [autoit]

    ; UDFs
    #include <Process.au3>
    #include <Array.au3>
    #include <GUIConstantsEx.au3>
    #include <GuiListView.au3>
    #include <WindowsConstants.au3>
    #include <Misc.au3>
    #include <Math.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global Enum $PRECHOICE, $PROCESSCHOICE, $WINCHOICE
    Global $selectionStatus = $PRECHOICE
    Global $hGUI, $xChoiceList, $xChoiceItem

    [/autoit] [autoit][/autoit] [autoit]

    HotKeySet($sHotkey, "_init")
    Opt("GUIOnEventMode", 1) ; Change to OnEvent mode

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; Hauptschleife
    While Sleep(1000000)
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; Funktionen

    [/autoit] [autoit][/autoit] [autoit]

    Func _init()
    ConsoleWrite($selectionStatus & @CRLF)
    If $selectionStatus <> $PRECHOICE Then Return
    $aProc = _GetProcesses()
    $selectionStatus = $PROCESSCHOICE
    _ShowSelectionWindow($aProc)
    EndFunc ;==>_init

    [/autoit] [autoit][/autoit] [autoit]

    Func _WinChoice()
    ConsoleWrite("winchoice '" & $xChoiceItem & "'" & @CRLF)
    $aList = _GetWindowsByProcessName($xChoiceItem)
    _DebugWindowList($aList)
    If UBound($aList) > 1 Then
    ; Nummern vergeben
    For $j = 0 To UBound($aList) - 1
    If StringInStr($aList[$j], "|") Then ContinueLoop
    $aList[$j] = ($j + 1) & "|" & $aList[$j]
    Next
    $selectionStatus = $WINCHOICE
    _ShowSelectionWindow($aList)
    Else
    ConsoleWrite("activating " & WinGetTitle(HWnd($aList[0])) & @CRLF)
    WinActivate(HWnd($aList[0]))
    $selectionStatus = $PRECHOICE
    EndIf
    EndFunc ;==>_WinChoice

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _ShowSelectionWindow($aArray)
    ConsoleWrite("_ShowSelectionWindow " & UBound($aArray) & @CRLF)
    $xChoiceList = $aArray
    $iHeight = 28 + 28 * UBound($aArray)
    $iWidth = _Iif($selectionStatus = $PROCESSCHOICE, 150, 450)
    $sTitle = _Iif($selectionStatus = $PROCESSCHOICE, "Prozess", "Fenster")
    $hGUI = GUICreate("Auswahl", $iWidth, $iHeight, Default, Default, $WS_POPUP)
    GUISetFont(14)
    $hListView = GUICtrlCreateListView("Nr.|" & $sTitle, 0, 0, $iWidth, $iHeight)
    ; Liste aufbauen
    Switch $selectionStatus
    Case $PROCESSCHOICE
    For $i = 0 To UBound($aArray) - 1
    $parts = StringSplit($aArray[$i], "|")
    GUICtrlCreateListViewItem($parts[1] & "|" & StringTrimRight($parts[2], 4), $hListView)
    Next
    Case $WINCHOICE
    For $i = 0 To UBound($aArray) - 1
    $parts = StringSplit($aArray[$i], "|")
    GUICtrlCreateListViewItem($parts[1] & "|" & WinGetTitle(HWnd($parts[2])), $hListView)
    Next
    EndSwitch

    [/autoit] [autoit][/autoit] [autoit]

    ; Hotkeys setzen
    For $i = 1 To UBound($aArray)
    HotKeySet("{F" & $i & "}", "_selected")
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ; Anzeigen
    GUISetOnEvent($GUI_EVENT_CLOSE, "_HideWin")
    GUISetState(@SW_SHOW, $hGUI)
    EndFunc ;==>_ShowSelectionWindow

    [/autoit] [autoit][/autoit] [autoit]

    Func _selected()
    ; gewähltes Item erkennen
    $iIndex = StringTrimRight(StringTrimLeft(@HotKeyPressed, 2), 1)
    $iMax = _Min(Int($iIndex), UBound($xChoiceList) - 1) ; Int-Aufruf hier existentiell!
    For $i = 0 To $iMax
    If StringInStr($xChoiceList[$i], $iIndex & "|") == 1 Then
    $xChoiceItem = $xChoiceList[$i]
    $xChoiceItem = StringRegExpReplace($xChoiceItem, "^\d*.", "") ; entferne 1| und ähnliches
    ConsoleWrite("chosen item " & $xChoiceItem & @CRLF)
    ExitLoop
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ; Wie geht es weiter?
    GUIDelete($hGUI)
    Switch $selectionStatus
    Case $PROCESSCHOICE
    _WinChoice()
    Case $WINCHOICE
    ConsoleWrite("activating " & WinGetTitle(HWnd($xChoiceItem)) & @CRLF)
    WinActivate(HWnd($xChoiceItem))
    $selectionStatus = $PRECHOICE
    EndSwitch
    EndFunc ;==>_selected

    [/autoit] [autoit][/autoit] [autoit]

    Func _GetProcesses()
    ; Alle Fenster holen
    $aList = _GetAllWindows()
    ; Fensterhandles durch Prozessnamen ersetzen
    For $i = 0 To UBound($aList) - 1
    $aList[$i] = _ProcessGetName(WinGetProcess($aList[$i]))
    Next
    ; Dubletten entfernen
    $aList = _ArrayUnique($aList)
    _ArrayDelete($aList, 0) ; Anzahl in [0] entfernen

    [/autoit] [autoit][/autoit] [autoit]

    ; gewünschte Sortierung sicherstellen
    For $i = 0 To UBound($aFixOrder) - 1
    For $j = 0 To UBound($aList) - 1
    If $aFixOrder[$i] = $aList[$j] Then
    $aList[$j] = ($i + 1) & "|" & $aList[$j]
    ContinueLoop 2
    EndIf
    Next
    Next
    ; Rest automatisch vergeben
    $iNumber = UBound($aFixOrder) + 1
    For $j = 0 To UBound($aList) - 1
    If StringInStr($aList[$j], "|") Then ContinueLoop
    $aList[$j] = $iNumber & "|" & $aList[$j]
    $iNumber += 1
    Next
    ; sortieren
    _ArraySort($aList)
    Return $aList
    EndFunc ;==>_GetProcesses

    [/autoit] [autoit][/autoit] [autoit]

    Func _GetAllWindows()
    Return _GetWindowsByProcessName("")
    EndFunc ;==>_GetAllWindows

    [/autoit] [autoit][/autoit] [autoit]

    Func _GetWindowsByProcessName($sProcessName = "")
    ConsoleWrite("getwinbyprocname " & $sProcessName & @CRLF)
    $aWinList = WinList()
    If $aWinList[0][0] = 0 Then Return -1
    Local $aReturn[$aWinList[0][0]], $iCount = 0

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To $aWinList[0][0]
    ; nur sichtbare Fenster beachten
    If ($aWinList[$i][0] = "") Or Not _IsWindowVisible($aWinList[$i][1]) Then ContinueLoop
    ; Prozessnamen finden und abgleichen
    If $sProcessName <> "" Then
    $sRealProcessName = _ProcessGetName(WinGetProcess($aWinList[$i][1]))
    If $sRealProcessName <> $sProcessName Then ContinueLoop
    EndIf
    ; Filtern
    For $j = 0 To UBound($aFilter) - 1
    If ($aFilter[$j][0] = $aWinList[$i][0]) And ($aFilter[$j][1] = $sProcessName) Then ContinueLoop 2 ; außen fortsetzen
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ; in Rückgabe schreiben
    $aReturn[$iCount] = $aWinList[$i][1]
    $iCount = $iCount + 1
    Next
    ; Rückgabe sauber dimensionieren
    If $iCount = 0 Then Return -1
    ReDim $aReturn[$iCount]
    Return $aReturn
    EndFunc ;==>_GetWindowsByProcessName

    [/autoit] [autoit][/autoit] [autoit]

    Func _DebugWindowList($aList)
    For $i = 0 To UBound($aList) - 1
    ConsoleWrite(StringFormat("Titel: '%s', Prozess: '%s', Daten: %i", WinGetTitle($aList[$i]), _ProcessGetName(WinGetProcess($aList[$i])), WinGetState($aList[$i])) & @CRLF)
    Next
    EndFunc ;==>_DebugWindowList

    [/autoit] [autoit][/autoit] [autoit]

    Func _IsWindowVisible($handle)
    If BitAND(WinGetState($handle), 2) Then
    Return 1
    Else
    Return 0
    EndIf
    EndFunc ;==>_IsWindowVisible

    [/autoit] [autoit][/autoit] [autoit]

    Func _HideWin()
    GUIDelete($hGUI)
    $selectionStatus = $PRECHOICE

    [/autoit] [autoit][/autoit] [autoit]

    ; Hotkeys entfernen
    For $i = 1 To 11
    HotKeySet("{F" & $i & "}")
    Next
    EndFunc ;==>_HideWin

    [/autoit] [autoit][/autoit] [autoit]

    Func _exit()
    Exit
    EndFunc ;==>_exit

    [/autoit]

    Demo:
    http://slzm.de/winnav

    Download:
    autoit.de/wcf/attachment/13029/

    Die Funktion zum Darstellen der Wahlmöglichkeiten ist leicht austauschbar, vielleicht will sich da ein GDI-Künstler mal ranwagen? :)


    Viel Spaß damit und gerne Feedback!
    Johannes

  • Mh nette Idee, aber unter Win 7 hast das gleiche ja schon mit Alt+TAB und das wesentlich intuitiver durch zusätzlicher Miniaturvorschau.

    Edit: Hab das Script nun mal laufen lassen. Zumindestens unter x64 läuft das nicht rund. Selbst bei nur zwei Fenstern dauert es ewig bis etwas kommt und wenn man die Sidebar auswählt dann endet das scheinbar in einer Endlosschleife innerhalb des Scriptes.

    Andy hat mir ein Schnitzel gebacken aber da war ein Raupi drauf und bevor Oscar das Bugfixen konnte kam Alina und gab mir ein AspirinJunkie.

    2 Mal editiert, zuletzt von chip (5. April 2011 um 22:46)

  • Auf Win Vista fehlt allerdings die Gruppierung nach den Prozessen der Fenster. Und das mit der Minivorschau lässt sich vielleicht auch realisieren. Es scheint ja auch noch nicht ganz fertig zu sein, was die Optik betrifft (

    Zitat

    Die Funktion zum Darstellen der Wahlmöglichkeiten ist leicht austauschbar, vielleicht will sich da ein GDI-Künstler mal ranwagen?

    )

    • Offizieller Beitrag

    Mh nette Idee, aber unter Win 7 hast das gleiche ja schon mit Alt+TAB und das wesentlich intuitiver durch zusätzlicher Miniaturvorschau.

    Danke für das Feedback :). Offenbar muss ich noch ein bisschen genauer den Mehrwert erläutern :D. Ich kann mit meinem Skript besser kontrollieren, wie ich ein Fenster erreiche. Die Reihenfolge der Fenster in der Alt-Tab-Ansicht ist leider im besten Fall logisch, intuitiv aber auf keinen Fall, weil sich niemand die Reihenfolge so vieler Elemente merken kann und will. Außerdem kann man durch das Pinning die Auswahl schnell verkleinern und mit dem Filtern Fenster dauerhaft aus der Auswahl heraus halten. Das ist so die Überlegung dahinter :).

    Kannst du mehr zu dem Fehler bei dir sagen? Ich habe es unter 64-Bit Windows 7 entwickelt und es funktioniert bei 8-10 Fenstern mit gut einer Sekunde Ladezeit (im Video ja angesprochen, dass Caching noch nicht implementiert ist und auch sonst keine Optimierungen).

    Johannes

  • Also bei mir zeitgt mit dein Script aktuell immer die exakt gleiche Reihenfolge die mir auch ALt+Tab ausgibt :).

    Mehr kann ich dir zu dem Fehler auch nicht sagen, habe das nun auf einem weiteren Win 7 x64 Rechner getestet und auch dort dauert das eine ganze Weile. Ich vermute mal das es schlicht mit der Anzahl der vorhanden Prozesse zusammen hängt. Da ja die Prozesse aber nur willst die auch ein Fenster haben dürfte der Weg über WinList schneller sein.

    Andy hat mir ein Schnitzel gebacken aber da war ein Raupi drauf und bevor Oscar das Bugfixen konnte kam Alina und gab mir ein AspirinJunkie.

    • Offizieller Beitrag

    So, ich war mit dieser UDF noch mal optimieren. Die Geschwindigkeit ist dramatisch verbessert worden, vielleicht kannst du noch mal testen, chip?
    Das mit der Reihenfolge kann ich nicht so ganz nachvollziehen. Im Moment taucht der Firefox in WinNav z.B. immer auf Position 1 auf. Das hängt bei Alt-Tab ja davon ab, wann es zuletzt den Fokus hatte.

    Johannes

  • So, ich war mit dieser UDF noch mal optimieren. Die Geschwindigkeit ist dramatisch verbessert worden, vielleicht kannst du noch mal testen, chip?

    Viel besser, jetzt kommt die List sofort.


    Das mit der Reihenfolge kann ich nicht so ganz nachvollziehen. Im Moment taucht der Firefox in WinNav z.B. immer auf Position 1 auf. Das hängt bei Alt-Tab ja davon ab, wann es zuletzt den Fokus hatte.

    War dann scheinbar nur ein Zufall bei mir.

    Andy hat mir ein Schnitzel gebacken aber da war ein Raupi drauf und bevor Oscar das Bugfixen konnte kam Alina und gab mir ein AspirinJunkie.

    • Offizieller Beitrag

    Viel besser, jetzt kommt die List sofort.

    Sehr gut, danke für den Restest! :) Die Änderung war nur ein Umstellen von Filterprüfungen, erstaunlich, dass sich das derart auf die Laufzeit auswirkt, aber es bestätigt meine These, dass schlechte Programmierung oft mehr Performance kostet als die Sprache "verbockt" ;).

    Johannes

  • Moin Johannes.

    Ich fidne das Tool sehr gut.

    Vorschlag wäre, das wenn man z. B. die 4 ausgewählt hat, das wenn man danach ENTER drückt, automatisch F4 gedrückt wird.

    Ansonsten erst einmal ein HAPPY-WEEKEND.

    L I N A

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    OuBVU5ebLhHu5QvlnAyQB4A7SzBrvWulwL7RLl2BdH5tI6sIYspeMKeXMSXl