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

Posted

技术标签:

【中文标题】C Windows API 确定用户是不是处于非活动状态,包括播放媒体【英文标题】:C Windows API determine if user is inactive inclusive of playing mediaC Windows API 确定用户是否处于非活动状态,包括播放媒体 【发布时间】:2020-04-27 04:15:38 【问题描述】:

我编写了一些代码,利用计时器检查最后一次用户输入的时间并将其打印到 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;

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

GetLastInputInfo() 不会考虑用户是否正在播放媒体(例如:在 Google Chrome 中观看视频或收听音频) 当确定系统处于非活动状态时,如何从当前时间戳中减去以毫秒为单位的 InactiveThreshold 时间以确定非活动期的开始,因为使用的数据类型不同 一旦确定用户处于非活动状态,如何设置事件回调以再次等待用户鼠标/键盘输入?

【问题讨论】:

我已从您的帖子中删除了 C++ 标签。您所写的内容与 C++ 没有任何关系。代码的标题和整个代码完全是 C。请不要使用与您的帖子不直接相关的标签来标记垃圾邮件。胡萝卜、汽车和猫不是一回事,因为它们都以 ca 开头。标签在这里有意义,所以请只使用那些实际适用的。谢谢。 @ken:这是一个随意的选择。出于同样的原因,问题中没有任何东西不能使它成为 C++。那么为什么要标记一个而不标记另一个。任何一个都同样适用。我正在还原您的更改。 @mic:可以通过多种方式请求当前时间。如果您需要与GetLastInputInfo 返回的值兼容的时间戳,则需要调用GetTickCount "一旦确定用户处于非活动状态,如何设置事件回调以再次等待用户鼠标/键盘输入?" - 可以检测到新的用户活动使用SetWindowsHookEx()RegisterRawInputDevices() 【参考方案1】:

GetLastInputInfo() 不考虑用户是否在玩 媒体(例如:在 Google Chrome 中观看视频或收听音频)

据我了解,系统本身仅跟踪来自GetLastInputInfo() 的活动。

诸如“用户正在观看视频”之类的情况通过发送WM_SYSCOMMANDSC_SCREENSAVESC_MONITORPOWER 来处理,因此如果应用程序吞下此类消息而不是传递给DefWindowProc,屏幕不会变为空白。或者通过SetThreadExecutionStateES_DISPLAY_REQUIRED

背景音频等情况由SetThreadExecutionStateES_SYSTEM_REQUIRED处理。

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

恐怕应用程序无法可靠地检测到所有此类情况。

【讨论】:

以上是关于C Windows API 确定用户是不是处于非活动状态,包括播放媒体的主要内容,如果未能解决你的问题,请参考以下文章

Android:检测用户是不是停止使用手机一段时间

如何确定夏令时是不是在 C 中处于活动状态?

如何确定用户的 iPhone 是不是处于纵向模式?

windows中哪些API能了解用户是不是在使用鼠标或者键盘?

C/C++/Assembly 以编程方式检测超线程在 Windows、Mac 和 Linux 上是不是处于活动状态 [重复]

即使用户在横向模式下旋转他们的设备,是不是在 Gluon API 中保持我们的应用程序处于纵向模式?