Skip to content

Instantly share code, notes, and snippets.

@ristomatti
Last active May 4, 2023 17:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ristomatti/f075020025cf870aaf8f73a930996f14 to your computer and use it in GitHub Desktop.
Save ristomatti/f075020025cf870aaf8f73a930996f14 to your computer and use it in GitHub Desktop.
AutoHotkey v1 script to mimic some aspects of tiling window managers in Windows
#Persistent
Menu, Tray, NoStandard
Menu, Tray, Add, Suspend, SuspendScript
Menu, Tray, Add, Exit, QuitScript
Menu, Tray, Tip, IonMove
Return
SuspendScript:
Suspend
Menu, Tray, ToggleCheck, Suspend
Return
QuitScript:
ExitApp
Return
#Left::ChangeFocus("left")
#Right::ChangeFocus("right")
#Up::ChangeFocus("up")
#Down::ChangeFocus("down")
#LButton::ClickControl("move")
#RButton::ClickControl("resize")
#MButton::ClickControl("fill")
; Param (dir) values: left, right, up, down
ChangeFocus(dir) {
; Set mouse move options
CoordMode, Mouse, Screen
SetMouseDelay, -1
; Get position of active window and the list of open applications
WinGetPos, actX, actY, actW, actH, A
WinGet,AppList,List
; Variables for keeping the best match window
closeCoord =
closeId =
; Loop through list of open applications
Loop, %AppList% {
; Find the properties of current application on the list
curId := AppList%A_Index%
WinGetPos, curX,curY,curW,curH,ahk_id %curId%
WinGetTitle, curT,ahk_id %curId%
WinGet, curMin, MinMax, ahk_id %curId%
WinGetClass, curC, ahk_id %curId%
; Skip windows that are on top of each other
if (curX = actX && curY = actY && curW = actW && curH = actW) {
continue
}
; If title of the window is not empty and the window is not minimized
if ((curT <> "") && (curMin <> -1) && (curC <> "Shell_TrayWnd") && (curC <> "Progman")) {
if (dir = "left") {
if ((curX < actX) && (actY < curY+curH) && (curY < actY+actH) ) {
if ((curX > closeCoord) || (closeCoord = "")) {
closeCoord = %curX%
closeId = %curId%
}
}
}
else if (dir = "right") {
if ((curX > actX) && (actY < curY+curH) && (curY < actY+actH) ) {
if ((curX < closeCoord) || (closeCoord = "")) {
closeCoord = %curX%
closeId = %curId%
}
}
}
else if (dir = "up") {
if ((curY < actY) && (actX < curX+curW) && (curX < actX+actW)) {
if ((curY > closeCoord) || (closeCoord = "") || (curX = actX && curW = actW)) {
closeCoord = %curY%
closeId = %curId%
; Prioritize windows that are the same width and on the same x-coordinates
if (curX = actX && curW = actW && curY != actY) {
break
}
}
}
}
else if (dir = "down") {
if ((curY > actY) && (actX < curX+curW) && (curX < actX+actW)) {
if ((curY < closeCoord) || (closeCoord = "") || (curX = actX && curW = actW)) {
closeCoord = %curY%
closeId = %curId%
; Prioritize windows that are the same width and on the same x-coordinates
if (curX = actX && curW = actW && curY != actY) {
break
}
}
}
}
}
}
; If found a window to change the focus
if (closeId <> "") {
; First move the mouse over the center of the title
WinGetPos, actX,actY,actW,actH,ahk_id %closeId%
MouseMove, actX+actW/2,actY+13,0,
; Then activate the window
WinActivate, ahk_id %closeId%
WinSet, Top,,ahk_id %closeId%
}
}
ClickControl(function) {
;GroupAdd, CCIgnore, ahk_class
CoordMode, Mouse, Screen
MouseGetPos, mouseX, mouseY, id
WinGetPos, winX, winY, winW, winH, ahk_id %id%
WinSet, Top,, ahk_id %id%
WinGet, minMax, MinMax, ahk_id %id%
WinGetTitle, winT, ahk_id %id%
WinGetClass, winC, ahk_id %id%
; If window maximized, restore it
if (minMax == 1) {
WinRestore, ahk_id %id%
return
}
dir =
; If top half clicked
if ((mouseY > winY) && (mouseY < (winY+(winH/4))))
dir = T
; If bottom half clicked
else if ((mouseY < (winY+winH)) && (mouseY > ((winY+winH)-(winH/4))))
dir = B
; If left side clicked
if ((mouseX > winX) && (mouseX < (winX+(winW/4))))
dir = %dir%L
; If right side clicked
else if ((mouseX < (winX+winW)) && (mouseX > ((winX+winW)-(winW/4))))
dir = %dir%R
; Return if center of window clicked
if (dir = "")
dir = C
clickedMon =
SysGet, monCount, MonitorCount
Loop, %monCount% {
SysGet, monWorkArea, MonitorWorkArea, %A_Index%
if ((mouseX > monWorkAreaLeft) && (mouseX < monWorkAreaRight))
clickedMon = %A_Index%
}
SysGet, monWorkArea, MonitorWorkArea, %clickedMon%
monWorkAreaWidth := monWorkAreaRight-monWorkAreaLeft
monWorkAreaHeigth := monWorkAreaBottom-monWorkAreaTop
if (function == "move") {
; Window movement
if (dir == "T")
WinMove, ahk_id %id%,,winX,monWorkAreaTop
if (dir == "B")
WinMove, ahk_id %id%,,winX,(monWorkAreaBottom-winH)
if (dir == "L")
WinMove, ahk_id %id%,,monWorkAreaLeft,winY
if (dir == "R")
WinMove, ahk_id %id%,,(monWorkAreaRight-winW),winY
if (dir == "TL")
WinMove, ahk_id %id%,,monWorkAreaLeft,monWorkAreaTop
if (dir == "TR")
WinMove, ahk_id %id%,,(monWorkAreaRight-winW),monWorkAreaTop
if (dir == "BL")
WinMove, ahk_id %id%,,monWorkAreaLeft,(monWorkAreaBottom-winH)
if (dir == "BR")
WinMove, ahk_id %id%,,(monWorkAreaRight-winW),(monWorkAreaBottom-winH)
; Center window
if (dir == "C") {
WinMove, ahk_id %id%,,((monWorkAreaLeft+(monWorkAreaWidth/2)) - (winW/2)),((monWorkAreaTop+(monWorkAreaHeigth/2)) - (winH/2))
}
}
if (function == "resize") {
; If resize task, store previous state
if (dir != "C") {
global prevX := winX
global prevY := winY
global prevW := winW
global prevH := winH
global prevId := id
}
; Window resizing
if (dir == "T")
AltWinMove(winC,id,winX,monWorkAreaTop,winW,(winH+winY-monWorkAreaTop))
if (dir == "B")
AltWinMove(winC,id,winX,winY,winW,(monWorkAreaBottom-winY))
if (dir == "L")
AltWinMove(winC,id,monWorkAreaLeft,winY,(winW+winX-monWorkAreaLeft),winH)
if (dir == "R")
AltWinMove(winC,id,winX,winY,(monWorkAreaRight-winX),winH)
if (dir == "TL")
AltWinMove(winC,id,monWorkAreaLeft,monWorkAreaTop,(winW+winX-monWorkAreaLeft),(winH+winY-monWorkAreaTop))
if (dir == "TR")
AltWinMove(winC,id,winX,monWorkAreaTop,(monWorkAreaRight-winX),(winH+winY-monWorkAreaTop))
if (dir == "BL")
AltWinMove(winC,id,monWorkAreaLeft,winY,(winW+winX-monWorkAreaLeft),(monWorkAreaBottom-winY))
if (dir == "BR")
AltWinMove(winC,id,winX,winY,(monWorkAreaRight-winX),(monWorkAreaBottom-winY))
; Restore previous state
if (dir == "C") {
newW := monWorkAreaWidth/2
newH := monWorkAreaHeigth/2
AltWinMove(winC,id,((monWorkAreaLeft+(monWorkAreaWidth/2))-(newW/2)),((monWorkAreaTop+(monWorkAreaHeigth/2)) - (newH/2)),newW,newH)
; if (prevId == id)
; WinMove, ahk_id %id%,,prevX,prevY,prevW,prevH
}
}
; If fill available space mode function
if (function == "fill") {
global firstClick, selectedId, selectedC
; If first click (select)
if (firstClick == true || firstClick == "") {
; Don't select windows with no class or title or Progman
if (winC == "" || winT == "" || winC == "Progman")
return
selectedId := id
WinGetClass, selectedC, ahk_id %selectedId%
firstClick := false
return
}
; If second click (fill space)
if (firstClick == false) {
; If clicked on existing window, resize to that size
if (winC != "Progman" && id != selectedId) {
AltWinMove(selectedC, selectedId, winX, winY, winW, winH)
WinActivate, ahk_id %selectedId%
firstClick := true
}
else {
; Initially nearest coordinates are the current monitor work are
nearestTop := monWorkAreaTop
nearestBottom := monWorkAreaBottom
nearestLeft := monWorkAreaLeft
nearestRight := monWorkAreaRight
WinGet, appList,List
Loop, %appList% {
curId := appList%A_Index%
WinGetPos, curLeft,curTop,curW,curH,ahk_id %curId%
WinGetTitle, curT,ahk_id %curId%
WinGet, curMin, MinMax, ahk_id %curId%
WinGetClass, curC, ahk_id %curId%
curRight := curLeft+curW
curBottom := curTop+curH
; Skip window if not on the clicked monitor, is Progman or is minimized
if (curC == "Progman" || curC == "Shell_TrayWnd")
continue
if (curMin != 0)
continue
if (!(curLeft >= monWorkAreaLeft && (curLeft+curW) <= monWorkAreaRight && curTop >= monWorkAreaTop && (curTop+curH) <= monWorkAreaBottom))
continue
if (curT == "" || curId == selectedId || curC = "TApplication")
continue
; Find nearest coordinates
if (curRight < mouseX && curBottom > mouseY) {
if (curRight > nearestLeft)
nearestLeft := curRight
}
if (curLeft > mouseX && curBottom > mouseY) {
if (curLeft < nearestRight) {
nearestRight := curLeft
}
}
if (curBottom < mouseY && curRight > mouseX) {
if (curBottom > nearestTop)
nearestTop := curBottom
}
if (curTop > mouseY && curLeft < mouseX && curRight > mouseX) {
if (curTop < nearestBottom)
nearestBottom := curTop
}
}
; If full screen available maximize instead of resize
if (nearestTop == monWorkAreaTop && nearestBottom == monWorkAreaBottom && nearestLeft == monWorkAreaLeft && nearestRight == monWorkAreaRight) {
WinMove, ahk_id %selectedId%,, nearestLeft, nearestTop
WinMaximize, ahk_id %selectedId%
}
else {
AltWinMove(selectedC, selectedId, nearestLeft, nearestTop, (nearestRight-nearestLeft), (nearestBottom-nearestTop))
WinActivate, ahk_id %selectedId%
}
}
firstClick := true
return
}
}
}
AltWinMove(c, id, x, y, w, h) {
WM_ENTERSIZEMOVE = 0x231
WM_EXITSIZEMOVE = 0x232
if (c == "PuTTY" || c == "Nutty") {
WinActivate, ahk_class "Program"
SendMessage, 0x231, , , , ahk_id %id%
WinMove, ahk_id %id%,, x, y, w, h
SendMessage, 0x232, , , , ahk_id %id%
}
else {
WinMove, ahk_id %id%,, x, y, w, h
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment