Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check in C++ if the system is active?

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?

like image 301
user1143336 Avatar asked Jan 11 '12 14:01

user1143336


2 Answers

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.

like image 197
Niklas B. Avatar answered Oct 25 '22 02:10

Niklas B.


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 has cbSize initialized

  • instead of checking SPI_GETSCREENSAVERACTIVE, SPI_GETSCREENSAVERRUNNING is checked

  • idle_time is calculated and compared with idle_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 );
    }
}
like image 20
krizajb Avatar answered Oct 25 '22 02:10

krizajb