#cs ----------------------------------------------------------------------------

	AutoIt Version: 3.3.6.1
	Author:         Johannes Mitlmeier

	Script Function:
	Window navigation via keyboard.

#ce ----------------------------------------------------------------------------

; Vorbereitungen
Global $sHotkey = "^+a"
Global $aFilter[2][2] = [["Start", "explorer.exe"],["Program Manager", "explorer.exe"]]
Global $aFixOrder[3] = ["firefox.exe", "explorer.exe", "scite.exe"]

; UDFs
#include <Process.au3>
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <WindowsConstants.au3>
#include <Misc.au3>
#include <Math.au3>

Global Enum $PRECHOICE, $PROCESSCHOICE, $WINCHOICE
Global $selectionStatus = $PRECHOICE
Global $hGUI, $xChoiceList, $xChoiceItem

HotKeySet($sHotkey, "_init")
Opt("GUIOnEventMode", 1) ; Change to OnEvent mode


; Hauptschleife
While Sleep(1000000)
WEnd


; Funktionen

Func _init()
	ConsoleWrite($selectionStatus & @CRLF)
	If $selectionStatus <> $PRECHOICE Then Return
	$aProc = _GetProcesses()
	$selectionStatus = $PROCESSCHOICE
	_ShowSelectionWindow($aProc)
EndFunc   ;==>_init

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


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

	; Hotkeys setzen
	For $i = 1 To UBound($aArray)
		HotKeySet("{F" & $i & "}", "_selected")
	Next

	; Anzeigen
	GUISetOnEvent($GUI_EVENT_CLOSE, "_HideWin")
	GUISetState(@SW_SHOW, $hGUI)
EndFunc   ;==>_ShowSelectionWindow

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

	; 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

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

	; 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

Func _GetAllWindows()
	Return _GetWindowsByProcessName("")
EndFunc   ;==>_GetAllWindows

Func _GetWindowsByProcessName($sProcessName = "")
	ConsoleWrite("getwinbyprocname " & $sProcessName & @CRLF)
	$aWinList = WinList()
	If $aWinList[0][0] = 0 Then Return -1
	Local $aReturn[$aWinList[0][0]], $iCount = 0

	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

		; 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

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

Func _IsWindowVisible($handle)
	If BitAND(WinGetState($handle), 2) Then
		Return 1
	Else
		Return 0
	EndIf
EndFunc   ;==>_IsWindowVisible

Func _HideWin()
	GUIDelete($hGUI)
	$selectionStatus = $PRECHOICE

	; Hotkeys entfernen
	For $i = 1 To 11
		HotKeySet("{F" & $i & "}")
	Next
EndFunc   ;==>_HideWin

Func _exit()
	Exit
EndFunc   ;==>_exit
