drm / 1.2 / drm.ahk 201 lines  5.33 kB  Raw
#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, E&xit, ButtonExit
return

ButtonExit:
ExitApp

; 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)
}