Qt監聽Windows鎖屏、解鎖、休眠、喚醒、登入、登出訊息

jixhua發表於2024-10-12

環境:Windows 11 筆記本,其它環境未測試

根據其它部落格的直接在視窗 nativeEvent 中監聽 WM_WTSSESSION_CHANGE 會話訊息和 WM_POWERBROADCAST 電源訊息發現不起作用,查閱嘗試後找到可行方法如下:

會話事件和電源訊息都需要先用Windows API註冊視窗控制代碼

void MainWindow::registerSysNotification()
{
#ifdef Q_OS_WINDOWS
    // 註冊指定視窗以接收會話更改通知,獲取鎖屏,解鎖,登入,登出等訊息
    bool ret = WTSRegisterSessionNotification((HWND)this->winId(), NOTIFY_FOR_THIS_SESSION);
    qDebug() << "會話事件通知註冊" << (ret ? "成功" : "失敗");
    // 註冊以便在系統暫停或恢復時接收通知,最低支援 win8
    HPOWERNOTIFY res = RegisterSuspendResumeNotification((HWND)this->winId(), DEVICE_NOTIFY_WINDOW_HANDLE);
    qDebug() << "電源事件通知註冊" << (res != NULL ? "成功" : "失敗");
#endif
}

注意:根據MSDN文件,WTSRegisterSessionNotificationRegisterSuspendResumeNotification 函式都只能用在 win8 及以上桌面系統中,不支援 win7。

然後在 nativeEvent 中處理訊息

bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
#ifdef Q_OS_WIN32

    MSG* msg = (MSG*)message;
    switch (msg->message) {
    case WM_WTSSESSION_CHANGE://判斷登入、登出、鎖屏等
    {
        switch (msg->wParam) {
        case WTS_SESSION_LOCK:
            qDebug() << "鎖屏";
            isScreenLock = true;
            break;
        case WTS_SESSION_UNLOCK:
            qDebug() << "解鎖";
            isScreenLock = false;
            break;
        case WTS_SESSION_LOGON:
            qDebug() << "登入";
            break;
        case WTS_SESSION_LOGOFF:
            qDebug() << "登出";
            break;
        case WTS_SESSION_REMOTE_CONTROL:
            qDebug() << "被遠端控制";
            break;
        default:
            break;
        }
    case WM_POWERBROADCAST:
    {
        switch (msg->wParam) {
        case PBT_APMSUSPEND:
            qDebug() << "系統進入休眠狀態";
            isPowerSleep = true;
            break;
        case PBT_APMRESUMEAUTOMATIC:
            qDebug() << "系統從休眠狀態恢復";
            isPowerSleep = false;
            break;
        case PBT_APMPOWERSTATUSCHANGE:
            qDebug() << "系統電源狀態更改";
            break;
        default:
            break;
        }
    }
    }
    default:
        break;
    }

#endif
    return QMainWindow::nativeEvent(eventType, message, result);
}

相關文章