SlightlyKosumi
SlightlyKosumi

Reputation: 775

How to resize display resolution on windows with nim

I'd like to use nim to resize the default display resolution on a machine (windows 10 only), I want to basically do it via a command line call like setDisplay 1280 1024

I've seen and used the python example Resize display resolution using python with cross platform support which I can follow, but just can't translate. I just don't get how to fill in EnumDisplaySettings

import winim/lean
import strformat

var
  cxScreen = GetSystemMetrics(SM_CXSCREEN)
  cyScreen = GetSystemMetrics(SM_CYSCREEN)
  msg = fmt"The screen is {cxScreen} pixels wide by {cyScreen} pixels high."
EnumDisplaySettings(Null,0, 0) #total type mismatch

MessageBox(0, msg, "Winim Example Screen Size", 0)

Tried checking stuff like https://cpp.hotexamples.com/fr/examples/-/-/EnumDisplaySettings/cpp-enumdisplaysettings-function-examples.html but wasn't much help, same for https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-changedisplaysettingsa

Upvotes: 2

Views: 258

Answers (1)

SlightlyKosumi
SlightlyKosumi

Reputation: 775

I wrote about 2% of this answer myself, and the rest came from pointystick on discord - thanks to them! The solution is a bit lazy, but it's so fast that for most that won't matter. With no cmd line args it will just set the display to the default recommendation, else with 2 cmd line args it can reset your display if it finds a match

import winim/lean
import os
import strutils

var modeToFind = (width: 1920, height: 1080, bitsPerPixel: 32,
    refreshRate: 60)
var reset = 0

type ModeNotFoundError = object of CatchableError

proc getDisplayMode(): DEVMODEW =
  ## Finds the wanted screen resolution or raises a ModeNotFoundError.

  var
    nextMode: DWORD = 0
    mode: DEVMODEW

  while EnumDisplaySettings(nil, nextMode, mode) != 0:
    echo $mode.dmPelsWidth & " x " & $mode.dmPelsHeight &
        " x " & $mode.dmBitsPerPel &
        " - " & $mode.dmDisplayFrequency
    inc nextMode

    if (mode.dmPelsWidth == modeToFind.width) and
       (mode.dmPelsHeight == modeToFind.height):
      echo "Found it!"
      return mode

  if(reset==1):
    return mode
  raise newException(ModeNotFoundError, "Cannot find wanted screen mode")

proc changeResolution(): bool =
  ## Actually changes the resolution.  The return value indicates if it worked.
  result = false
  try:
    let wantedMode = getDisplayMode()
    result = ChangeDisplaySettings(wantedMode.unsafeAddr, 0.DWORD) == DISP_CHANGE_SUCCESSFUL
  except ModeNotFoundError: discard

when isMainModule:
  var
    cxScreen:int32 = 0 #= GetSystemMetrics(SM_CXSCREEN)
    cyScreen:int32 = 0 # = GetSystemMetrics(SM_CYSCREEN)

  try:
    cxScreen = (int32) parseInt(paramStr(1))
    cyScreen = (int32) parseInt(paramStr(2))
    modeToFind.width = cxScreen
    modeToFind.height = cyScreen
  except:
    reset = 1

  if not changeResolution():
    echo "Change Resolution Failed"

Upvotes: 2

Related Questions