Turning extended display on/off in Windows 10?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Lishtenbird
Posts: 2
Joined: 09 Aug 2016, 08:30

Turning extended display on/off in Windows 10?

09 Aug 2016, 08:45

I've been trying to create an AHK script to turn the secondary display on (extended) and off, and I cannot use the Win+P method or its shortcut because Windows identifies the last display (TV via HDMI) as 1, and the primary display as 2 while the secondary is 3.

There have been a lot of scripts on the forum, but most of them are old and do absolutely nothing on Autohotkey Unicode on Windows 10 x64 (anniversary edition patch), and so far this is the only script that does something:

Code: Select all

SysGet, Monitor, Monitor, %A_Index%
SysGet, MonitorWorkArea, MonitorWorkArea, %A_Index%
MsgBox, %MonitorRight% x %MonitorBottom%
 
ChangeDisplaySettings( (ClrDep:=32) , (Wid:=1920) , (Hei:=1080) , (Hz:=60) )
 
SysGet, Monitor, Monitor, %A_Index%
SysGet, MonitorWorkArea, MonitorWorkArea, %A_Index%
MsgBox, %MonitorRight% x %MonitorBottom%
 
ChangeDisplaySettings(cD, sW, sH, rR) {
  VarSetCapacity(dM,156,0)
  NumPut(156,dM,36)
  NumPut(0x5c0000,dM,40)
  NumPut(cD,dM,104)
  NumPut(sW,dM,108)
  NumPut(sH,dM,112)
  NumPut(rR,dM,120)
  DllCall( "ChangeDisplaySettingsA", UInt,&dM, UInt,0 )
}
It does change resolution via ChangeDisplaySettingsA, but apparently I need ChangeDisplaySettingsExA instead to extend/turn off other displays without changing resolution. Could anyone help me with getting the correct DllCall for it? I'm fine with hardcoding it.

Thanks in advance.
lexikos
Posts: 9690
Joined: 30 Sep 2013, 04:07
Contact:

Re: Turning extended display on/off in Windows 10?

10 Aug 2016, 04:26

When I had three screens connected, I found that Win+P seemed to remember whatever settings I changed in Control Panel. That is, I set "Second screen only" and then extended the desktop onto screen #3, and after that "Second screen only" always activated both screen #2 and screen #3 while "PC screen only" activated only screen #1.

I realize that's not what you're trying to achieve, but are you sure that Win+P won't work? Have you tried selecting a Win+P option, adjusting settings in Control Panel and swapping Win+P back and forth?

I used to have a hotkey that did what you want, but I forget which script it used. You can try either of the following, but they might not work (they were written in 2009 or earlier):

Code: Select all

