Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #Requires AutoHotkey v2.0
- #SingleInstance Force
- ; Prevent capslock from turning on when using as a modifier.
- CapsLock::{
- KeyWait "CapsLock"
- if (A_ThisHotkey = "CapsLock")
- SetCapsLockState(GetKeyState("CapsLock", "T") ? "AlwaysOff" : "AlwaysOn")
- }
- class WindowManager {
- static max_grid_size := 4
- static modifier := "CapsLock"
- static grid_line_color := 0x3CA4EA
- static window_border_color := 0x237FD5
- static __New() {
- this.current_col_count := 0
- this.current_row_count := 0
- this.Overlay := this.GdipOverlay()
- this.BackgroundBrush := this.GdipOverlay.Brush(140 << 24 | 0x0C0C0C)
- this.GridBorderSize := 2
- this.GridPen := this.GdipOverlay.Pen(200 << 24 | this.grid_line_color, this.GridBorderSize)
- this.WindowBorderSize := 4
- this.BorderPen := this.GdipOverlay.Pen(255 << 24 | this.window_border_color, this.WindowBorderSize)
- HotIf (*) => GetKeyState(this.modifier, "P")
- ; modifier + key
- Hotkey "*j", HotkeyCallback(ObjBindMethod(this, "MoveWindow", 1)) ; Move left
- Hotkey "*i", HotkeyCallback(ObjBindMethod(this, "MoveWindow", 2)) ; Move up
- Hotkey "*l", HotkeyCallback(ObjBindMethod(this, "MoveWindow", 3)) ; Move right
- Hotkey "*k", HotkeyCallback(ObjBindMethod(this, "MoveWindow", 4)) ; Move down
- Hotkey "*u", (*) => (Send("#+{Left}"), this.HideGuides()) ; move to previous monitor
- Hotkey "*o", (*) => (Send("#+{Right}"), this.HideGuides()) ; move to next monitor
- Hotkey "*m", ObjBindMethod(this, "Maximize") ; maximize
- ; modifier + shift + key
- Hotkey "*+j", HotkeyCallback(ObjBindMethod(this, "Resize", 1)) ; decrease width
- Hotkey "*+i", HotkeyCallback(ObjBindMethod(this, "Resize", 2)) ; decrease height
- Hotkey "*+l", HotkeyCallback(ObjBindMethod(this, "Resize", 3)) ; increase width
- Hotkey "*+k", HotkeyCallback(ObjBindMethod(this, "Resize", 4)) ; increase height
- ; modifier + alt + key
- Hotkey "*!i", HotkeyCallback(ObjBindMethod(this, "ChangeRowCountAndAlign", -1)) ; increase row count
- Hotkey "*!k", HotkeyCallback(ObjBindMethod(this, "ChangeRowCountAndAlign", 1)) ; decrease row count
- Hotkey "*!j", HotkeyCallback(ObjBindMethod(this, "ChangeColCountAndAlign", -1)) ; decrease col count
- Hotkey "*!l", HotkeyCallback(ObjBindMethod(this, "ChangeColCountAndAlign", 1)) ; increase col count
- HotIf ObjBindMethod(this, "GridIsVisible")
- Hotkey "*" this.modifier " Up", (*) => this.HideGuides()
- HotIf ; End hotif
- HotkeyCallback(callback) {
- ; If not excluded window, call the callback, and show guides if guides are not visible.
- return (*) => (this.IsWindowExcluded() || (callback(coords := this.GetCoords()), this.GridIsVisible() || this.DrawGrid(coords)))
- }
- WM_DISPLAYCHANGE := 0x007E
- OnMessage(WM_DISPLAYCHANGE, (*) => (this.Overlay.Hide(), this.Overlay := this.gdipOverlay()))
- }
- static GridIsVisible(*) => DllCall("IsWindowVisible", "ptr", this.Overlay.hwnd)
- static IsWindowExcluded(win:="A") => InStr("(Shell_TrayWnd|Shell_SecondaryTrayWnd|WorkerW|AutoHotkeyGUI|XamlExplorerHostIslandWindow)", WinGetClass(win))
- static Maximize(*) {
- this.current_col_count := this.current_row_count := 0
- WinMaximize("A")
- this.HideGuides()
- }
- static ChangeColCountAndAlign(inc, coords) {
- Critical
- this.ChangeColCount(inc, coords)
- coords := this.GetCoords(coords)
- WinMoveEx(coords.X, coords.Y, coords.W, coords.H, "A")
- this.DrawGrid(coords)
- }
- static ChangeRowCountAndAlign(inc, coords) {
- Critical
- coords := this.ChangeRowCount(inc, coords)
- WinMoveEx(coords.X, coords.Y, coords.W, coords.H, "A")
- this.DrawGrid(coords)
- }
- static ChangeColCount(inc, coords) {
- this.current_col_count += inc
- if this.current_col_count > this.max_grid_size
- this.current_col_count := 1
- if this.current_col_count < 1
- this.current_col_count := this.max_grid_size
- return this.GetCoords(coords)
- }
- static ChangeRowCount(inc, coords) {
- this.current_row_count += inc
- if this.current_row_count > this.max_grid_size
- this.current_row_count := 1
- if this.current_row_count < 1
- this.current_row_count := this.max_grid_size
- return this.GetCoords(coords)
- }
- static GetCoords(coords?) {
- Critical
- SetWinDelay(-1)
- win := WinExist("A")
- this.Mon := MonInfoFromWindow(win)
- if WinIsMax := (WinGetMinMax(win) = 1)
- WinRestore(win)
- if !IsSet(coords) {
- if WinIsMax
- winX := this.Mon.WALeft, winY := this.Mon.WATop, winW := this.Mon.WAWidth, winH := this.Mon.WAHeight
- else
- WinGetPosEx(&winX, &winY, &winW, &winH, win)
- } else {
- winX := coords.X, winY := coords.Y, winW := coords.W, winH := coords.H
- }
- ; If first run, find closest blockWidth and blockHeight to current window.
- if this.current_col_count = 0 && this.current_row_count = 0 {
- MonWidth := this.Mon.WAWidth
- MonHeight := this.Mon.WAHeight
- lowest_diffX := MonWidth
- lowest_diffY := MonHeight
- lowest_diffW := MonWidth
- lowest_diffH := MonHeight
- loop this.max_grid_size {
- blockWidth := MonWidth / A_Index
- blockHeight := MonHeight / A_Index
- diffW := Abs(blockWidth - winW)
- diffH := Abs(blockHeight - winH)
- if diffW <= lowest_diffW {
- lowest_diffW := diffW
- this.current_col_count := A_Index
- this.blockWidth := blockWidth
- }
- if diffH <= lowest_diffH {
- lowest_diffH := diffH
- this.current_row_count := A_Index
- this.blockHeight := blockHeight
- }
- }
- } else {
- this.blockWidth := this.Mon.WAWidth / this.current_col_count
- this.blockHeight := this.Mon.WAHeight / this.current_row_count
- }
- blockWidth := this.blockWidth
- blockHeight := this.blockHeight
- ; Find closest X, Y, W, H in grid
- X := Floor(WinX / blockWidth) * blockWidth
- if Winx > X + blockWidth/2 ; If winX is greater than X + half of blockWidth, winX is closer to the right block than the left block
- X += blockWidth ; Move X one block right.
- X := Min(Max(this.Mon.WALeft, X), this.Mon.WARight-blockWidth) ; Keep x position within monitor
- Y := Floor(WinY / blockHeight) * blockHeight
- if WinY > Y + blockHeight/2
- Y += blockHeight
- Y := Min(Max(this.Mon.WATop, Y), this.Mon.WABottom-blockHeight)
- W := Ceil(winW / blockWidth) * blockWidth
- if (X + W - blockWidth/2) > WinX+WinW
- W -= blockWidth
- W := Max(Min(W, this.Mon.WARight - X), blockWidth)
- H := Ceil(winH / blockHeight) * blockHeight
- if (Y + H - blockHeight/2) > WinY+WinH
- H -= blockHeight
- H := Max(Min(H, this.Mon.WABottom - Y), blockHeight)
- tolerance := 4
- Edge := ""
- Abs(X - this.Mon.WALeft) < tolerance && Edge .= "L"
- Abs(Y - this.Mon.WATop) < tolerance && Edge .= "T"
- Abs((this.Mon.WARight - W) - X) < tolerance && Edge .= "R"
- Abs((this.Mon.WABottom - H) - Y) < tolerance && Edge .= "B"
- Aligned := Abs(winX - X) < tolerance && Abs(winY - Y) < tolerance
- Resized := Aligned && (W > this.blockWidth || H > this.blockHeight) && Abs(winW - W) < tolerance && Abs(winH - H) < tolerance
- return {
- X:X,
- Y:Y,
- W:W,
- H:H,
- R:X+W,
- B:Y+H,
- Aligned:Aligned,
- Resized:Resized,
- Edge:Edge
- }
- }
- static MoveWindow(Dir, coords) {
- Critical
- switch Dir {
- case 1: ; Left
- if coords.Aligned {
- if InStr(coords.Edge, "L")
- this.ChangeColCount(1, coords)
- coords.X -= this.blockWidth
- }
- case 2: ; Up
- if coords.Aligned {
- if Instr(coords.Edge, "T")
- this.ChangeRowCount(1, coords)
- coords.Y -= this.blockHeight
- }
- case 3: ; Right
- if coords.Aligned {
- if InStr(coords.Edge, "R")
- this.ChangeColCount(1, coords)
- coords.X += this.blockWidth
- if coords.Resized && InStr(coords.Edge, "R") && !InStr(coords.Edge, "L")
- coords.X -= (this.blockWidth/2)
- }
- case 4: ; Down
- if coords.Aligned {
- if InStr(coords.Edge, "B")
- this.ChangeRowCount(1, coords)
- coords.Y += this.blockHeight
- if coords.Resized && InStr(coords.Edge, "B") && !InStr(coords.Edge, "T")
- coords.Y -= (this.blockHeight/2)
- }
- }
- coords := this.GetCoords(coords)
- WinMoveEx(coords.X, coords.Y, coords.W, coords.H, "A")
- this.DrawGrid(coords)
- }
- static Resize(dir, coords) {
- Critical
- switch dir {
- case 1: ; Left
- coords.W -= this.blockWidth
- case 2: ; Top
- coords.H -= this.blockHeight
- case 3: ; Right
- coords.W += this.blockWidth
- case 4: ; Down
- coords.H += this.blockHeight
- }
- coords := this.GetCoords(coords)
- this.DrawGrid(coords)
- WinMoveEx(coords.X, coords.Y, coords.W, coords.H, "A")
- }
- static DrawGrid(coords) {
- colLineCount := this.current_col_count + 1
- rowLineCount := this.current_row_count + 1
- RowsCompleted := colsCompleted := 0
- hdc := DllCall("CreateCompatibleDC", "ptr", 0)
- ; Create a buffered bitmap to draw on
- ; https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader
- NumPut("uint", 40, "uint", this.Mon.WAWidth, "uint", this.Mon.WAHeight, "ushort", 1, "ushort", 32, "uint", 0, bi := Buffer(40, 0))
- hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", bi, "uint", 0, "ptr*", &ppvBits:=0, "ptr", 0, "uint", 0, "ptr")
- obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm)
- Graphics := this.GdipOverlay.GraphicsFromHDC(hdc)
- path := this.GdipOverlay.Path()
- path.AddPathRectangle(0, 0, this.Mon.WAWidth, this.Mon.WAHeight)
- path.AddPathRectangle(coords.X - this.Mon.WALeft, coords.Y - this.Mon.WATop, coords.W, coords.H)
- Graphics.FillPath(this.BackgroundBrush, path)
- b := this.GridBorderSize
- ; Draw grid
- loop rowLineCount {
- y := this.blockHeight * (A_Index - 1)
- switch A_Index {
- case 1 : y += b/2
- case rowLineCount : y -= b/2
- }
- Graphics.DrawLine(this.GridPen, 0, this.Mon.WAWidth, y, y)
- }
- loop colLineCount {
- x := this.blockWidth * (A_Index - 1)
- switch A_Index {
- case 1 : x += b/2
- case colLineCount : x -= b/2
- }
- Graphics.DrawLine(this.GridPen, x, x, 0, this.Mon.WAHeight)
- }
- b := this.WindowBorderSize
- ; Draw border around window.
- Graphics.DrawRectangle(this.BorderPen, coords.X - this.Mon.WALeft+b/2, coords.Y - this.Mon.WATop+b/2, coords.W-b, coords.H-b)
- DllCall("UpdateLayeredWindow"
- , "ptr", this.Overlay.hwnd
- , "ptr", 0
- , "ptr", 0
- , "int64*", this.Mon.WAWidth|this.Mon.WAHeight<<32
- , "ptr", hdc
- , "int64*", 0
- , "uint", 0
- , "uint*", 255<<16|1<<24
- , "uint", 2)
- this.Overlay.Show("NA x" this.Mon.WALeft " y" this.Mon.WATop " w" this.Mon.WAWidth " h" this.Mon.WAHeight)
- DllCall("SelectObject", "ptr", hdc, "ptr", obm) ; Select object back into the hdc
- DllCall("DeleteObject", "ptr", hbm) ; Delete the bitmap
- DllCall("DeleteDC", "ptr", hdc)
- }
- static HideGuides(*) => this.Overlay.Hide()
- class GdipOverlay extends Gui {
- __New() {
- static module := 0
- if !module && !DllCall("GetModuleHandle", "Str", "gdiplus", "ptr")
- module := DllCall("LoadLibrary", "str", "gdiplus")
- NumPut("uint", 1, si := Buffer(A_PtrSize = 8 ? 24 : 16, 0))
- DllCall("gdiplus\GdiplusStartup", "ptr*", &pToken:=0, "ptr", si, "uptr", 0)
- if !pToken
- throw Error("Gdiplus failed to start. Please ensure you have gdiplus on your system")
- this.gdipToken := pToken
- super.__New("-Caption +E0x80000 +AlwaysOnTop +ToolWindow +E0x20")
- }
- __Delete() {
- DllCall("gdiplus\GdiplusShutdown","ptr", this.gdipToken)
- }
- class GraphicsFromHDC {
- __New(hdc) {
- DllCall("gdiplus\GdipCreateFromHDC", "ptr", hdc, "uptr*", &pGraphics:=0)
- this.ptr := pGraphics
- }
- __Delete() {
- DllCall("gdiplus\GdipDeleteGraphics", "ptr", this)
- }
- DrawLine(pen, x1, x2, y1, y2) {
- DllCall("gdiplus\GdipDrawLine", "ptr", this, "ptr", pen, "float", x1, "float", y1, "float", x2, "float", y2)
- }
- DrawRectangle(pen, x, y, w, h) {
- DllCall("gdiplus\GdipDrawRectangle", "ptr", this, "ptr", pen, "float", x, "float", y, "float", w, "float", h)
- }
- FillRectangle(brush, x, y, w, h) {
- DllCall("gdiplus\GdipFillRectangle", "ptr", this, "ptr", brush, "float", x, "float", y, "float", w, "float", h)
- }
- FillPath(brush, path) {
- DllCall("gdiplus\GdipFillPath", "ptr", this, "ptr", brush, "ptr", path)
- }
- }
- class Brush {
- __New(color:=0xFF000000) {
- DllCall("gdiplus\GdipCreateSolidFill", "uint", color, "ptr*", &pBrush:=0)
- this.ptr := pBrush
- }
- __Delete() => DllCall("gdiplus\GdipDeleteBrush", "ptr", this)
- }
- class Pen {
- __New(color:=0xFF000000, width:=1) {
- DllCall("gdiplus\GdipCreatePen1", "uint", color, "float", width, "int", 2, "ptr*", &pPen:=0)
- this.ptr := pPen
- }
- __Delete() => DllCall("gdiplus\GdipDeletePen", "ptr", this)
- }
- class Path {
- __New() {
- DllCall("gdiplus\GdipCreatePath", "int", 0, "ptr*", &pPath:=0)
- this.ptr := pPath
- }
- AddPathRectangle(x, y, w, h) {
- DllCall("gdiplus\GdipAddPathRectangle", "ptr", this, "float", x, "float", y, "float", w, "float", h)
- }
- __Delete() => DllCall("gdiplus\GdipDeletePath", "ptr", this)
- }
- }
- }
- ; move window and fix offset from invisible border
- WinMoveEx(x?, y?, w?, h?, hwnd?) {
- if !(hwnd is integer)
- hwnd := WinExist(hwnd)
- if !IsSet(hwnd)
- hwnd := WinExist()
- ; compare pos and get offset
- WinGetPosEx(&fX, &fY, &fW, &fH, hwnd)
- WinGetPos(&wX, &wY, &wW, &wH, hwnd)
- diffX := fX - wX
- diffY := fY - wY
- diffW := fW - wW
- diffH := fH - wH
- ; new x, y, w, h with offset corrected.
- IsSet(x) && nX := x - diffX
- IsSet(y) && nY := y - diffY
- IsSet(w) && nW := w - diffW
- IsSet(h) && nH := h - diffH
- WinMove(nX?, nY?, nW?, nH?, hwnd?)
- }
- ; get window position without the invisible border
- WinGetPosEx(&x?, &y?, &w?, &h?, hwnd?) {
- static DWMWA_EXTENDED_FRAME_BOUNDS := 9
- if !(hwnd is integer)
- hwnd := WinExist(hwnd)
- if !IsSet(hwnd)
- hwnd := WinExist() ; last found window
- DllCall("dwmapi\DwmGetWindowAttribute",
- "ptr" , hwnd,
- "uint", DWMWA_EXTENDED_FRAME_BOUNDS,
- "ptr" , RECT := Buffer(16, 0),
- "int" , RECT.size,
- "uint")
- x := NumGet(RECT, 0, "int")
- y := NumGet(RECT, 4, "int")
- w := NumGet(RECT, 8, "int") - x
- h := NumGet(RECT, 12, "int") - y
- }
- MonInfoFromWindow(hwnd) {
- hMon := DllCall("MonitorFromWindow", "ptr", WinExist(hwnd), "uint", 2, "ptr")
- NumPut("uint", 40, mi := Buffer(40))
- DllCall("user32\GetMonitorInfo", "ptr", hMon, "ptr", mi)
- return {Left : L := NumGet(mi, 4, "int")
- , Top : T := NumGet(mi, 8, "int")
- , Right : R := NumGet(mi, 12, "int")
- , Bottom : B := NumGet(mi, 16, "int")
- , WALeft : WL := NumGet(mi, 20, "int")
- , WATop : WT := NumGet(mi, 24, "int")
- , WARight : WR := NumGet(mi, 28, "int")
- , WABottom : WB := NumGet(mi, 32, "int")
- , Width : Width := R - L
- , Height : Height := B - T
- , WAWidth : WR - WL
- , WAHeight : WB - WT
- , Primary : NumGet(mi, 36, "uint")
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement