 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Goodfare Guest
|
Posted: Mon Aug 06, 2007 1:19 am Post subject: Secondary Monitor |
|
|
Is it possible to enable/disable a secondary monitor using a hotkey?
If so can someone please explain. |
|
| Back to top |
|
 |
Superfraggle
Joined: 02 Nov 2004 Posts: 901 Location: London, UK
|
Posted: Mon Aug 06, 2007 6:08 am Post subject: |
|
|
This can be done by one of two methods I believe
1st would be by automating the usual process of enabling the second monitor, script recorder could make a basic one.
2nd would be several dll calls I believe
EnumDisplayDevices
and
ChangeDisplaySettingsEx
I am still learning the dllcalls side so the second is beyond me  _________________ Steve F AKA Superfraggle
http://r.yuwie.com/superfraggle |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2589 Location: Australia, Qld
|
Posted: Wed Aug 08, 2007 9:41 am Post subject: |
|
|
I figured out how to enable a monitor by using ChangeDisplaySettingsEx, but not how to disable it. Fortunately there is a solution using RegWrite. The following script should disable or enable the secondary monitor when run. (To be more accurate, it disables or enables the "Extend the desktop onto this monitor" setting.)
| Code: | ;
; AutoHotkey Version: 1.0.47.02
; Language: English
; Platform: Win9x/NT ??
; Author: Lexikos
;
; Script Function:
; Enable or disable a secondary monitor. ("Extend the desktop onto this monitor")
;
#NoEnv
#NoTrayIcon
GetDisplayDeviceList("Display", false)
if Display2
{
RegRead, Attached, HKEY_CURRENT_CONFIG
, System\CurrentControlSet\Control\VIDEO\%Display2ID%\0001
, Attach.ToDesktop
; This part is in case I get the Display..ID wrong,
; so I don't write junk into the registry.
if (ErrorLevel) {
MsgBox, Error getting display attached status.
return
}
Attached := ! Attached
RegWrite, REG_DWORD, HKEY_CURRENT_CONFIG
, System\CurrentControlSet\Control\VIDEO\%Display2ID%\0001
, Attach.ToDesktop
, %Attached%
; Apply display settings from registry.
DllCall("ChangeDisplaySettings", "UInt", 0, "UInt", 0)
}
ExitApp
; Creates a global array using ArrayName as the base.
; %ArrayName% Number of display devices.
; %ArrayName%Primary The index of the primary display device.
; %ArrayName%%N% Name of display device (used by ChangeDisplaySettingsEx.)
; %ArrayName%%N%ID {GUID} value required for some registry operations.
; Only set if DesktopOnly=false:
; %ArrayName%%N%Attached =1 if "Extend the desktop onto this monitor" is enabled.
GetDisplayDeviceList(ArrayName, DesktopOnly=true)
{
local DisplayDevice, Count, DeviceName, StateFlags, DeviceKey
; DISPLAY_DEVICE DisplayDevice
VarSetCapacity(DisplayDevice, 424)
; lpDisplayDevice.cb := sizeof(DISPLAY_DEVICE)
NumPut(424, DisplayDevice, 0)
if %ArrayName%Primary
%ArrayName%Primary =
VarSetCapacity(DeviceName, 32, 0)
VarSetCapacity(DeviceKey , 128, 0)
Loop
{
if ! DllCall("EnumDisplayDevices"
, "UInt", 0 ; lpDevice (NULL: use iDevNum to identify devices)
, "UInt", A_Index-1 ; iDevNum
, "UInt", &DisplayDevice ; lpDisplayDevice
, "UInt", 0) ; dwFlags
break
StateFlags := NumGet(DisplayDevice, 164)
; Useful DISPLAY_DEVICE.StateFlags:
; #define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001
; #define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004
; #define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008
if (StateFlags & 8) ; always exclude pseudo-devices
continue
if (DesktopOnly && !(StateFlags & 1))
continue
Count += 1
DllCall("lstrcpynA", "Str", DeviceName , "UInt", &DisplayDevice+4 , "int", 32)
DllCall("lstrcpynA", "Str", DeviceKey , "UInt", &DisplayDevice+296, "int", 128)
%ArrayName%%Count% := DeviceName
; DeviceKey is something like:
; \Registry\Machine\System\CurrentControlSet\Control\Video\{device-specific-value}\0000
; We want the:
; {device-specific-value}
SplitPath, DeviceKey,, DeviceKey ; "up one level"
SplitPath, DeviceKey, %ArrayName%%Count%ID
if (StateFlags & 4)
%ArrayName%Primary := Count
if (!DesktopOnly)
%ArrayName%%Count%Attached := (StateFlags&1)
; else: function only returns attached monitors, no need for %..%Attached.
}
%ArrayName% := Count
} |
If the GetDisplayDeviceList() function seems overly complex, that's probably because it's not specifically written for this script. For the RegWrite solution, it's only required because different display devices need a different path in the registry.
Note the "\0001" part of the registry key is the four digit zero-based index of the monitor.
Also, this won't necessarily work the same on all multi-monitor setups. It should at least work on any setups where one graphics card is powering multiple monitors. |
|
| Back to top |
|
 |
