问题
I'm writing code that need to run only when there is no human activity on the PC, like when the screensaver is running. Any suggestions on how to do this in c++ under windows?
@talnicolas, simply to use unused resources, how many times people leave the computer on but they are in another place?
回答1:
You can use GetLastInputInfo to check how long the user has been idle (not moved around the mouse or typed something on the keyboard) and SystemParametersInfo to check if a screensaver is active.
Example
#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
// do something after 10 minutes of user inactivity
static const unsigned int idle_milliseconds = 60*10*1000;
// wait at least an hour between two runs
static const unsigned int interval = 60*60*1000;
int main() {
LASTINPUTINFO last_input;
BOOL screensaver_active;
// main loop to check if user has been idle long enough
for (;;) {
if ( !GetLastInputInfo(&last_input)
|| !SystemParametersInfo(SPI_GETSCREENSAVERACTIVE, 0,
&screensaver_active, 0))
{
std::cerr << "WinAPI failed!" << std::endl;
return ERROR_FAILURE;
}
if (last_input.dwTime < idle_milliseconds && !screensaver_active) {
// user hasn't been idle for long enough
// AND no screensaver is running
Sleep(1000);
continue;
}
// user has been idle at least 10 minutes
do_something();
// done. Wait before doing the next loop.
Sleep(interval);
}
}
Note that I wrote that code on a Linux machine, so I couldn't test it.
回答2:
Use SystemParametersInfo(...)
private const int SPI_GETSCREENSAVERACTIVE = 16;
SystemParametersInfo( SPI_GETSCREENSAVERACTIVE, 0,
ref isActive, 0 );
return isActive;
Reference: http://www.codeproject.com/KB/cs/ScreenSaverControl.aspx
回答3:
This is just a minor update to Niklas B. answer which is tested on Windows 8.1 and Windows 10.
Description of changes is as follows:
LASTINPUTINFO
hascbSize
initializedinstead of checking
SPI_GETSCREENSAVERACTIVE
,SPI_GETSCREENSAVERRUNNING
is checkedidle_time
is calculated and compared withidle_milliseconds
user is notified only on change, check is executed every ~500ms
since windows can trigger event id 4803 immediately after 4802 one can determine that screensaver is still on with user
idle_time
, see the problem I had
Additionally this only works if screensaver timer is smaller then screen power off timer!
#define start
#include <windows.h>
#include <iostream>
// do something after 10 minutes of user inactivity
static const unsigned int idle_milliseconds = 60*10*1000;
int main() {
LASTINPUTINFO last_input;
// without setting cbSize GetLastError() returns the parameter is incorrect
last_input.cbSize = sizeof(last_input);
BOOL screensaver_running;
DWORD idle_time;
bool screensaverOn = false;
// main loop to check if user has been idle long enough
for (;;) {
if ( !GetLastInputInfo( &last_input )
|| !SystemParametersInfo( SPI_GETSCREENSAVERRUNNING, 0,
&screensaver_running, 0 ) )
{
std::cerr << "WinAPI failed!" << std::endl;
return ERROR_FAILURE;
}
// calculate idle time
idle_time = GetTickCount() - last_input.dwTime;
if ( idle_time > this->user_idle_time && TRUE == screensaver_running )
{
if ( !screensaverOn )
{
// screensaver is running
screensaverOn = true;
notify( true );
}
}
else if ( idle_time < this->user_idle_time && screensaverOn )
{
// screensaver is not running
screensaverOn = false;
notify( false );
}
// wait 500ms before next loop
Sleep( 500 );
}
}
回答4:
check at this answer that looks similar.
However you need to determine exactly was "inactivity" means. That modifies the scope of your question.
Also check this code
hdesk = OpenDesktop(TEXT("Screen-saver"),
0,
FALSE,
DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
if (hdesk)
{
EnumDesktopWindows (hdesk, (WNDENUMPROC)KillScreenSaverFunc, 0);
CloseDesktop (hdesk);
}
// ----------------------------------------------------------------
BOOL CALLBACK KillScreenSaverFunc (HWND hwnd, LPARAM lParam)
{
PostMessage(hwnd, WM_CLOSE, 0, 0);
return TRUE;
}
from here.
来源:https://stackoverflow.com/questions/8820615/how-to-check-in-c-if-the-system-is-active