Можно установить таймер (см. SetTimer ), чтобы пользовательский обратный вызов вызывался по истечении произвольного тайм-аута. Это позволяет снять блокировку GetMessage
l oop.
. Обратный вызов может проверить метку времени последнего входа и сравнить ее с текущей меткой времени. Если этот интервал времени превышает желаемый таймаут бездействия, он может выполнить необходимые шаги. В противном случае он перезапускает таймер с оставшейся частью времени ожидания.
Следующий код иллюстрирует это:
#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);
}
}
Весь лог c содержится в TimerProc
. Чтобы запустить таймер неактивности, StartInactivityTimer
запускает таймер, который истекает немедленно. Когда TimerProc
берет на себя управление, он выполняет необходимые вычисления и либо перезапускает таймер, либо вызывает процедуру тайм-аута, TimeoutExpired
.
Эта реализация имеет два преимущества: во-первых, весь таймер перезапускает логи c находится в одном месте. Что еще более важно, состояние неактивности оценивается при первом вызове. Если StartInactivityTimer
вызывается без какого-либо пользовательского ввода в интервале неактивности, он мгновенно выполняет TimeoutExpired
.
Также обратите внимание, что для вычисления интервала используется целое число без знака c, а именно вычитание. Благодаря тому, что целое число без знака 'underflow' хорошо определено как в C, так и в C ++, это решение неуязвимо для GetTickCount , возвращая значение 0 после приблизительно 49,7 дней.