; Enables, disables or toggles a display device.
;
; DeviceName:   The name of the device, e.g. \\.\DISPLAY1
;               Alternatively, it can be the index of the device, which might
;               not be the same as the number shown in Display Settings, since
;               it includes displays that aren't currently enabled.
; Action:       The action to take.
;                    0   Disable (false is synonymous with 0)
;                    1   Enable (true is synonymous with 1)
;                   -1   Toggle
; NoReset:      If true, settings will be saved to the registry, but not applied.
;
; The following can be used to apply settings saved in the registry:
;   DllCall("ChangeDisplaySettings", "uint", 0, "uint", 1)
;
; Return values:
;    DISP_CHANGE_SUCCESSFUL       0
;    DISP_CHANGE_RESTART          1
;    DISP_CHANGE_FAILED          -1
;    DISP_CHANGE_BADMODE         -2
;    DISP_CHANGE_NOTUPDATED      -3
;    DISP_CHANGE_BADFLAGS        -4
;    DISP_CHANGE_BADPARAM        -5
;
; Examples:
;   ; disable display 2
;     EnableDisplayDevice(2, false)
;     Sleep, 10000
; 
;   ; simultaneously enable display 2 and disable display 1
;     EnableDisplayDevice(2, true, true)
;     EnableDisplayDevice(1, false)
;     Sleep, 10000
; 
;   ; ensure both are enabled
;     EnableDisplayDevice(2, true, true)
;     EnableDisplayDevice(1)
;
EnableDisplayDevice(DeviceName, Action=1, NoReset=false)
{
    if (Action = -1) || (DeviceName+0 != "")
    {
        VarSetCapacity(DisplayDevice, 424), NumPut(424, DisplayDevice, 0)
        VarSetCapacity(ThisDeviceName, 32, 0)
        Index = 0
        Loop {
            if !DllCall("EnumDisplayDevices", "UInt", 0, "UInt", A_Index-1, "UInt", &DisplayDevice, "UInt", 0)
                return -5
            Index += 1
            DllCall("lstrcpynA", "Str", ThisDeviceName, "UInt", &DisplayDevice+4, "int", 32)
            if (DeviceName = Index || DeviceName = ThisDeviceName)
            {
                if Action = -1
                    Action := !(NumGet(DisplayDevice,164) & 1)
                DeviceName := ThisDeviceName
                break
            }
        }
    }
    VarSetCapacity(devmode, 156, 0), NumPut(156, devmode, 36, "UShort")
    if Action
        NumPut(0x000020, devmode, 40) ; Enable by setting position = {0,0}
    else
        NumPut(0x180020, devmode, 40) ; Disable by setting size = {0,0}, position = {0,0}
    err := DllCall("ChangeDisplaySettingsEx", "str", DeviceName, "uint", &devmode, "uint", 0, "uint", 0x10000001, "uint", 0)
    if !err && !NoReset
        err := DllCall("ChangeDisplaySettings", "uint", 0, "uint", 1)
    return err, ErrorLevel:=Action
}

Code: Select all

; if ! DisplayPosition_Get("\\.\DISPLAY1", x1, y1)
;     return
; if ! DisplayPosition_Get("\\.\DISPLAY2", x2, y2)
;     return
; 
; if (!x1 && !y1) ; DISPLAY1 is primary
;     DisplayPosition_Set("\\.\DISPLAY1", -x2, -y2)
; else
;     DisplayPosition_Set("\\.\DISPLAY2", -x1, -y1)


DisplayPosition_Set(device_name, x, y, defer=false)
{
    ; Prepare the DEVMODE structure.
    VarSetCapacity(devmode, 158, 0), NumPut(158, devmode, 0, "ushort")
    ; Get current display settings. -1=current, -2=registry
    DllCall("EnumDisplaySettings","str",device_name,"int",-1,"uint",&devmode)
    if ! NumGet(devmode, 108) ; dmPelsWidth (=0 means display is disabled)
    {
        DllCall("EnumDisplaySettings","str",device_name,"int",-2,"uint",&devmode)
        if ! NumGet(devmode, 108)
            DllCall("EnumDisplaySettings","str",device_name,"int",0,"uint",&devmode)
    }
    
    ; dmFlags |= DM_POSITION
    NumPut(NumGet(devmode,40)|0x20, devmode, 40)
        
    ; dmPosition.X := x, dmPosition.Y := y
    NumPut(x,devmode,44,"int"), NumPut(y,devmode,48,"int")

    err := DllCall("ChangeDisplaySettingsEx","str",device_name,"uint",&devmode,"uint",0,"uint",0x10000001,"uint",0)
    
    ; ChangeDisplaySettings() is called here for two reasons:
    ;   - A restart is otherwise required to enable a secondary display device.
    ;       See: http://support.microsoft.com/kb/308216
    ;   - Disabling display devices with just ChangeDisplaySettingsEx()
    ;     tends to leave them turned on.
    if (!err && !defer)
        err := DllCall("ChangeDisplaySettings", "uint", 0, "uint", 1)
    
    return err
}

DisplayPosition_Get(device_name, ByRef x, ByRef y)
{
    VarSetCapacity(devmode, 156, 0)
    if (DllCall("EnumDisplaySettings","str",device_name,"int",-1,"uint",&devmode))
    {
        x:=NumGet(devmode,44,"int"), y:=NumGet(devmode,48,"int")
        return true
    }
    return false
}

