当显示器(HDMI)关闭时,如何让 Windows 进入睡眠状态?

当显示器(HDMI)关闭时,如何让 Windows 进入睡眠状态?

我有一台通过 HDMI 连接到电视的 HTPC(英特尔 NUC)。电视关闭时可以让 Windows 进入睡眠状态吗?

看来 Windows 确实内置了显示器关闭时的检测功能;也许它为此公开了一个 API?我愿意自己编写解决方案。

答案1

我发现此论坛帖子,其中包含 C++ 代码。我自己还没有尝试过。

您需要一个编译器才能使其工作。

#include <windows.h>
#include <setupapi.h>

#ifdef _MSC_VER
#pragma comment(lib, "Setupapi.lib")
#endif

#include <list>
#include <vector>
#include <string>
using namespace std;

// my StlPort configured w/o iostreams at the moment
#include <stdio.h> 

//------------------------------------------------------------------------------

struct DevData
{
    std::wstring Description;  // SPDRP_DEVICEDESC
    CM_POWER_DATA PowerData;   // SPDRP_DEVICE_POWER_DATA

    DevData() 
    {
        PowerData.PD_Size = sizeof(PowerData);
    }//constructor
};//DevData

//------------------------------------------------------------------------------

bool GetDeviceRegString(HDEVINFO infoSet, SP_DEVINFO_DATA *pinfoData, 
                        DWORD prop, wstring &val)
{
    DWORD req_sz = 0;
    BOOL res = SetupDiGetDeviceRegistryPropertyW(infoSet, pinfoData, prop,
                                                 0, 0, 0, &req_sz);
    if (!res && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
    {
        if (GetLastError() != ERROR_INVALID_DATA)
        {
            printf("SetupDiGetDeviceRegistryPropertyW() failed, le = &#37;u",
                   GetLastError());
        }//if

        return false;
    }//if

    vector<wchar_t> vec_buff; // in case we have to go to the heap
    wchar_t auto_buff[512];

    DWORD buff_sz;
    wchar_t *buff;
    if (req_sz > sizeof(auto_buff))
    {
        vec_buff.reserve(req_sz/2 + 2);
        buff = &vec_buff[0];
        buff_sz = req_sz;
    }//if
    else
    {
        buff = auto_buff;
        buff_sz = sizeof(auto_buff);
    }//else

    res = SetupDiGetDeviceRegistryPropertyW(infoSet, pinfoData, prop,
                                            0, (PBYTE)buff, buff_sz, 0);
    if (!res)
    {
        DWORD le = GetLastError();
        if (le != ERROR_INVALID_DATA)
        {
            printf("SetupDiGetDeviceRegistryPropertyW(%d) "
                   "failed, le = %u",
                   prop, le);
            return false;
        }//if

        // return empty string on ERROR_INVALID_DATA
        val.erase(val.begin(), val.end());
        return true;
    }//else

    val.assign(buff, req_sz);
    return true;
}//GetDeviceRegString

//------------------------------------------------------------------------------

template <typename T>
bool GetDeviceRegData(HDEVINFO infoSet, SP_DEVINFO_DATA *pinfoData, 
                        DWORD prop, T &val)
{
    SetLastError(0);
    BOOL res = SetupDiGetDeviceRegistryPropertyW(infoSet, pinfoData, prop,
                                                 0, (PBYTE)&val, 
                                                 sizeof(val), 0);
    DWORD le = GetLastError();
    if (!res || (le == ERROR_INVALID_DATA))
    {
        if (le != ERROR_INVALID_DATA)
            printf("GetDeviceRegData() failed, le = %u", le);
        return false;
    }//if

    return true;
}//GetDeviceRegData

//------------------------------------------------------------------------------

void ListDeviceClassData(const GUID *classGuid, std::list<DevData> &devList)
{
    devList.clear();

    const DWORD flags = DIGCF_PRESENT;
    HDEVINFO infoSet = SetupDiGetClassDevsW(classGuid, 0, 0, flags);
    if (infoSet == INVALID_HANDLE_VALUE)
    {
        printf("SetupDiGetClassDevs() failed, le = %u", 
               GetLastError());
        return;
    }//if

    SP_DEVINFO_DATA infoData;
    infoData.cbSize = sizeof(SP_DEVINFO_DATA);

    DWORD n;
    for (n = 0; SetupDiEnumDeviceInfo(infoSet, n, &infoData); ++n)
    {
        DevData dd;
        if (GetDeviceRegString(infoSet, &infoData, SPDRP_DEVICEDESC, 
                               dd.Description) &&
            GetDeviceRegData(infoSet, &infoData, SPDRP_DEVICE_POWER_DATA, 
                             dd.PowerData))
        {
            devList.push_back(dd);
        }//if
    }//for

    if (GetLastError() != ERROR_NO_MORE_ITEMS)
    {
        printf("Last call to SetupDiEnumDeviceInfo(%d) failed, le = %u",
               n, GetLastError());
    }//if

    SetupDiDestroyDeviceInfoList(infoSet);
}//ListDeviceClassData

//------------------------------------------------------------------------------

void print_monitor_info()
{
    const GUID MonitorClassGuid =
        {0x4d36e96e, 0xe325, 0x11ce, 
            {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}};

    list<DevData> monitors;
    ListDeviceClassData(&MonitorClassGuid, monitors);

    printf("# Monitors = %d\n", monitors.size());

    list<DevData>::iterator it = monitors.begin(),
                            it_end = monitors.end();
    for (; it != it_end; ++it)
    {
        const char *off_msg = "";

        if (it->PowerData.PD_MostRecentPowerState > PowerDeviceD0)
            off_msg = ", *** Sleeping State ***";

        printf("[%ls]\n"
               "   PowerState = %d%s\n", 
               it->Description.c_str(),
               it->PowerData.PD_MostRecentPowerState,
               off_msg);
    }//for

    putchar('\n');
}//print_monitor_info

//------------------------------------------------------------------------------

int main()
{
    printf("*** Current Status of Monitor(s) ***\n\n");
    print_monitor_info();

    printf("*** Turning OFF Monitor(s) ***\n\n");
    fflush(stdout);
    Sleep(500); // don't use mouse or keyboard
    SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM)2);

    print_monitor_info();

    printf("*** Turning ON Monitor(s) ***\n\n");
    SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM)-1);

    print_monitor_info();

    return 0;
}//main

//------------------------------------------------------------------------------

答案2

HDMI 具有消费电子控制 (CEC)。https://en.wikipedia.org/wiki/Consumer_Electronics_Control#CEC基本上,HDMI 设备(如果它们支持)可以相互通信。例如,如果您使用 HTPC 遥控器,则可以通过 HTPC 的 CEC 关闭显示器或电视。HTPC- 家庭影院电脑。谷歌搜索 HDMI cec,您可能会得到一些想法。

相关内容