C Windows API determine if user is inactive inclusive of playing media - c++

I have written some code that makes use of a timer checking when the last user input was and prints it out to Visual Studio's debug console.
#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;
}
Ideally it should print when the timestamp of the start of the inactive period was, then when the user is active again to print the timestamp of when the inactive period finished. However there's three main issues (also indicated in the code with square bracket comments //[] ):
GetLastInputInfo() doesn't take into account if the user is playing media (ex: watching a video or listening to audio in Google Chrome)
When determining the system is inactive, how would you subtract the InactiveThreshold time in ms from the current timestamp to determine the start of the inactive period as the data types used are different
How could you set an event callback to wait for user mouse/keyboard input again once it is decided that the user is inactive?

GetLastInputInfo() doesn't take into account if the user is playing
media (ex: watching a video or listening to audio in Google Chrome)
As I understand, system itself track activity only as whatever is available from GetLastInputInfo().
Cases like "user is watching video" are handled by sending WM_SYSCOMMAND with SC_SCREENSAVE or SC_MONITORPOWER, so that screen does not go blank if application swallows such message instead of passing to DefWindowProc. Or alternatively by SetThreadExecutionState with ES_DISPLAY_REQUIRED
Cases like background audio are handled by SetThreadExecutionState with ES_SYSTEM_REQUIRED.
This all means that user inactivity does happen, but some other conditions prevent from taking actions on this inactivity.
I'm afraid an application cannot reliably detect all such conditions.

Related

WinAPI: repeatable check in a separate thread that notifies UI thread when check fails

My application has a separate thread that repeatably performs some check. If the check fails, the UI thread is notified (a MessageBox is displayed that requires user action what to do next).
Unfortunately, I have to use C++03 compiler (Visual Studio 2010 SP1) and boost library usage is prohibited. Therefore, I cannot use <thread>, <atomic>, <chrono>, etc. Thats why I have to use CreateThread, PostMessage and other WinAPI functions.
Here is my UI thread code (simplified). My main window is CMDIFrameWnd (from MFC):
//a struct with all parameters that is needed for a repeatable check
struct RepeatFunctionParameters
{
unsigned int repeatDelayInMilliseconds;
HWND checkIsFailedPostMessageWindowHandler;
UINT checkIsFailedPostMessageMessageId;
HANDLE checkIsPausedMutexHandle;
RepeatFunctionParameters(unsigned int _repeatDelayInMilliseconds, HWND _checkIsFailedPostMessageWindowHandler,
UINT _checkIsFailedPostMessageMessageId, HANDLE _haspSerialCheckIsPausedMutexHandle)
: repeatDelayInMilliseconds(_repeatDelayInMilliseconds), checkIsFailedPostMessageWindowHandler(_checkIsFailedPostMessageWindowHandler),
checkIsFailedPostMessageMessageId(_checkIsFailedPostMessageMessageId), haspSerialCheckIsPausedMutexHandle(_haspSerialCheckIsPausedMutexHandle)
{}
};
----------------------------
//creating a mutex to pause repeatable checks (whe Messagebox is displayed in UI thread)
HANDLE haspSerialCheckIsPausedMutexHandle = CreateMutex(NULL, FALSE, NULL);
//starting a separate thread with a check that repeats every 5000 milliseconds
auto params = new RepeatFunctionParameters(5000, myApp_hWnd, WM_USER_HASP_CHECK_FAILED, haspSerialCheckIsPausedMutexHandle);
CreateThread(NULL, 0, RepeatFunction, params, 0, NULL);
----------------------------
//special message that is sended when check is failed
#define WM_USER_HASP_CHECK_FAILED (WM_USER+0x150)
//mapping message handling function to that message
ON_MESSAGE( WM_USER_HASP_CHECK_FAILED, OnUserHaspCheckFailed)
//message handling function definition
afx_msg LRESULT OnUserHaspCheckFailed(WPARAM wParam, LPARAM lParam);
//message handling function body
LRESULT CMainWnd::OnUserHaspCheckFailed(WPARAM wParam, LPARAM lParam)
{
//capturing a mutex that signals to pause repeatable checks
WaitForSingleObject(haspSerialCheckIsPausedMutexHandle, INFINITE);
//show a messagebox that requires user action what to do next
if (::MessageBox(myApp_hWnd, ("Check is failed! Retry or cancel?").c_str(),
myApp_name, MB_RETRYCANCEL | MB_ICONERROR | MB_SYSTEMMODAL) == IDCANCEL)
//closing main windows if user clicks Cancel
pWnd->SendMessage(WM_CLOSE, 0x00010000, 0);
//releasing a mutex that signals to pause repeatable checks
ReleaseMutex(haspSerialCheckIsPausedMutexHandle);
return 0;
}
//WM_CLOSE handling function body
LRESULT CMainWnd::OnClose( WPARAM wParam, LPARAM lParam)
{
----------------------------
if( haspSerialCheckIsPausedMutexHandle != NULL)
CloseHandle( haspSerialCheckIsPausedMutexHandle);
----------------------------
CMDIFrameWnd::OnClose();
return NULL;
}
Here is my separate thread with repeatable check code (simplified):
DWORD WINAPI RepeatFunction(LPVOID parameters)
{
//getting parameters struct from a pointer
auto temp = static_cast<RepeatFunctionParameters*>(parameters);
//make a struct local copy (Further, all work goes only with it, regardless of the
state of the object, the pointer to which came as a function parameter)
auto params = *temp;
//deleting the structure, the pointer to which came as a function parameter
delete temp;
//repeatable check
while (true)
{
//checking a mutex that signals to pause repeatable checks. if it is free
//then there is no messagebox in UI thread and we can perform a check.
//if it is captured - wait until user clicks some button in that messagebox
WaitForSingleObject(params.haspSerialCheckIsPausedMutexHandle, INFINITE);
//and releasing it immediately
ReleaseMutex(params.haspSerialCheckIsPausedMutexHandle);
auto startMilliseconds = GetTickCount();
//performing a check
BOOL success = PerformACheck();
unsigned long defaultSleepDelay = 1000;
//if PerformACheck() will last longer than params.repeatDelayInMilliseconds,
//then check will be repeated after 1000 milliseconds, otherwise -
//after params.repeatDelayInMilliseconds minus PerformACheck() call time
auto endMilliseconds = GetTickCount();
if ((endMilliseconds - startMilliseconds) < params.repeatDelayInMilliseconds)
sleepDelay = params.repeatDelayInMilliseconds - (endMilliseconds - startMilliseconds);
//if check is failed
if (!success)
{
//sending a message with an identifier params.checkIsFailedPostMessageMessageId
//to a HWND params.checkIsFailedPostMessageWindowHandler so in it's
//handling function a messagebox with will be displayed and a mutex
//params.haspSerialCheckCanRunMutexHandle will be captured until
//user click some button in that messagebox
PostMessage(params.checkIsFailedPostMessageWindowHandler, params.checkIsFailedPostMessageMessageId, 0, 0);
//if check is failed then next check always repeats after 1000 milliseconds
sleepDelay = 1000;
}
Sleep(sleepDelay);
}
}
The result is that the main window becomes unresponsive after some time. It looks like my code has some logical mistake, or a memory leak.
I'm a newbie to C++ (and especially to outdated standards).

