【问题标题】:Detecting if laptop lid is closed/integrated screen is off检测笔记本电脑盖是否关闭/集成屏幕是否关闭
【发布时间】:2015-12-14 09:08:29
【问题描述】:

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


已经有人问了“相同”的问题:
Get current laptop lid state

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

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

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


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

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

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

【问题讨论】:

  • 你看到这个了吗:stackoverflow.com/questions/4486674/…
  • @theB 当然。它实际上与我在问题中提到的Detect laptop lid closure and opening 相同。我正在寻找当前的盖子状态,而不是更改通知。
  • 今天早上我的阅读理解能力很差。
  • 你检查过 WMI 的 Win32_DesktopMonitor 吗?也许某些字段(可用性?)与您的上下文相关。
  • @SimonMourier 感谢您的建议。虽然select * from Win32_DesktopMonitor 查询甚至不会产生集成屏幕。

标签: windows winapi monitor multiple-monitors


【解决方案1】:

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

如果操作系统“仍然为其扩展桌面使用关闭屏幕”,那么这意味着(从操作系统的角度来看)该屏幕可用于应用程序。换句话说 - 您的应用程序不会是唯一遇到该问题的应用程序。虽然我不得不说我从未亲眼观察过这种特殊行为。

如果您需要在应用程序运行时移动它,那么您可以注册RegisterPowerSettingNotification 并采取行动。

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

EnumDisplayDevices

这将为您提供有关您的屏幕是否连接到桌面并且处于活动状态的信息。这是您从 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 才能使其正常工作并包含将增加您的应用程序大小的标头:

#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 个代码 sn-ps 都来自我的一些项目,因此您只需复制粘贴代码,它应该可以工作(在我即时修改代码时,对丢失的函数或变量进行了一些小修复在此处发布时减小其大小)

【讨论】:

  • 感谢您的回复。你是对的,我实际上是在寻找屏幕可用性而不是盖子状态(我在问题的最后一段中提到了自己)。问题是受影响的系统认为关闭的 lib 屏幕可用。如果没有,它可能会从桌面本身移除屏幕。因此,不幸的是,当盖子关闭时,您的所有三种方法也会显示集成屏幕可用。
猜你喜欢
  • 2010-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多