novis Guest
|
Posted: Sun Sep 30, 2007 3:12 pm Post subject: |
|
|
i think this is what im looking for. could you show how to bind a hotkey to this function? thanks
also is it possible to switch off primary and switch to secondary instead of extend? |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2589 Location: Australia, Qld
|
Posted: Mon Oct 01, 2007 4:00 am Post subject: |
|
|
The registry-editing approach doesn't work for the primary monitor. Since my last post, I've figured out how to use ChangeDisplaySettingsEx to enable or disable a display device. Unfortunately it doesn't preserve the position(s) of the display(s).
For instance, if I disable and re-enable my secondary display, it will move from the right side of my primary to the left side. (If it's already on the left side, it should stay where it is.) Disabling and re-enabling my primary display seems to work without problems, though.
The hotkeys I use are:
| Code: | #+NumpadMult::EnableDisplayDevice("\\.\DISPLAY1", -1) ; toggle primary
#+NumpadDiv::EnableDisplayDevice("\\.\DISPLAY2", -1) ; toggle secondary | Since the device names might be different, this might not work for you. If that is the case, let me know and I'll post a (better) function for getting the right device name (or you could use GetDisplayDeviceList() from my previous post.)
EnableDisplayDevice.ahk: | Code: | ; Enables, disables or toggles a display device.
;
; DeviceName: The name of the device, e.g. \\.\DISPLAY1
; Action: The action to take.
; 0 Disable
; 1 Enable
; -1 Toggle (may not be reliable if NoReset=true)
; 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("\\.\DISPLAY2", 0)
; Sleep, 10000
;
; ; simultaneously enable display 2 and disable display 1
; EnableDisplayDevice("\\.\DISPLAY2", 1, true)
; EnableDisplayDevice("\\.\DISPLAY1", 0)
; Sleep, 10000
;
; ; ensure both are enabled
; EnableDisplayDevice("\\.\DISPLAY2", 1, true)
; EnableDisplayDevice("\\.\DISPLAY1")
;
; Note: DeviceNames may vary. Rather than hard-coding the device name,
; EnumDisplayDevices() should be used to enumerate the devices.
;
EnableDisplayDevice(DeviceName, Action=1, NoReset=false)
{
if (Action = -1)
{ ; Determine if the display should be enabled or disabled.
Loop {
if ! EnumDisplayDevices(A_Index, this_name, this_state)
break
if (this_name = DeviceName) {
Action := !(this_state & 1) ; DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
break
}
}
; If Action is still -1, an invalid DeviceName was specified.
; The script will attempt to enable the display device, but
; ChangeDisplaySettingsEx() will most likely return error -5.
}
VarSetCapacity(devmode, 156, 0)
NumPut(156, devmode, 36, "UShort")
; Set DEVMODE.dmFields to indicate which fields are valid.
if (Action) ; Enable
NumPut(0x000020, devmode, 40) ; position={0,0}
else ; Disable
NumPut(0x180020, devmode, 40) ; width=0, height=0, position={0,0}
; Since CDS_NORESET is specified here, if NoReset=true, the user must
; manually call ChangeDisplaySettings(NULL,1) or restart the computer.
err := DllCall("ChangeDisplaySettingsEx", "str", DeviceName
, "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 && !NoReset)
err := DllCall("ChangeDisplaySettings", "uint", 0, "uint", 1)
return err
}
|
I have it saved as EnableDisplayDevice.ahk in my user library, so that no #include is necessary.
To bind my previous script to a hotkey (to toggle the secondary display), simply put the hotkey (e.g. #+NumpadMult::) before | Code: | | GetDisplayDeviceList("Display", false) | and return instead of ExitApp. |
|
| Back to top |
|
 |
novis Guest
|
Posted: Tue Oct 02, 2007 6:07 pm Post subject: |
|
|
| Quote: | #+NumpadMult::EnableDisplayDevice("\\.\DISPLAY1", -1) ; toggle primary
#+NumpadDiv::EnableDisplayDevice("\\.\DISPLAY2", -1) ; toggle secondary |
thank you
| Quote: | | Unfortunately it doesn't preserve the position(s) of the display(s). |
np in my case. i got a plasma on dvi#2 for movies so i dont want the primary display to be on at all after the switch.
My matrox driver only let me Extend even though they call it "independent mode". With my old quadro card and nvidia driver i could simple choose to switch to the other display ie change output from DVI1 to DVI2... such a simple task must be possible? |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2589 Location: Australia, Qld
|
Posted: Wed Oct 03, 2007 1:24 am Post subject: |
|
|
| novis wrote: | | My matrox driver only let me Extend even though they call it "independent mode". With my old quadro card and nvidia driver i could simple choose to switch to the other display ie change output from DVI1 to DVI2... such a simple task must be possible? | You mean have only one display on at a time? There's an expample in the comments of my script how to simultaneously enable one display and disable the other (i.e. swap.) |
|
| Back to top |
|
 |
novis Guest
|
Posted: Wed Oct 03, 2007 5:24 am Post subject: |
|
|
yes thats what i need! its a nice script ..i just need it to work.
i get a error enumerating the device. how do i hardcode it for my display? or do u know what might be the problem?
| Quote: | | --> if ! EnumDisplayDevices(A_Index, this_name, this_state) |
|
|
| Back to top |
|
 |
engunneer
Joined: 30 Aug 2005 Posts: 6804 Location: Pacific Northwest, US
|
Posted: Wed Oct 03, 2007 8:03 am Post subject: |
|
|
what is the error? function not found or some syntax issue? what version of ahk are you using? _________________
Unless otherwise noted, all code is untested.
Common Answers: 1.(Loops, Viruses, etc.) 2. Search 3.RTFM |
|
| Back to top |
|
 |
tic
Joined: 22 Apr 2007 Posts: 1364
|
Posted: Wed Oct 03, 2007 10:48 am Post subject: |
|
|
i recommend just using wizmo:
http://www.grc.com/wizmo/wizmo.htm
and putting it in the same folder as your ahk, and then just running it with the argument to turn off your 2nd monitor. |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2589 Location: Australia, Qld
|
Posted: Wed Oct 03, 2007 1:28 pm Post subject: |
|
|
| novis wrote: | | i get a error enumerating the device. how do i hardcode it for my display? or do u know what might be the problem? | You need EnumDisplayDevices, which I hadn't posted.
| Code: | ; EnumDisplayDevices(Index [, ByRef Name, ByRef StateFlags ] )
;
; Index: One-based index of device to get info for.
; DeviceName: [out] The name of the device.
; StateFlags: [out] Any reasonable combination of the following flags:
; 0x00000001 DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
; 0x00000004 DISPLAY_DEVICE_PRIMARY_DEVICE
; 0x00000008 DISPLAY_DEVICE_MIRRORING_DRIVER
; DeviceKey: [out] Path to the device's registry key relative to HKEY_LOCAL_MACHINE.
;
; Returns true if the display device exists, otherwise false.
;
/* Example 1 (requires EnableDisplayDevice()):
SecondaryDevice =
count = 0
Loop {
if ! EnumDisplayDevices(A_Index, DeviceName, StateFlags)
break
if !(StateFlags & 8) ; not a pseudo-device
if (++count = 2) ; second device
break
}
if DeviceName
EnableDisplayDevice(DeviceName, -1) ; toggle
*/
/* Example 2:
Loop {
if ! EnumDisplayDevices(A_Index, DeviceName, StateFlags)
break
if (StateFlags & 4)
text .= DeviceName " is the primary display device.`n"
else if (StateFlags & 1)
text .= "The desktop extends onto " DeviceName ".`n"
if (StateFlags & 8)
text .= DeviceName " is a pseudo-device.`n"
}
MsgBox %text%
*/
EnumDisplayDevices(Index, ByRef DeviceName, ByRef StateFlags="", ByRef DeviceKey="")
{
; DISPLAY_DEVICE DisplayDevice
VarSetCapacity(DisplayDevice, 424)
; lpDisplayDevice.cb := sizeof(DISPLAY_DEVICE)
NumPut(424, DisplayDevice, 0)
VarSetCapacity(DeviceName, 32, 0)
VarSetCapacity(DeviceKey, 128, 0)
; For consistency, clear StateFlags in case of failure.
StateFlags = 0
if ! DllCall("EnumDisplayDevices"
, "UInt", 0
, "UInt", Index-1
, "UInt", &DisplayDevice
, "UInt", 0)
return false
StateFlags := NumGet(DisplayDevice, 164)
DllCall("lstrcpynA", "Str", DeviceName, "UInt", &DisplayDevice+4, "int", 32)
DllCall("lstrcpynA", "Str", DeviceKey, "UInt", &DisplayDevice+296, "int", 128)
if (SubStr(DeviceKey,1,18)="\Registry\Machine\")
DeviceKey := SubStr(DeviceKey,19)
return true
}
| Example 2 (in the comments) can be used to list all of the display devices. |
|
| Back to top |
|
 |
novis Guest
|
Posted: Wed Oct 03, 2007 3:31 pm Post subject: |
|
|
| just got back from work so i havent tested anything yet but thanks everyone helping me out. Nice community! |
|
| Back to top |
|
 |
novis Guest
|
Posted: Wed Oct 03, 2007 5:30 pm Post subject: |
|
|
this might be too much for my fragile little mind ...how should i use example2 in the EnumDisplayDevices-code, replace it in the 2nd script?
Is this a pseudo/place-holding-name that i should replace: \\.\DISPLAY1 ?
should i un-comment anything before i can run it?
-----
Version 1.0.47.04 of AHK
Winxp sp2
Matrox p650 pci-e |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2589 Location: Australia, Qld
|
Posted: Thu Oct 04, 2007 4:25 am Post subject: |
|
|
No, \\.\DISPLAY1 is an actual display device name. EnumDisplayDevices Example 2 outputs this on my system: | Quote: | \\.\DISPLAY1 is the primary display device.
The desktop extends onto \\.\DISPLAY2.
\\.\DISPLAYV1 is a pseudo-device.
\\.\DISPLAYV2 is a pseudo-device. | \\.\DISPLAY1 is my primary display, while \\.\DISPLAY2 is my secondary. \\.\DISPLAYV1 and \\.\DISPLAYV2 are "mirroring drivers," i.e. they don't exist. It may be possible for the desktop to extend onto a pseudo-device, in which case the script would output something like: | Quote: | The desktop extends onto \\.\DISPLAYV1.
\\.\DISPLAYV1 is a pseudo-device. | The exact code I use for my hotkeys is just what I wrote in my previous post: | Code: | #+NumpadMult::EnableDisplayDevice("\\.\DISPLAY1", -1)
#+NumpadDiv::EnableDisplayDevice("\\.\DISPLAY2", -1) | \\.\DISPLAY1 is a display device name, and -1 means "toggle." 0 is disable, and 1 is enable. |
|
| Back to top |
|
 |
novis Guest
|
Posted: Thu Oct 04, 2007 4:58 am Post subject: |
|
|
damn. then it doesnt work for me :/
just to be sure. i got this in a new .ahk and i press: LWin+*, LWin+\ (on Numpad)
| Code: |
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#+NumpadMult::EnableDisplayDevice("\\.\DISPLAY1", -1)
#+NumpadDiv::EnableDisplayDevice("\\.\DISPLAY2", -1)
; EnumDisplayDevices(Index [, ByRef Name, ByRef StateFlags ] )
;
; Index: One-based index of device to get info for.
; DeviceName: [out] The name of the device.
; StateFlags: [out] Any reasonable combination of the following flags:
; 0x00000001 DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
; 0x00000004 DISPLAY_DEVICE_PRIMARY_DEVICE
; 0x00000008 DISPLAY_DEVICE_MIRRORING_DRIVER
; DeviceKey: [out] Path to the device's registry key relative to HKEY_LOCAL_MACHINE.
;
; Returns true if the display device exists, otherwise false.
;
/* Example 1 (requires EnableDisplayDevice()):
SecondaryDevice =
count = 0
Loop {
if ! EnumDisplayDevices(A_Index, DeviceName, StateFlags)
break
if !(StateFlags & 8) ; not a pseudo-device
if (++count = 2) ; second device
break
}
if DeviceName
EnableDisplayDevice(DeviceName, -1) ; toggle
*/
/* Example 2:
Loop {
if ! EnumDisplayDevices(A_Index, DeviceName, StateFlags)
break
if (StateFlags & 4)
text .= DeviceName " is the primary display device.`n"
else if (StateFlags & 1)
text .= "The desktop extends onto " DeviceName ".`n"
if (StateFlags & 8)
text .= DeviceName " is a pseudo-device.`n"
}
MsgBox %text%
*/
EnumDisplayDevices(Index, ByRef DeviceName, ByRef StateFlags="", ByRef DeviceKey="")
{
; DISPLAY_DEVICE DisplayDevice
VarSetCapacity(DisplayDevice, 424)
; lpDisplayDevice.cb := sizeof(DISPLAY_DEVICE)
NumPut(424, DisplayDevice, 0)
VarSetCapacity(DeviceName, 32, 0)
VarSetCapacity(DeviceKey, 128, 0)
; For consistency, clear StateFlags in case of failure.
StateFlags = 0
if ! DllCall("EnumDisplayDevices"
, "UInt", 0
, "UInt", Index-1
, "UInt", &DisplayDevice
, "UInt", 0)
return false
StateFlags := NumGet(DisplayDevice, 164)
DllCall("lstrcpynA", "Str", DeviceName, "UInt", &DisplayDevice+4, "int", 32)
DllCall("lstrcpynA", "Str", DeviceKey, "UInt", &DisplayDevice+296, "int", 128)
if (SubStr(DeviceKey,1,18)="\Registry\Machine\")
DeviceKey := SubStr(DeviceKey,19)
return true
}
; Enables, disables or toggles a display device.
;
; DeviceName: The name of the device, e.g. \\.\DISPLAY1
; Action: The action to take.
; 0 Disable
; 1 Enable
; -1 Toggle (may not be reliable if NoReset=true)
; 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("\\.\DISPLAY2", 0)
; Sleep, 10000
;
; ; simultaneously enable display 2 and disable display 1
; EnableDisplayDevice("\\.\DISPLAY2", 1, true)
; EnableDisplayDevice("\\.\DISPLAY1", 0)
; Sleep, 10000
;
; ; ensure both are enabled
; EnableDisplayDevice("\\.\DISPLAY2", 1, true)
; EnableDisplayDevice("\\.\DISPLAY1")
;
; Note: DeviceNames may vary. Rather than hard-coding the device name,
; EnumDisplayDevices() should be used to enumerate the devices.
;
EnableDisplayDevice(DeviceName, Action=1, NoReset=false)
{
if (Action = -1)
{ ; Determine if the display should be enabled or disabled.
Loop {
if ! EnumDisplayDevices(A_Index, this_name, this_state)
break
if (this_name = DeviceName) {
Action := !(this_state & 1) ; DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
break
}
}
; If Action is still -1, an invalid DeviceName was specified.
; The script will attempt to enable the display device, but
; ChangeDisplaySettingsEx() will most likely return error -5.
}
VarSetCapacity(devmode, 156, 0)
NumPut(156, devmode, 36, "UShort")
; Set DEVMODE.dmFields to indicate which fields are valid.
if (Action) ; Enable
NumPut(0x000020, devmode, 40) ; position={0,0}
else ; Disable
NumPut(0x180020, devmode, 40) ; width=0, height=0, position={0,0}
; Since CDS_NORESET is specified here, if NoReset=true, the user must
; manually call ChangeDisplaySettings(NULL,1) or restart the computer.
err := DllCall("ChangeDisplaySettingsEx", "str", DeviceName
, "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 && !NoReset)
err := DllCall("ChangeDisplaySettings", "uint", 0, "uint", 1)
return err
}
|
|
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|