Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate

Secondary Monitor


  • Please log in to reply
70 replies to this topic
Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

Thank you! But I get an error:
call to nonexistent function
specifically: NumPut(424, DisplayDevice, 0)

1.0.47 - June 19, 2007
...
Added NumGet() and NumPut(), which retrieve/store binary numbers with much greater speed than Extract/InsertInteger.

-> AutoHotkey Download

jamn
  • Guests
  • Last active:
  • Joined: --
:shock: I ran a much older version than I thought... Sorted now. The script now gives no error, but it does not seem to do much either. At least it does not enable my second display (a LCD TV). Is there some setting I could/should change?

canta
  • Members
  • 49 posts
  • Last active: May 30 2013 03:08 PM
  • Joined: 30 May 2006
I put EnableDisplayDevice.ahk & EnumDisplayDevices.ahk in my lib and ran
EnableDisplayDevice("\\.\DISPLAY2", -1)
It disables my second monitor just fine, but wont enable it again. Changing -1 to 1 doesnt help either.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
If EnableDisplayDevice doesn't work, try the more primitive registry method I mentioned earlier in this thread. If it fails to enable the display by name, it is probably a quirk of your display drivers, so the registry method might not work either.

Btw, the most recent version of EnableDisplayDevice does not use EnumDisplayDevices.ahk (though EnumDisplayDevices example 2 may still be used to determine the existing display devices.)

The script now gives no error, but it does not seem to do much either.

Can the LCD TV be seen in Display Settings? If not, you will probably have to resort to using whatever utility came with your display drivers.

If it shows in Display Settings, try passing whatever number is shown there to EnableDisplayDevice. For instance,
EnableDisplayDevice(2, -1) ; not "\\.\DISPLAY2"
I realise now my previous comment is inaccurate since Display Settings also shows disabled displays. (The numbers are less likely to differ than I thought, though it is still a possibility.)

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.



Superfraggle
  • Members
  • 1019 posts
  • Last active: Sep 25 2011 01:06 AM
  • Joined: 02 Nov 2004

I also tried this and couldnt get it to work.

I used

EnableDisplayDevice("\\.\DISPLAY2", 1)

where \\.\DISPLAY2 is the name reported by enumdisplay adapters when my second monitor was on. But it did nothing.

If your second monitor was already on, attempting to turn it on should do nothing. :p Use -1 to toggle or 0 to turn it off. Sorry for not replying sooner; I guess I missed your post.


I turned it off before trying to turn it on, don't worry I'm not that bad. It just wasnt detecting it when it was off.

Ill try the new one next time I am in work.
Steve F AKA Superfraggle

http://r.yuwie.com/superfraggle

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Make sure the display can be enabled via Display Settings. If it cannot, it is likely that your display drivers remove the display device, and you must use whatever utility that came with them to re-enable it. I suspect this is how it would work if your video card has multiple inputs (e.g. VGA, DVI and S-Video) but doesn't support all of them simultaneously.

Something I forgot to mention: check the return value of EnableDisplayDevice.

Superfraggle
  • Members
  • 1019 posts
  • Last active: Sep 25 2011 01:06 AM
  • Joined: 02 Nov 2004
Oh well, I guess it just doesnt like my display driver.

Return value is always 0. It can be turned on normally by windows. Although enumdisplaydevices cannot pick it up unless it is on. So I'm guessing the video driver does disable it for this

I can turn it off, but I just can't turn it on.

EDIT:::: Ive finally cracked it, I noticed this quote on MSDN

When adding a display monitor to a multiple-monitor system programmatically, set DEVMODE.dmFields to DM_POSITION and specify a position (in DEVMODE.dmPosition) for the monitor you are adding that is adjacent to at least one pixel of the display area of an existing monitor. To detach the monitor, set DEVMODE.dmFields to DM_POSITION but set DEVMODE.dmPelsWidth and DEVMODE.dmPelsHeight to zero. For more information, see Multiple Display Monitors.


Then I realised your code had the comment

; Enable by setting position = {0,0}


So I added some extra info to the structure positioning it to the right of my monitor.

Specifically the lines,

VarSetCapacity(Point,8,0)
Numput(A_ScreenWidth + 1,Point)
Numput(&point,devmode,44)

just after the line with the above comment.

This is now working spot on for me and I can enable/disable my second monitor on the fly.

The full very slightly adjust code, is as follows.

