#NoEnv #SingleInstance Force #Persistent ; Retrieve user-set resolutions or fall back on defaults RegRead, ResolutionsString, HKEY_CURRENT_USER\Software\JohnAJ\DRM, Resolutions if (ErrorLevel = 1) { ResolutionsString = 1600x1200|1024x768|800x600|640x480 ; 4:3 if (A_ScreenWidth/A_ScreenHeight = 1.6) ResolutionsString = 1920x1200|1680x1050|1440x900|1280x800 ; 16:10 if (Round(A_ScreenWidth/A_ScreenHeight, 2) = 1.77) ResolutionsString = 1920x1080|1366x768|1280x720|854x480 ; 16:9 RegWrite, REG_SZ, HKEY_CURRENT_USER\Software\JohnAJ\DRM, Resolutions, %ResolutionsString% } Resolutions := StrSplit(ResolutionsString, "|") ; Retrieve user-set exceptions RegRead, IgnoreString, HKEY_CURRENT_USER\Software\JohnAJ\DRM, Ignore IgnoreString := "|" IgnoreString ; leading pipe for easy string matching if (ErrorLevel = 1) { IgnoreString = "" RegWrite, REG_SZ, HKEY_CURRENT_USER\Software\JohnAJ\DRM, Ignore, % "" } RegRead, IgnoreSizeString, HKEY_CURRENT_USER\Software\JohnAJ\DRM, IgnoreSize IgnoreSizeString := "|" IgnoreSizeString ; leading pipe for easy string matching if (ErrorLevel = 1) { IgnoreSizeString = "" RegWrite, REG_SZ, HKEY_CURRENT_USER\Software\JohnAJ\DRM, IgnoreSize, % "" } ; Set up tray menu Menu, Tray, NoStandard Menu, Tray, Tip, Dynamic Resolution Manager for k, res in Resolutions Menu, Tray, Add, %res%, SelectMenuResolution Menu, Tray, Add Menu, Tray, Add, &Configure..., Configure Menu, Tray, Add, E&xit, ButtonExit return ButtonExit: ExitApp ; Open configuration Configure() { RegWrite, REG_SZ, HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit, LastKey, HKEY_CURRENT_USER\Software\JohnAJ\DRM Run, regedit /m } ; Select resolution from tray menu SelectMenuResolution(ItemName, ItemPos, MenuName) { ResArray := StrSplit(ItemName, "x") SwitchToResolutionFrom(ResArray[1], ResArray[2], A_ScreenWidth, A_ScreenHeight) } ; Save window positions, switch to given resolution, restore window positions SwitchToResolutionFrom(WidthNew, HeightNew, WidthOrig, HeightOrig) { Positions := {} Save(Positions) SetResolution(WidthNew, HeightNew) Sleep, 500 Restore(Positions) TrayTip, Resolution changed, % "Press Escape within 3 seconds to revert." KeyWait, Esc, D T3 TrayTip if (ErrorLevel = 1) ; user didn't press escape return SetResolution(%WidthOrig%, %HeightOrig%) Sleep, 500 Restore(Positions) } Save(ByRef Positions) { global IgnoreString global IgnoreSizeString Positions := {} WinGet, id, list SysGet, WorkArea, MonitorWorkArea Width := WorkAreaRight - WorkAreaLeft Height := WorkAreaBottom - WorkAreaTop Loop, %id% { i := id%A_Index% WinReallyGetPos(i, x, y, w, h) WinGet, exe, ProcessName, ahk_id %i% ; Ignore position and size (2) if (InStr(IgnoreString, "|" exe)) Positions[i] := [x, y, w, h, 2, 0] ; Ignore size, but retain position (1) else if (InStr(IgnoreSizeString, "|" exe)) { rx := x / Width ry := y / Height ; Calculate position relative to right/bottom if necessary Align := 1 ; to align right, this should be divisible by 3; bottom, by 5 if (x > Width / 2) { Align := Align * 3 rx := (Width - (x + w)) / Width } if (y > Height / 2) { Align := Align * 5 ry := (Height - (y + h)) / Height } Positions[i] := [rx, ry, w, h, 1, Align] } ; Retain position and size (0) else Positions[i] := [x / Width, y / Height, w / Width, h / Height, 0, 0] } } Restore(Positions) { SysGet, WorkArea, MonitorWorkArea Width := WorkAreaRight - WorkAreaLeft Height := WorkAreaBottom - WorkAreaTop for i, props in Positions { x := props[1] y := props[2] w := props[3] h := props[4] if (props[5] = 2) ; ignore position and size WinReallyMove(i, x, y, w, h) else if (props[5] = 1) ; ignore size, but retain position { rx := x * Width ry := y * Height if (Mod(props[6], 3) = 0) ; align right rx := Width - rx - w if (Mod(props[6], 5) = 0) ; align bottom ry := Height - ry - h WinReallyMove(i, rx, ry, w, h) } else ; retain position and size WinReallyMove(i, x * Width, y * Height, w * Width, h * Height) } } ; Set screen resolution SetResolution(Width, Height, ColorDepth := 32) { VarSetCapacity(DeviceMode, 156, 0) NumPut(156, DeviceMode, 36) DllCall("EnumDisplaySettingsA", UInt, 0, UInt, -1, UInt, &DeviceMode) NumPut(0x5c0000, DeviceMode, 40) NumPut(ColorDepth, DeviceMode, 104) NumPut(Width, DeviceMode, 108) NumPut(Height, DeviceMode, 112) DllCall("ChangeDisplaySettingsA", UInt, &DeviceMode, UInt, 0) } ; Get position of any window, even a minimized one WinReallyGetPos(hwnd, ByRef x, ByRef y, ByRef w="", ByRef h="") { VarSetCapacity(wp, 44), NumPut(44, wp) DllCall("GetWindowPlacement", "uint", hwnd, "uint", &wp) x := NumGet(wp, 28, "int") y := NumGet(wp, 32, "int") w := NumGet(wp, 36, "int") - x h := NumGet(wp, 40, "int") - y } ; Set position of any window, even a minimized one WinReallyMove(hwnd, x, y, w, h) { VarSetCapacity(wp, 44, 0), NumPut(44, wp, "uint") NumPut(5, wp, 8, "uint") NumPut(x, wp, 28, "int") NumPut(y, wp, 32, "int") NumPut(w + x, wp, 36, "int") NumPut(h + y, wp, 40, "int") DllCall("SetWindowPlacement", "ptr", hwnd, "ptr", &wp) }