C Windows API 确定用户是否处于非活动状态,包括播放媒体。

问题描述 投票:0回答:1

我写了一些代码,利用定时器检查最后一个用户输入的时间,并将其打印到Visual Studio的调试控制台。

#include <Windows.h>
#include <stdio.h>

DWORD InactiveThreshold; // The allowable amount of inactive time milliseconds
BOOL Inactive;

SYSTEMTIME CurrentTime(char *ddmmyyyy, char *hhmmss)
{
    SYSTEMTIME lt;

    GetLocalTime(&lt);
    snprintf(ddmmyyyy, 11, "%d/%d/%d", lt.wDay, lt.wMonth, lt.wYear);
    snprintf(hhmmss, 9, "%d:%d:%d", lt.wHour, lt.wMinute, lt.wSecond);

    return lt;
}

void DebugOutput(char *ddmmyyyy, char *hhmmss)
{
    OutputDebugString(TEXT("\n\n"));
    OutputDebugString(ddmmyyyy);
    OutputDebugString(TEXT("  --  "));
    OutputDebugString(hhmmss);
    OutputDebugString(TEXT("  :  "));
    OutputDebugString(TEXT("Inactive"));
}

void CALLBACK TimerProc(HWND hwnd, UINT unt, UINT_PTR id, DWORD current_time)
{
    LASTINPUTINFO li;
    SYSTEMTIME lt;
    DWORD TimeSinceInput, RemainingTime;
    char ddmmyyyy[11], hhmmss[9];

    // Timers continue to expire, so we need to stop it first.
    KillTimer(NULL, id);

    li.cbSize = sizeof(LASTINPUTINFO);
    GetLastInputInfo(&li);

    TimeSinceInput = current_time - li.dwTime;
    if (TimeSinceInput > InactiveThreshold)
    {
        // [Also find a way to check if audio or video was playing during the user inactive period]
        if (!(Inactive))
        {
            // Set flag so it only outputs that it is inactive once during an inactive period
            Inactive = TRUE;

            lt = CurrentTime(ddmmyyyy, hhmmss);

            // [Find way to print the start of the inactive period as timestamp, 
            // subtracting InactiveThreshold from current time]

            DebugOutput(ddmmyyyy, hhmmss);

        }
        // [Change below so once Inactive, stop timer and instead set event loop 
        // to check for user input(keyboard / mouse) to end the inactive period
        // and output timestamp of the end of the inactive period]

            SetTimer(NULL, 0, InactiveThreshold, &TimerProc);
    }
    else
    {
        Inactive = FALSE;
        RemainingTime = InactiveThreshold - TimeSinceInput;
        SetTimer(NULL, 0, RemainingTime, &TimerProc);
    }
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg;
    Inactive = FALSE;
    InactiveThreshold = 30000;  // 30 seconds

    SetTimer(NULL, 0, InactiveThreshold, &TimerProc);

    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {
        DispatchMessage(&msg);
    }

    return 0;
}

理想情况下,它应该打印非活动期开始的时间戳,然后当用户再次活动时打印非活动期结束的时间戳。然而有三个主要的问题(也在代码中用方括号注释/[]表示)。

  • GetLastInputInfo()没有考虑到用户是否在播放媒体(例如:在Google Chrome浏览器中观看视频或收听音频)。
  • 当确定系统处于非活动状态时,由于使用的数据类型不同,如何从当前时间戳中减去InactiveThreshold时间(以毫秒为单位),以确定非活动期的开始。
  • 如何设置一个事件回调,一旦判定用户不活动,就再次等待用户鼠标键盘输入?
c++ c winapi
1个回答
1
投票

GetLastInputInfo()不考虑用户是否在播放媒体(例如:在Google Chrome浏览器中观看视频或收听音频)。

据我所知,系统本身只跟踪活动,因为无论从什么地方都可以获得。GetLastInputInfo().

像 "用户正在观看视频 "这样的情况是通过发送 WM_SYSCOMMANDSC_SCREENSAVESC_MONITORPOWER所以,如果应用程序吞下了这样的消息,而不是传给了你,屏幕就不会空白。DefWindowProc. 或者通过 SetThreadExecutionStateES_DISPLAY_REQUIRED

背景音频等情况由 SetThreadExecutionStateES_SYSTEM_REQUIRED.

这都意味着用户的不活动确实发生了,但一些其他条件阻止了对这种不活动采取行动。

恐怕一个应用程序无法可靠地检测到所有这些条件。

© www.soinside.com 2019 - 2024. All rights reserved.