C Windows API determine if user inactive for certain period

So I've created a basic program with a blocking message event loop (to use little to no CPU while waiting) and waits for a user to change the foreground window, then executes some code:
#include <Windows.h>
VOID ExitFunction()
{
// Do Something
}
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType)
{
switch (dwCtrlType)
{
case CTRL_SHUTDOWN_EVENT:
ExitFunction();
return TRUE;
case CTRL_LOGOFF_EVENT:
ExitFunction();
return TRUE;
//default:
//We don't care about this event
//Default handler is used
}
return FALSE;
}
VOID CALLBACK WinEventProcCallback(HWINEVENTHOOK hWinEventHook, DWORD dwEvent, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
if (dwEvent == EVENT_SYSTEM_FOREGROUND)
{
// Do Stuff
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
HWINEVENTHOOK WindowChangeEvent;
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
WindowChangeEvent = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, NULL, WinEventProcCallback, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
while (GetMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
ExitFunction();
return 0;
}
I also want to incorporate checking if the user has been inactive for a certain amount of time (no mouse/keyboard input) but keep resource usage low. There are a couple of ways to approach this that I can think of:
Have the blocking event loop check if there has been mouse or keyboard input which resets some kind of timer back to zero and also checks within the same loop if the mouse input resulted in a foreground window change (which may cause issues if there is a delay between the mouse click event and the foreground window change (meaning the foreground window change won't be captured). Have an event triggered when the user input timer has completed the specified time.
Run the mouse & keyboard activity event timer on a separate thread or asynchronously to the foreground window change event. When the timer has completed fire off an event (run on separate thread or asynchronously to make sure a foreground window change event isn't missed).
On a separate thread or asynchronously, check every couple seconds the GetLastInputInfo() function to see if the inactivity threshold time has elapsed.
It can be called like so:
LASTINPUTINFO li;
li.cbSize = sizeof(LASTINPUTINFO);
GetLastInputInfo(&li);
Keeping in mind lowest resource usage, what way is best to implement the mouse/keyboard inactivity checking while also checking for foreground window changes.
You can set up a timer (see SetTimer) to have a user-defined callback called when an arbitrary timeout expires. This allows you to break out of the blocking GetMessage loop.
The callback can check the timestamp of the last input, and compare it to the current timestamp. If that time interval exceeds the desired inactivity timeout, it can perform the necessary steps. Otherwise it restarts the timer with the remainder of the timeout.
The following code illustrates this:
#include <Windows.h>
#include <iostream>
static const DWORD timeout_in_ms { 5 * 1000 };
void TimeoutExpired() { std::wcout << L"Timeout elapsed" << std::endl; }
void CALLBACK TimerProc(HWND, UINT, UINT_PTR id, DWORD current_time)
{
// Timers are periodic, but we want it to fire only once.
KillTimer(nullptr, id);
LASTINPUTINFO lii { sizeof(lii) };
GetLastInputInfo(&lii);
auto const time_since_input { current_time - lii.dwTime };
if (time_since_input < timeout_in_ms)
{
// User input was recorded inside the timeout interval -> restart timer.
auto const remaining_time { timeout_in_ms - time_since_input };
SetTimer(nullptr, 0, remaining_time, &TimerProc);
}
else
{
TimeoutExpired();
}
}
void StartInactivityTimer()
{
// Start a timer that expires immediately;
// the TimerProc will do the required adjustments and
// restart the timer if necessary.
SetTimer(nullptr, 0, 0, &TimerProc);
}
int wmain()
{
StartInactivityTimer();
MSG msg {};
while (GetMessageW(&msg, nullptr, 0, 0) > 0)
{
DispatchMessageW(&msg);
}
}
The entire logic is contained within TimerProc. To trigger the inactivity timer, StartInactivityTimer starts a timer that expires immediately. When TimerProc takes control it does the required calculations, and either restarts the timer, or calls the timeout procedure, TimeoutExpired.
This implementation has two advantages: For one, the entire timer restart logic is in a single place. More importantly, the inactivity condition is evaluated on first call. If StartInactivityTimer is called without any user input in the inactivity interval, it instantly executes TimeoutExpired.
Also note that the interval calculations use unsigned integer arithmetic, specifically subtraction. With unsigned integer 'underflow' being well defined in both C and C++, this solution is immune to GetTickCount's return value wrapping around to 0 after approximately 49.7 days.

win32 main loop interval issue C++

I'm making a keylogger that logs key strokes (duh..). Now when I've implemented the basic keylogger in C++, I wanted to add a new feature to the application: I want it to mail the logs to my email. So far so good, I found this open source email client that fits perfect for my needs. The only problem I have is to make the application send the logs in intervals of x minutes.
int main(int argc, char *argv[])
{
//stealth();
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, MyLowLevelKeyBoardProc, NULL, 0);
if(hHook == NULL)
{
cout << "Hook failed" << endl;
}
MSG message;
while(GetMessage(&message, NULL, 0, 0))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
return 0;
}
Somehow I need to implement somekind of counter which will at some point use a function send();.
Anyone got any idea how to modify the MSG loop to execute the funktion send(); each and every 5 minutes?
Take a look at the SetTimer function, I think it does exactly what you need.
Before event loop you should call this function with desired interval and you have to pass to it a callback function. Alternatively you can use another function CreateTimerQueueTimer
VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime) {
}
UINT timer = SetTimer(NULL, 0, 500, &TimerProc);
MSG message;
while(GetMessage(&message, NULL, 0, 0))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
KillTimer(NULL, timerId);
Make a new thread to sleep x milis and then send in a while(!interrupted) loop.
As you may know, accessing the same data for read and write from 2 separate threads simultaneously will cause an error.
http://msdn.microsoft.com/en-us/library/kdzttdcb(v=vs.80).aspx
To avoid that you can use critical section
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686908(v=vs.85).aspx
Or just make your thread to sleep and turn a boolean value to true meaning 'yes we waited enough' and your main function always send data when that boolean is true then set it back to false.
edit:
I believe this is the simplier way to archieve this
while(!interrupted) { // Your thread will do this.
sleep(60000);
maysend = true;
}
[...]
if(maysend) { // Your main function will contain this
send();
maysend = false;
}

Shell_NotifyIcon: balloon tooltip is shown after 10 seconds delay

My code to show balloon tooltip is:
BOOL CTrayIcon::ShowBaloon(LPCTSTR title, LPCTSTR text, HICON hIcon)
{
BOOL bRes = FALSE;
if(m_hWnd != NULL)
{
NOTIFYICONDATA nfidata = {sizeof(NOTIFYICONDATA)};
nfidata.cbSize = sizeof(nfidata);
nfidata.hWnd = m_hWnd;
nfidata.guidItem = guid;
nfidata.uFlags = NIF_INFO | NIF_GUID;
if (hIcon)
{
nfidata.hBalloonIcon = hIcon;
nfidata.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON;
}
StringCchCopy(nfidata.szInfo, ARRAYSIZE(nfidata.szInfo), text);
StringCchCopy(nfidata.szInfoTitle, ARRAYSIZE(nfidata.szInfoTitle), title);
bRes = Shell_NotifyIcon(NIM_MODIFY, &nfidata);
}
return bRes;
}
The problem is that sometimes the balloon is shown after 10 seconds delay. This only happens when debugger is not connected to the application. If I connect debugger to the app then tooltip is shown immediately. I know that Windows 7 manages balloon tooltips with a different way than previous Win versions. But where can I read more about this? And how can I change this behavior? I need to show tooltip immediately after function call. Or maybe there are any alternatives to Shell_NotifyIcon?
If it's vital that the notification should be seen immediately, for example notification of a telephone ringing, then you should probably be setting the NIF_REALTIME flag.
However, be aware that this also means that the notification won't be displayed at all if for some reason it can't be displayed immediately. The assumption is that if it's a realtime notification, it is only relevant at the time it occurs.
Something like a notification that you've just received an email is not a realtime event.

Limit occurrences of an event

I have a function that controls a bulb. The bulb is programmed to flash whenever a key is pressed. However, I want to limit the minimum interval between flashes to prevent the bulb from burning out. The bulb is controlled by a relay switch connected to the serial port, and the code is as follows:
void WINAPI flash (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil)
{
//MATT: Define the serial port procedure
HANDLE hSerial;
//MATT: Fire the flash (by initialising and uninitialising the port)
hSerial = CreateFile("COM1",GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); CloseHandle(hSerial);
}
How do I limit the minimum flash interval in milliseconds (millisecond accuracy is very important)?
You could use a simple variable that keeps the time as reported by QueryPerformanceCounter. The accuracy of QPC is very, very high on most systems. On my system, the frequency is 2.8million- or one tick per ten processor clocks.
class bulb {
__int64 clocks;
__int64 frequency;
public:
static const int max_ms_between_flashes = 1;
bulb() {
LARGE_INTEGER li;
QueryPerformanceFrequency(&li);
frequency = li.QuadPart;
clocks = 0;
}
void flash(...) {
LARGE_INTEGER li;
QueryPerformanceCounter(&li);
if (clocks == 0) {
// We are the first time, so set the clocks var
// and flash the bulb
clocks = li.QuadPart;
} else {
__int64 timepassed = clocks - li.QuadPart;
if (timepassed >= (((double)frequency) / (max_ms_between_flashes * 1000))) {
// It's been more than 1ms
clocks = li.QuadPart;
// flash the bulb
}
}
}
}
You could keep a static variable in that function storing the last time the switch was triggered.
Then all you need to do is check that the current time is at least x milliseconds after that time.
You could use GetSystemTimeAsFileTime or GetSystemTime to get the current timestamp, which is supposed to have millisecond resolution.
If you could store the millisecond interval between flashes in a global variable, say FLASH_INETRVAL:
void WINAPI flash (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
HANDLE hSerial;
static long lastFlashMillis;
// currentTimeMillis() should be defined using a system
// call that returns current
// system time in milliseconds.
long interval = currentTimeMillis() - lastFlashMillis;
if (interval < FLASH_INTERVAL)
Sleep (interval);
lastFlashMillis = currentTimeMillis();
//MATT: Fire the flash (by initialising and uninitialising the port)
hSerial = CreateFile("COM1",GENERIC_WRITE, 0, 0, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0); CloseHandle(hSerial);
}