我想放慢一段时间,只有一个命令,而不是程序-初学者级别-C++

2022-05-23 00:00:00 windows sleep c++

我想创建一个带秒的密钥计数器。我试过了,但它会减慢程序的速度,而不仅仅是几秒钟。

#include <iostream>
#include <Windows.h>
#include <conio.h>
using namespace std;

int x = 1;
int secs = 0;
int clicks = 0;


int main() {
    while (true) {
        if (x == 1) {
            secs++;
            Sleep(1000);
            system("CLS");
            cout << "Clicks: " << clicks << "             Time: " << secs;
            x = 2;
        }
        else if (2 == x) {
            _getch();
            clicks++;
            system("CLS");
            cout << "Clicks: " << clicks << "             Time: " << secs;
            x = 1;
        }
    }
}

解决方案

您似乎希望Sleep函数在等待计时器时不阻塞整个程序,但在等待计时器时继续处理键盘输入。此外,您似乎希望getch函数在等待键盘输入时不会阻塞整个程序,而是在等待键盘输入时继续处理计时器。然而,这不是这些函数的工作方式。这两个函数将一直阻塞,直到它们等待的特定类型的事件发生。

您想要的是一个能够同时等待几种不同类型事件的函数。该函数应该只阻止,直到这些事件中的任何一个发生。一旦发生此类事件,该函数应立即返回并指定发生的事件类型,即它是计时器事件还是键盘输入事件。这样,事件可以立即得到处理。

通常可以使用WaitForMultipleObjects函数来实现此目的。然而,在本例中,函数WaitForSingleObject就足够了,因为该函数将允许您指定除了要等待的对象句柄之外的超时间隔。这样,您就可以同时在计时器和对象句柄上等待键盘输入。

不幸的是,根据我的测试,在控制台的输入句柄上使用WaitForSingleObject只有在使用ReadConsoleInput等低级控制台API函数处理控制台输入时才能可靠地工作。似乎无法可靠地预测kbhitgetch是否会工作,也不能可靠地与ReadConsole一起工作。

我相信这个程序能达到您的要求:

#include <Windows.h>
#include <iostream>
#include <cstdio>

int main()
{
    HANDLE hStdin = INVALID_HANDLE_VALUE;
    ULONGLONG ullStartTime;

    //counter of the number of times a keypress was registered
    int num_keypresses = 0;

    //get input handle
    hStdin= GetStdHandle( STD_INPUT_HANDLE );
    if ( hStdin == INVALID_HANDLE_VALUE )
    {
        std::cerr << "error opening input handle!
" << std::flush;
        exit( EXIT_FAILURE );
    }

    //remember time that program started
    ullStartTime = GetTickCount64();

    for (;;) //infinite loop, equivalent to while(1)
    {
        ULONGLONG ullElapsedTime = GetTickCount64() - ullStartTime;

        int seconds   = (int) ( ullElapsedTime / 1000 );
        int remainder = (int) ( ullElapsedTime % 1000 );

        //round up to next second, if appropriate
        if ( remainder >= 500 )
        {
            seconds++;
            remainder -= 1000;
        }

        //uncomment the folllowing line to clear the screen
        //std::system( "cls" );

        //write data to screen
        std::cout << "Keypresses: " << num_keypresses << "     Time: " << seconds << " seconds
" << std::flush;

        //wait for either a keypress to occur, or for a timeout to occur
        switch ( WaitForSingleObject( hStdin, 1000 - remainder ) )
        {
            case WAIT_OBJECT_0:
            {
                DWORD dwRead;
                INPUT_RECORD ir;

                //console input event occurred, so read it
                if ( !ReadConsoleInput( hStdin, &ir, 1, &dwRead ) || dwRead != 1 )
                {
                    std::cerr << "error reading input!
" << std::flush;
                    std::exit( EXIT_FAILURE );
                }

                if ( ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown )
                {
                    num_keypresses += ir.Event.KeyEvent.wRepeatCount;
                }
                break;
            }
            case WAIT_TIMEOUT:
            {
                //timeout occurred
                break;
            }
            default:
            {
                std::cerr << "unexpected error!
" << std::flush;
                std::exit( EXIT_FAILURE );
            }
        }
    }
}

如果我等待大约5秒才开始按键,然后按几个键,则我得到的输出如下:

Keypresses: 0     Time: 0 seconds
Keypresses: 0     Time: 1 seconds
Keypresses: 0     Time: 2 seconds
Keypresses: 0     Time: 3 seconds
Keypresses: 0     Time: 4 seconds
Keypresses: 0     Time: 5 seconds
Keypresses: 1     Time: 6 seconds
Keypresses: 1     Time: 6 seconds
Keypresses: 2     Time: 7 seconds
Keypresses: 2     Time: 7 seconds
Keypresses: 2     Time: 8 seconds
Keypresses: 3     Time: 9 seconds
Keypresses: 3     Time: 9 seconds
Keypresses: 4     Time: 10 seconds
Keypresses: 4     Time: 10 seconds
Keypresses: 4     Time: 11 seconds
Keypresses: 5     Time: 11 seconds
Keypresses: 5     Time: 11 seconds
Keypresses: 5     Time: 12 seconds
Keypresses: 6     Time: 12 seconds
Keypresses: 6     Time: 13 seconds
Keypresses: 6     Time: 14 seconds
Keypresses: 7     Time: 15 seconds
Keypresses: 7     Time: 15 seconds
Keypresses: 7     Time: 16 seconds
Keypresses: 7     Time: 17 seconds
在原始程序中,您使用std::system("cls");清除屏幕,而不是每次打印一行。在我的程序中,我没有清除屏幕,但是,您可以取消对std::system("cls");行的注释,它应该可以工作。我已经把它放在正确的位置了。但是请注意,使用std::systemis not recommended。有关更好的替代方案,请参阅Microsoft官方文档中的this page。

相关文章