#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, Icon, % "HBITMAP:*" . Create_tray_ico() Menu, Tray, Tip, Dynamic Resolution Manager for k, res in Resolutions if (res = "") Menu, Tray, Add else Menu, Tray, Add, %res%, ButtonResolution Menu, Tray, Add Menu, Tray, Add, &Configure..., ButtonConfigure Menu, Tray, Add, E&xit, ButtonExit AddCheckmark() OnMessage(0x404, "NotifyIcon") return ButtonExit: ExitApp ButtonRestart: Reload return ; Handle tray opening NotifyIcon(wParam, lParam) { if (lParam = 0x205) ; WM_RBUTTONUP { Menu, Tray, UseErrorLevel Menu, Tray, Delete, &Restart Menu, Tray, Delete, E&xit Menu, Tray, UseErrorLevel, Off if (GetKeyState("Shift") = 1) Menu, Tray, Add, &Restart, ButtonRestart else Menu, Tray, Add, E&xit, ButtonExit Menu, Tray, Show return 1 } } ; Open configuration ButtonConfigure() { 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 ButtonResolution(ItemName, ItemPos, MenuName) { w := 0 h := 0 r := 0 for k, v in StrSplit(ItemName, " ") { if (k = 1) { a := StrSplit(v, "x") w := a[1] h := a[2] } else if ("Hz" = SubStr(v, StrLen(v) - 1)) r := SubStr(v, 1, StrLen(v) - 2) } if (w = 0 or h = 0) MsgBox, Invalid width or height new := {width: w, height: h, rate: r, depth: 32} old := Get() SwitchResolution(new, old) } ; Add checkmark to current resolution (if available) AddCheckmark(res := 0) { if (res = 0) res := Get() Menu, Tray, UseErrorLevel Menu, Tray, Check, % res.width "x" res.height " " res.rate "Hz" if (ErrorLevel = 1) Menu, Tray, Check, % res.width "x" res.height Menu, Tray, UseErrorLevel, Off } RemoveCheckmark(res := 0) { if (res = 0) res := Get() Menu, Tray, UseErrorLevel Menu, Tray, Uncheck, % res.width "x" res.height " " res.rate "Hz" if (ErrorLevel = 1) Menu, Tray, Uncheck, % res.width "x" res.height Menu, Tray, UseErrorLevel, Off } ; Save window positions, switch to given resolution, restore window positions SwitchResolution(new, old) { Positions := {} Save(Positions) Set(new) Sleep, 500 Restore(Positions) RemoveCheckmark(old) AddCheckmark(new) TrayTip, Resolution changed, % "Press Escape within 3 seconds to revert." KeyWait, Esc, D T3 TrayTip if (ErrorLevel = 1) ; user didn't press escape return Set(old) Sleep, 500 Restore(Positions) RemoveCheckmark(new) AddCheckmark(old) } Save(ByRef Positions) { global IgnoreString global IgnoreSizeString Positions := {} WinGet, id, list SysGet, WorkArea, MonitorWorkArea wa := { w: WorkAreaRight - WorkAreaLeft, h: WorkAreaBottom - WorkAreaTop } Loop, %id% { i := id%A_Index% p := {} DoIgnore := DoIgnoreSize := false WinReallyGetPos(i, x, y, w, h) WinGet, exe, ProcessName, ahk_id %i% SysGet, bx, 32 ; window border thickness (x) SysGet, by, 33 ; window border thickness (y) cw := w - bx * 2 ; client width ch := h - by * 2 ; client height ; Custom rules ; Example: ; if (exe = "mpc-hc.exe" and cw = 294) ; DoIgnoreSize := true ; Ignore position and size (2) if (DoIgnore or InStr(IgnoreString, "|" exe)) p := {x: x, y: y, w: w, h: h, ignore: 2, align: 0} ; Ignore size, but retain position (1) else if (DoIgnoreSize or InStr(IgnoreSizeString, "|" exe)) { p.ignore := 1 p.w := w p.h := h p.x := x / wa.w p.y := y / wa.h ; Re-calculate position relative to right/bottom if necessary p.align := 1 ; to align right, this should be divisible by 3; bottom, by 5 if (x > wa.w - (x + w)) { p.align := p.align * 3 p.x := (wa.w - (x + w)) / wa.w } if (y > wa.h - (y + h)) { p.align := p.align * 5 p.y := (wa.h - (y + h)) / wa.h } } ; Retain position and size (0) else p := {x: x / wa.w, y: y / wa.h, w: w / wa.w, h: h / wa.h, ignore: 0, align: 0} Positions[i] := p } } Restore(Positions) { SysGet, WorkArea, MonitorWorkArea wa := { w: WorkAreaRight - WorkAreaLeft, h: WorkAreaBottom - WorkAreaTop } for i, p in Positions { if (p.ignore = 2) ; ignore position and size WinReallyMove(i, p.x, p.y, p.w, p.h) else if (p.ignore = 1) ; ignore size, but retain position { x := p.x * wa.w y := p.y * wa.h if (Mod(p.align, 3) = 0) ; align right x := wa.w - x - p.w if (Mod(p.align, 5) = 0) ; align bottom y := wa.h - y - p.h WinReallyMove(i, x, y, p.w, p.h) } else ; retain position and size WinReallyMove(i, p.x * wa.w, p.y * wa.h, p.w * wa.w, p.h * wa.h) } } ; Set screen resolution Set(res) { VarSetCapacity(DeviceMode, 156, 0) NumPut(156, DeviceMode, 36) DllCall("EnumDisplaySettingsA", UInt, 0, UInt, -1, UInt, &DeviceMode) NumPut(0x5c0000, DeviceMode, 40) NumPut(res.depth, DeviceMode, 104) NumPut(res.width, DeviceMode, 108) NumPut(res.height, DeviceMode, 112) if (res.rate > 0) NumPut(res.rate, DeviceMode, 120) DllCall("ChangeDisplaySettingsA", UInt, &DeviceMode, UInt, 0) } ; Get screen resolution Get() { VarSetCapacity(DeviceMode, 156, 0) NumPut(156, DeviceMode, 36) DllCall("EnumDisplaySettingsA", UInt, 0, UInt, -1, UInt, &DeviceMode) w := NumGet(&DeviceMode, 108, "uint4") h := NumGet(&DeviceMode, 112, "uint4") d := NumGet(&DeviceMode, 104, "uint4") r := NumGet(&DeviceMode, 120, "uint4") return {width: w, height: h, depth: d, rate: r} } ; 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) } ; ################################################################################## ; # This #Include file was generated by Image2Include.ahk, you must not change it! # ; ################################################################################## Create_tray_ico(NewHandle := False) { Static hBitmap := 0 If (NewHandle) hBitmap := 0 If (hBitmap) Return hBitmap VarSetCapacity(B64, 2984 << !!A_IsUnicode) B64 := "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" If !DllCall("Crypt32.dll\CryptStringToBinary", "Ptr", &B64, "UInt", 0, "UInt", 0x01, "Ptr", 0, "UIntP", DecLen, "Ptr", 0, "Ptr", 0) Return False VarSetCapacity(Dec, DecLen, 0) If !DllCall("Crypt32.dll\CryptStringToBinary", "Ptr", &B64, "UInt", 0, "UInt", 0x01, "Ptr", &Dec, "UIntP", DecLen, "Ptr", 0, "Ptr", 0) Return False ; Bitmap creation adopted from "How to convert Image data (JPEG/PNG/GIF) to hBITMAP?" by SKAN ; -> http://www.autohotkey.com/board/topic/21213-how-to-convert-image-data-jpegpnggif-to-hbitmap/?p=139257 hData := DllCall("Kernel32.dll\GlobalAlloc", "UInt", 2, "UPtr", DecLen, "UPtr") pData := DllCall("Kernel32.dll\GlobalLock", "Ptr", hData, "UPtr") DllCall("Kernel32.dll\RtlMoveMemory", "Ptr", pData, "Ptr", &Dec, "UPtr", DecLen) DllCall("Kernel32.dll\GlobalUnlock", "Ptr", hData) DllCall("Ole32.dll\CreateStreamOnHGlobal", "Ptr", hData, "Int", True, "PtrP", pStream) hGdip := DllCall("Kernel32.dll\LoadLibrary", "Str", "Gdiplus.dll", "UPtr") VarSetCapacity(SI, 16, 0), NumPut(1, SI, 0, "UChar") DllCall("Gdiplus.dll\GdiplusStartup", "PtrP", pToken, "Ptr", &SI, "Ptr", 0) DllCall("Gdiplus.dll\GdipCreateBitmapFromStream", "Ptr", pStream, "PtrP", pBitmap) DllCall("Gdiplus.dll\GdipCreateHBITMAPFromBitmap", "Ptr", pBitmap, "PtrP", hBitmap, "UInt", 0) DllCall("Gdiplus.dll\GdipDisposeImage", "Ptr", pBitmap) DllCall("Gdiplus.dll\GdiplusShutdown", "Ptr", pToken) DllCall("Kernel32.dll\FreeLibrary", "Ptr", hGdip) DllCall(NumGet(NumGet(pStream + 0, 0, "UPtr") + (A_PtrSize * 2), 0, "UPtr"), "Ptr", pStream) Return hBitmap }