首页 文章

检测笔记本电脑盖是否关闭/集成屏幕是否已关闭

提问于
浏览
9

是否有Windows API来检测笔记本电脑盖是否关闭(=集成的笔记本电脑屏幕是否关闭)?


已经有"same"问题了:
Get current laptop lid state

虽然(自我)接受的答案依赖于移除集成屏幕“设备”,但盖子关闭时 . 但这并不是所有笔记本电脑都会发生的 . 有些屏幕保持屏幕“可用”(即使实际上没有显示任何内容),即使盖子关闭也是如此 . 这意味着Windows桌面仍然会在关闭的屏幕上延伸(如果“多个显示”设置设置为“扩展这些显示”) .

我还没有确定,是否可以配置此行为或是否是特定于驱动程序:
Remove closed laptop screen from Windows desktop

但即使在这样的系统上,操作系统也知道盖子关闭,因为它可以关闭/睡眠机器 . 它会广播通知( WM_POWERBROADCAST ):
Detect laptop lid closure and opening


背景:我有一个应用程序从同一个显示器开始,最后一次关闭 . 如果在集成的笔记本电脑屏幕上关闭并且下次启动应用程序时关闭盖子(因为用户现在正在使用外部显示器),我的应用程序将从现在不可见的集成笔记本电脑屏幕开始 .

因此,我想检测盖子是否关闭,并将应用程序强制到外部显示器上 .

所以我正在寻找一种方法来检测,如果盖子关闭 . 或者为了检测某个特定屏幕关闭的方式(什么是更清洁的解决方案) .

1 回答

  • 2

    听起来你并不关心盖子是否关闭,只是想知道你要启动应用程序的屏幕区域是否可用 .

    如果操作系统"still uses the shut off screen for its extended desktop"那意味着(从操作系统的角度来看)该屏幕可用于应用程序 . 换句话说 - 您的应用程序不会是唯一遭受该问题的应用程序 . 虽然我不得不说我从未亲眼观察到这种特殊行为 .

    如果您需要在应用程序运行时移动它,那么您可以注册 RegisterPowerSettingNotification 并对其进行操作 .

    但是,如果您正在启动并需要知道屏幕是打开还是关闭,您有两个选择:

    EnumDisplayDevices

    这将为您提供有关您的屏幕是否已连接到桌面并处于活动状态的信息 . 这是"system info",您可以从 User32.dll 获取API

    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)

    这为您提供了与上述基本相同的信息,但采用了更现代的方法(可能更少的误报) . 当然,这需要你链接 DXGI 为此工作并包括将增加你的应用程序大小的 Headers :

    #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();
    }
    

    希望有所帮助 .

    Direct3D9

    此方法还提供显示信息,但方式略有不同 - 通过连接到这些适配器的适配器和监视器列表 . 请记住链接到 d3d9 库以使其工作:

    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();
    }
    

    所有3个代码片段都来自我的一些项目,所以你可以复制粘贴代码,它应该工作(为缺少的函数或变量提供一些小修复,因为我在运行时修改代码以减少它的大小在这里)

相关问题