ultravnc / UltraVNC

UltraVNC Server, UltraVNC Viewer and UltraVNC SC | Official repository: https://github.com/ultravnc/UltraVNC
https://uvnc.com
GNU General Public License v3.0
793 stars 188 forks source link

Automatically toggle listen mode in UltraVNC Viewer when the PC is idle/not idle #197

Open panreyes opened 3 months ago

panreyes commented 3 months ago

It would be a nice feature to automatically disable listen mode in UltraVNC Viewer then the PC is idle and enable it back again when the user gets back.

It would be helpful to:

I believe it could be done with GetLastInputInfo from windows.h: https://learn.microsoft.com/bs-latn-ba/windows/win32/api/winuser/nf-winuser-getlastinputinfo

Here's an example snippet:

#include <iostream>
#include <windows.h>

// Function to get the idle time in seconds
DWORD GetIdleTime() {
    LASTINPUTINFO lastInputInfo;
    lastInputInfo.cbSize = sizeof(LASTINPUTINFO);
    if (GetLastInputInfo(&lastInputInfo)) {
        DWORD currentTime = GetTickCount();
        return (currentTime - lastInputInfo.dwTime) / 1000;
    }
    return 0;
}

int main() {
    while (true) {
        DWORD idleTime = GetIdleTime();
        std::cout << "Idle time in seconds: " << idleTime << std::endl;
        Sleep(1000);  // Sleep for 1 second before checking again
    }
    return 0;
}
RudiDeVos commented 3 months ago

The it would be better to disable it when the screenlock get into action and start back when unlocked. Idle is also watching a youtube.

panreyes commented 3 months ago

That would be really useful too for most cases, although I never use screen lock in my home PC (which is also my work PC).

About the case of "idle + watching YouTube", it looks like there's no public API to check if there are any Video Wake Locks active, but it might be good enough to check if the current monitor has gone to sleep mode:

#include <Windows.h>
#include <iostream>
#include <powrprof.h>
#pragma comment(lib, "PowrProf.lib")

// GUID for session display status changes.
const GUID GUID_SESSION_DISPLAY_STATUS = { 0x2b84c20e, 0xad23, 0x4ddf, {0x93, 0xdb, 0x05, 0xff, 0xbd, 0x7e, 0xfc, 0xa5} };

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
    case WM_POWERBROADCAST:
        if (wParam == PBT_POWERSETTINGCHANGE) {
            POWERBROADCAST_SETTING* pbs = (POWERBROADCAST_SETTING*)lParam;
            if (pbs && IsEqualGUID(pbs->PowerSetting, GUID_SESSION_DISPLAY_STATUS)) {
                DWORD displayStatus = *(DWORD*)pbs->Data;
                if (displayStatus == 0) {
                    std::cout << "Display is off" << std::endl;
                }
                else {
                    std::cout << "Display is on" << std::endl;
                }
            }
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

int main() {
    HINSTANCE hInstance = GetModuleHandle(nullptr);

    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = L"SessionDisplayStatusWindowClass";

    if (!RegisterClass(&wc)) {
        std::cerr << "Window registration failed!" << std::endl;
        return 1;
    }

    HWND hWnd = CreateWindowEx(0, wc.lpszClassName, L"Hidden Display Status Monitor",
        0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, hInstance, nullptr);

    if (!hWnd) {
        std::cerr << "Message-only window creation failed!" << std::endl;
        return 1;
    }

    // Register for session display status notifications
    HPOWERNOTIFY hPowerNotify = RegisterPowerSettingNotification(hWnd, &GUID_SESSION_DISPLAY_STATUS, DEVICE_NOTIFY_WINDOW_HANDLE);
    if (!hPowerNotify) {
        std::cerr << "Power setting notification registration failed!" << std::endl;
    }

    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // Unregister the power setting notification
    if (hPowerNotify) {
        UnregisterPowerSettingNotification(hPowerNotify);
    }

    return static_cast<int>(msg.wParam);
}

(Sorry if that snippet is not good enough, I'm not too good with C++ and I'm consulting ChatGPT!)