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.