Detecting if laptop lid is closed/integrated screen is off
Asked Answered
B

1

9

Is there a Windows API to detect if a laptop lid is closed (= integrated laptop screen is off)?


There's already the "same" question asked:
Get current laptop lid state

Though the (self-)accepted answer relies on an integrated screen "device" being removed, when the lid closes. But that does not happen on all laptops. Some keep the screen "available" to the system (while not displaying anything actually), even when the lid is closed. This means that the Windows desktop still stretches over the closed screen (if the "Multiple Displays" settings is set to "Extend these displays").

I have not determined yet, if this behavior can be configured or if it is driver-specific:
Remove closed laptop screen from Windows desktop

But even on such systems, the OS knows that the lid closes, as it can shutdown/sleep the machine when it does. And it broadcasts a notification (WM_POWERBROADCAST):
Detect laptop lid closure and opening


Background: I have an application that starts on the same display, where it was closed the last time. If it was closed on the integrated laptop screen and the lid is closed the next time the application starts (because the user is now using an external monitor), my application starts on the now-invisible integrated laptop screen.

Hence I want to detect that the lid is closed and force the application onto an external monitor.

So I'm looking either for a way to detect, if lid is closed. Or for a way to detect, that a particular screen is off (what would be a cleaner solution).

Barmen answered 17/9, 2015 at 13:18 Comment(7)
Did you see this one: #4487174 ?Lockup
@Lockup Sure. It's actually the same as Detect laptop lid closure and opening that I refer to in my question. I'm looking for the current lid state, not for a change notification.Barmen
Apparently reading comprehension is failing me this morning.Lockup
Have you check WMI's Win32_DesktopMonitor? Maybe some fields (Availability?) are relevant in your context.Sigler
@SimonMourier Thanks for your suggestion. Though a select * from Win32_DesktopMonitor query does not even yield the integrated screen.Barmen
Then I suppose you need to call ACPI's "_LID" method (acpi.info/DOWNLOADS/ACPIspec50.pdf) but this requires a kernel driver. A user-mode driver is possible with Windows8+ (msdn.microsoft.com/en-us/library/windows/hardware/ff536139.aspx)Sigler
@SimonMourier Well, that's overkill for my purpose, unfortunately.Barmen
M
2

Sounds like you don't really care if the lid is closed or not and just want to know if the screen area where you are about to launch your application is available or not.

If the OS "still uses the shut off screen for its extended desktop" then that means (from the OS's point of view) that the screen is available to be used for applications. In other words - your application would not be the only one suffering from that issue. Though I have to say I have never observed that particular behavior first-hand.

If you need to move your application while it is running then you can register for the RegisterPowerSettingNotification and act on it.

However if you are launching and need to know if the screen is on or off you have two options:

EnumDisplayDevices

This will provide you with the information on whether your screen is attached to a desktop and is active. This is "system info" that you get from the API in User32.dll

DISPLAY_DEVICE ddi;
ddi.cb = sizeof(ddi);
DWORD iDevNum = 0; // or iterate 0..15
EnumDisplayDevices(NULL, iDevNum, &ddi, /*EDD_GET_DEVICE_INTERFACE_NAME*/0);
if( (ddi.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0 &&
    (ddi.StateFlags & DISPLAY_DEVICE_ACTIVE) != 0 ){...}

DXGI (DX11)

This gives you basically the same info as above but with a more modern approach (and potentially fewer false positives). Of course that would require you to link-in DXGI for this to work and include the header which will increase your application size:

#include <atltypes.h>

IDXGIAdapter * pAdapter; 
std::vector <IDXGIAdapter*> vAdapters; 
IDXGIFactory* pFactory = NULL; 
// Create a DXGIFactory object.
if(FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory) ,(void**)&pFactory)))
{
    return;
}
for(UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i){
    DXGI_ADAPTER_DESC ad = {0};
    if(SUCCEEDED(pAdapter->GetDesc(&ad))){
        UINT j = 0;
        IDXGIOutput * pOutput;
        while(pAdapter->EnumOutputs(j, &pOutput) != DXGI_ERROR_NOT_FOUND)
        {
            DXGI_OUTPUT_DESC od = {0};
            if(SUCCEEDED(pOutput->GetDesc(&od))){
                // in here you can access od.DesktopCoordinates
                // od.AttachedToDesktop tells you if the screen is attached
            }
            pOutput->Release();
            ++j;
        }
    }
    pAdapter->Release();
} 

if(pFactory)
{
    pFactory->Release();
}

Hope that helps.

Direct3D9

This method also provides display information but in a slightly different way - via a list of adapters and monitors attached to those adapters. Remember to link-in d3d9 library for this to work:

void d3d_adapterInfo(IDirect3D9 * _pD3D9, UINT _n)
{
    D3DADAPTER_IDENTIFIER9 id;
    const DWORD flags = 0;
    if(SUCCEEDED(_pD3D9->GetAdapterIdentifier(_n, flags, &id))){
        // id provides info on Driver, Description, Name
        HMONITOR hm = _pD3D9->GetAdapterMonitor(_n);
        // and based on that hm you get the same monitor info as
        // with the first method
    }
}

void d3d_enumDisplays()
{
    cout << endl << "--- Information by Direct3D9 ---" << endl;
    IDirect3D9 * pD3D9 = Direct3DCreate9(D3D_SDK_VERSION);
    const auto nAdapters = pD3D9->GetAdapterCount();
    cout << "A total of " << nAdapters << " adapters are listed by Direct3D9" << endl;
    for(UINT i = 0; i < nAdapters; ++i){
        d3d_adapterInfo(pD3D9, i);
    }
    pD3D9->Release();
}

All 3 code snippets are from some of my projects so you can just copy-paste the code and it should work (baring some minor fixes for missing functions or variables as I was modifying the code on-the-fly to reduce its size when posted it here)

Mechanics answered 25/9, 2015 at 3:41 Comment(1)
Thanks for your response. You are right, that I actually look for a screen availability rather than the lid state (I mention that myself in the last paragraph of my question). The problem is that the affected systems believe the closed lib screen is available. Had it not, it would probably remove the screen from desktop itself. So all your three methods also present the integrated screen as available when the lid is closed, unfortunately.Barmen

© 2022 - 2024 — McMap. All rights reserved.