If application support tabs (for ex, Notepad++), it closes active tab instead whole application.
I found it handy for my daily routine.
This action if very common: everybody do it hundred times a day.
You don't need to look for a red close button by your eyes (no eye movement required), you don't need to drag mouse pointer to a specified small area.
Just double right click in any place of active window.
I also used a double click to task bar to close window groups.
But this feature rely highly on ImageSearch and it doesn't work properly where you are inside RDP-session for me and it also depends highly on your Window version.
If you want to try it, you need to create a folder "Additional_files" near a script and place png-files attached.
Then you can try double click by a group of tabs in taskbar and all windows should be closed if all is OK.
Code: Select all
#SingleInstance force
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
#NoTrayIcon
#If, !WinActive("ahk_class AutoHotkey") && !WinActive("ahk_exe winword.exe") && WinGetClassFunc(MouseGetPosFunc()) <> "TaskListThumbnailWnd"
~*RButton Up::
;~ OutputDebug, click_Main_
if (A_TimeSincePriorHotkey < 250 && A_PriorHotkey = A_ThisHotkey && IsFirstClick("") = true)
{
IsFirstClick(false)
WinGet, hw1, ID, A
WinGet, proc1, ProcessName, A
;~ OutputDebug, double click!!! %hw1% %proc1%
WinGetClass, classNN1, ahk_id %hw1%
if (classNN1 = "#32770")
{
;check for a "Properties"-dialog
WinGetActiveTitle, title1
if ((title1 ~= "(^Свойства: )|( Properties$)") > 0)
{
Send, {CtrlDown}{AltDown}{AltUp}{CtrlUp}
WinClose, ahk_id %hw1%
;do not execute code below (cause the windows has been already closed)
return
}
}
;some rules for certain known processes to handle their behaviour
;in more accurate and flexible way
if (proc1 = "explorer.exe")
{
;if double click has been made to task bar - close taskbar group
if (WinGetClassFunc(MouseGetPosFunc()) = "Shell_TrayWnd")
{
CoordMode, Mouse, Screen
MouseGetPos, x1, y1
CoordMode, Pixel, Screen
x2 := x1
y2 := y1
;we will search for a clos button relatively from mouse point coordinates
;by x: [-180 ; -80]
;by y: [-110 ; 0]
xMin := x2 - 280, xMax := x2 - 8, yMin := y2 - 210, yMax := y2 - 0
OutputDebug xmin: %xmin% xmax: %xmax% ymin: %ymin% ymax: %ymax%
;~ xmin = 0
;~ ymin = 0
;~ xmax = 1920
;~ ymax = 1080
OutputDebug A_OSVersion: %A_OSVersion%
;I use operator "contains" because there are two different
;Windows versions: "WIN_8" and "WIN_8.1"
if A_OSVersion contains WIN_8
ImageSearch, x1, y1, %xMin%, %yMin%, %xMax%, %yMax%, Additional_files\CloseTaskbarItemWin8.png
else if (A_OSVersion = "WIN_7")
{
;~ ImageSearch, x1, y1, %xMin%, %yMin%, %xMax%, %yMax%, Additional_files\CloseTaskbarItemWin7.png
ImageSearch, x1, y1, %xMin%, %yMin%, %xMax%, %yMax%, *10 TransFFFFFF Additional_files\CloseTaskbarItem_RuTitle_Win7.png
OutputDebug ErrorLevel 10: %ErrorLevel%
if (ErrorLevel <> 0)
{
;~ ImageSearch, x1, y1, %xMin%, %yMin%, %xMax%, %yMax%, Additional_files\CloseTaskbarItemWinServer.png
ImageSearch, x1, y1, %xMin%, %yMin%, %xMax%, %yMax%, *10 TransFFFFFF Additional_files\CloseTaskbarItem_EngTitle_WinServer.png
OutputDebug ErrorLevel 11: %ErrorLevel%
ImageSearch, x1, y1, %xMin%, %yMin%, %xMax%, %yMax%, Additional_files\CloseTaskbarItemWinServer.png
}
}
;~ OutputDebug ErrorLevel_ 1: %ErrorLevel%
if (ErrorLevel = 0)
{
Click, %x1%, %y1%
;move mouse to a previous position
Click, %x2%, %y2%, 0
OutputDebug ErrorLevel all: %ErrorLevel%
}
else
{
OutputDebug ErrorLevel 22: %ErrorLevel%
}
}
else
{
WinGetClass, classNN1, ahk_id %hw1%
WinGetActiveTitle, title1
if (classNN1 = "Progman" && title1 = "Program Manager")
{
;Win 8.1 desktop double click is detected
;or file properties (dir properties) window is detected
;Close context menu and sleep to hide context menu correctly
Send, {AltDown}{AltUp}
Sleep, 100
WinClose, ahk_id %hw1%
}
else
WinClose, ahk_id %hw1%
}
}
else if (proc1 = "DLLHost.exe")
{
;this is a "Средство просмотра фотографий Windows"
WinGetActiveTitle, title1
if title1 contains Средство просмотра фотографий Windows
{
;~ OutputDebug Alt Ф Ы
;keyboad hotkey doesn't work if English keyboard locale is used
SwitchLocale("Ru")
;Alt + Ф + Ы (main menu item "Файл" -> "вЫход")
Send, {AltDown}{vk41}{vk53}{AltUp}
;~ Send, {AltDown}фы{AltUp}
;~ OutputDebug alt f4
;sometimes Alt + F4 method produces glitches and waits and window hang
;~ Send, {AltDown}{F4}{AltUp}
;sometimes WinClose-method produces an exception: "COM surrogate exception"
;so I try to use Alt + F4
;~ Send, {AltDown}{AltUp}
;~ Sleep, 60
;~ WinClose, ahk_id %hw1%
}
else
{
OutputDebug winclose1
WinClose, ahk_id %hw1%
}
}
else if (proc1 = "kmplayer.exe")
{
if (classNN1 = "Winamp v1.x" || classNN1 = "Winamp PE")
Process, Close, %proc1%
else
{
Send, {CtrlDown}{AltDown}{AltUp}{CtrlUp}
WinClose, ahk_id %hw1%
}
}
else if (proc1 = "firefox.exe")
{
;native function works well (it closes current tab)
;but other cases (ex, dialog windows) must be handled here by myself
WinGetTitle, title1, ahk_id %hw1%
WinGetClass, classNN1, ahk_id %hw1%
;I don't see any reliable way to determine if the firefox's window is a source code window
if (classNN1 = "MozillaWindowClass")
{
if ((title1 ~= "Mozilla Firefox$") > 0)
{
;double click to web-page
;closing a tab is processed by firefox plugin (tab mix plus)
;press Tab button to hide context menu when empty page is opened
if (title1 ~= "Fast Dial - Mozilla Firefox")
Send, {Tab}
return
}
else if ((title1 != "i).iim - iMacros Editor$") > 0 )
{
;iMacros Code Editor window
WinClose, ahk_id %hw1%
}
else
{
;else => TOR Browser
;closing tab without additional addons installed
Send, {CtrlDown}{F4}{CtrlUp}
}
}
else
{
WinClose, ahk_id %hw1%
}
}
else if (proc1 = "gdt_proj.exe")
{
;Data Module (ORTEMS)
;
;standard way using WinClose doesn't work for Data Module's windows
;some strange errors occurs because of MDI interface is used
;
;
;Ctrl + F4 must close these windows
;but it works bad for some kinds of windows
;sometimes it doesn't work at all
;so disable this hotkey for its windows
;~ Send, {CtrlDown}{F4}{CtrlUp}
;~ WinGet, hw1, PID, ahk_id %hw1%
;~ Process, Close, %hw1%
;~ OutputDebug PID=ErrorLevel: %hw1% = %ErrorLevel%
}
else if (proc1 = "skype.exe")
{
;if double click was performed with Ctrl button pressed
if (GetKeyState("Ctrl", "P"))
{
;kill Skype
Process, Close, skype.exe
}
else
{
;close the window
Send, {AltDown}{AltUp}
PostMessage, 0x112, 0xF060,,, ahk_id %hw1%
}
}
else if (proc1 = "SciTE.exe")
{
WinGetClass, classNN1, ahk_id %hw1%
if (classNN1 = "SciTEWindow")
{
;double click on main window has been detected
;close current tab
Send, {AltDown}{AltUp}
Sleep, 30
SendMessage, 0x111, 105, 0,, ahk_id %hw1%
}
else
WinClose, ahk_id %hw1%
}
else if (proc1 = "perfmon.exe")
{
OutputDebug 1pf
{
Send, {CtrlDown}{AltDown}{AltUp}{CtrlUp}
Send, {AltDown}{F4}{AltUp}
}
}
else if (proc1 = "notepad++.exe")
{
WinGetClass, classNN1, ahk_id %hw1%
;~ MouseGetPos, x1, y1, wi, ctHover, 2sss
;~ MsgBox, %x1% %y1% %wi% cth %ctHover% cl %classNN1%
;~ OutputDebug notepda++ catched
if (classNN1 = "Notepad++")
{
if (GetKeyState("Ctrl", "P"))
{
;close tab without saving
;~ OutputDebug Ctrl + RButton
Send, {AltDown}{AltUp}
;~ Sleep, 30
;close a current tab
;PostMessage must be there
;when SendMessage was used next commands weren't executed
;- waited for SendMessage result?)
PostMessage, 0x111, 41003,,, ahk_id %hw1%
;close window with confirmation about saving
WinWaitActive, ahk_class #32770, , 1
if (ErrorLevel = 1)
return
;Press No
Send, {Tab}{Enter}
}
else
{
;~ OutputDebug normal
Send, {AltDown}{AltUp}
;~ Sleep, 30
;close a current tab
PostMessage, 0x111, 41003,,, ahk_id %hw1%
}
}
else
WinClose, ahk_id %hw1%
}
else if (proc1 = "notepad.exe")
{
;if Ctrl pressed during right-double click
;then close notepad without saving
if (GetKeyState("Ctrl", "P"))
{
;~ OutputDebug pressed!
;pros of this method of closing is a faster speed
;there is flashing confirmation dialog about saving a file
WinGet, hw1, PID, ahk_id %hw1%
Process, Close, %hw1%
;~ OutputDebug PID=ErrorLevel: %hw1% = %ErrorLevel%
}
else
{
;~ OutputDebug no
;I send Alt keystroke to hide context menu unneeded
;this is more safe way to hide context menu because
;escape button may close some types of windows
;in certain circumstances instead of Alt button
Send, {AltDown}{AltUp}
Sleep, 10
WinClose, ahk_id %hw1%
}
}
else if (proc1 = "devenv.exe")
{
WinGetPos, , , x1, y1, ahk_id %hw1%
;~ OutputDebug x1: %x1% y1: %y1% x2: %x2% y2: %y2%
;close dialog boxes
if (classNN1 = "#32770")
{
;check for a "Properties"-dialog
WinClose, ahk_id %hw1%
}
else if (x1 >= 1900 || y1 >= 1030)
{
;if main window opened (detection by window width or height):
;close opened menu (it block input) and close a tab
Send, {AltDown}{ShiftDown}{ShiftUp}{AltUp}
Send, {CtrlDown}{F4}{CtrlUp}
}
else
{
;if any other windows opened: just close it
WinClose, ahk_id %hw1%
}
}
else if (proc1 = "ssms.exe" || proc1 = "sqlwb.exe")
{
;sqlwb.exe = ssms.exe for 2005 version
WinGetClass, classNN1, ahk_id %hw1%
;~ OutputDebug ssms!
;#32770 - is a dialog box - it must be always closed
if (classNN1 = "#32770")
{
;this is usually a dialog box with closing a nonsaved tab
WinClose, ahk_id %hw1%
}
else
{
WinGetActiveTitle, title1
sqlVer := GetSqlServerVersionV2()
lang1 := GetSqlServerLang(title1)
if (sqlVer = 2005)
{
OutputDebug SQL 2005
CoordMode, Mouse, Screen
MouseGetPos, x1, y1
;~ OutputDebug y1: %y1%
if (GetKeyState("Control", "D") || y1 = 0)
{
Send, {CtrlDown}{AltDown}{AltUp}{CtrlUp}
Send, ^{F4}
Sleep, 50
if WinActive("ahk_exe sqlwb.exe ahk_class #32770")
{
Send, {Right}
Sleep, 60
Send, {Enter}
}
}
else
{
;~ Send, {CtrlDown}{AltDown}{AltUp}{CtrlUp}
Send, ^{F4}
}
}
else if (sqlVer = 2008)
{
OutputDebug SQL 2008
;Close current tab without saving using a File's menu item
;this is more reliable way than sending standard ^{F4} shotcut
;the tab will be closed without saving holding Ctrl button
;during double Right click, or double Right clicking to a certain
;place on the screen - at the zero pixel (the upper pixel on the screen)
CoordMode, Mouse, Screen
MouseGetPos, x1, y1
;~ OutputDebug y1: %y1%
if (GetKeyState("Control", "D") || y1 = 0)
{
;remove context menu using Ctrl + Shift (it might block next hotkey (Ctrl + F4))
;this send command must be here, after GetKeyState has been checked
Send, {CtrlDown}{AltDown}{AltUp}{CtrlUp}
Send, ^{F4}
;that sleep command is vital for WinActive function in this script
Sleep, 50
if WinActive("ahk_exe ssms.exe ahk_class #32770")
{
Send, {Right}
Sleep, 60
Send, {Enter}
}
}
else
{
Send, {CtrlDown}{AltDown}{AltUp}{CtrlUp}
Send, ^{F4}
}
}
else if (sqlVer = 2012)
{
OutputDebug SQL 2012
;during double Right click, or double Right clicking to a certain
;place on the screen - at the zero pixel (the upper pixel on the screen)
CoordMode, Mouse, Screen
MouseGetPos, x1, y1
;~ OutputDebug y1: %y1%
if (GetKeyState("Control", "D") || y1 = 0)
{
;remove context menu using AppsKey (it might block next hotkey (Ctrl + F4))
;this send command must be here, after GetKeyState has been checked
Send, {AppsKey}^{F4}
;that sleep command is vital for WinActive function in this script
Sleep, 50
if WinActive("ahk_exe ssms.exe ahk_class #32770")
{
Send, {Right}
Sleep, 60
Send, {Enter}
}
}
else
{
Send, {AppsKey}
Send, ^{F4}
}
}
else
{
OutputDebug SQL window for close
WinClose, ahk_id %hw1%
}
}
}
else if (proc1 = "mstsc.exe")
{
WinGetClass, classNN1, ahk_id %hw1%
if (classNN1 = "#32770")
WinClose, ahk_id %hw1%
else
;propagate a click to RDP window instead of closing it
Send, {A_ThisHotkey}
}
else if proc1 contains vmware,vmplayer
{
;get classname of the control a mouse is hovering on
MouseGetPos, , , , ctHover
if ctHover contains MKSEmbedded
{
;propagate a click to a window instead of closing it
Send, {A_ThisHotkey}
}
else
{
WinClose, ahk_id %hw1%
Sleep, 100
Send, {Enter}
}
}
else if proc1 in taskmgr.exe,ortplan.exe,mediainfo.exe,everything.exe,picpick.exe
{
Send, {CtrlDown}{AltDown}{AltUp}{CtrlUp}
Sleep, 30
WinClose, ahk_id %hw1%
}
else if (proc1 = "iexplore.exe")
{
;closing by double click give a huge context menu after closing
;to prevent showing this menu at all I kill this process
WinGet, hw1, PID, ahk_id %hw1%
Process, Close, %hw1%
}
else if proc1 in AU3_Spy.exe,SBIECTRL.exe,picpick.exe
{
Send, {AltDown}{AltUp}
WinClose, ahk_id %hw1%
}
; windows that aren't react on WinClose, but PostMessage
else if proc1 in excel.exe,outlook.exe
{
WinGetClass, classNN1, ahk_id %hw1%
;~ OutputDebug classNN1: %classNN1%
if ((classNN1 ~= "i)dialog|bosa_sdm_XL9") > 0)
{
;here I handle excel-dialogs (like a properties of diagram)
WinClose, ahk_id %hw1%
}
else
{
;here I handle main windows and other usual windows
;because winword, excel and outlook aren't closed by WM_CLOSE
PostMessage, 0x112, 0xF060,,, ahk_id %hw1%
}
}
else if (proc1 = "teamviewer.exe")
{
;if teamviewer's main window is opened - do not close it by double RButton
;propagate these click to it
;~ OutputDebug teamviewer found!
WinGetClass, classNN1, ahk_id %hw1%
if (classNN1 = "TV_CClientWindowClass")
{
;do nothing
OutputDebug do nothing
}
else
WinClose, ahk_id %hw1%
}
else if (proc1 = "HxD.exe")
{
;if HexViewer's main window is opened - press Ctrl + F4 to close current tab
WinGetClass, classNN1, ahk_id %hw1%
if (classNN1 = "TFormMain.UnicodeClass")
{
if (CurrentWindowTitle() = "HxD")
{
;if there is no any tabs opened - close main window
WinClose, ahk_id %hw1%
}
else
{
;if tab opened, close context menu and press Ctrl + F4 to close the tab
Send, {AltDown}{AltUp}
Send, {CtrlDown}{F4}{CtrlUp}
}
}
else
{
;close all other windows of this process (Dialog windows, etc)
WinClose, ahk_id %hw1%
}
} ;Beyond Compare
else if (proc1 = "BCompare.exe")
{
WinGetTitle, title1, ahk_id %hw1%
;if title end with this literal, assume that it is a main window
;so we want to close a tab in it
if ((title1 ~= " - Beyond Compare$") > 0)
{
;~ OutputDebug fnd
Send, {CtrlDown}{AltDown}{AltUp}{CtrlUp}
;Ctrl + F4 to close a current tab
;~ Send, {CtrlDown}{F4}{CtrlUp}
Send, {CtrlDown}{vk57}{CtrlUp}
}
else
{
;~ OutputDebug close!
WinClose, ahk_id %hw1%
}
}
else if (proc1 = "STDUViewerApp.exe")
{
WinGetClass, classNN1, ahk_id %hw1%
if (classNN1 = "STDUViewerMainWindowClass")
{
;close context menu, then close a tab
Send, {CtrlDown}{AltDown}{AltUp}{CtrlUp}
Send, {CtrlDown}{F4}{CtrlUp}
}
else
{
;for other STDUViewer's windows types
WinClose, ahk_id %hw1%
}
}
else if (proc1 = "bdeadmin.exe")
{
;close context menu, then close the window using Alt + F4
Send, {AltDown}{F4}{AltUp}
}
else if (proc1 = "hh.exe")
{
;hh.exe is a chm-help file (like old AutoHotkey help)
;close the window using Alt + F4
Send, {AltDown}{F4}{AltUp}
}
else if (proc1 = "mmc.exe")
{
;mmc.exe is a gpedit.msc (оснастка, редактор групповой политики)
;close the window using Alt + F4
Send, {AltDown}{F4}{AltUp}
}
else if (proc1 = "WebMoney.exe")
{
;winclose-method crashes webmoney keeper application, so lets try another way to close window
;postmessage-method doesn't work at all
Send, {AltDown}{AltUp}
Send, {AltDown}{F4}{AltUp}
}
else if (proc1 = "communicator.exe")
{
;communicator.exe is a Microsoft Lync
WinGetClass, classNN1, ahk_id %hw1%
if (classNN1 = "CommunicatorMainWindowClass")
{
Send, {AltDown}{F4}{AltUp}
}
else
{
;for other Lync's windows types
WinClose, ahk_id %hw1%
}
}
else if (proc1 = "Launchy.exe" && classNN1 = "QTool")
{
OutputDebug launchy
}
else
{
;~ OutputDebug some app
Send, {CtrlDown}{AltDown}{AltUp}{CtrlUp}
WinClose, ahk_id %hw1%
}
;there are three common ways to close a window (if first one doesn't work try another one):
;~ WinClose, ahk_id %hw1%
;~ PostMessage, 0x112, 0xF060,,, ahk_id %hw1%
;~ WinKill, ahk_id %hw1%
}
else
{
;~ OutputDebug 1
;~ OutputDebug, Click
IsFirstClick(true)
}
return
#If
;Double RButton at AutoHotkey's main window (Key history) => closes it
;AutoHotkey's main window doesn't work properly while handling "RButton Up"
;when the window is a current script's window
;so here is a special case to handle this issue
#If, i1 := WinActive("ahk_class AutoHotkey") || WinActive("ahk_exe qbittorrent.exe") || WinActive("ahk_class rctrl_renwnd32 ahk_exe OUTLOOK.EXE")
~RButton Up::
;~ OutputDebug rclick1
if (A_TimeSincePriorHotkey < 250 && A_PriorHotkey = A_ThisHotkey && IsFirstClick("") = true)
{
IsFirstClick(false)
;restore previous mouse position
x1++
MouseMove, x1, y1
;minimize the window (but not close/terminate it)
if (i1 > 0)
PostMessage, 0x112, 0xF060,,, A
}
else
{
IsFirstClick(true)
;here is a dirty hack to force next RButton click to be able detected:
;move mouse left at one pixel so the next RButton occurs not at the same point
;and will be detected by this hotkey
MouseGetPos, x1, y1
x1--
MouseMove, x1, y1
}
return
#If
;function returns class of a window by its HWND
WinGetClassFunc(hw8)
{
local classNN9
WinGetClass, classNN9, ahk_id %hw8%
return classNN9
}
;function returns current x/y mouse pointer position
MouseGetPosFunc()
{
global
local x9, y9, hw9
;$OBFUSCATOR: $DEFLOSVARS: x9, y9, hw9
MouseGetPos, x9, y9, hw9, , 1
return hw9
}
;this function is made to prevent triple right mouse click behave like quadruple click
IsFirstClick(isSec)
{
global
;the static varibale is used like a flag to differ single click from double click
static isSecond
if (isSec = "")
return isSecond
else
isSecond := isSec
}
;Change current keyboard language layout
;if parameter locale is empty - change to opposite,
;if it is "Ru" then switch to Russian,
;otherwise - English
SwitchLocale(locale_arg)
{
global
local Ru1, En1, btrp1, Locale1, Locale2
;$OBFUSCATOR: $DEFLOSVARS: Ru1, En1, btrp1, Locale1, Locale2
;0x50 is a WM_INPUTLANGCHANGEREQUEST message
;PostMessage or SendMessage?
if (locale_arg = "")
SendMessage, 0x50, 4, 0, , A
else
{
SetFormat, IntegerFast, H
VarSetCapacity(List1, A_PtrSize*2)
DllCall("GetKeyboardLayoutList", Int, 2, Ptr, &List1)
Locale1 := NumGet(List1)
btrp1 := SubStr(Locale2 := NumGet(List1, A_PtrSize), -3) = 0409
En1 := btrp1 ? Locale2 : Locale1
Ru1 := btrp1 ? Locale1 : Locale2
SendMessage, 0x50,, locale_arg = "Ru" ? Ru1 : En1,, A
}
}
;returns SQL Server Management Studio version
GetSqlServerVersionV2()
{
WinGetClass, classNN2, A
;~ OutputDebug classNN2: %classNN2%
if (classNN2 = "wndclass_desked_gsk")
{
WinGet, tx1, ProcessName, A
;~ OutputDebug tx1: %tx1%
if (tx1 = "sqlwb.exe")
{
return 2005
}
else
{
return 2008
}
}
;should start with "HwndWrapper..."
else if (InStr(classNN2, "HwndWrapper[DefaultDomain;;") = 1)
{
return 2012
}
else
{
;~ OutputDebug unknown classNN2: %classNN2%
return 0
}
}
;This function gets SQL Server language depending on it's main window title
GetSqlServerLang(ti1)
{
if (InStr(ti1, "Среда") > 0)
{
return "Ru"
}
else
return "En"
}
;Gets title of active window
CurrentWindowTitle()
{
WinGetActiveTitle, title8
return title8
}