; Most important flags (second last parameter):
;    0            Change mode dynamically.
;    1            CDS_UPDATEREGISTRY - Change mode dynamically and save settings to registry.
;    0x10000001   CDS_NORESET - Save to registry but don't change mode yet.

; ChangeDisplaySettingsEx Return values:
;    DISP_CHANGE_SUCCESSFUL       0
;    DISP_CHANGE_RESTART          1
;    DISP_CHANGE_FAILED          -1
;    DISP_CHANGE_BADMODE         -2
;    DISP_CHANGE_NOTUPDATED      -3
;    DISP_CHANGE_BADFLAGS        -4
;    DISP_CHANGE_BADPARAM        -5
I probably won't be of any further help (by choice) since this particular API gives me a headache.
Lishtenbird
Posts: 2
Joined: 09 Aug 2016, 08:30

Re: Turning extended display on/off in Windows 10?

10 Aug 2016, 06:59

lexikos wrote:I probably won't be of any further help (by choice) since this particular API gives me a headache.
Thanks for replying anyway! Unfortunately, neither of those do anything.

But to anyone from the future who stumble upon this page, here's an alternative fast, free and lightweight solution:
  • 2. Run MonitorSwitcherGUI.exe and create the profiles you need (Single and Dual in my case); close the GUI, you won't need it anymore
  • 3. Add the following code to your AHK hotkey/separate file (add #NoTrayIcon in the latter case to avoid flashing the AHK tray icon) for each profile name:

Code: Select all

Run, C:\YOURPATH\MonitorProfileSwitcher\MonitorSwitcher.exe -load:C:\Users\USERNAME\AppData\Roaming\MonitorSwitcher\Profiles\GUICREATEDPROFILENAME.xml, , Hide,
  • 4. Enjoy easy monitor switching without DLL calls and extra programs that run in the background!
chaoscreater
Posts: 60
Joined: 12 Sep 2019, 21:15

Re: Turning extended display on/off in Windows 10?

02 Apr 2024, 20:29

Lishtenbird wrote:
10 Aug 2016, 06:59
lexikos wrote:I probably won't be of any further help (by choice) since this particular API gives me a headache.
Thanks for replying anyway! Unfortunately, neither of those do anything.

But to anyone from the future who stumble upon this page, here's an alternative fast, free and lightweight solution:
  • 2. Run MonitorSwitcherGUI.exe and create the profiles you need (Single and Dual in my case); close the GUI, you won't need it anymore
  • 3. Add the following code to your AHK hotkey/separate file (add #NoTrayIcon in the latter case to avoid flashing the AHK tray icon) for each profile name:

Code: Select all

Run, C:\YOURPATH\MonitorProfileSwitcher\MonitorSwitcher.exe -load:C:\Users\USERNAME\AppData\Roaming\MonitorSwitcher\Profiles\GUICREATEDPROFILENAME.xml, , Hide,
  • 4. Enjoy easy monitor switching without DLL calls and extra programs that run in the background!
You are a legend! Just want to say thank you for sharing this. For the better part of the past 3 years or so, I've been looking and trying out different solutions. I've used DisplayFusion, various AHK scripts and tools, all to achieve one very simple thing. At my job, we have a hot-desk setup. Anyone can sit at any desk and each desk may have 2~3 monitors. Due to the different monitors per desk, it means that Windows will pick them up as new monitors and lose the existing configuration you have. Even if the monitors are the same brand across the desks, they have different serial numbers and so Windows will always recognize them as a new monitor. Of course, Windows will remember your configuration once you've connected to them and made changes in your display settings, but the first time you connect, it's always going to lose settings.

Basically, my daily routine will be to fix the monitor configuration. I have to set them to extend, change the scaling, change the resolution, change the monitor order, etc. It's just a waste of time. The tool you've found allows me to apply the profile very quickly and easily and saves me so much time! Thanks again.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot] and 384 guests