Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Timeout utility * FILE: base/applications/cmdutils/timeout/timeout.c * PURPOSE: An enhanced alternative to the Pause command. * PROGRAMMERS: Lee Schroeder (spaceseel at gmail dot com) * Hermes Belusca-Maito (hermes.belusca@sfr.fr) */
#include <stdio.h>#include <stdlib.h>
#include <windef.h>#include <winbase.h>#include <wincon.h>#include <winuser.h>
#include <conutils.h>
#include "resource.h"
VOID PrintError(DWORD dwError){ if (dwError == ERROR_SUCCESS) return;
ConMsgPuts(StdErr, FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, LANG_USER_DEFAULT); ConPuts(StdErr, L"\n");}
BOOLWINAPICtrlCIntercept(DWORD dwCtrlType){ switch (dwCtrlType) { case CTRL_C_EVENT: ConPuts(StdOut, L"\n"); SetConsoleCtrlHandler(NULL, FALSE); ExitProcess(EXIT_FAILURE); return TRUE; } return FALSE;}
INT InputWait(BOOL bNoBreak, INT timerValue){ INT Status = EXIT_SUCCESS; HANDLE hInput; BOOL bUseTimer = (timerValue != -1); HANDLE hTimer = NULL; DWORD dwStartTime; LONG timeElapsed; DWORD dwWaitState; INPUT_RECORD InputRecords[5]; ULONG NumRecords, i; BOOL DisplayMsg = TRUE; UINT WaitMsgId = (bNoBreak ? IDS_NOBREAK_INPUT : IDS_USER_INPUT); UINT WaitCountMsgId = (bNoBreak ? IDS_NOBREAK_INPUT_COUNT : IDS_USER_INPUT_COUNT);
/* Retrieve the current input handle */ hInput = ConStreamGetOSHandle(StdIn); if (hInput == INVALID_HANDLE_VALUE) { ConResPrintf(StdErr, IDS_ERROR_INVALID_HANDLE_VALUE, GetLastError()); return EXIT_FAILURE; }
/* Start a new wait if we use the timer */ if (bNoBreak && bUseTimer) { hTimer = CreateWaitableTimer(NULL, TRUE, NULL); if (hTimer == NULL) { /* A problem happened, bail out */ PrintError(GetLastError()); return EXIT_FAILURE; } } if (bUseTimer) dwStartTime = GetTickCount();
/* If /NOBREAK is used, monitor for Ctrl-C input */ if (bNoBreak) SetConsoleCtrlHandler(CtrlCIntercept, TRUE);
/* Initially flush the console input queue to remove any pending events */ if (!GetNumberOfConsoleInputEvents(hInput, &NumRecords) || !FlushConsoleInputBuffer(hInput)) { /* A problem happened, bail out */ PrintError(GetLastError()); Status = EXIT_FAILURE; goto Quit; }
ConPuts(StdOut, L"\n");
/* If the timer is not used, just show the message */ if (!bUseTimer) { ConPuts(StdOut, L"\r"); ConResPuts(StdOut, WaitMsgId); }
while (TRUE) { /* Decrease the timer if we use it */ if (bUseTimer) { /* * Compute how much time the previous operations took. * This allows us in particular to take account for any time * elapsed if something slowed down, or if the console has been * paused in the meantime. */ timeElapsed = GetTickCount() - dwStartTime; if (timeElapsed >= 1000) { /* Increase dwStartTime by steps of 1 second */ timeElapsed /= 1000; dwStartTime += (1000 * timeElapsed);
if (timeElapsed <= timerValue) timerValue -= timeElapsed; else timerValue = 0;
DisplayMsg = TRUE; }
if (DisplayMsg) { ConPuts(StdOut, L"\r"); ConResPrintf(StdOut, WaitCountMsgId, timerValue); ConPuts(StdOut, L" \b");
DisplayMsg = FALSE; }
/* Stop when the timer reaches zero */ if (timerValue <= 0) break; }
/* If /NOBREAK is used, only allow Ctrl-C input which is handled by the console handler */ if (bNoBreak) { if (bUseTimer) { LARGE_INTEGER DueTime;
/* We use the timer: use a passive wait of maximum 1 second */ timeElapsed = GetTickCount() - dwStartTime; if (timeElapsed < 1000) { DueTime.QuadPart = Int32x32To64(1000 - timeElapsed, -10000); SetWaitableTimer(hTimer, &DueTime, 0, NULL, NULL, FALSE); dwWaitState = WaitForSingleObject(hTimer, INFINITE);
/* Check whether the timer has been signaled */ if (dwWaitState != WAIT_OBJECT_0) { /* An error happened, bail out */ PrintError(GetLastError()); Status = EXIT_FAILURE; break; } } } else { /* No timer is used: wait indefinitely */ Sleep(INFINITE); }
continue; }
/* /NOBREAK is not used, check for user key presses */
/* * If the timer is used, use a passive wait of maximum 1 second * while monitoring for incoming console input events, so that * we are still able to display the timing count. * Indeed, ReadConsoleInputW() indefinitely waits until an input * event appears. ReadConsoleInputW() is however used to retrieve * the input events where there are some, as well as for waiting * indefinitely in case we do not use the timer. */ if (bUseTimer) { /* Wait a maximum of 1 second for input events */ timeElapsed = GetTickCount() - dwStartTime; if (timeElapsed < 1000) dwWaitState = WaitForSingleObject(hInput, 1000 - timeElapsed); else dwWaitState = WAIT_TIMEOUT;
/* Check whether the input event has been signaled, or a timeout happened */ if (dwWaitState == WAIT_TIMEOUT) continue; if (dwWaitState != WAIT_OBJECT_0) { /* An error happened, bail out */ PrintError(GetLastError()); Status = EXIT_FAILURE; break; }
/* Be sure there is something in the console input queue */ if (!PeekConsoleInputW(hInput, InputRecords, ARRAYSIZE(InputRecords), &NumRecords)) { /* An error happened, bail out */ ConResPrintf(StdErr, IDS_ERROR_READ_INPUT, GetLastError()); Status = EXIT_FAILURE; break; }
if (NumRecords == 0) continue; }
/* * Some events have been detected, pop them out from the input queue. * In case we do not use the timer, wait indefinitely until an input * event appears. */ if (!ReadConsoleInputW(hInput, InputRecords, ARRAYSIZE(InputRecords), &NumRecords)) { /* An error happened, bail out */ ConResPrintf(StdErr, IDS_ERROR_READ_INPUT, GetLastError()); Status = EXIT_FAILURE; break; }
/* Check the input events for a key press */ for (i = 0; i < NumRecords; ++i) { /* Ignore any non-key event */ if (InputRecords[i].EventType != KEY_EVENT) continue;
/* Ignore any system key event */ if ((InputRecords[i].Event.KeyEvent.wVirtualKeyCode == VK_CONTROL) || // (InputRecords[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED )) || // (InputRecords[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) || (InputRecords[i].Event.KeyEvent.wVirtualKeyCode == VK_MENU)) { continue; }
/* This is a non-system key event, stop waiting */ goto Stop; } }
Stop: ConPuts(StdOut, L"\n");
Quit: if (bNoBreak) SetConsoleCtrlHandler(NULL, FALSE);
if (bNoBreak && bUseTimer) CloseHandle(hTimer);
return Status;}
int wmain(int argc, WCHAR* argv[]){ INT timerValue = -1; PWCHAR pszNext; BOOL bDisableInput = FALSE, fTimerFlags = 0; int index = 0;
/* Initialize the Console Standard Streams */ ConInitStdStreams();
if (argc == 1) { ConResPrintf(StdOut, IDS_USAGE); return EXIT_SUCCESS; }
/* Parse the command line for options */ for (index = 1; index < argc; index++) { if (argv[index][0] == L'-' || argv[index][0] == L'/') { switch (towupper(argv[index][1])) { case L'?': /* Help */ { ConResPrintf(StdOut, IDS_USAGE); return EXIT_SUCCESS; }
case L'T': /* Timer */ { /* Consecutive /T switches are invalid */ if (fTimerFlags & 2) { ConResPrintf(StdErr, IDS_ERROR_ONE_TIME); return EXIT_FAILURE; }
/* Remember that a /T switch has been encountered */ fTimerFlags |= 2;
/* Go to the next (timer) value */ continue; } }
/* This flag is used to ignore any keyboard keys but Ctrl-C */ if (_wcsicmp(&argv[index][1], L"NOBREAK") == 0) { bDisableInput = TRUE;
/* Go to next value */ continue; } }
/* The timer value can also be specified without the /T switch */
/* Only one timer value is supported */ if (fTimerFlags & 1) { ConResPrintf(StdErr, IDS_ERROR_ONE_TIME); return EXIT_FAILURE; }
timerValue = wcstol(argv[index], &pszNext, 10); if (*pszNext) { ConResPrintf(StdErr, IDS_ERROR_OUT_OF_RANGE); return EXIT_FAILURE; }
/* Remember that the timer value has been set */ fTimerFlags |= 1; }
/* A timer value is mandatory in order to continue */ if (!(fTimerFlags & 1)) { ConResPrintf(StdErr, IDS_ERROR_NO_TIMER_VALUE); return EXIT_FAILURE; }
/* Make sure the timer value is within range */ if ((timerValue < -1) || (timerValue > 99999)) { ConResPrintf(StdErr, IDS_ERROR_OUT_OF_RANGE); return EXIT_FAILURE; }
return InputWait(bDisableInput, timerValue);}