|
/** |
|
* Advanced Window Snap (Extended |
|
* Snaps the Active Window to one of nine different window positions. |
|
* |
|
* @Editing author Jarrett Urech |
|
* @Original author Andrew Moore <[email protected]> |
|
* @version 2.1 |
|
* |
|
**/ |
|
|
|
/** |
|
* SnapActiveWindow resizes and moves (snaps) the active window to a given position. |
|
* @param {string} winPlaceVertical The vertical placement of the active window. |
|
* Expecting "bottom" or "middle", otherwise assumes |
|
* "top" placement. |
|
* @param {string} winPlaceHorizontal The horizontal placement of the active window. |
|
* Expecting "left" or "right", otherwise assumes |
|
* window should span the "full" width of the monitor. |
|
* @param {string} winSizeHeight The height of the active window in relation to |
|
* the active monitor's height. Expecting "half" size, |
|
* otherwise will resize window to a "third". |
|
*/ |
|
|
|
#NoEnv |
|
#NoTrayIcon |
|
#SingleInstance force |
|
#MaxThreads 1 |
|
|
|
|
|
SnapActiveWindow(winPlaceVertical, winPlaceHorizontal, winSizeHeight, activeMon := 0) { |
|
WinGet activeWin, ID, A |
|
SysGet, MonitorCount, MonitorCount |
|
|
|
if (!activeMon) { |
|
activeMon := GetMonitorIndexFromWindow(activeWin) |
|
} else if (activeMon > MonitorCount) { |
|
activeMon := 1 |
|
} |
|
|
|
SysGet, MonitorWorkArea, MonitorWorkArea, %activeMon% |
|
|
|
if (winSizeHeight == "half") { |
|
height := (MonitorWorkAreaBottom - MonitorWorkAreaTop)/2 |
|
} else if (winSizeHeight == "third") { |
|
height := (MonitorWorkAreaBottom - MonitorWorkAreaTop)/3 |
|
} else { |
|
height := (MonitorWorkAreaBottom - MonitorWorkAreaTop) |
|
} |
|
|
|
if (winPlaceHorizontal == "left") { |
|
posX := MonitorWorkAreaLeft |
|
width := (MonitorWorkAreaRight - MonitorWorkAreaLeft)/2 |
|
} else if (winPlaceHorizontal == "right") { |
|
posX := MonitorWorkAreaLeft + (MonitorWorkAreaRight - MonitorWorkAreaLeft)/2 |
|
width := (MonitorWorkAreaRight - MonitorWorkAreaLeft)/2 |
|
} else { |
|
posX := MonitorWorkAreaLeft |
|
width := MonitorWorkAreaRight - MonitorWorkAreaLeft |
|
} |
|
|
|
if (winPlaceVertical == "bottom") { |
|
posY := MonitorWorkAreaBottom - height |
|
} else if (winPlaceVertical == "middle") { |
|
posY := MonitorWorkAreaTop + height |
|
} else { |
|
posY := MonitorWorkAreaTop |
|
} |
|
|
|
; Rounding |
|
posX := floor(posX) |
|
posY := floor(posY) |
|
width := floor(width) |
|
height := floor(height) |
|
|
|
; Borders (Windows 10) |
|
SysGet, BorderX, 32 |
|
SysGet, BorderY, 33 |
|
if (BorderX) { |
|
posX := posX - BorderX |
|
width := width + (BorderX * 2) |
|
} |
|
if (BorderY) { |
|
height := height + BorderY |
|
} |
|
|
|
; If window is already there move to same spot on next monitor |
|
WinGetPos, curPosX, curPosY, curWidth, curHeight, A |
|
if ((posX = curPosX) && (posY = curPosY) && (width = curWidth) && (height = curHeight)) { |
|
activeMon := activeMon + 1 |
|
SnapActiveWindow(winPlaceVertical, winPlaceHorizontal, winSizeHeight, activeMon) |
|
} else { |
|
WinMove,A,,%posX%,%posY%,%width%,%height% |
|
} |
|
} |
|
|
|
/** |
|
* GetMonitorIndexFromWindow retrieves the HWND (unique ID) of a given window. |
|
* @param {Uint} windowHandle |
|
* @author shinywong |
|
* @link http://www.autohotkey.com/board/topic/69464-how-to-determine-a-window-is-in-which-monitor/?p=440355 |
|
*/ |
|
GetMonitorIndexFromWindow(windowHandle) { |
|
; Starts with 1. |
|
monitorIndex := 1 |
|
|
|
VarSetCapacity(monitorInfo, 40) |
|
NumPut(40, monitorInfo) |
|
|
|
if (monitorHandle := DllCall("MonitorFromWindow", "uint", windowHandle, "uint", 0x2)) |
|
&& DllCall("GetMonitorInfo", "uint", monitorHandle, "uint", &monitorInfo) { |
|
monitorLeft := NumGet(monitorInfo, 4, "Int") |
|
monitorTop := NumGet(monitorInfo, 8, "Int") |
|
monitorRight := NumGet(monitorInfo, 12, "Int") |
|
monitorBottom := NumGet(monitorInfo, 16, "Int") |
|
workLeft := NumGet(monitorInfo, 20, "Int") |
|
workTop := NumGet(monitorInfo, 24, "Int") |
|
workRight := NumGet(monitorInfo, 28, "Int") |
|
workBottom := NumGet(monitorInfo, 32, "Int") |
|
isPrimary := NumGet(monitorInfo, 36, "Int") & 1 |
|
|
|
SysGet, monitorCount, MonitorCount |
|
|
|
Loop, %monitorCount% { |
|
SysGet, tempMon, Monitor, %A_Index% |
|
|
|
; Compare location to determine the monitor index. |
|
if ((monitorLeft = tempMonLeft) and (monitorTop = tempMonTop) |
|
and (monitorRight = tempMonRight) and (monitorBottom = tempMonBottom)) { |
|
monitorIndex := A_Index |
|
break |
|
} |
|
} |
|
} |
|
|
|
return %monitorIndex% |
|
} |
|
|
|
dynamicPickup(initial:=0) { |
|
; Pickup the initial keypress |
|
pressed%initial% := true |
|
|
|
; Disable Additional Presses |
|
loop 9 |
|
Hotkey, ^#Numpad%A_Index%, dynamicPickup, Off |
|
|
|
; Pickup Areas |
|
while (GetKeyState("Control") || GetKeyState("LWin") || GetKeyState("RWin")) { |
|
if (GetKeyState("Numpad1")) |
|
pressed1 := true |
|
if (GetKeyState("Numpad2")) |
|
pressed2 := true |
|
if (GetKeyState("Numpad3")) |
|
pressed3 := true |
|
if (GetKeyState("Numpad4")) |
|
pressed4 := true |
|
if (GetKeyState("Numpad5")) |
|
pressed5 := true |
|
if (GetKeyState("Numpad6")) |
|
pressed6 := true |
|
if (GetKeyState("Numpad7")) |
|
pressed7 := true |
|
if (GetKeyState("Numpad8")) |
|
pressed8 := true |
|
if (GetKeyState("Numpad9")) |
|
pressed9 := true |
|
} |
|
|
|
; Calc Window Height |
|
height:=0 |
|
if ((pressed1 || pressed2 || pressed3) && (pressed7 || pressed8 || pressed9)) { |
|
height := 3 |
|
} else { |
|
if (pressed1 || pressed2 || pressed3) |
|
height := height + 1 |
|
if (pressed4 || pressed5 || pressed6) |
|
height := height + 1 |
|
if (pressed7 || pressed8 || pressed9) |
|
height := height + 1 |
|
} |
|
|
|
|
|
; Calc Window Width |
|
width:=0 |
|
if ((pressed1 || pressed4 || pressed7) && (pressed3 || pressed6 || pressed9)) { |
|
width := 3 |
|
} else { |
|
if (pressed1 || pressed4 || pressed7) |
|
width := width + 1 |
|
if (pressed2 || pressed5 || pressed8) |
|
width := width + 1 |
|
if (pressed3 || pressed6 || pressed9) |
|
width := width + 1 |
|
} |
|
|
|
; Calc Anchor Point (matches numpad for zones) (order matters here) |
|
anchor := 0 |
|
if (pressed3 && (height = 1)) |
|
anchor := 9 |
|
if (pressed2 && (height = 1)) |
|
anchor := 8 |
|
if (pressed1 && (height = 1)) |
|
anchor := 7 |
|
if (pressed6 && (height < 3)) |
|
anchor := 6 |
|
if ((pressed5 || (pressed2 && pressed6)) && (height < 3)) |
|
anchor := 5 |
|
if ((pressed4 || (pressed1 && (pressed5 || pressed6))) && (height < 3)) |
|
anchor := 4 |
|
if (pressed9) |
|
anchor := 3 |
|
if (pressed8 || (pressed9 && (pressed5 || pressed2))) |
|
anchor := 2 |
|
if (pressed7 || ((pressed4 || pressed1) && (pressed8 || pressed9))) |
|
anchor := 1 |
|
|
|
; Set This window up! |
|
SnapActiveWindowAdvanced(anchor, width, height) |
|
|
|
; Enable Hotkeys |
|
loop 9 |
|
Hotkey, ^#Numpad%A_Index%, dynamicPickup, On |
|
} |
|
|
|
SnapActiveWindowAdvanced(anchor, widthUnit, heightUnit, snapGrid := 3,activeMon := 0) { |
|
; SnapGrid units are the width/height of the active monitor evenly split into the snapgrid number |
|
; Width and Height is multiples of snapGrid units |
|
; The anchor points are arranged in order from left to right, top to bottom |
|
|
|
WinGet activeWin, ID, A |
|
SysGet, MonitorCount, MonitorCount |
|
|
|
if (!activeMon) { |
|
activeMon := GetMonitorIndexFromWindow(activeWin) |
|
} else if (activeMon > MonitorCount) { |
|
activeMon := 1 |
|
} |
|
|
|
SysGet, MonitorWorkArea, MonitorWorkArea, %activeMon% |
|
|
|
; Snap Units |
|
unitX := (MonitorWorkAreaRight - MonitorWorkAreaLeft) / snapGrid |
|
unitY := (MonitorWorkAreaBottom - MonitorWorkAreaTop) / snapGrid |
|
|
|
; Resolve Anchor |
|
posX := MonitorWorkAreaLeft + (unitX * Mod(anchor - 1, snapGrid)) |
|
posY := MonitorWorkAreaTop + (unitY * floor((anchor - 1) / snapGrid) - 1) |
|
|
|
; Calculate size as a percentage of the screen |
|
width := (MonitorWorkAreaLeft + (unitX * (Mod(anchor - 1, snapGrid) + widthUnit))) - posX |
|
if ((posX + width) > (MonitorWorkAreaRight - 50)) |
|
width := MonitorWorkAreaRight - (posX - 1) |
|
|
|
height := (MonitorWorkAreaTop + (unitY * (floor((anchor - 1) / snapGrid) + heightUnit) - 1)) - posY |
|
if ((posY + height) > (MonitorWorkAreaBottom - 50)) |
|
height := MonitorWorkAreaBottom - (posY - 1) |
|
|
|
; Clover Special Case [START] (http://en.ejie.me) |
|
; If the internal windows explorer window is selected then switch to clover wrapper |
|
IfWinActive, ahk_class CabinetWClass ahk_exe explorer.exe |
|
{ |
|
WinGetPos, expX, expY,,, A |
|
WinGet, id, list,,, Program Manager |
|
Loop, %id% { |
|
this_id := id%A_Index% |
|
WinGetPos, clovX, clovY,,, ahk_id %this_id% |
|
if (((expX - 8) = clovX) && ((expY - 18) = clovY)) { |
|
WinActivate, ahk_id %this_id% |
|
break |
|
} |
|
} |
|
} |
|
; Adjust limits to accomodate the wrapper dimensions |
|
IfWinActive, ahk_class Clover_WidgetWin_0 ahk_exe clover.exe |
|
{ |
|
posX := posX + 2 |
|
width := width - 4 |
|
height := height - 3 |
|
} |
|
; Clover Special Case [END] |
|
|
|
; Borders (Windows 10) |
|
SysGet, BorderX, 32 |
|
SysGet, BorderY, 33 |
|
if (BorderX) { |
|
posX := (posX + 1) - BorderX |
|
width := (width - 2) + (BorderX * 2) |
|
} |
|
if (BorderY) { |
|
height := height + BorderY |
|
} |
|
|
|
; Rounding |
|
posX := floor(posX) |
|
posY := floor(posY) |
|
width := floor(width) |
|
height := floor(height) |
|
|
|
; If window is already there move to same spot on next monitor |
|
WinGetPos, curPosX, curPosY, curWidth, curHeight, A |
|
if ((posX = curPosX) && (posY = curPosY) && (width = curWidth) && (height = curHeight)) { |
|
activeMon := activeMon + 1 |
|
SnapActiveWindowAdvanced(anchor, widthUnit, heightUnit, snapGrid, activeMon) |
|
} else { |
|
WinRestore, A |
|
WinMove,A,,%posX%,%posY%,%width%,%height% |
|
} |
|
} |
|
|
|
; Dynamic Snapping |
|
loop 9 |
|
Hotkey, ^#Numpad%A_Index%, dynamicPickup, On |
|
return |
|
|
|
; Dynamic Hook Function |
|
dynamicPickup: |
|
dynamicPickup(SubStr(A_ThisHotkey,0)) |
|
return |
|
|
|
; Directional Arrow Hotkeys |
|
#!Up::SnapActiveWindow("top","full","half") |
|
#!Down::SnapActiveWindow("bottom","full","half") |
|
|
|
; Numberpad Hotkeys (Landscape) |
|
#!Numpad7::SnapActiveWindow("top","left","half") |
|
#!Numpad8::SnapActiveWindow("top","full","half") |
|
#!Numpad9::SnapActiveWindow("top","right","half") |
|
#!Numpad1::SnapActiveWindow("bottom","left","half") |
|
#!Numpad2::SnapActiveWindow("bottom","full","half") |
|
#!Numpad3::SnapActiveWindow("bottom","right","half") |
|
#!Numpad4::SnapActiveWindow("top","left","full") |
|
#!Numpad6::SnapActiveWindow("top","right","full") |
|
|
|
; Numberpad Hotkeys (Portrait) |
|
^#!Numpad8::SnapActiveWindow("top","full","third") |
|
^#!Numpad5::SnapActiveWindow("middle","full","third") |
|
^#!Numpad2::SnapActiveWindow("bottom","full","third") |
|
^#!Numpad7::SnapActiveWindow("top","left","third") |
|
^#!Numpad4::SnapActiveWindow("middle","left","third") |
|
^#!Numpad1::SnapActiveWindow("bottom","left","third") |
|
^#!Numpad9::SnapActiveWindow("top","right","third") |
|
^#!Numpad6::SnapActiveWindow("middle","right","third") |
|
^#!Numpad3::SnapActiveWindow("bottom","right","third") |
|
|
|
|
This doesn't seem to work on my vertical monitor. The original script worked perfectly. When spiting two windows to top half and bottom half they are both over 100 pixels too long on the bottom. So the top window overlaps with the bottom one, and the bottom window extends below the screen.