HELP = ; Gui, 99 (LTrim0 ALT-TAB REPLACEMENT (WITH ICONS AND WINDOW TITLES IN A LISTVIEW). Latest version can be found at: http://file.autohotkey.net/evl/AltTab/AltTab.ahk Forum topic for discussion: http://www.autohotkey.com/forum/viewtopic.php?t=6422 HOTKEYS: Default: Alt+Tab - move forwards in window stack Alt+Shift+Tab - move backwards in window stack Alt+Esc - cancel switching window Mouse wheel over the taskbar scrolls the list - Middle button selects a window in this mode. Window Groups can be assigned hotkeys to load the group/cycle through the windows. EVENTS: Double-click a row to select that item and switch to it. Type first letter of program's title to cycle through them while still holding Alt Columns can be sorted by clicking on their titles. Tabs (window groups) can be re-ordered by drag-and-drop. Right-Click (context menu): Basic hotkey support for switching to specific windows (using window groups and adding window classes) Exclude (and un-exclude) specific windows and specific .EXEs - see "Window Groups" below. Edge-docking - dock windows to the edges of the screen and have them auto-hide (like the taskbar can). Window Groups - define lists of windows to easily switch between only showing certain apps. Manage groups of windows and processes (min/max all, close all, etc). Close windows: Alt+Middle mouse - close window under the mouse pointer in the Alt-Tab listview. Alt+\ "hotkey" - close selected window (while list is displayed) Alt+/ "hotkey" - close ALL windows whose EXE matches that of the selected entry (while list is displayed) Process menu entry - end selected process or all instance of the EXE in the list. SETTINGS: See "; USER EDITABLE SETTINGS:" section near top of source code. TO EXIT: Choose Exit from the system tray icon's menu. NOTE: Stroke-It (and maybe other mouse gesture programs) can cause the context menu to be shown twice/problematic. Solution: exclude the program within the gesture recognition program (window title = Alt-Tab Replacement). ) LATEST_VERSION_CHANGES = ; Gui, 98 (LTrim0 TO DO (maybe): settings window save other settings between restarts include a filter for docked windows to be displayed in alt-tab or not (ie a tab for docked windows) - perhaps alter title? e.g. DOCKED*** stick items to top or bottom of list use listview insert command to place windows at specific locations in list? LATEST VERSION CHANGES: since 25-04-06: +: Groups of windows are shown in tabs - they can be re-arranged by drag-and-drop. +: Settings tab. + & FIX: Updates to the listview colour code - much smoother now (thanks to ambi for updating the Listview script). + & FIX: Sorting of columns with direction indication ([+] or [-]) +: Mouse wheel over the TASKBAR scrolls the list - Middle button SELECTS a window in this mode (it normally CLOSES a window!). +: Save data on big changes (in addition to program exit) - e.g. new group created, hotkeys changed CHANGE: Selections with the mouse are now made with a double click (or just release the Alt key) instead of a single one. CHANGE: Adjusted display position to be centered by default. CHANGE: Dialog windows only indicated by red higlight (not by title too). CHANGE: Not Responding windows indicated in a new column (not by title). CHANGE: Many speed optimisations and code improvements (it's almost decipherable now ;-)) FIX: Handling of "Not Responding" windows with no delays. > For older changes, see the forum: http://www.autohotkey.com/forum/viewtopic.php?t=6422 ) ;======================================================================================================== ; USER EDITABLE SETTINGS: ; Icons Use_Large_Icons =1 ; 0 = small icons, 1 = large icons in listview ; Fonts Font_Size =12 Font_Size_Tab =8 Font_Type_Tab =Courier New Font_Type =Arial ; Position Gui_x =Center Gui_y =Center ; Max height Height_Max_Modifier =0.92 ; multiplier for screen height (e.g. 0.92 = 92% of screen height max ) ; Width Listview_Width := A_ScreenWidth * 0.55 SB_Width := Listview_Width / 4 ; StatusBar section sizes Exe_Width_Max := Listview_Width / 5 ; Exe column max width ; Edge-Docking of windows to screen edges Edge_Dock_Activation_Delay =750 ; Delay in milliseconds for hovering over edge-docked window/dismissing window Edge_Dock_Border_Visible =5 ; number of pixels of window to remain visible on screen edge ;======================================================================================================== ; USER OVERRIDABLE SETTINGS: ; Widths Col_1 =Auto ; icon column Col_2 =0 ; hidden column for row number ; col 3 is autosized based on other column sizes Col_4 =Auto ; exe Col_5 =AutoHdr ; State Col_6 =Auto ; OnTop Col_7 =Auto ; Status - e.g. Not Responding Gui1_Tab__width := Listview_Width - 2 ; Max height Height_Max := A_ScreenHeight * Height_Max_Modifier ; limit height of listview Small_to_Large_Ratio =1.6 ; height of small rows compared to large rows ; Colours in RGB hex Tab_Colour =005F87 ;Tab_Colour =C4C5FB Listview_Colour =FFFFFF ; does not need converting as only used for background ;Listview_Colour =E1E2FD ; does not need converting as only used for background StatusBar_Background_Colour =C4C5FB ; convert colours to correct format for listview color functions: Listview_Colour_Min_Text := RGBtoBGR("0x000000") ; highlight minimised windows Listview_Colour_Min_Back := RGBtoBGR("0xC2C6FC") Listview_Colour_OnTop_Text := RGBtoBGR("0x000000") ; highlight alwaysontop windows Listview_Colour_OnTop_Back := RGBtoBGR("0x8079FB") Listview_Colour_Dialog_Text := RGBtoBGR("0x000000") Listview_Colour_Dialog_Back := RGBtoBGR("0xFB5959") Listview_Colour_Selected_Text := RGBtoBGR("0xFFFFFF") Listview_Colour_Selected_Back := RGBtoBGR("0x000071") Listview_Colour_Not_Responding_Text := RGBtoBGR("0xFFFFFF") Listview_Colour_Not_Responding_Back := RGBtoBGR("0xFF0000") ;======================================================================================================== #NoEnv #SingleInstance force #Persistent #InstallKeybdHook #InstallMouseHook #NoTrayIcon Process Priority,,High SetWinDelay, -1 SetBatchLines, -1 IniFile_Data("Read") OnExit, OnExit_Script_Closing OnMessage( 0x06, "WM_ACTIVATE" ) ; alt tab list window lost focus > hide list LV_ColorInitiate() ; initiate listview color change procedure Gosub, Initiate_Hotkeys ; initiate Alt-Tab and Alt-Shift-Tab hotkeys and translate some modifier symbols WS_EX_CONTROLPARENT =0x10000 WS_EX_DLGMODALFRAME =0x1 WS_CLIPCHILDREN =0x2000000 WS_EX_APPWINDOW =0x40000 WS_EX_TOOLWINDOW =0x80 WS_DISABLED =0x8000000 WS_VSCROLL =0x200000 WS_POPUP =0x80000000 SysGet, Scrollbar_Vertical_Thickness, 2 ; 2 is SM_CXVSCROLL, Width of a vertical scroll bar If A_OSVersion =WIN_2000 lv_h_win_2000_adj =2 ; adjust height of main listview by +2 pixels to avoid scrollbar in windows 2000 Else lv_h_win_2000_adj =0 WinGet, TaskBar_ID, ID, ahk_class Shell_TrayWnd ; for docked windows check Display_List_Shown =0 Window_Hotkey =0 Use_Large_Icons_Current =%Use_Large_Icons% ; for remembering original user setting but changing on the fly Gui_Dock_Windows_List = ; keep track of number of docked windows Time_Since_Last_Alt_Close =0 ; initialise time for repeat rate allowed for closing windows with alt+\ Viewed_Window_List = Col_Title_List =#| |Window|Exe|View|Top|Status StringSplit, Col_Title, Col_Title_List,| ; create list of listview header titles ~WheelUp:: Gosub, ~WheelDown If (Scroll_Over_wID = TaskBar_ID) Loop, 2 Gosub, Alt_Shift_Tab Return ~WheelDown:: MouseGetPos, JUNK, JUNK, Scroll_Over_wID If ! (Scroll_Over_wID = TaskBar_ID) Return Gosub, Single_Key_Show_Alt_Tab Hotkey, %Alt_Hotkey%%Use_AND_Symbol%Mbutton, ListView_Destroy, %state% UseErrorLevel ; select the window if launched from the taskbar Return ;======================================================================================================== Initiate_Hotkeys: Use_AND_Symbol = ; initiate ; If both Alt and Tab are modifier keys, write Tab as a word not a modifier symbol, else Alt-Tab is invalid hotkey If Alt_Hotkey contains #,!,^,+ { If Tab_Hotkey contains #,!,^,+ Replace_Modifier_Symbol( "Tab_Hotkey" , "Tab_Hotkey" ) } Else If Alt_Hotkey contains XButton1,XButton2 Use_AND_Symbol :=" & " Else If Tab_Hotkey contains WheelUp,WheelDown Use_AND_Symbol :=" & " Hotkey, %Alt_Hotkey%%Use_AND_Symbol%%Tab_Hotkey%, Alt_Tab, On ; turn on alt-tab hotkey here to be able to turn it off for simple switching of apps in script Hotkey, %Alt_Hotkey%%Use_AND_Symbol%%Shift_Tab_Hotkey%, Alt_Shift_Tab, On ; turn on alt-tab hotkey here to be able to turn it off for simple switching of apps in script If Single_Key_Show_Alt_Tab != Hotkey, *%Single_Key_Show_Alt_Tab%, Single_Key_Show_Alt_Tab, On Replace_Modifier_Symbol( "Alt_Hotkey" , "Alt_Hotkey2" ) If (! InStr(Tab_Hotkey, "Wheel") and ! InStr(Shift_Tab_Hotkey, "Wheel")) ; wheel isn't used as an alt-tab hotkey so can be used for scrolling list instead Use_Wheel_Scroll_List =1 Return Alt_Tab: ; alt-tab hotkey Alt_Tab_Common_Function("Alt_Tab") Return Alt_Shift_Tab: ; alt-shift-tab hotkey Alt_Tab_Common_Function("Alt_Shift_Tab") Return Alt_Tab_Common_Function(Key) ; Key = "Alt_Tab" or "Alt_Shift_Tab" { Global If Display_List_Shown =0 { WinGet, Active_ID, ID, A Gosub, Custom_Group__make_array_of_contents Gosub, Display_List Gosub, Alt_Tab_Common__Check_auto_switch_icon_sizes ; limit gui height / auto-switch icon sizes Gosub, Alt_Tab_Common__Highlight_Active_Window If ( GetKeyState(Alt_Hotkey2, "P") or GetKeyState(Alt_Hotkey2)) ; Alt key still pressed, else gui not shown { Gui, 1: Show, AutoSize x%Gui_x% y%Gui_y%, Alt-Tab Replacement Hotkeys_Toggle_Temp_Hotkeys("On") ; (state = "On" or "Off") ; ensure hotkeys are on } } Selected_Row := LV_GetNext(0, "F") If Key =Alt_Tab { Selected_Row += 1 If (Selected_Row > Window_Found_Count) Selected_Row =1 } Else If Key =Alt_Shift_Tab { Selected_Row -= 1 If Selected_Row < 1 Selected_Row := Window_Found_Count } LV_Modify(Selected_Row, "Focus Select Vis") ; get selected row and ensure selection is visible SetTimer, Check_Alt_Hotkey2_Up, 30 GuiControl, Focus, Listview1 ; workaround for gui tab bug - gosub not activated when already activated button clicked on again Gosub, SB_Update__ProcessCPU SetTimer, SB_Update__ProcessCPU, 1000 Return Alt_Tab_Common__Check_auto_switch_icon_sizes: ; limit gui height / auto-switch icon sizes If (Listview_NowH > Height_Max AND Use_Large_Icons_Current =1) ; switch to small icons { Use_Large_Icons_Current =0 Gosub, Alt_Tab_Common__Switching_Icon_Sizes } If ((Listview_NowH * Small_to_Large_Ratio) < Height_Max AND Use_Large_Icons_Current =0 AND Use_Large_Icons=1) ; switch to large icons { Use_Large_Icons_Current =1 Gosub, Alt_Tab_Common__Switching_Icon_Sizes } Return Alt_Tab_Common__Switching_Icon_Sizes: Gui, 1: Destroy Display_List_Shown =0 Gosub, Display_List ; update colours Return Alt_Tab_Common__Highlight_Active_Window: Active_ID_Found =0 ; init Loop, %Window_Found_Count% ; select active program in list (not always the top item) { LV_GetText(RowText, A_Index, 2) ; Get hidden column numbers If (Window%RowText% = Active_ID) { Active_ID_Found :=A_Index Break } } If Active_ID_Found =0 ; active window has an icon in another main window & was excluded from Alt-Tab list { WinGet, Active_Process, ProcessName, ahk_id %Active_ID% WinGetClass, Active_Class, ahk_id %Active_ID% ; If desktop/taskbar selected or nothing at all, don't select item in alt-tab list If ( !(Active_Class ="Progman" OR Active_Class ="WorkerW" OR Active_Class ="Shell_TrayWnd" OR Active_Class ="")) Loop, %Window_Found_Count% ; find top item in window list with same exe name as active window If (Exe_Name%A_Index% = Active_Process) { Active_ID := Window%A_Index% ; find this new ID in the listview LV_GetText(RowText, A_Index, 2) ; Get hidden column numbers If (Window%RowText% = Active_ID) { Active_ID_Found :=A_Index Break } } } If Active_ID_Found !=0 LV_Modify(Active_ID_Found, "Focus Select Vis") Return } Single_Key_Show_Alt_Tab: Single_Key_Show_Alt_Tab_Used =1 Send, {%Alt_Hotkey2% down} Gosub, Alt_Tab Hotkey, *%Single_Key_Hide_Alt_Tab%, ListView_Destroy, On Return Alt_Esc: ; abort switching Alt_Esc =1 Gosub, ListView_Destroy Return Alt_Esc_Check_Alt_State: ; hides alt-tab gui - shows again if alt still pressed Gosub, Alt_Esc If ( GetKeyState(Alt_Hotkey2, "P") or GetKeyState(Alt_Hotkey2)) ; Alt key still pressed - show alt-tab again Gosub, Alt_Tab Return Hotkeys_Toggle_Temp_Hotkeys(state) ; (state = "On" or "Off") { Global ; UseErrorLevel in case of exiting script before hotkey created Hotkey, %Alt_Hotkey%%Use_AND_Symbol%%Esc_Hotkey%, Alt_Esc, %state% UseErrorLevel ; abort If Use_Wheel_Scroll_List =1 { Hotkey, %Alt_Hotkey%%Use_AND_Symbol%WheelUp, Alt_Shift_Tab, %state% UseErrorLevel ; previous window Hotkey, %Alt_Hotkey%%Use_AND_Symbol%WheelDown, Alt_Tab, %state% UseErrorLevel ; next window } Hotkey, %Alt_Hotkey%%Use_AND_Symbol%Mbutton, MButton_Close, %state% UseErrorLevel ; close the window clicked on Hotkey, *~LButton, LButton_Tab_Check, %state% UseErrorLevel ; check if user clicked/dragged a tab } Check_Alt_Hotkey2_Up: If ! ( GetKeyState(Alt_Hotkey2, "P") or GetKeyState(Alt_Hotkey2)) ; Alt key released Gosub, ListView_Destroy Return ;======================================================================================================== Display_List: LV_ColorChange() ; clear all highlighting If Display_List_Shown =1 ; empty listview and image list if only updating - e.g. when closing a window (mbutton) LV_Delete() Else ; not shown - need to create gui for updating listview { ; Create the ListView gui Gui, 1: +AlwaysOnTop +ToolWindow -Caption Gui, 1: Color, %Tab_Colour% ; i.e. border/background (default = 404040) ; barely visible - right and bottom sides only Gui, 1: Margin, 4, 4 ; Tab stuff Gui, 1: Font, s%Font_Size_Tab%, %Font_Type_Tab% ;Gui, 1: Add, Tab2, vGui1_Tab HWNDhw_Gui1_Tab Background w%Gui1_Tab__width% -0x200, %Group_List% ; -0x200 = ! TCS_MULTILINE ;Gui, 1: Tab, %Group_Active%,, Exact ; Future controls are owned by this tab ;Gui, 1: Add, StatusBar, Background%StatusBar_Background_Colour% ; add before changing font Gui, 1: Font, s%Font_Size%, %Font_Type% Gui, 1: Add, ListView, w%Listview_Width% AltSubmit -Hdr -Multi NoSort Background%Listview_Colour% Count10 gListView_Event vListView1 HWNDhw_LV_ColorChange,%Col_Title_List% ;Gui, 1: Add, ListView, x-1 y+-4 w%Listview_Width% AltSubmit -Multi NoSort Background%Listview_Colour% Count10 gListView_Event vListView1 HWNDhw_LV_ColorChange,%Col_Title_List% LV_ModifyCol(2, "Integer") ; sort hidden column 2 as numbers SB_SetParts(SB_Width, SB_Width, SB_Width) ;Gosub, SB_Update__CPU ;SetTimer, SB_Update__CPU, 1000 } GuiControl,, Gui1_Tab, |%Group_List% ; update in case of changes GuiControl, ChooseString, Gui1_Tab, %Group_Active% ImageListID1 := IL_Create(10,5,Use_Large_Icons_Current) ; Create an ImageList so that the ListView can display some icons LV_SetImageList(ImageListID1, 1) ; Attach the ImageLists to the ListView so that it can later display the icons Gosub, Display_List__Find_windows_and_icons If Window_Found_Count =0 { Window_Found_Count =1 LV_Add("","","","","","","") ; No Windows Found! - avoids an error on selection if nothing is added } ColumnClickSort(Sort_By_Column, 1) ; Col = column clicked on, Update = 1 if true else blank (apply only, not change order) Gosub, Gui_Resize_and_Position If Display_List_Shown =1 ; resize gui for updating listview { Gui, 1: Show, AutoSize x%Gui_x% y%Gui_y%, Alt-Tab Replacement If Selected_Row >%Window_Found_Count% ; less windows now - select last one instead of default 1st row Selected_Row =%Window_Found_Count% LV_Modify(Selected_Row, "Focus Select Vis") ; select 1st entry since nothing selected } Display_List_Shown =1 ; Gui 1 is shown back in Alt_Tab_Common_Function() for initial creation Return Display_List__Find_windows_and_icons: WinGet, Window_List, List ; Gather a list of running programs Window_Found_Count =0 Loop, %Window_List% { wid := Window_List%A_Index% WinGetTitle, wid_Title, ahk_id %wid% WinGet, Style, Style, ahk_id %wid% If ((Style & WS_DISABLED) or ! (wid_Title)) ; skip unimportant windows ; ! wid_Title or Continue WinGet, es, ExStyle, ahk_id %wid% Parent := Decimal_to_Hex( DllCall( "GetParent", "uint", wid ) ) WinGet, Style_parent, Style, ahk_id %Parent% Owner := Decimal_to_Hex( DllCall( "GetWindow", "uint", wid , "uint", "4" ) ) ; GW_OWNER = 4 WinGet, Style_Owner, Style, ahk_id %Owner% If (((es & WS_EX_TOOLWINDOW) and !(Parent)) ; filters out program manager, etc or ( !(es & WS_EX_APPWINDOW) and (((Parent) and ((Style_parent & WS_DISABLED) =0)) ; These 2 lines filter out windows that have a parent or owner window that is NOT disabled - or ((Owner) and ((Style_Owner & WS_DISABLED) =0))))) ; NOTE - some windows result in blank value so must test for zero instead of using NOT operator! continue WinGet, Exe_Name, ProcessName, ahk_id %wid% WinGetClass, Win_Class, ahk_id %wid% hw_popup := Decimal_to_Hex(DllCall("GetLastActivePopup", "uint", wid)) ; CUSTOM GROUP FILTERING If (Group_Active != "Settings" AND Group_Active != "ALL") ; i.e. list is filtered, check filter contents to include { Custom_Group_Include_wid_temp = ; initialise/reset Loop, %Group_Active_0% ; check current window id against the list to filter { Loop_Item := Group_Active_%A_Index% StringLeft, Exclude_Item, Loop_Item, 1 If Exclude_Item =! ; remove ! for matching strings StringTrimLeft, Loop_Item, Loop_Item, 1 If ((Loop_Item = Exe_Name) or InStr(wid_Title, Loop_Item)) ; match exe name, title { Custom_Group_Include_wid_temp =1 ; include this window Break } } If (((Custom_Group_Include_wid_temp =1) and (Exclude_Item ="!")) or ((Custom_Group_Include_wid_temp !=1) and (Exclude_Not_In_List =1))) Continue } Dialog =0 ; init/reset If (Parent and ! Style_parent) CPA_file_name := GetCPA_file_name( wid ) ; check if it's a control panel window Else CPA_file_name = If (CPA_file_name or (Win_Class ="#32770") or ((style & WS_POPUP) and (es & WS_EX_DLGMODALFRAME))) Dialog =1 ; found a Dialog window If (CPA_file_name) { Window_Found_Count += 1 Gui_Icon_Number := IL_Add( ImageListID1, CPA_file_name, 1 ) } Else Get_Window_Icon(wid, Use_Large_Icons_Current) ; (window id, whether to get large icons) Window__Store_attributes(Window_Found_Count, wid, "") ; Index, wid, parent (or blank if none) LV_Add("Icon" . Window_Found_Count,"", Window_Found_Count, Title%Window_Found_Count%, Exe_Name%Window_Found_Count%, State%Window_Found_Count%, OnTop%Window_Found_Count%, Status%Window_Found_Count%) } Return Window__Store_attributes(Index, wid, ID_Parent) ; Index = Window_Found_Count, wid = window id, ID_Parent = parent or blank if none { Local State_temp Window%Index% =%wid% ; store ahk_id's to a list Window_Parent%Index% =%ID_Parent% ; store Parent ahk_id's to a list to later see if window is owned Title%Index% := wid_Title ; store titles to a list hw_popup%Index% := hw_popup ; store the active popup window to a list (eg the find window in notepad) WinGet, Exe_Name%Index%, ProcessName, ahk_id %wid% ; store processes to a list WinGet, PID%Index%, PID, ahk_id %wid% ; store pid's to a list Dialog%Index% := Dialog ; 1 if found a Dialog window, else 0 WinGet, State_temp, MinMax, ahk_id %wid% If State_temp =1 State%Index% =Max Else If State_temp =-1 State%Index% =Min Else If State_temp =0 State%Index% = WinGet, es_hw_popup, ExStyle, ahk_id %hw_popup% ; eg to detect on top status of zoomplayer window If ((es & 0x8) or (es_hw_popup & 0x8)) ; 0x8 is WS_EX_TOPMOST. { OnTop%Index% =Top OnTop_Found =1 } Else OnTop%Index% = If Responding Status%Index% = Else { Status%Index% =Not Responding Status_Found =1 } ; Listview Higlighting Colours If Status%Index% =Not Responding LV_ColorChange(Index, Listview_Colour_Not_Responding_Text, Listview_Colour_Not_Responding_Back) Else If Dialog%Index% LV_ColorChange(Index, Listview_Colour_Dialog_Text, Listview_Colour_Dialog_Back) Else If OnTop%Index% =Top LV_ColorChange(Index, Listview_Colour_OnTop_Text, Listview_Colour_OnTop_Back) Else If State%Index% =Min LV_ColorChange(Index, Listview_Colour_Min_Text, Listview_Colour_Min_Back) } LButton_Tab_Check: Tab_Button_Clicked := TCM_HITTEST() If Tab_Button_Clicked { Tab_Button_Clicked_Text := Tab_Button_Get_Text(Tab_Button_Clicked) SetTimer, Tab__Drag_and_Drop, 60 ; check status of drag operation } Return Tab__Drag_and_Drop: If ! GetKeyState("LButton") { SetTimer, Tab__Drag_and_Drop, Off Group_Active := Tab_Button_Clicked_Text Gosub, Gui_Window_Group_Load__part2 Return } If TCM_HITTEST() Tab_Button_Over := TCM_HITTEST() Tab_Button_Over_Text := Tab_Button_Get_Text(Tab_Button_Over) If (Tab_Button_Over < Tab_Button_Clicked) Tab_Swap(Group_List, Tab_Button_Clicked_Text, Tab_Button_Over_Text) Else If (Tab_Button_Over > Tab_Button_Clicked) Tab_Swap(Group_List, Tab_Button_Over_Text, Tab_Button_Clicked_Text) Return Tab_Swap(ByRef Tab_List, ByRef Text1, ByRef Text2) { Global StringReplace, Tab_List, Tab_List, %Text1% , %Text2% StringReplace, Tab_List, Tab_List, %Text2% , %Text1% Tab_Button_Clicked := Tab_Button_Over ; update GuiControl,, Gui1_Tab, |%Group_List% GuiControl, ChooseString, Gui1_Tab, %Tab_Button_Clicked_Text% } TCM_HITTEST() ; returns 1-based index of clicked tab { Global hw_Gui1_Tab MouseGetPos, mX, mY, hWnd, Control, 2 If (Control != hw_Gui1_Tab) ; not clicked on tab control Return, False ControlGetPos, cX, cY,,,, ahk_id %Control% x:=mX-cX, y:=mY-cY ; co-ordinatess relative to tab control VarSetCapacity(lparam, 12, 0) NumPut(x, lparam, 0, "Int") NumPut(y, lparam, 4, "Int") SendMessage, 0x130D, 0, &lparam,, ahk_id %Control% ; TCM_HITTEST result := ErrorLevel ; 0-based index, FAIL, or 0xFFFFFFFF (in a tab but not the button) If (result = "FAIL" or result = 0xFFFFFFFF) Return, False Else Return, result + 1 ; change to 1-based index } Tab_Button_Get_Text(Tab_Index) { Global If Tab_Index Loop, Parse, Group_List,| If (A_Index = Tab_Index) Return, A_LoopField } Gui_Settings_Tab: Return Gui_Resize_and_Position: DetectHiddenWindows, On ; retrieving column widths to enable calculation of col 3 width Gui, +LastFound Gui_ID := WinExist() ; for auto-sizing columns later If Display_List_Shown =0 ; resize listview columns - no need to resize columns for updating listview { LV_ModifyCol(1, Col_1) ; icon column LV_ModifyCol(2, Col_2) ; hidden column for row number ; col 3 - see below LV_ModifyCol(4, Col_4) ; exe SendMessage, 0x1000+29, 3, 0,, ahk_id %hw_LV_ColorChange% ; LVM_GETCOLUMNWIDTH is 0x1000+29 Width_Column_4 := ErrorLevel If Width_Column_4 > %Exe_Width_Max% LV_ModifyCol(4, Exe_Width_Max) ; resize title column LV_ModifyCol(5, Col_5) ; State If OnTop_Found LV_ModifyCol(6, Col_6) ; OnTop Else LV_ModifyCol(6, 0) ; OnTop If Status_Found LV_ModifyCol(7, Col_7) ; Status Else LV_ModifyCol(7, 0) ; Status Loop, 7 { SendMessage, 0x1000+29, A_Index -1, 0,, ahk_id %hw_LV_ColorChange% ; LVM_GETCOLUMNWIDTH is 0x1000+29 Width_Column_%A_Index% := ErrorLevel } Col_3_w := Listview_Width - Width_Column_1 - Width_Column_2 - Width_Column_4 - Width_Column_5 - Width_Column_6 - Width_Column_7 - 4 ; total width of columns - 4 for border LV_ModifyCol(3, Col_3_w) ; resize title column } ListView_Resize_Vertically(Gui_ID) ; Automatically resize listview vertically - pass the gui id value GuiControlGet, Listview_Now, Pos, ListView1 ; retrieve listview dimensions/position ; for auto-sizing (elsewhere) ; resize listview according to scrollbar presence If (Listview_NowH > Height_Max AND Use_Large_Icons_Current =0) ; already using small icons so limit height { Col_3_w -= Scrollbar_Vertical_Thickness ; allow for vertical scrollbar being visible LV_ModifyCol(3, Col_3_w) ; resize title column GuiControl, Move, ListView1, h%Height_Max% } DetectHiddenWindows, Off Return SB_Update__CPU: Format_Float := A_FormatFloat SetFormat, Float, 4.1 SB_SetText( "CPU (%): " GetSystemTimes(), 1) SetFormat, Float, %Format_Float% Return SB_Update__ProcessCPU: Format_Float := A_FormatFloat SetFormat, Float, 4.1 Get__Selected_Row_and_RowText() SB_SetText( "Process CPU (%): " GetProcessTimes(PID%RowText%), 2) SetFormat, Float, %Format_Float% Return Get__Selected_Row_and_RowText() { Global If ListView1__Disabled = 1 ; don't update - for statusbar (timer) Return Selected_Row := LV_GetNext(0, "F") LV_GetText(RowText, Selected_Row, 2) ; Get the row's 2nd column's text for real order number (hidden column). } ;======================================================================================================== ListView_Event: If MButton_Clicked =1 ; closing a window so don't process events Return If A_GuiEvent =DoubleClick ; activate clicked window Gosub, ListView_Destroy If A_GuiEvent =K ; letter was pressed, select next window name starting with that letter Gosub, Key_Pressed_1st_Letter If A_GuiEvent =ColClick ; column was clicked - do custom sort to allow for sorting hidden column + remembering state ColumnClickSort(A_EventInfo) ; A_EventInfo = column clicked on Return GuiContextMenu: ; right-click or press of the Apps key -> displays the menu only for clicks inside the ListView If Menu__Gui_1 ; destroy previously generated menus Get__Selected_Row_and_RowText() Gui_wid := Window%RowText% Gui_wid_Title :=Title%RowText% StringLeft, Gui_wid_Title, Gui_wid_Title, 40 Menu, Tray, UseErrorLevel ; Clear previous entries Menu, ContextMenu1, DeleteAll Menu, Gui_MinMax_Windows, DeleteAll Menu, Gui_Dock_Windows, DeleteAll Menu, Gui_Un_Exclude_Windows, DeleteAll Menu, Gui_Window_Group_Load, DeleteAll Menu, Gui_Window_Group_Delete, DeleteAll Menu, Gui_Processes, DeleteAll Menu, Gui_Settings_Help, DeleteAll ; Min/Max windows Menu, Gui_MinMax_Windows, Add, % "Maximize all: " Exe_Name%RowText%, Gui_MinMax_Windows Menu, Gui_MinMax_Windows, Add, % "Minimize all: " Exe_Name%RowText%, Gui_MinMax_Windows Menu, Gui_MinMax_Windows, Add Menu, Gui_MinMax_Windows, Add, % "Normal all: " Exe_Name%RowText%, Gui_MinMax_Windows Menu, ContextMenu1, Add, &Min / Max, :Gui_MinMax_Windows ; Dock to Screen Edge entries Menu, Gui_Dock_Windows, Add, Left, Gui_Dock_Windows Menu, Gui_Dock_Windows, Add, Right, Gui_Dock_Windows Menu, Gui_Dock_Windows, Add, Top, Gui_Dock_Windows Menu, Gui_Dock_Windows, Add, Bottom, Gui_Dock_Windows Menu, Gui_Dock_Windows, Add Menu, Gui_Dock_Windows, Add, Corner - Top Left, Gui_Dock_Windows Menu, Gui_Dock_Windows, Add, Corner - Top Right, Gui_Dock_Windows Menu, Gui_Dock_Windows, Add, Corner - Bottom Left, Gui_Dock_Windows Menu, Gui_Dock_Windows, Add, Corner - Bottom Right, Gui_Dock_Windows Menu, Gui_Dock_Windows, Add Menu, Gui_Dock_Windows, Add, Un-Dock, Gui_Un_Dock_Window Menu, Gui_Dock_Windows, Add, Un-Dock All, Gui_Un_Dock_Windows_All IfNotInString, Gui_Dock_Windows_List,%Gui_wid% Menu, Gui_Dock_Windows, Disable, Un-Dock Else { Menu, Gui_Dock_Windows, Disable, Left Menu, Gui_Dock_Windows, Disable, Right Menu, Gui_Dock_Windows, Disable, Top Menu, Gui_Dock_Windows, Disable, Bottom Menu, Gui_Dock_Windows, Disable, Corner - Top Left Menu, Gui_Dock_Windows, Disable, Corner - Top Right Menu, Gui_Dock_Windows, Disable, Corner - Bottom Left Menu, Gui_Dock_Windows, Disable, Corner - Bottom Right If (Edge_Dock_Position_%Gui_wid% !="") ; produces error if doesn't exist Menu, Gui_Dock_Windows, Check, % Edge_Dock_Position_%Gui_wid% } If Gui_Dock_Windows_List = Menu, Gui_Dock_Windows, Disable, Un-Dock All Menu, ContextMenu1, Add, &Dock to Edge, :Gui_Dock_Windows ; Window Group sub-menu entry Menu, ContextMenu1, Add ; spacer Menu, ContextMenu1, Add, Group - &No Filter, Gui_Window_Group_No_Filter If (Group_Active != "Settings" AND Group_Active != "ALL") Menu, ContextMenu1, Disable, Group - &No Filter Loop, Parse, Group_List,| If (A_LoopField != "Settings") Menu, Gui_Window_Group_Load, Add,%A_LoopField%, Gui_Window_Group_Load Menu, Gui_Window_Group_Load, Check, %Group_Active% Menu, ContextMenu1, Add, Group - &Load, :Gui_Window_Group_Load Menu, ContextMenu1, Add, Group - &Save/Edit, Gui_Window_Group_Save_Edit Menu, ContextMenu1, Add, Group - Global &Include, Gui_Window_Group_Global_Include Menu, ContextMenu1, Add, Group - Global &Exclude, Gui_Window_Group_Global_Exclude Loop, Parse, Group_List,| If (A_LoopField != "Settings" AND A_LoopField != "ALL") Menu, Gui_Window_Group_Delete, Add,%A_LoopField%, Gui_Window_Group_Delete Menu, Gui_Window_Group_Delete, Check, %Group_Active% Menu, Gui_Window_Group_Delete, Color, E10000, Single ; warning colour Menu, ContextMenu1, Add, Group - &Delete, :Gui_Window_Group_Delete ; Hotkeys entry Menu, ContextMenu1, Add ; spacer Menu, ContextMenu1, Add, &Hotkeys, Gui_Hotkeys ; Processes entry Menu, ContextMenu1, Add ; spacer Menu, Gui_Processes, Add, % "End: " Gui_wid_Title, End_Process_Single Menu, Gui_Processes, Add ; spacer Menu, Gui_Processes, Add, % "End All: " Exe_Name%RowText%, End_Process_All_Instances Menu, Gui_Processes, Color, E10000, Single ; warning colour Menu, ContextMenu1, Add, &Processes, :Gui_Processes ; Help + Latest changes Menu, ContextMenu1, Add ; spacer Menu, Gui_Settings_Help, Add, Delete Settings (.ini) && Reload, Delete_Ini_File_Settings Menu, Gui_Settings_Help, Add, ; spacer Menu, Gui_Settings_Help, Add, Help, HELP_and_LATEST_VERSION_CHANGES Menu, Gui_Settings_Help, Add, Latest Changes, HELP_and_LATEST_VERSION_CHANGES Menu, ContextMenu1, Add, Settings && Help, :Gui_Settings_Help Menu, ContextMenu1, Show, %A_GuiX%, %A_GuiY% Return Gui_MinMax_Windows: Gosub, GuiControl_Disable_ListView1 List_of_Process_To_MinMax = ; need to store list now as re-drawing the listview over-writes necessary variables Loop, %Window_Found_Count% { If ( Exe_Name%A_Index% = Exe_Name%RowText% and ! Dialog%A_Index% ) ; don't try to act on dialog windows (e.g. save prompts) List_of_Process_To_MinMax .= "|" . Window%A_Index% } StringTrimLeft, List_of_Process_To_MinMax, List_of_Process_To_MinMax, 1 ; remove 1st | character (empty reference otherwise) If A_ThisMenuItem contains Maximize MinMax_Message =0xF030 ; SC_MAXIMIZE Else If A_ThisMenuItem contains Minimize MinMax_Message =0xF020 ; SC_MINIMIZE Else If A_ThisMenuItem contains Normal MinMax_Message =0xF120 ; SC_RESTORE Loop, Parse, List_of_Process_To_MinMax,| PostMessage, 0x112, %MinMax_Message%,,, ahk_id %A_LoopField% ; 0x112 = WM_SYSCOMMAND Sleep, 50 ; wait for min/max state to change otherwise updated listview will be wrong Gosub, Display_List Gosub, GuiControl_Enable_ListView1 Return GuiControl_Disable_ListView1: OnMessage( 0x06, "" ) ; turn off: no alt tab list window lost focus -> hide list ListView1__Disabled = 1 GuiControl, Disable, ListView1 Return GuiControl_Enable_ListView1: GuiControl, Enable, ListView1 GuiControl, Focus, ListView1 ListView1__Disabled = 0 OnMessage( 0x06, "WM_ACTIVATE" ) ; turn on again - alt tab list window lost focus > hide list Return ; DOCKED WINDOWS MENU SECTION: ;============================================================================================================================ Gui_Dock_Windows: Edge_Dock_%Gui_wid% =%Gui_wid% ; write window ID to a unique variable Edge_Dock_Position_%Gui_wid% :=A_ThisMenuItem ; store Left, Right, etc WinGet, Edge_Dock_State_%Gui_wid%, MinMax, ahk_id %Gui_wid% If Edge_Dock_State_%Gui_wid% =-1 ; if window is mimised, un-minimise WinRestore, ahk_id %Gui_wid% WinGetPos, Edge_Dock_X_%Gui_wid%, Edge_Dock_Y_%Gui_wid%, Edge_Dock_Width_%Gui_wid%, Edge_Dock_Height_%Gui_wid%, ahk_id %Gui_wid% Edge_Dock_X_Initial_%Gui_wid% := Edge_Dock_X_%Gui_wid% Edge_Dock_Y_Initial_%Gui_wid% := Edge_Dock_Y_%Gui_wid% Edge_Dock_Width_Initial_%Gui_wid% := Edge_Dock_Width_%Gui_wid% Edge_Dock_Height_Initial_%Gui_wid% := Edge_Dock_Height_%Gui_wid% WinGet, Edge_Dock_AlwaysOnTop_%Gui_wid%, ExStyle, ahk_id %Gui_wid% ; store AlwaysOnTop original status If Gui_Dock_Windows_List = Gui_Dock_Windows_List =%Gui_wid% ; keep track of number of docked windows Else Gui_Dock_Windows_List .="|" Gui_wid WinSet, AlwaysOnTop, On, ahk_id %Gui_wid% Gosub, Alt_Esc_Check_Alt_State ; hides alt-tab gui - shows again if alt still pressed Gui_Dock_Windows_ReDock: Edge_Dock_X = Edge_Dock_Y = ; leave just 5 pixels (Edge_Dock_Border_Visible) of side visible If Edge_Dock_Position_%Gui_wid% contains Left Edge_Dock_X := - ( Edge_Dock_Width_%Gui_wid% - Edge_Dock_Border_Visible ) Else If Edge_Dock_Position_%Gui_wid% contains Right Edge_Dock_X := A_ScreenWidth - Edge_Dock_Border_Visible If Edge_Dock_Position_%Gui_wid% contains Top Edge_Dock_Y := - ( Edge_Dock_Height_%Gui_wid% - Edge_Dock_Border_Visible ) Else If Edge_Dock_Position_%Gui_wid% contains Bottom Edge_Dock_Y := A_ScreenHeight - Edge_Dock_Border_Visible WinMove, ahk_id %Gui_wid%,, %Edge_Dock_X%, %Edge_Dock_Y% SetTimer, Check_Mouse_Position, %Edge_Dock_Activation_Delay% ; change to affect response time to having mouse over edge-docked window Return Check_Mouse_Position: Gosub, Check_Docked_Windows_Exist WinGet, Previously_Active_Window_Before_Using_Docked, ID, A Edge_Dock_Active_Window = If ( Edge_Dock_%Previously_Active_Window_Before_Using_Docked% != "" ) ; check keyboard focus { CoordMode, Mouse, Screen MouseGetPos,Check_Mouse_Position_X, Check_Mouse_Position_Y Edge_Dock_Active_Window := Previously_Active_Window_Before_Using_Docked } MouseGetPos,,, Mouse_Over_Window If ( Edge_Dock_%Mouse_Over_Window% != "" ) ; over-ride keyboard with mouse "focus" if necessary { Edge_Dock_Active_Window := Mouse_Over_Window WinActivate, ahk_id %Mouse_Over_Window% } If Edge_Dock_Active_Window != ; i.e. window is already docked { SetTimer, Check_Mouse_Position, Off WinGet, PID_Edge_Dock_Active_Window, PID, ahk_id %Edge_Dock_Active_Window% Edge_Dock_X = Edge_Dock_Y = ; move window onto screen If Edge_Dock_Position_%Edge_Dock_Active_Window% contains Left Edge_Dock_X =0 Else If Edge_Dock_Position_%Edge_Dock_Active_Window% contains Right Edge_Dock_X := A_ScreenWidth - Edge_Dock_Width_%Edge_Dock_Active_Window% If Edge_Dock_Position_%Edge_Dock_Active_Window% contains Top Edge_Dock_Y =0 Else If Edge_Dock_Position_%Edge_Dock_Active_Window% contains Bottom Edge_Dock_Y := A_ScreenHeight - Edge_Dock_Height_%Edge_Dock_Active_Window% WinSet, AlwaysOnTop, Off, ahk_id %Edge_Dock_Active_Window% WinMove, ahk_id %Edge_Dock_Active_Window%,, %Edge_Dock_X%, %Edge_Dock_Y% SetTimer, Check_Mouse_Position_Deactivate, %Edge_Dock_Activation_Delay% } Return Check_Docked_Windows_Exist: If Gui_Dock_Windows_List = ; keep track of number of docked windows { SetTimer, Check_Mouse_Position, Off SetTimer, Check_Mouse_Position_Deactivate, Off Return } Loop, Parse, Gui_Dock_Windows_List,| ; check if windows in docked list have been closed before un-docking { IfWinNotExist, ahk_id %A_LoopField% { Gui_wid =%A_LoopField% Gui_Un_Dock_Window_No_Alt_Esc =1 Gosub, Gui_Un_Dock_Window } } Return Check_Mouse_Position_Deactivate: ; check if not over an edge-docked window any more Gosub, Check_Docked_Windows_Exist WinGet, Style, Style, ahk_id %Edge_Dock_Active_Window% If ( Style & WS_DISABLED ) ; don't allow disabled windows to be re-docked (e.g., showing save box) Return ; retrieve active window focus and mouse over window - active window has priority WinGet, PID_Active_Window_Now, PID, A WinGet, Active_Window_Now_ID, ID, A WinGetTitle, Active_Window_Now_Title, A ; use titles to check if in same program title but over a problematic control such as xplorer2 dropdownbox (different id and pid) WinGetTitle, Edge_Dock_Active_Window_Title, ahk_id %Edge_Dock_Active_Window% WinGetTitle, Active_Window_Now_Mouse_Title, ahk_id %Active_Window_Now_Mouse% CoordMode, Mouse, Screen MouseGetPos,Active_Window_Now_Mouse_X, Active_Window_Now_Mouse_Y, Active_Window_Now_Mouse If ((Check_Mouse_Position_X >= Active_Window_Now_Mouse_X -10 and Check_Mouse_Position_X <= Active_Window_Now_Mouse_X +10) ; ; mouse not moved - e.g. clicked taskbar and (Check_Mouse_Position_Y >= Active_Window_Now_Mouse_Y -10 and Check_Mouse_Position_Y <= Active_Window_Now_Mouse_Y +10) and (Active_Window_Now_Title = Edge_Dock_Active_Window_Title)) Return If (Active_Window_Now_Title = Edge_Dock_Active_Window_Title and Active_Window_Now_Mouse_Title = "" and (Active_Window_Now_ID != TaskBar_ID and Active_Window_Now_Mouse != TaskBar_ID)) Return If (PID_Active_Window_Now != PID_Edge_Dock_Active_Window) ; compare pid to check that a child window is not created/active Gosub, Gui_Dock_Windows_ReDock_Initiate Else { WinGet, PID_Active_Window_Now_Mouse, PID, ahk_id %Active_Window_Now_Mouse% If (PID_Active_Window_Now_Mouse != PID_Edge_Dock_Active_Window) { Gosub, Gui_Dock_Windows_ReDock_Initiate If Gui_Dock_Windows_List contains %Previously_Active_Window_Before_Using_Docked% ; activate window under mouse to prevent looping WinActivate, ahk_id %Active_Window_Now_Mouse% Else WinActivate, ahk_id %Previously_Active_Window_Before_Using_Docked% } } Return Gui_Dock_Windows_ReDock_Initiate: SetTimer, Check_Mouse_Position_Deactivate, Off WinSet, AlwaysOnTop, On, ahk_id %Edge_Dock_Active_Window% WinGetPos, Edge_Dock_X_%Edge_Dock_Active_Window%, Edge_Dock_Y_%Edge_Dock_Active_Window%, Edge_Dock_Width_%Edge_Dock_Active_Window% , Edge_Dock_Height_%Edge_Dock_Active_Window%, ahk_id %Edge_Dock_Active_Window% Gui_wid =%Edge_Dock_Active_Window% Gosub, Gui_Dock_Windows_ReDock Return Gui_Un_Dock_Window: If Gui_Un_Dock_Window_No_Alt_Esc !=1 Gosub, Alt_Esc_Check_Alt_State ; hides alt-tab gui - shows again if alt still pressed Gui_Un_Dock_Window_No_Alt_Esc = ; reset If ! ( Edge_Dock_AlwaysOnTop_%Gui_wid% & 0x8 ) ; 0x8 is WS_EX_TOPMOST - keep AlwaysOnTop if originally on top WinSet, AlwaysOnTop, Off, ahk_id %Gui_wid% WinMove, ahk_id %Gui_wid%,, % Edge_Dock_X_Initial_%Gui_wid%, % Edge_Dock_Y_Initial_%Gui_wid%, % Edge_Dock_Width_Initial_%Gui_wid% , % Edge_Dock_Height_Initial_%Gui_wid% ; original position ; erase variables Edge_Dock_%Gui_wid% = Edge_Dock_X_Initial_%Gui_wid% = Edge_Dock_Y_Initial_%Gui_wid% = Edge_Dock_Width_Initial_%Gui_wid% = Edge_Dock_Height_Initial_%Gui_wid% = Edge_Dock_State_%Gui_wid% = Edge_Dock_X_%Gui_wid% = Edge_Dock_Y_%Gui_wid% = Edge_Dock_Width_%Gui_wid% = Edge_Dock_Height_%Gui_wid% = Edge_Dock_Position_%Gui_wid% = Edge_Dock_AlwaysOnTop_%Gui_wid% = StringReplace, Gui_Dock_Windows_List, Gui_Dock_Windows_List,%Gui_wid%| ; remove entry If ErrorLevel =1 StringReplace, Gui_Dock_Windows_List, Gui_Dock_Windows_List,%Gui_wid% ; last window so no delimiter to replace too Return Gui_Un_Dock_Windows_All: Loop, Parse, Gui_Dock_Windows_List,| ; check if windows in docked list have been closed before un-docking { Gui_wid := A_LoopField Gui_Un_Dock_Window_No_Alt_Esc =1 Gosub, Gui_Un_Dock_Window } Return ; HOTKEYS MENU SECTION: ;============================================================================================================================ Gui_Hotkeys: Gosub, Alt_Esc Gui, 2: Default ; for listview operations Gui, 2: Font, s10 Gui, 2: Add, Text, xm y+15, Main hotkeys: Gui, 2: Font Gui, 2: Add, Text, x+5 yp+2, (Note that "Alt" must be either Alt, Ctrl, Shift, Win or mouse XButton1 / 2 - but using XButton requires "Shift+Tab" is a single key!) ; Gui_Add_Hotkey(Gui number, Text, Comment, variable name) Gui_Add_Hotkey(2, "Alt","(key in Alt+Tab)", "Alt_Hotkey") GuiControl, 2: Disable, Alt_Hotkey_Tab GuiControl, 2: Disable, Alt_Hotkey_Esc GuiControl, 2: Disable, Alt_Hotkey_Enter GuiControl, 2: Disable, Alt_Hotkey_WheelUp GuiControl, 2: Disable, Alt_Hotkey_WheelDown GuiControl, 2: Disable, Alt_Hotkey_Hotkey Gui_Add_Hotkey(2, "Tab","(key in Alt+Tab)", "Tab_Hotkey") Gui_Add_Hotkey(2, "Shift+Tab","(Key(s) in Alt+Shift+Tab)", "Shift_Tab_Hotkey") Gui_Add_Hotkey(2, "Esc","(key in Alt+Esc)", "Esc_Hotkey") Gui, 2: Font, s10 Gui, 2: Add, Text,xm y+15, Single keys: Gui, 2: Font Gui, 2: Add, Text, x+5 yp+2, (Alternative way to show the Alt+Tab list by 1 key (blank for no hotkey) and another for selection) Gui_Add_Hotkey(2, "Alt+Tab list", "", "Single_Key_Show_Alt_Tab") Gui_Add_Hotkey(2, "Alt+Tab selection", "", "Single_Key_Hide_Alt_Tab") Gui, 2: Font, s10 Gui, 2: Add, Text,xm y+30, Group hotkeys: Gui, 2: Font GuiControl, 2: Focus, Static1 Gui, 2: Add, ListView, section xm r15 w470 -Multi, Group name|Assigned hotkey Loop, Parse, Group_List, | If (A_LoopField != "Settings") LV_Add("", A_LoopField, %A_LoopField%_Group_Hotkey) Gui, 2: Add, Button, x+10 yp+40 gGui_2_Group_Hotkey_Assign w170, Assign hotkey to selected group: Gui, 2: Add, Hotkey, vGui_2_Group_Hotkey xp y+5, %Hotkey% Gui, 2: Add, Button, xp y+30 gGui_2_Group_Hotkey_Clear w170, Clear hotkey of selected group Gui, 2: Add, Text, xp y+30, ( Key: !=Alt, ^=Ctrl, +=Shift, #=Win ) Gui, 2: Add, Text, xm+250, WARNING! No error checking for hotkeys - be careful what you choose! (Delete the .ini file to reset settings) Gui, 2: Add, Button, xm+430 g2GuiClose w100, &Cancel Gui, 2: Add, Button, x+20 gGui_2_OK wp Default, &OK Gui, 2: Show,, Hotkeys Return Gui_2_Group_Hotkey_Assign: Gui, 2: Submit, NoHide Selected_Row := LV_GetNext(0, "F") If (! Selected_Row or ! Gui_2_Group_Hotkey) Return Loop, Parse, Group_List,| If %A_LoopField%_Group_Hotkey =%Gui_2_Group_Hotkey% { Msgbox, Hotkey already exists! Please clear the duplicate hotkey first. Return } LV_GetText(Gui_2_Group_Selected, Selected_Row) %Gui_2_Group_Selected%_Group_Hotkey := Gui_2_Group_Hotkey LV_Modify(Selected_Row, "Col2", Gui_2_Group_Hotkey) Return Gui_2_Group_Hotkey_Clear: Selected_Row := LV_GetNext(0, "F") If not Selected_Row Return LV_Modify(Selected_Row, "Col2", "") Return Gui_2_OK: Loop, % LV_GetCount() ; process group hotkeys from listview { LV_GetText(Group_Name, A_Index, 1) LV_GetText(Group_Hotkey, A_Index, 2) %Group_Name%_Group_Hotkey =%Group_Hotkey% } Gui, 2: Submit Gui, 2: Destroy Gui_Read_Hotkey(2, "Alt_Hotkey") ; Gui_Read_Hotkey(Gui number, associated variable) Gui_Read_Hotkey(2, "Tab_Hotkey") Gui_Read_Hotkey(2, "Shift_Tab_Hotkey") Gui_Read_Hotkey(2, "Esc_Hotkey") Gui_Read_Hotkey(2, "Single_Key_Show_Alt_Tab") Gui_Read_Hotkey(2, "Single_Key_Hide_Alt_Tab") IniFile_Data("Write") Reload Return Gui_Read_Hotkey(Gui, var_name) { Global %var_name% = If %var_name%_Alt =1 %var_name% = % %var_name% "!" If %var_name%_Ctrl =1 %var_name% = % %var_name% "^" If %var_name%_Shift =1 %var_name% = % %var_name% "+" If %var_name%_Win =1 %var_name% = % %var_name% "#" If %var_name%_Tab =1 %var_name% = % %var_name% "Tab" If %var_name%_Esc =1 %var_name% = % %var_name% "Esc" If %var_name%_Enter =1 %var_name% = % %var_name% "Enter" If %var_name%_XButton1 =1 %var_name% = % %var_name% "XButton1" If %var_name%_XButton2 =1 %var_name% = % %var_name% "XButton2" If %var_name%_WheelUp =1 %var_name% = % %var_name% "WheelUp" If %var_name%_WheelDown =1 %var_name% = % %var_name% "WheelDown" If (%var_name%_Hotkey != "None" and %var_name% = "") %var_name% = % %var_name% %var_name%_Hotkey } Gui_Add_Hotkey(Gui, Text, Comment, var_name) { Local Alt, Ctrl, Shift, Win, Tab, Esc, Enter, XButton1, XButton2, WheelUp, WheelDown, Hotkey, hotkey_temp, hotkey_list__symbols, hotkey_list__symbols0, hotkey_list__vars, hotkey_list__vars0, symbol_temp, var_temp hotkey_temp := %var_name% hotkey_list__symbols =!|^|+|#|Tab|Esc|Enter|XButton1|XButton2|WheelUp|WheelDown hotkey_list__vars =Alt|Ctrl|Shift|Win|Tab|Esc|Enter|XButton1|XButton2|WheelUp|WheelDown StringSplit, hotkey_list__symbols, hotkey_list__symbols ,| StringSplit, hotkey_list__vars, hotkey_list__vars ,| Loop, %hotkey_list__symbols0% { symbol_temp := hotkey_list__symbols%A_Index% var_temp := hotkey_list__vars%A_Index% If hotkey_temp contains %symbol_temp% { %var_temp% =1 StringReplace, hotkey_temp, hotkey_temp, %symbol_temp%, ; remove it from list } Else %var_temp% =0 } Hotkey=%hotkey_temp% ; remainder Gui, %Gui%: Font, bold Gui, %Gui%: Add, Text, xm, %Text% Gui, %Gui%: Font If Comment != Gui, %Gui%: Add, Text, x80 yp, %Comment% Gui, %Gui%: Add, Checkbox, v%var_name%_Alt Checked%Alt% x200 yp, Alt Gui, %Gui%: Add, Checkbox, v%var_name%_Ctrl Checked%Ctrl% x+10, Ctrl Gui, %Gui%: Add, Checkbox, v%var_name%_Shift Checked%Shift% x+10, Shift Gui, %Gui%: Add, Checkbox, v%var_name%_Win Checked%Win% x+10, Win Gui, %Gui%: Add, Checkbox, v%var_name%_Tab Checked%Tab% x+10, Tab Gui, %Gui%: Add, Checkbox, v%var_name%_Esc Checked%Esc% x+10, Esc Gui, %Gui%: Add, Checkbox, v%var_name%_Enter Checked%Enter% x+10, Enter Gui, %Gui%: Add, Text, x+10, XButton: Gui, %Gui%: Add, Checkbox, v%var_name%_XButton1 Checked%XButton1% x+2, 1 Gui, %Gui%: Add, Checkbox, v%var_name%_XButton2 Checked%XButton2% x+2, 2 Gui, %Gui%: Add, Text, x+10, Wheel: Gui, %Gui%: Add, Checkbox, v%var_name%_WheelUp Checked%WheelUp% x+2, Up Gui, %Gui%: Add, Checkbox, v%var_name%_WheelDown Checked%WheelDown% x+2, Down Gui, %Gui%: Add, Hotkey, v%var_name%_Hotkey x+10 yp-3, %Hotkey% } ; GROUPS MENU SECTION: ;============================================================================================================================ Gui_Window_Group_No_Filter: Group_Active =ALL Gosub, Alt_Esc_Check_Alt_State Return Gui_Window_Group_Load: Group_Active =%A_ThisMenuItem% Gui_Window_Group_Load__part2: Gosub, Custom_Group__make_array_of_contents Gosub, Alt_Esc_Check_Alt_State ; hides alt-tab gui - shows again if alt still pressed Return Custom_Group__make_array_of_contents: Exclude_Not_In_List = If (Group_Active != "Settings" AND Group_Active != "ALL") { Group_Active_Contents := %Group_Active% If Group_Active_Contents contains Exclude_Not_In_List { Exclude_Not_In_List =1 StringReplace, Group_Active_Contents, Group_Active_Contents, Exclude_Not_In_List|, ; remove text } StringSplit, Group_Active_, Group_Active_Contents,| } Return Gui_Window_Group_Save_Edit: Gosub, Alt_Esc Gui, 3: Default ; for listview operations Gui, 3: Add, Text, y+15, ( Choose window titles/exes to include/exclude when LOADING a list: - Double-click / F2 to rename an entry. - Titles match anywhere within a target window's title or parent's title (exe is ignored). - Delete the title completely to match the EXE instead. - To EXCLUDE a window, prefix title or EXE with an exclamation: e.g. !notepad.exe, or only ! in title column. - "Exclude all windows not in list?" ignores new windows that do not match the list. - Only ticked items are added to the list. Unticked are removed. - Priority of rules is top (highest) to bottom (lowest). - Not case sensitive. ) Gui, 3: Add, ListView, xm y+15 r15 w500 Checked -ReadOnly -Multi NoSortHdr AltSubmit gListView3_Event, (Partial) Window Title|EXE Gui_3_ImageList:= IL_Create(15,5,0) LV_SetImageList(Gui_3_ImageList, 1) IL_Add( Gui_3_ImageList, "shell32.dll" , 110) ; not included icon Gui, 3: Add, Picture, icon48 x+10 yp+100 gGui_3_ListView_Swap_Rows_Up, C:\WINDOWS\system32\progman.exe ; up arrow Gui, 3: Add, Picture, icon45 gGui_3_ListView_Swap_Rows_Down, C:\WINDOWS\system32\progman.exe ; down arrow Gui, 3: Add, Text, xm+20, Manual add: Gui_3_Manual_Allow_Blank =1 Gui, 3: Add, Edit, x+5 w200 gGui_3_Manual_Exe_Blank vGui_3_Manual_Title, [window title] Gui, 3: Add, Edit, x+5 w100 gGui_3_Manual_Title_Blank vGui_3_Manual_Exe, [program.exe] Gui, 3: Add, Button, x+10 w80 gGui3_Manual_Add, A&dd Gui, 3: Add, Text, xm+20 y+30, Group name: Gui, 3: Add, ComboBox, x+5 w200 vCustom_Name, %Group_List% GuiControl, ChooseString, Custom_Name, %Group_Active% Gui, 3: Add, Checkbox, x+20 vExclude_Not_In_List Checked, Exclude all windows not in list? If %Group_Active% not contains Exclude_Not_In_List GuiControl,, Exclude_Not_In_List, 0 ; check box Gui, 3: Add, Button, xm+10 y+20 w80 gGui3_RESET, &Reset List Gui, 3: Add, Button, x+20 wp gGui3_SelectALL, Select &All Gui, 3: Add, Button, x+20 wp gGui3_SelectNONE, Select &None Gui, 3: Add, Button, x+20 wp g3GuiClose, &Cancel Gui, 3: Add, Button, x+20 wp Default gGui3_OK, &OK If (Global_Include_Edit or Global_Exclude_Edit) { GuiControl, 3: Disable, Exclude_Not_In_List GuiControl, 3: Disable, Custom_Name } If Global_Include_Edit =1 Gui_3_Listview_Populate("Global_Include") Else If Global_Exclude_Edit =1 Gui_3_Listview_Populate("Global_Exclude") Else If (Group_Active = "Settings" OR Group_Active = "ALL") Loop, %Window_Found_Count% ; populate listview LV_Add("Check Icon2", Title%A_Index%, Exe_Name%A_Index%) ; Icon 1 = not included icon, Icon 2 = blank Else Gui_3_Listview_Populate(Group_Active) Gosub, Gui_3_Update_Icons DetectHiddenWindows, On Gui, 3: +LastFound Gui_3_ID := WinExist() ; for auto-sizing columns later LV_ModifyCol(1, 350) ControlGet, Gui_3_Listview_Style, Style,, SysListView321, ahk_id %Gui_3_ID% If ( Gui_3_Listview_Style & WS_VSCROLL ) ; has a vertical scrollbar - reduced width for listview Gui_3_Col_2_w := 500 - 350 - Scrollbar_Vertical_Thickness - 4 Else Gui_3_Col_2_w := 500 - 350 - 4 LV_ModifyCol(2, Gui_3_Col_2_w) Gui, 3: Show,, Group - Save/Edit Return Gui_3_Listview_Populate(list) { Global Loop, Parse, %list%,| { If A_LoopField =Exclude_Not_In_List Continue If A_LoopField contains .exe LV_Add("Check Icon2" ,"", A_LoopField) ; Icon 1 = not included icon, Icon 2 = blank Else LV_Add("Check Icon2" ,A_LoopField,"") ; Icon 1 = not included icon, Icon 2 = blank } } Gui_3_ListView_Swap_Rows_Up: ListView_Swap_Rows("Up") ; "move" selected row up 1 - higher priority Return Gui_3_ListView_Swap_Rows_Down: ListView_Swap_Rows("Down") ; "move" selected row down 1 - lower priority Return ListView_Swap_Rows(Direction) ; Direction=Up/Down -swaps all text in each column of 2 adjacent rows and their checked states { Row_Selected := LV_GetNext("Focused") If Row_Selected =0 ; no row selected { LV_Modify(1, "Select Focus") Return } If Direction =Up { Row_Swap_With := Row_Selected -1 If Row_Swap_With =0 ; reached top of listview Return } Else { Row_Swap_With := Row_Selected +1 If ( Row_Swap_With > LV_GetCount() ) ; reached end of listview Return } Loop, % LV_GetCount("Col") { LV_GetText(Row_Text_%Row_Selected%_%A_Index%, Row_Selected, A_Index) LV_GetText(Row_Text_%Row_Swap_With%_%A_Index%, Row_Swap_With, A_Index) } If ( LV_GetNext(Row_Selected - 1, "C") = Row_Selected ) ; save box checked states Row_Selected_Checked =Check Else Row_Selected_Checked =-Check If ( LV_GetNext(Row_Swap_With - 1, "C") = Row_Swap_With ) Row_Swap_With_Checked =Check Else Row_Swap_With_Checked =-Check Loop, % LV_GetCount("Col") { LV_Modify(Row_Selected, Row_Swap_With_Checked . " -Focus -Select Col" . A_Index, Row_Text_%Row_Swap_With%_%A_Index%) LV_Modify(Row_Swap_With, Row_Selected_Checked . " Focus Select Vis Col" . A_Index, Row_Text_%Row_Selected%_%A_Index%) } Gosub, Gui_3_Update_Icons } Gui3_OK: Gui, 3: Submit If Global_Include_Edit { Custom_Name =Global_Include Exclude_Not_In_List = } Else If Global_Exclude_Edit { Custom_Name =Global_Exclude Exclude_Not_In_List = } If (Custom_Name = "" OR Custom_Name = "Settings" OR Custom_Name = "ALL") { MsgBox, 48, ERROR, Enter a valid name for the group! Gui, 3: Show Return } StringReplace, Custom_Name, Custom_Name,%A_Space%,_,All If Exclude_Not_In_List =1 ; checked - add suffix to variable name to filter %Custom_Name% = |Exclude_Not_In_List ; add first entry - will parse and process when filtering alt-tab listview Else %Custom_Name% = ; make sure it is empty in case it previously existed (over-writing) RowNumber = 0 ; init Loop { RowNumber := LV_GetNext(RowNumber, "C") ; Resume the search at the row after that found by the previous iteration. If not RowNumber ; The above returned zero, so there are no more checked rows. Break LV_GetText(Title_temp, RowNumber) If Title_temp = ; blank therefore set the exe name instead LV_GetText(Title_temp, RowNumber, 2) If Title_temp =! ; exclude exe name instead { LV_GetText(Title_temp, RowNumber, 2) If Title_temp not contains ! Title_temp =!%Title_temp% } %Custom_Name% .= "|" . Title_temp } StringTrimLeft, %Custom_Name%, %Custom_Name%, 1 ; trim initial | If ! (Global_Include_Edit or Global_Exclude_Edit) { If Group_List not contains %Custom_Name% Group_List .= "|" Custom_Name ; store name to a list for finding later Group_Active := Custom_Name ; automatically apply the saved group filter } Gosub, 3GuiClose IniFile_Data("Write") Global_Include_Edit = ; reset Global_Exclude_Edit = Gosub, Alt_Esc_Check_Alt_State ; hides alt-tab gui - shows again if alt still pressed Return ListView3_Event: If A_GuiEvent = E ; edited a row Gosub, Gui_3_Update_Icons If A_GuiEvent = DoubleClick SendMessage, 0x1017, LV_GetNext(0, "Focused") - 1, 0, SysListView321 ; 0x1017 is LVM_EDITLABEL Return Gui_3_Update_Icons: Loop, % LV_GetCount() { Gui_3_Row_To_Modify := A_Index Gui_3_Icon =2 ; blank icon as default Loop, 2 ; check column 1 and 2 { LV_GetText(Title_temp, Gui_3_Row_To_Modify, A_Index) If Title_temp contains ! Gui_3_Icon =1 ; not included icon } LV_Modify(Gui_3_Row_To_Modify, "Icon" . Gui_3_Icon) } Return Gui3_Manual_Add: Gui, 3: Submit, NoHide Gui_3_Manual_Allow_Blank =1 Gosub, Gui_3_Manual_Title_Blank Gui_3_Manual_Allow_Blank =1 Gosub, Gui_3_Manual_Exe_Blank Gui_3_Icon =2 ; blank icon If Gui_3_Manual_Title contains ! Gui_3_Icon =1 ; not included icon If Gui_3_Manual_Exe contains ! Gui_3_Icon =1 LV_Add("Check Icon" . Gui_3_Icon,Gui_3_Manual_Title,Gui_3_Manual_Exe) GuiControl, Focus, &OK Sleep, 50 GuiControl, +Default, &OK Return Gui3_RESET: Gui, 3: Destroy Gosub, Gui_Window_Group_Save_Edit Return Gui3_SelectALL: Loop, %Window_Found_Count% LV_Modify(A_Index, "Check") Return Gui3_SelectNONE: Loop, %Window_Found_Count% LV_Modify(A_Index, "-Check") Return Gui_3_Manual_Title_Blank: If Gui_3_Manual_Allow_Blank =1 GuiControl,, Gui_3_Manual_Title, ; blank Gui_3_Manual_Allow_Blank =0 GuiControl, +Default, A&dd Return Gui_3_Manual_Exe_Blank: If Gui_3_Manual_Allow_Blank =1 GuiControl,, Gui_3_Manual_Exe, ; blank Gui_3_Manual_Allow_Blank =0 GuiControl, +Default, A&dd Return Gui_Window_Group_Global_Include: Global_Include_Edit =1 Gosub, Gui_Window_Group_Save_Edit Return Gui_Window_Group_Global_Exclude: Global_Exclude_Edit =1 Gosub, Gui_Window_Group_Save_Edit Return Gui_Window_Group_Delete: If Group_Active =%A_ThisMenuItem% Group_Active = ALL StringReplace, temp_List, Group_List, %A_ThisMenuItem% ; remove item from list Group_List = Loop, Parse, temp_List,| If A_LoopField Group_List .= "|" A_LoopField StringTrimLeft, Group_List, Group_List, 1 ; remove leading | Hotkey, % %A_ThisMenuItem%_Group_Hotkey, Off, UseErrorLevel IniDelete, Alt_Tab_Settings.ini, Groups, %A_ThisMenuItem% IniDelete, Alt_Tab_Settings.ini, Groups, %A_ThisMenuItem%_Group_Hotkey Gosub, Alt_Esc_Check_Alt_State ; hides alt-tab gui - shows again if alt still pressed Return Group_Hotkey: ; from loading ini file - determine hotkey behaviour based on current hotkey Group_Active_Before := Group_Active Loop, Parse, Group_List,| { If %A_LoopField%_Group_Hotkey =%A_ThisHotkey% ; find which group to activate { If Group_Active !=%A_LoopField% { Group_Active=%A_LoopField% ; load custom group Gosub, Custom_Group__make_array_of_contents } ; check if currently active window is in the newly loaded group, else switch to 1st Gosub, Single_Key_Show_Alt_Tab ; show list to generate updated variables to check Viewed_Window_List .="|" Active_ID Loop, %Window_Found_Count% ; abort switching and start to cycle through windows in list next { If (! InStr(Viewed_Window_List, Window%A_Index%) or Window_Found_Count <=1) { Gosub, ListView_Destroy WinActivate, % "ahk_id" Window%A_Index% If A_Index =%Window_Found_Count% Viewed_Window_List = ; viewed all windows so reset list Break } } Break } } Group_Active := Group_Active_Before Return MButton_Close: MButton_Clicked =1 MouseGetPos,,, Mouse_Over_Gui If Mouse_Over_Gui =%Gui_ID% ; check to be safe { SetTimer, MButton_Close_Cont, 50 Click, Left ; weird pause after left click - hence using timers - continues after moving mouse } MButton_Clicked = Return MButton_Close_Cont: SetTimer, MButton_Close_Cont, Off Get__Selected_Row_and_RowText() Gui_wid =% Window%RowText% If Gui_wid ; prevent error if nothing was selected due to delay in program Gosub, End_Process_Single Return End_Process_Single: Gosub, GuiControl_Disable_ListView1 Selected_Row ++ ; find window after window to close for positioning focus in listview afterwards LV_GetText(RowText, Selected_Row, 2) ; Get the row's hidden text Window_After_1st_Ending_Window_ID := Window%RowText% Gosub, End_Process_Subroutine Gosub, End_Process_Update_Listview Return End_Process_Subroutine: Loop, Parse, Gui_Dock_Windows_List,| ; un-dock docked window first (might remember off-screen position) If A_LoopField =%Gui_wid% { Gui_Un_Dock_Window_No_Alt_Esc =1 Gosub, Gui_Un_Dock_Window } PostMessage, 0x112, 0xF060,,, ahk_id %Gui_wid% ; 0x112 = WM_SYSCOMMAND, 0xF060 = SC_CLOSE WinWaitClose, ahk_id %Gui_wid%,, 1 Return End_Process_All_Instances: Gosub, GuiControl_Disable_ListView1 List_of_Process_To_End = ; need to store list now as re-drawing the listview over-writes necessary variables Loop, %Window_Found_Count% { If Dialog%A_Index% ; don't try to close dialog windows (e.g. save prompts) Continue If Exe_Name%RowText% = % Exe_Name%A_Index% List_of_Process_To_End .= "|" . Window%A_Index% } StringTrimLeft, List_of_Process_To_End, List_of_Process_To_End, 1 ; remove 1st | character (empty reference otherwise) Window_After_1st_Ending_Window_ID := Selected_Row + 1 ; find window after window to close for positioning focus in listview afterwards LV_GetText(RowText, Window_After_1st_Ending_Window_ID, 2) ; Get the row's hidden text Window_After_1st_Ending_Window_ID =% Window%RowText% ; over-ridden below if necessary If Exe_Name%RowText% = % Exe_Name%Selected_Row% ; find an earlier window which won't be closed { Loop, %Window_Found_Count% { Window_After_1st_Ending_Window_ID := Selected_Row + 1 + A_Index If Window_After_1st_Ending_Window_ID =% Window_Found_Count { LV_GetText(RowText, %Window_Found_Count%, 2) ; Get the row's hidden text If RowText not between 1 and %Window_Found_Count% ; avoid an error when closing all windows Break Window_After_1st_Ending_Window_ID =% Window%RowText% Break } LV_GetText(RowText, Window_After_1st_Ending_Window_ID, 2) ; Get the row's hidden text If Exe_Name%RowText% != % Exe_Name%Selected_Row% ; find an earlier window which won't be closed { Window_After_1st_Ending_Window_ID =% Window%RowText% Break } } } Loop, Parse, List_of_Process_To_End,| { Gui_wid := A_LoopField Gosub, End_Process_Subroutine } List_of_Process_To_End = ; reset Gosub, End_Process_Update_Listview Return End_Process_Update_Listview: Gosub, Display_List Loop, %Window_Found_Count% { If Window%A_Index% =%Window_After_1st_Ending_Window_ID% { LV_GetText(RowText, A_Index, 2) ; Get the row's hidden text LV_Modify(RowText, "Focus Select Vis") } } Gosub, GuiControl_Enable_ListView1 Return Key_Pressed_1st_Letter: Key_Pressed_ASCII =%A_EventInfo% Get__Selected_Row_and_RowText() ;TrayTip, ,%Key_Pressed_ASCII% If Key_Pressed_ASCII =93 ; Alt+Apps key - context menu { Gosub, GuiContextMenu Return } If (Key_Pressed_ASCII =40) ; Down arrow { GoSub Alt_Tab Return } If (Key_Pressed_ASCII =17) ; likaci mod ctrl17, Caps40 { Sleep 50 GetKeyState, AltIsDown, Alt, P if AltIsDown<>D ;likaci mod this is a fuck thing ,if don't Check the state of alt will double operated Return GoSub Alt_Shift_Tab Return } If (Key_Pressed_ASCII =38) ; Up arrow { GoSub Alt_Shift_Tab Return } If (Key_Pressed_ASCII =none) ; todo Show desktop { WinActivate, ahk_class Progman Return } ; \ key - close window If (Key_Pressed_ASCII =92 or Key_Pressed_ASCII =220 or Key_Pressed_ASCII =222 or Key_Pressed_ASCII=16) ; \ or Alt+\ or likaci mod shift { If ( A_TickCount - Time_Since_Last_Alt_Close < 200 ) ; prevention of accidentally closing too many windows Return Time_Since_Last_Alt_Close := A_TickCount Gui_wid := Window%RowText% Gosub, End_Process_Single Return } ; / key - close all instances of exe If (Key_Pressed_ASCII =47 or Key_Pressed_ASCII =191 ) ; / or Alt+/ { If ( A_TickCount - Time_Since_Last_Alt_Close < 200 ) ; prevention of accidentally closing too many windows Return Time_Since_Last_Alt_Close := A_TickCount Gui_wid := Window%RowText% Gosub, End_Process_All_Instances Return } Loop, %Window_Found_Count% { Selected_Row +=1 If Selected_Row > %Window_Found_Count% ; wrap around to start Selected_Row =1 LV_GetText(List_Title_Text, Selected_Row, 2) ; hidden number column ; Check for parent's title for typing first letter If Window_Parent%List_Title_Text% != WinGetTitle, List_Title_Text, % "ahk_id " Window_Parent%List_Title_Text% Else WinGetTitle, List_Title_Text, % "ahk_id " Window%List_Title_Text% StringUpper, List_Title_Text, List_Title_Text ; need to match against upper case when alt is held down List_Title_Text:=Asc(List_Title_Text) ; convert to ASCII key code If Key_Pressed_ASCII =%List_Title_Text% { LV_Modify(Selected_Row, "Focus Select Vis") Break } } Return ColumnClickSort(Col, Update="") ; Col = column clicked on, Update = 1 if true else blank (apply only, not change order) { Global If Update= { If ((Sort_By_Direction = "Sort") and (Col = Sort_By_Column)) ; opposite sort direction - unless choosing a new column { Sort_By_Direction =SortDesc Sort_Direction_Symbol =[-] } Else { Sort_By_Direction =Sort Sort_Direction_Symbol =[+] } } Loop, %Col_Title0% ; reset column titles to remove [+] or [-] suffix { Col_Title_temp := Col_Title%A_Index% LV_ModifyCol(A_Index,"", Col_Title_temp) } If (Col ="1" or Col ="2") ; Col 1 sorts using Col 2 (hidden) { LV_ModifyCol(2, Sort_By_Direction) LV_ModifyCol(1,"", Col_Title1 " " Sort_Direction_Symbol) } Else LV_ModifyCol(Col, Sort_By_Direction, Col_Title%Col% " " Sort_Direction_Symbol) If Update=1 Return Sort_By_Column := Col ; store Display_List_Shown =0 ; set to execute update of listview widths Gosub, Gui_Resize_and_Position Display_List_Shown =1 } ListView_Destroy: SetTimer, Check_Alt_Hotkey2_Up, Off SetTimer, SB_Update__CPU, Off SetTimer, SB_Update__ProcessCPU, Off If Single_Key_Show_Alt_Tab_Used =1 { Send, {%Alt_Hotkey2% up} Hotkey, *%Single_Key_Hide_Alt_Tab%, Off Single_Key_Show_Alt_Tab_Used = ; reset } Hotkeys_Toggle_Temp_Hotkeys("Off") ; (state = "On" or "Off") Gui, 1: Default If Alt_Esc != 1 ; i.e. not called from Alt_Esc Get__Selected_Row_and_RowText() Display_List_Shown =0 If Status%RowText% =Not Responding ; do not activate a Not Responding window (O/S unstable) Alt_Esc =1 If Alt_Esc != 1 ; i.e. not called from Alt_Esc { wid := Window%RowText% hw_popup := hw_popup%RowText% WinGet, wid_MinMax, MinMax, ahk_id %wid% If wid_MinMax =-1 ;minimised WinRestore, ahk_id %wid% If hw_popup WinActivate, ahk_id %hw_popup% Else WinActivate, ahk_id %wid% } Else If Alt_Esc =1 ; WM_ACTIVATE - clicked outside alt-tab gui 1 WinActivate, ahk_id %Active_ID% Gui, 1: Destroy ; destroy after switching to avoid re-activation of some windows LV_ColorChange() ; clear all highlighting OnTop_Found = ; reset Status_Found = ; reset Alt_Esc = ; reset Return Get_Window_Icon(wid, Use_Large_Icons_Current) ; (window id, whether to get large icons) { Local NR_temp, h_icon Window_Found_Count += 1 ; check status of window - if window is responding or "Not Responding" NR_temp =0 ; init h_icon = Responding := DllCall("SendMessageTimeout", "UInt", wid, "UInt", 0x0, "Int", 0, "Int", 0, "UInt", 0x2, "UInt", 150, "UInt *", NR_temp) ; 150 = timeout in millisecs If (Responding) { ; WM_GETICON values - ICON_SMALL =0, ICON_BIG =1, ICON_SMALL2 =2 If Use_Large_Icons_Current =1 { SendMessage, 0x7F, 1, 0,, ahk_id %wid% h_icon := ErrorLevel } If ( ! h_icon ) { SendMessage, 0x7F, 2, 0,, ahk_id %wid% h_icon := ErrorLevel If ( ! h_icon ) { SendMessage, 0x7F, 0, 0,, ahk_id %wid% h_icon := ErrorLevel If ( ! h_icon ) { If Use_Large_Icons_Current =1 h_icon := DllCall( "GetClassLong", "uint", wid, "int", -14 ) ; GCL_HICON is -14 If ( ! h_icon ) { h_icon := DllCall( "GetClassLong", "uint", wid, "int", -34 ) ; GCL_HICONSM is -34 If ( ! h_icon ) h_icon := DllCall( "LoadIcon", "uint", 0, "uint", 32512 ) ; IDI_APPLICATION is 32512 } } } } } If ! ( h_icon = "" or h_icon = "FAIL") ; Add the HICON directly to the icon list Gui_Icon_Number := DllCall("ImageList_ReplaceIcon", UInt, ImageListID1, Int, -1, UInt, h_icon) Else ; use a generic icon Gui_Icon_Number := IL_Add(ImageListID1, "shell32.dll" , 3) } 2GuiClose: 2GuiEscape: Gui, 2: Destroy Gui, 1: Default Return 3GuiClose: 3GuiEscape: Gui, 3: Destroy Gui, 1: Default Return IniFile_Data(Read_or_Write) { Global IniFile_Read_or_Write := Read_or_Write ; store ; Hotkeys IniFile("Alt_Hotkey", "Hotkeys", "!") IniFile("Tab_Hotkey", "Hotkeys", "Tab") IniFile("Shift_Tab_Hotkey", "Hotkeys", "+Tab") IniFile("Esc_Hotkey", "Hotkeys", "Esc") IniFile("Single_Key_Show_Alt_Tab", "Hotkeys", "") IniFile("Single_Key_Hide_Alt_Tab", "Hotkeys", "Enter") ; Sort_Order IniFile("Sort_By_Column", "Sort_Order", "2") ; initial column to sort (2 is a hidden column) IniFile("Sort_By_Direction", "Sort_Order", "Sort") ; initial sort direction IniFile("Sort_Direction_Symbol", "Sort_Order", "[+]") ; initial sort direction ; Groups + Group_Hotkey - remember lists of windows IniFile("Group_List", "Groups", "Settings|ALL") If ! (Global_Include_Edit or Global_Exclude_Edit) IniFile("Global_Include", "Groups", "") IniFile("Global_Include", "Groups", "") IniFile("Group_Active", "Groups", "ALL") Loop, Parse, Group_List,| { IniFile(A_LoopField, "Groups", "") IniFile(A_LoopField . "_Group_Hotkey","Groups", "") If %A_LoopField%_Group_Hotkey { Hotkey_temp := A_LoopField . "_Group_Hotkey" Hotkey, % %Hotkey_temp%, Group_Hotkey, On } } } Return IniFile(Var, Section, Default="") { Global If IniFile_Read_or_Write =Read { IniRead, %Var%, Alt_Tab_Settings.ini, %Section%, %Var%, %Default% If %Var% =ERROR %Var% = ; set to blank value instead of "error" } ;Else If IniFile_Read_or_Write =Write ; IniWrite, % %Var%, Alt_Tab_Settings.ini, %Section%, %Var% } ;============================================================================================================================ Replace_Modifier_Symbol( Variable_Name , New_Variable_Name ) { ; replace 1st modifier symbol in Alt_Hotkey,etc with its equivalent text (for hotkey up event compatability) Global %New_Variable_Name% :=%Variable_Name% StringReplace, %New_Variable_Name%, %New_Variable_Name%,#,LWin StringReplace, %New_Variable_Name%, %New_Variable_Name%,!,Alt StringReplace, %New_Variable_Name%, %New_Variable_Name%,^,Control StringReplace, %New_Variable_Name%, %New_Variable_Name%,+,Shift StringReplace, %New_Variable_Name%, %New_Variable_Name%,%A_Space%&%A_Space%, ; remove & for hotkeys like XButton1 } ListView_Resize_Vertically(Gui_ID) ; Automatically resize listview vertically { Global Window_Found_Count, lv_h_win_2000_adj SendMessage, 0x1000+31, 0, 0, SysListView321, ahk_id %Gui_ID% ; LVM_GETHEADER WinGetPos,,,, lv_header_h, ahk_id %ErrorLevel% VarSetCapacity( rect, 16, 0 ) SendMessage, 0x1000+14, 0, &rect, SysListView321, ahk_id %Gui_ID% ; LVM_GETITEMRECT ; LVIR_BOUNDS y1 := 0 y2 := 0 Loop, 4 { y1 += *( &rect + 3 + A_Index ) y2 += *( &rect + 11 + A_Index ) } lv_row_h := y2 - y1 lv_h := 4 + lv_header_h + ( lv_row_h * Window_Found_Count ) + lv_h_win_2000_adj GuiControl, Move, SysListView321, h%lv_h% } GetCPA_file_name( p_hw_target ) ; retrives Control Panel applet icon { WinGet, pid_target, PID, ahk_id %p_hw_target% hp_target := DllCall( "OpenProcess", "uint", 0x18, "int", false, "uint", pid_target ) hm_kernel32 := DllCall( "GetModuleHandle", "str", "kernel32.dll" ) pGetCommandLineA := DllCall( "GetProcAddress", "uint", hm_kernel32, "str", "GetCommandLineA" ) buffer_size = 6 VarSetCapacity( buffer, buffer_size ) DllCall( "ReadProcessMemory", "uint", hp_target, "uint", pGetCommandLineA, "uint", &buffer, "uint", buffer_size, "uint", 0 ) loop, 4 ppCommandLine += ( ( *( &buffer+A_Index ) ) << ( 8*( A_Index-1 ) ) ) buffer_size = 4 VarSetCapacity( buffer, buffer_size, 0 ) DllCall( "ReadProcessMemory", "uint", hp_target, "uint", ppCommandLine, "uint", &buffer, "uint", buffer_size, "uint", 0 ) loop, 4 pCommandLine += ( ( *( &buffer+A_Index-1 ) ) << ( 8*( A_Index-1 ) ) ) buffer_size = 260 VarSetCapacity( buffer, buffer_size, 1 ) DllCall( "ReadProcessMemory", "uint", hp_target, "uint", pCommandLine, "uint", &buffer, "uint", buffer_size, "uint", 0 ) DllCall( "CloseHandle", "uint", hp_target ) IfInString, buffer, desk.cpl ; exception to usual string format return, "C:\WINDOWS\system32\desk.cpl" ix_b := InStr( buffer, "Control_RunDLL" )+16 ix_e := InStr( buffer, ".cpl", false, ix_b )+3 StringMid, CPA_file_name, buffer, ix_b, ix_e-ix_b+1 if ( ix_e ) return, CPA_file_name else return, false } ;============================================================================================================================ WM_ACTIVATE(wParam) { Global If ( wParam =0 and A_Gui =1 and Display_List_Shown =1) ; i.e. don't trigger when submitting gui { Alt_Esc =1 Gosub, Alt_Esc ; hides alt-tab gui } } OnExit_Script_Closing: IniFile_Data("Write") Gui_Un_Dock_Windows_All_No_Alt_Esc = 1 Gosub, Gui_Un_Dock_Windows_All ExitApp Return ;============================================================================================================================ ; Listview color highlighting functions ;============================================================================================================================ LV_ColorInitiate() ; initiate listview color change procedure { global ; MUST include HWNDhw_LV_ColorChange when creating listview (Gui, Add, ListView, ... HWNDhw_LV_ColorChange) VarSetCapacity(LvItem, 36, 0) OnMessage( 0x4E, "WM_NOTIFY" ) } LV_ColorChange(Index="", TextColor="", BackColor="") ; change specific line's color or reset all lines { global If Index = Loop, %Window_Found_Count% ; or use another count if listview not visible LV_ColorChange(A_Index) Else { Line_Color_%Index%_Text := TextColor Line_Color_%Index%_Back := BackColor WinSet, Redraw,, ahk_id %hw_LV_ColorChange% } } WM_NOTIFY( p_w, p_l, p_m ) { local draw_stage, Current_Line, Index, IsSelected=0 Critical if ( DecodeInteger( "uint4", p_l, 0 ) = hw_LV_ColorChange ) { ; NMHDR->hwndFrom if ( DecodeInteger( "int4", p_l, 8 ) = -12 ) { ; NMHDR->code ; NM_CUSTOMDRAW draw_stage := DecodeInteger( "uint4", p_l, 12 ) ; NMCUSTOMDRAW->dwDrawStage Current_Line := DecodeInteger( "uint4", p_l, 36 )+1 ; NMCUSTOMDRAW->dwItemSpec if ( draw_stage = 1 ) ; CDDS_PREPAINT return, 0x20 ; CDRF_NOTIFYITEMDRAW else if ( draw_stage = 0x10000|1 ) { ; CDDS_ITEMPREPAINT If ( DllCall("GetFocus") = hw_LV_ColorChange ) { ; Control has Keyboard Focus? SendMessage, 4140, Current_Line-1, 2, , ahk_id %hw_LV_ColorChange% ; LVM_GETITEMSTATE IsSelected := ErrorLevel If ( IsSelected = 2 ) { ; LVIS_SELECTED ; custom selected color highlighting EncodeInteger( Listview_Colour_Selected_Text, 4, p_l, 48 ) ; NMCUSTOMDRAW->clrText ; foreground EncodeInteger( Listview_Colour_Selected_Back, 4, p_l, 52 ) ; NMCUSTOMDRAW->clrTextBk ; background EncodeInteger(0x0, 4, &LvItem, 12) ; LVITEM->state EncodeInteger(0x2, 4, &LvItem, 16) ; LVITEM->stateMask ; LVIS_SELECTED SendMessage, 4139, Current_Line-1, &LvItem, , ahk_id %hw_LV_ColorChange% ; Disable Highlighting ; We want item post-paint notifications Return, 0x00000010 ; CDRF_NOTIFYPOSTPAINT } ; change the 3rd parameter in the line below if the line number isn't in the 2nd column! LV_GetText(Index, Current_Line, 2) If (Line_Color_%Index%_Text != "") { EncodeInteger( Line_Color_%Index%_Text, 4, p_l, 48 ) ; NMLVCUSTOMDRAW->clrText ; foreground EncodeInteger( Line_Color_%Index%_Back, 4, p_l, 52 ) ; NMLVCUSTOMDRAW->clrTextBk ; background } } } else if ( draw_stage = 0x10000|2 ) ; CDDS_ITEMPOSTPAINT If ( IsSelected ) { EncodeInteger(0x02, 4, &LvItem, 12) ; LVITEM->state EncodeInteger(0x02, 4, &LvItem, 16) ; LVITEM->stateMask ; LVIS_SELECTED SendMessage, 4139, Current_Line-1, &LvItem, , ahk_id %hw_LV_ColorChange% ; LVM_SETITEMSTATE } } } } ;============================================================================================================================ ; MISC ;============================================================================================================================ Decimal_to_Hex(var) { SetFormat, integer, hex var += 0 SetFormat, integer, d return var } DecodeInteger( p_type, p_address, p_offset, p_hex=true ) { old_FormatInteger := A_FormatInteger ifEqual, p_hex, 1, SetFormat, Integer, hex else, SetFormat, Integer, dec StringRight, size, p_type, 1 loop, %size% value += *( ( p_address+p_offset )+( A_Index-1 ) ) << ( 8*( A_Index-1 ) ) if ( size <= 4 and InStr( p_type, "u" ) != 1 and *( p_address+p_offset+( size-1 ) ) & 0x80 ) value := -( ( ~value+1 ) & ( ( 2**( 8*size ) )-1 ) ) SetFormat, Integer, %old_FormatInteger% return, value } EncodeInteger( p_value, p_size, p_address, p_offset ) { loop, %p_size% DllCall( "RtlFillMemory", "uint", p_address+p_offset+A_Index-1, "uint", 1, "uchar", p_value >> ( 8*( A_Index-1 ) ) ) } RGBtoBGR(oldValue) { return (oldValue & 0x00ff00) + ((oldValue & 0xff0000) >> 16) + ((oldValue & 0x0000ff) << 16) } GetProcessTimes(pid) ; Individual CPU Load of the process with pid { Static oldKrnlTime, oldUserTime Static newKrnlTime, newUserTime Static PreviousPID oldKrnlTime := newKrnlTime oldUserTime := newUserTime hProc := DllCall("OpenProcess", "Uint", 0x400, "int", 0, "Uint", pid) DllCall("GetProcessTimes", "Uint", hProc, "int64P", CreationTime, "int64P", ExitTime, "int64P", newKrnlTime, "int64P", newUserTime) DllCall("CloseHandle", "Uint", hProc) If (PreviousPID != pid) { PreviousPID := pid Return 0 +0.0 } Return (newKrnlTime-oldKrnlTime + newUserTime-oldUserTime)/10000000 * 100 ; 1sec: 10**7 } GetSystemTimes() ; Total CPU Load { Static oldIdleTime, oldKrnlTime, oldUserTime Static newIdleTime, newKrnlTime, newUserTime oldIdleTime := newIdleTime oldKrnlTime := newKrnlTime oldUserTime := newUserTime DllCall("GetSystemTimes", "int64P", newIdleTime, "int64P", newKrnlTime, "int64P", newUserTime) Return (1 - (newIdleTime-oldIdleTime)/(newKrnlTime-oldKrnlTime + newUserTime-oldUserTime)) * 100 } ;============================================================================================================================ Delete_Ini_File_Settings: MsgBox, 1, ALT-TAB REPLACEMENT, Delete Settings (.ini) and load defaults? IfMsgbox, Cancel Return FileDelete, Alt_Tab_Settings.ini IniFile_Data("Read") ; load defaults Return HELP_and_LATEST_VERSION_CHANGES: Gosub, Alt_Esc ; hides alt-tab gui Gui, 99: Font, s9, Courier New Gui, 99: Default If A_ThisMenuItem =Help Gui, 99: Add, Edit, vGui_99_Edit ReadOnly, %HELP% If A_ThisMenuItem =Latest Changes Gui, 99: Add, Edit, vGui_99_Edit ReadOnly, %LATEST_VERSION_CHANGES% Gui, 99: Show,, %A_ThisMenuItem% WinWaitActive, %A_ThisMenuItem% ControlSend, Edit1, ^{Home}, %A_ThisMenuItem% Return 99GuiClose: 99GuiEscape: Gui, 99: Destroy Return