5

When I'm connected to an external display, I would like to close the laptop without it going to sleep. When I'm not connected to an external display, I would like to have closing the lid put the laptop to sleep.
I know I can achieve this by manually switching the power settings, but I'd like something automatic. Any idea? Сan we track the external display connection?
Windows 10

4 Answers4

1

@miroxlav solution did not work for me. I changed the script as follows.

  • You still have to create two power saving configs
  • The AutoHotKey script is typically executed at startup.
  • The caught event is a bit different (WM_DISPLAYCHANGE)
  • You have to identify your main monitor instance nam from powershell get-WmiObject or device manager or...
  • power config UUIDs are hard coded in script too.
    /*
       Please note that it is not sufficient to count the number of monitors because the
       main monitors goes off line when you close the lid.
       Which resets the count to... 1
       So instead, we just make our decision on the presence of a different monitor than the known
       main one (hardcoded id, SN is a poor criterion).
    */

    /*  
        Subscribe to windows event
        0x7E = WM_DISPLAYCHANGE
    */
    OnMessage(0x7E, "MsgMonitor")

    MsgMonitor(wParam, lParam, msg) {

    /* Sleep 2 sec because there is a delay before display is known to WMI */
    Sleep 2000

    /* default */
    strComputer := "."

    /* This is the one for my PC... */
    myMonitor := "DISPLAY\LGD056E\4&13419694&0&UID265988_0"

    objWMIService := ComObjGet("winmgmts:{impersonationLevel=impersonate}!\\" . strComputer . "\root\wmi")
    colItems := objWMIService.ExecQuery("Select * FROM WMIMonitorID")._NewEnum

    hasExternal := false

    While colItems[objItem]
    if objItem.instanceName != myMonitor {
        hasExternal := True
    }

    if ( hasExternal ) {
        /* this is the power config that does not set laptop to sleep on lid closing */event
        Run, powercfg /s a48ebd52-0590-400d-b032-ac7f4302c0e1
    } Else {
        /* this instead is the power config that does set laptop to sleep on lid closing event */
        Run, powercfg /s 377a8558-bff4-4f51-ab43-626b1aa5a65f
    }

}
1

@miroxlav solution worked, however when you remove the external display, it will not return to the original power setting. Here's how I did it.

  1. Create a power plan which disables sleep when the lid is closed.
  2. Create a power plan which DOES NOT disable sleep when the lid is closed.
  3. Install AutoHotKey

Open notepad and paste the code below. Save as AHK and run.

This autohotkey script detects the monitor count and primary monitor. If the monitor count is greater than 1, then it will change the power setting. Don't forget to paste the corresponding power schemes.

If this works, you can run this script on startup by hitting Win + R, then type shell:startup and then pasting the script there.

OnMessage(0x219, "MsgMonitor")
     MsgMonitor(wParam, lParam, msg)
     {

        SysGet, MonitorCount, MonitorCount
        SysGet, MonitorPrimary, MonitorPrimary

        count := 0
        Loop, %MonitorCount%
        {
            count++
        }

        IfLessOrEqual, count, 1
            Run, powercfg /s c7046c63-d4a3-4246-910c-c994cd704433 /* no external monitor power setting */
        Else
            Run, powercfg /s 3791f438-87b9-4243-89a1-00c797e02c84 /* external monitor connected */
     }
1

Here is my script for AutoHotKey v2.
I actually enhanced the code from the previous answer here(@AlainPannetier) and added action to react with the "charging status" of the laptop.

  • For identifying your main monitor instance you will need this command(run in PowerShell): Get-WmiObject -Namespace "root\wmi" -Class WMIMonitorID | Select-Object InstanceName
    In the device manager, the path is missing the last piece "_0" for some reason, you can just add "_0" to the end of the copied path.
  • For configuring power configs and changing the action for "when the lid close" you actually need this option, often there is no option like this, and if your config doesn't have this option, you need to execute this command(you need to run cmd as administrator): REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Power\PowerSettings\4f971e89-eebd-4455-a8de-9e59040e7347\5ca83367-6e45-459f-a27b-476b1d01c936 /v Attributes /t REG_DWORD /d 2 /f
    You can delete this option whenever you want so don't worry, here is the command: powercfg -attributes SUB_BUTTONS 5ca83367-6e45-459f-a27b-476b1d01c936 +ATTRIB_HIDE
  • GUID of power configs that are used in the script, you can find with this command: powercfg /l
  • More in my video(use auto-translate for captions, video is in ukr)
Persistent
OnMessage 0x007E, MsgMonitor
OnMessage 0x218, MsgMonitor
MsgMonitor(wParam, lParam, msg, hwnd) {
    ; Sleep 2 sec because there is a delay before display is known to WMI
    Sleep 2000
    ; default
    strComputer := "."
; This is the one for my PC...
myMonitor := "DISPLAY\CMN15E7\4&3513ECC3&0&UID265988_0"

objWMIService := ComObjGet("winmgmts:{impersonationLevel=impersonate}!\\" . strComputer . "\root\wmi")
colItems := objWMIService.ExecQuery("Select * FROM WMIMonitorID")._NewEnum
hasExternal := false
For objItem in colItems {
    if (objItem.InstanceName != myMonitor) {
        hasExternal := true
        break
    }
}
powerStatus := false
; \\.\root\CIMV2
objWMIService := ComObjGet("winmgmts:")
colItems := objWMIService.ExecQuery("Select * from Win32_Battery")
for objItem in colItems {
    if (objItem.BatteryStatus = 2) {
        powerStatus := true
        break
    }
}

; GUID should be replaced with the GUID name of your “power plan”, run powercfg /l, example: 61116a43-1b96-41fd-8dae-a75e84260a80

if (hasExternal) {
    ; If an external monitor is connected
    if (powerStatus) {
        ; If the laptop is plugged in and an external monitor is connected
        Run("powercfg /s GUID")
    }
    else {
        ; If the laptop is running on battery and an external monitor is connected
        Run("powercfg /s GUID")
    }
}
else {
    ; If no external monitor is connected
    if (powerStatus) {
        ; If the laptop is plugged in and no external monitor is connected
        Run("powercfg /s GUID")
    }
    else {
        ; If the laptop is running on battery and no external monitor is connected
        Run("powercfg /s GUID")
    }
}
return

}

0
  1. Determine (or create, if necessary) two power schemes, one with sleep button enabled, one with disabled.

  2. Using command powercfg /l determine GUID's of these schemes.

  3. Install AutoHotKey and set up launching this monitoring script after each start of Windows. Every time the monitor is connected and disconnected, AutoHotKey will run the script for you, switching the power scheme:

    OnMessage(0x219, "MsgMonitor")
    MsgMonitor(wParam, lParam, msg)
    {
        if (wParam = 7) {
            Run, powercfg /s 381b4222-f694-41f0-9685-ff5bb260df2e
        } Else {
            Run, powercfg /s 381b4222-0001-2222-3333-000000000000
        }
        MsgBox check %wParam% and %lParam% and decide to run programs with %msg%
    }
    ;wParam: 7 lParam: 0  monitor connected
    ;wParam: 32772 lParam: 8977536 should be on disconected

Important: Replace sample GUID's in the above code with GUID's you determined in step 2.

Sources:

miroxlav
  • 14,845