I've also added a minimize, but it doesn't work very well. I'm wondering if someone can help me to get it working properly.
Ideally when u minimize it hooks to the window that was minimized. So the next commands should work on that window. I have it so that if you minimize it usually restores, but not always.
Here's the key layout:
fill left half (win+alt+z), fill right half (win+alt+x) -- win+ctrl = alternate
1/4 screen top left = q, top right = w, bottom left = a, bottom right = s
top half = e, bottom half = d, center screen = c.
Maximize = up arrow
Minimize = down arrow
also, fill left half works with left arrow, and fill right works with right arrow.
Heres my code: (Ignore the comments from the original version)
; WindowPad: ; ; Move and resize windows with Win+Numpad. ; Win+Numpad1 = Fill bottom-left quarter of screen ; Win+Numpad2 = Fill bottom half of screen ; etc. ; ; Move windows across monitors. For example: ; Win+Numpad4 places the window on the left half of the screen. ; Win+Numpad4 again moves it to the monitor to the right. ; ; Quick monitor switch: ; Win+Numpad5 places the window in the center of the screen. ; Win+Numpad5 again moves the window to the next monitor. ; (This works by monitor number, not necessarily left to right.) ; ; QUICKER Monitor Switch: ; Win+NumpadDot switches to the next monitor (1->2->3->1 etc.) ; Win+NumpadDiv moves ALL windows to monitor 2. ; Win+NumpadMult moves ALL windows to monitor 1. ; ; Other shortcuts: ; Win+Numpad0 toggles maximize. ; Insert (or some other key) can be used in place of "Win". ; ; Credits: ; Concept based on HiRes Screen Splitter by JOnGliko. ; Written from scratch by Lexikos to support multiple monitors. ; NumpadDot key functionality suggested by bobbo. ; ; Built with AutoHotkey v1.0.47.02 ; ; HISTORY ; ; Version 1.1: ; - "Gather windows" hotkeys (NumpadDiv and NumpadMult) ; - NumpadDot to move window to next monitor ; - Added more EasyKey combos (for symmetry) ; - Original functionality of EasyKey is retained (on key-release) ; - SetWinDelay, -1 to reduce lag when making multiple moves (quickly) ; ; Version 1: ; - intial release WindowPadInit: Prefix_Active = #! ; Alt+Win+Char = Move active window Prefix_Other = #^ ; Ctrl+Win+Numpad = Move previously active window ; Note: Shift (+) should not be used, as +Numpad is hooked by the OS ; to do left/right/up/down/etc. (reverse Numlock) -- at least on Vista. EasyKey = Insert ; Insert is near Numpad on my keyboard... ; Note: Prefix_Other must not be a sub-string of Prefix_Active. ; (If you want it to be, first edit the line "if (InStr(A_ThisHotkey, Prefix_Other))") Hotkey, IfWinActive ; in case this is included in another script... ;;Edit all the hotkeys here: ; Left and Right Leftt = z Rightt = x ; Grid of four TopLeft = q TopRight = w BottomLeft = a BottomRight = s ; Top and Bottom Top = e Bottom = d ; Center Center = c Hotkey1a = %Prefix_Active%%BottomLeft% Hotkey1o = %Prefix_Other%%BottomLeft% Hotkey2a = %Prefix_Active%%Bottom% Hotkey2o = %Prefix_Other%%Bottom% Hotkey3a = %Prefix_Active%%BottomRight% Hotkey3o = %Prefix_Other%%BottomRight% Hotkey4a = %Prefix_Active%%Leftt% Hotkey4o = %Prefix_Other%%Leftt% Hotkey4a2 = %Prefix_Active%Left Hotkey4o2 = %Prefix_Other%Left Hotkey5a = %Prefix_Active%%Center% Hotkey5o = %Prefix_Other%%Center% Hotkey6a = %Prefix_Active%%Rightt% Hotkey6o = %Prefix_Other%%Rightt% Hotkey6a2 = %Prefix_Active%Right Hotkey6o2 = %Prefix_Other%Right Hotkey7a = %Prefix_Active%%TopLeft% Hotkey7o = %Prefix_Other%%TopLeft% Hotkey8a = %Prefix_Active%%Top% Hotkey8o = %Prefix_Other%%Top% Hotkey9a = %Prefix_Active%%TopRight% Hotkey9o = %Prefix_Other%%TopRight% Hotkey, %Hotkey1a%, DoMoveWindowInDirection Hotkey, %Hotkey1o%, DoMoveWindowInDirection Hotkey, %Hotkey2a%, DoMoveWindowInDirection Hotkey, %Hotkey2o%, DoMoveWindowInDirection Hotkey, %Hotkey3a%, DoMoveWindowInDirection Hotkey, %Hotkey3o%, DoMoveWindowInDirection Hotkey, %Hotkey4a%, DoMoveWindowInDirection Hotkey, %Hotkey4o%, DoMoveWindowInDirection Hotkey, %Hotkey4a2%, DoMoveWindowInDirection Hotkey, %Hotkey4o2%, DoMoveWindowInDirection Hotkey, %Hotkey5a%, DoMoveWindowInDirection Hotkey, %Hotkey5o%, DoMoveWindowInDirection Hotkey, %Hotkey6a%, DoMoveWindowInDirection Hotkey, %Hotkey6o%, DoMoveWindowInDirection Hotkey, %Hotkey6a2%, DoMoveWindowInDirection Hotkey, %Hotkey6o2%, DoMoveWindowInDirection Hotkey, %Hotkey7a%, DoMoveWindowInDirection Hotkey, %Hotkey7o%, DoMoveWindowInDirection Hotkey, %Hotkey8a%, DoMoveWindowInDirection Hotkey, %Hotkey8o%, DoMoveWindowInDirection Hotkey, %Hotkey9a%, DoMoveWindowInDirection Hotkey, %Hotkey9o%, DoMoveWindowInDirection ; Setup Hotkeys ;Loop, 9 ;{ ; Register hotkeys. ; Hotkey, %Prefix_Active%Numpad%A_Index%, DoMoveWindowInDirection ; Hotkey, %Prefix_Other%Numpad%A_Index%, DoMoveWindowInDirection ; ; ; OPTIONAL ; if EasyKey ; Hotkey, %EasyKey% & Numpad%A_Index%, DoMoveWindowInDirection ;} Hotkey, %Prefix_Active%Up, DoMaximizeToggle Hotkey, %Prefix_Other%Up, DoMaximizeToggle Hotkey, %Prefix_Active%Down, DoMinimizeToggle Hotkey, %Prefix_Other%Down, DoMinimizeToggle Hotkey, %Prefix_Active%NumpadDot, MoveWindowToNextScreen Hotkey, %Prefix_Other%NumpadDot, MoveWindowToNextScreen Hotkey, %Prefix_Active%NumpadDiv, GatherWindowsLeft Hotkey, %Prefix_Active%NumpadMult, GatherWindowsRight ;if (EasyKey) { ; Hotkey, %EasyKey% & Numpad0, DoMaximizeToggle ; Hotkey, %EasyKey% & NumpadDot, MoveWindowToNextScreen ; Hotkey, %EasyKey% & NumpadDiv, GatherWindowsLeft ; Hotkey, %EasyKey% & NumpadMult, GatherWindowsRight ; Hotkey, %EasyKey%, SendEasyKey ; let EasyKey's original function work (on release) ;} return SendEasyKey: Send {%EasyKey%} return ; This is actually based on monitor number, so if your secondary is on the ; right, you may want to switch these around. GatherWindowsLeft: GatherWindows(1) return GatherWindowsRight: GatherWindows(2) return ; Hotkey handler. DoMoveWindowInDirection: ; Define constants. if (!Directions1) { dir = -1:+1,0:+1,+1:+1,-1:0,0:0,+1:0,-1:-1,0:-1,+1:-1 StringSplit, Directions, dir, `, } gosub WP_SetLastFoundWindowByHotkey ; Determine which direction we want to go. ;if (!RegExMatch(A_ThisHotkey, "\d+", dir) or !Directions%dir%) ;{ ; MsgBox Error: "%A_ThisHotkey%" was registered and I can't figure out which number it is! ; return ;} if (A_ThisHotKey = Hotkey1a) or (A_ThisHotKey = Hotkey1o) { dir := Directions1 } else if (A_ThisHotKey = Hotkey2a) or (A_ThisHotKey = Hotkey2o) { dir := Directions2 } else if (A_ThisHotKey = Hotkey3a) or (A_ThisHotKey = Hotkey3o) { dir := Directions3 } else if (A_ThisHotKey = Hotkey4a) or (A_ThisHotKey = Hotkey4o) or (A_ThisHotKey = Hotkey4a2) or (A_ThisHotKey = Hotkey4o2) { dir := Directions4 } else if (A_ThisHotKey = Hotkey5a) or (A_ThisHotKey = Hotkey5o) { dir := Directions5 } else if (A_ThisHotKey = Hotkey6a) or (A_ThisHotKey = Hotkey6o) or (A_ThisHotKey = Hotkey6a2) or (A_ThisHotKey = Hotkey6o2) { dir := Directions6 } else if (A_ThisHotKey = Hotkey7a) or (A_ThisHotKey = Hotkey7o) { dir := Directions7 } else if (A_ThisHotKey = Hotkey8a) or (A_ThisHotKey = Hotkey8o) { dir := Directions8 } else if (A_ThisHotKey = Hotkey9a) or (A_ThisHotKey = Hotkey9o) { dir := Directions9 } ;dir := Directions%dir% StringSplit, dir, dir, : ; Determine width/height factors. if (dir1 or dir2) { ; to a side widthFactor := dir1 ? 0.5 : 1.0 heightFactor := dir2 ? 0.5 : 1.0 } else { ; to center widthFactor := 0.5 heightFactor := 0.5 } ; Move the window! MoveWindowInDirection(dir1, dir2, widthFactor, heightFactor) return WP_SetLastFoundWindowByHotkey: ; Set Last Found Window. if (InStr(A_ThisHotkey, Prefix_Other)) WinPreviouslyActive() else WinExist("A") return ; "Maximize" DoMaximizeToggle: gosub WP_SetLastFoundWindowByHotkey WinGet, state, MinMax if minimizedId { WinRestore, ahk_id %minimizedId% minimizedId = 0 } else { if state WinRestore else WinMaximize } return ; "Minimize" DoMinimizeToggle: gosub WP_SetLastFoundWindowByHotkey WinGet, state, MinMax WinGet, active_id, ID, A if minimizedId { ; Msgbox minimizedId = %minimizedId% WinPreviouslyActive() if state { WinRestore, ahk_id %minimizedId% } minimizedId = 0 } else { ; Msgbox minimizedId = %minimizedId% if state >= 0 { minimizedId = %active_id% WinMinimize, ahk_id %minimizedId% } } return ; Does the grunt work of the script. MoveWindowInDirection(sideX, sideY, widthFactor, heightFactor, screenMoveOnly=false) { WinGetPos, x, y, w, h ; Determine which monitor contains the center of the window. m := GetMonitorAt(x+w/2, y+h/2) ; Get work area of active monitor. gosub CalcMonitorStats ; Calculate possible new position for window. gosub CalcNewPosition ; If the window is already there, if (newx "," newy "," neww "," newh) = (x "," y "," w "," h) { ; ..move to the next monitor along instead. if (sideX or sideY) { ; Move in the direction of sideX or sideY. SysGet, monB, Monitor, %m% ; get bounds of entire monitor (vs. work area) x := (sideX>0 ? monBRight : monBLeft) + sideX y := (sideY>0 ? monBBottom : monBTop) + sideY newm := GetMonitorAt(x, y, m) } else { ; Move to center (Numpad5) newm := m+1 SysGet, mon, MonitorCount if (newm > mon) newm := 1 } if (newm != m) { m := newm ; Move to opposite side of monitor (left of a monitor is another monitor's right edge) sideX *= -1 sideY *= -1 ; Get new monitor's work area. gosub CalcMonitorStats } ; Calculate new position for window. gosub CalcNewPosition } ; Restore before resizing... WinGet, state, MinMax if state WinRestore ; Finally, move the window! SetWinDelay, -1 WinMove,,, newx, newy, neww, newh return CalcNewPosition: ; Calculate new size. if (IsResizable()) { neww := Round(monWidth * widthFactor) newh := Round(monHeight * heightFactor) } else { neww := w newh := h } ; Calculate new position. newx := Round(monLeft + (sideX+1) * (monWidth - neww)/2) newy := Round(monTop + (sideY+1) * (monHeight - newh)/2) return CalcMonitorStats: ; Get work area (excludes taskbar-reserved space.) SysGet, mon, MonitorWorkArea, %m% monWidth := monRight - monLeft monHeight := monBottom - monTop return } ; Get the index of the monitor containing the specified x and y co-ordinates. GetMonitorAt(x, y, default=1) { y := 100 SysGet, m, MonitorCount ; Iterate through all monitors. Loop, %m% { ; Check if the window is on this monitor. SysGet, Mon, Monitor, %A_Index% if (x >= MonLeft && x <= MonRight && y >= MonTop && y <= MonBottom) return A_Index } return default } IsResizable() { WinGet, Style, Style return (Style & 0x40000) ; WS_SIZEBOX } ; Note: This may not work properly with always-on-top windows. (Needs testing) WinPreviouslyActive() { active := WinActive("A") WinGet, win, List ; Find the active window. ; (Might not be win1 if there are always-on-top windows?) Loop, %win% if (win%A_Index% = active) { if (A_Index < win) N := A_Index+1 ; hack for PSPad: +1 seems to get the document (child!) window, so do +2 ifWinActive, ahk_class TfPSPad N += 1 break } ; Use WinExist to set Last Found Window (for consistency with WinActive()) return WinExist("ahk_id " . win%N%) } ; ; Switch without moving/resizing (relative to screen) ; MoveWindowToNextScreen: gosub WP_SetLastFoundWindowByHotkey MoveWindowToNextScreen() return MoveWindowToNextScreen() { WinGetPos, x, y, w, h ; Determine which monitor contains the center of the window. ms := GetMonitorAt(x+w/2, y+h/2) ; Determine which monitor to move to. md := ms+1 SysGet, mon, MonitorCount if (md > mon) md := 1 ; This may happen if someone tries it with only one screen. :P if (md = ms) return ; Get source and destination work areas (excludes taskbar-reserved space.) SysGet, ms, MonitorWorkArea, %ms% SysGet, md, MonitorWorkArea, %md% msw := msRight - msLeft, msh := msBottom - msTop mdw := mdRight - mdLeft, mdh := mdBottom - mdTop ; Calculate new size. if (IsResizable()) { w *= (mdw/msw) h *= (mdh/msh) } SetWinDelay, -1 ; Move window, using resolution difference to scale co-ordinates. WinMove,,, mdLeft + (x-msLeft)*(mdw/msw), mdTop + (y-msTop)*(mdh/msh), w, h } ; ; "Gather" windows on a specific screen. ; GatherWindows(md=1) { SetWinDelay, -1 ; Makes a BIG difference to perceived performance. ; List all visible windows. WinGet, win, List ; Copy bounds of all monitors to an array. SysGet, mc, MonitorCount Loop, %mc% SysGet, mon%A_Index%, MonitorWorkArea, %A_Index% ; Destination monitor mdx := mon%md%Left mdy := mon%md%Top mdw := mon%md%Right - mdx mdh := mon%md%Bottom - mdy Loop, %win% { ; Set Last Found Window. if (!WinExist("ahk_id " . win%A_Index%)) continue WinGetPos, x, y, w, h ; Determine which monitor this window is on. xc := x+w/2, yc := y+h/2 ms := 1 Loop, %mc% if (xc >= mon%A_Index%Left && xc <= mon%A_Index%Right && yc >= mon%A_Index%Top && yc <= mon%A_Index%Bottom) { ms := A_Index break } ; If already on destination monitor, skip this window. if (ms = md) continue ; Source monitor msx := mon%ms%Left msy := mon%ms%Top msw := mon%ms%Right - msx msh := mon%ms%Bottom - msy ; If the window is resizable, scale it by the monitors' resolution difference. if (IsResizable()) { w *= (mdw/msw) h *= (mdh/msh) } ; Move window, using resolution difference to scale co-ordinates. WinMove,,, mdx + (x-msx)*(mdw/msw), mdy + (y-msy)*(mdh/msh), w, h } }