; 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.
; 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
;
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
            ThisDeviceState := NumGet(DisplayDevice, 164)
            Index += 1
            DllCall("lstrcpynA", "Str", ThisDeviceName, "UInt", &DisplayDevice+4, "int", 32)
            if (DeviceName = Index || DeviceName = ThisDeviceName)
            {
                if Action = -1
                    Action := !(ThisDeviceState & 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}
        VarSetCapacity(Point,8,0)
        Numput(A_ScreenWidth + 1,Point)
        Numput(&point,devmode,44)
    }
    else
        NumPut(0x180020, devmode, 40) ; Disable by setting size = {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
}

I'm sure it could be enhanced more to allow better positioning.
Steve F AKA Superfraggle

http://r.yuwie.com/superfraggle

jamn
  • Guests
  • Last active:
  • Joined: --
With the last changes from superfraggle this now works perfectly on my system. Thank you!

ProsperousOne
  • Members
  • 115 posts
  • Last active: Mar 12 2011 09:15 PM
  • Joined: 19 Sep 2005
OK, I've got it working. Unfortunatly, it's extending my destkop. I'm looking to just clone it (aka unchecking "Extend my Windows Desktop onto this monitor." in the Display Properties Settings dialog).

Any suggestions?

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
So "Extend the desktop onto this monitor" toggles clone mode? On my computer, unchecking it just disables the monitor...

If you have an nVidia card, you could use the NvCpl API. (Edit: On Vista, I get "Error: API not supported on this version of Windows.")

Clash
  • Members
  • 182 posts
  • Last active: Oct 26 2009 08:31 PM
  • Joined: 27 Jun 2006
Lexikos's script worked for me, but my primary monitor flashed funny shaped black boxes on the screen (not sure if that could damage it) and it switches the secondary screen to be on the opposite side.
Posted Image Posted Image

ProsperousOne
  • Members
  • 115 posts
  • Last active: Mar 12 2011 09:15 PM
  • Joined: 19 Sep 2005

So "Extend the desktop onto this monitor" toggles clone mode? On my computer, unchecking it just disables the monitor...

If you have an nVidia card, you could use the NvCpl API. (Edit: On Vista, I get "Error: API not supported on this version of Windows.")


Correct. Running the script has the effect of toggling th e"Extend Destop on to this monitor" checkbox. I'll play iwth the nVidia card and see if I can get that to work. Unfortunatly, I'm running VISTA, so I'll see if there's updated Vista drivers....

nod5
  • Guests
  • Last active:
  • Joined: --
I have made a script based on superfraggles function and with some custom icons. Available here:
http://nod5.dcmembers.com/tv_out.html

Now I'm looking for some way to place the second display to the left of the display (not to the right which is the default position).

I think this is the crucial line of code from superfraggle:
Numput(A_ScreenWidth + 1,Point)

I've tried changing the first value in the paranthesis to a negative (like -1360) but then it doesn't work. Can anyone see a solution for this?

TheQwerty
  • Members
  • 1 posts
  • Last active:
  • Joined: 12 Sep 2007

Now I'm looking for some way to place the second display to the left of the display (not to the right which is the default position).

I think this is the crucial line of code from superfraggle:

Numput(A_ScreenWidth + 1,Point)

I've tried changing the first value in the paranthesis to a negative (like -1360) but then it doesn't work. Can anyone see a solution for this?

Okay, this was driving me nuts today, but I think I got it figured out.

The following was never actually using the value put into Point, instead it was using the pointer directly to position the monitor:
VarSetCapacity(Point,8,0)
Numput(A_ScreenWidth + 1,Point)
Numput(&point,devmode,44)

What is really wanted is to put the X and Y values directly into devmode, so replace those 3 lines with:
NumPut(X, devmode, 44, "Int")
NumPut(Y, devmode, 48, "Int")
Now either adjust the function call to accept X and Y parameters, or replace them with the new X-Y coordinates of the monitor. This seems to be working for me, so hopefully it's a solution for you.

EDIT: Just to note, it seems to disable the monitor (without error) if you set it to a position already occupied, or at least 0,0, so perhaps it's only disabled if it conflicts with the primary monitor.

Matt2k
  • Guests
  • Last active:
  • Joined: --
Wow! Thanks for the script. The original worked great, and the updates by Superfraggle work even better. I had a C++ program that was doing it, but this is a lot simpler to maintain and understand.

I've been running AHK for a few years and until tonight had no idea it had this sort of capability. Completely came across this in a google search for disabling second monitor via script and was like "Hey.. I have that program already"