如何使用输入功能的延时?

时间:2014-02-09 19:38:25

标签: c

delay(msec)sleep(sec)等函数将程序延迟指定的时间,但仅在控件传递给它之后。例如,在printf()之前使用delay()函数,首先执行printf(),然后执行delay()。但是,如果我们使用scanf()getchar()和其他输入处理函数,则在我输入之前,控件不会传递给delay()。正确?

有没有办法在指定时间内执行scanf(),然后在完成时间后退出,即使没有输入?是否有任何函数仅在指定的时间段内执行scanf()或任何其他输入函数?

2 个答案:

答案 0 :(得分:0)

你是正确的,因为你的程序只有一个线程,sleep()之后的scanf()scanf()结束之前不会被执行。

我认为你要做的是读取一个字符串,等待时间限制。解决方法是构建要单独扫描的字符串(同时检查时间限制是否已过期),然后将字符串传递给sscanf()(注意其他s)以供稍后处理。

第一位是困难的部分。可能最简单的方法是在select()(即输入流)上使用循环和STDIN,并使用较小的超时。每次角色到达时,将其添加到字符串中。您需要手动处理(例如)删除。使用gettimeofday读取时间,如果此时间与开始时间之间的差异超过给定超时,则以您已超时为基础退出。

另一种方法是使用SIGALRM的警报处理程序。您可能(或可能不会)发现此终止fgets()令人满意。您需要sigaction而不需要SA_RESTART。随着风,这应该工作。我说“随风而来”,因为似乎有错误的c库版本,当收到EINTR时无条件重试。例如,请参阅:http://alumnus.caltech.edu/~dank/sigtest.c

当然可能有图书馆可以帮到你。 readline没有内置超时。 editline可能。

答案 1 :(得分:0)

好的,不了解其他平台,但Windows用户有一种解决方法:在Windows.h下,有GetKeyState( keyID ),允许检查键盘键的状态。

这是我做过的实现:

#include <stdio.h>
#include <Windows.h>

void PrintKey( int * key ) {

    /* initially lowercase */
    int lowercase = 1;

    /* if shift is being held, indicated by the leftmost bit
    invert the lowercase boolean */
    if ( ( GetKeyState( VK_SHIFT ) & 0x8000 ) == 0x8000 ) lowercase ^= 1;

    /* if Caps Lock is toggled, indicated by the rightmost bit
    invert the lowercase boolean (again) */
    if ( ( GetKeyState( VK_CAPITAL ) & 0x0001 ) == 0x0001 ) lowercase ^= 1;

    /* print the key */
    if ( *key > '9' && lowercase ) putchar( *key + 'a' - 'A' );
    else putchar( *key );

}

int main( )
{
    int timeout = 10000;                /* timeout (in milliseconds) */
    char keysheld['Z' + 1] = { 0 };     /* record of keys being held (1: being hold, 0: released) */
    int lastkeyonhold = 0;              /* last key that has been pressed */
    int holddelay;                      /* delay before repeating starts (in millisec) */
    int repeatperiod = 40;              /* how much before each repeat (in millisec) */

    while ( timeout > 0 ) {
    /* until timeout */

        /* check keys from 0 to Z */
        for ( int i = '0'; i <= 'Z'; i++ ) {
            if ( i == '9' + 1 ) i = 'A';

            /* 0x8000 is the leftmost bit for 2 bytes...
            leftmost bit is given as 1, if the key is being pressed */
            if ( ( GetKeyState( i ) & 0x8000 ) == 0x8000 ) {

                /* if the key wasn't already being known as held
                make it known as the last key that has been pressed
                refresh the delay record to 500 milliseconds
                and print the key once */
                if ( !keysheld[i] ) {
                    lastkeyonhold = i;
                    holddelay = 500;
                    PrintKey( &i );
                }

                /* regardless, make the key known as pressed */
                keysheld[i] = 1;
            }

            /* if the key is not being hold, make it known so
            this is important, because this is what will allow us to have
            a freshly pressed key to be our lastkeyonhold */
            else keysheld[i] = 0;
        }

        /* if the console window is the active window */
        if ( GetConsoleWindow( ) == GetForegroundWindow( ) ) {

            /* and the last key pressed is still being pressed */
            if ( keysheld[lastkeyonhold] ) {
                /* and the hold delay is over... then repeatedly print the key */
                if ( holddelay < 0 ) PrintKey( &lastkeyonhold );
                /* else, just keep on consuming the delay */
                else holddelay -= repeatperiod;
            }

            /* if return has been pressed while the console window is active
            break out... */
            if ( ( GetKeyState( VK_RETURN ) & 0x8000 ) == 0x8000 ) {
                break;
            }

        }

        Sleep( repeatperiod );
        timeout -= repeatperiod;
    }

    /* print a New Line ('\n' or 10, whatever) after breaking out, for whatever reason */
    putchar( 10 );
    system( "pause" );

    return 0;
}

如果您通过检测键盘按键的状态按下或按住键盘按键,它基本上只会复制您在任何文本编辑器上的内容。您可以阅读代码中的注释以获取详细说明。

不幸的是,它仅用于字母上方的字母和数字键...我可以很好地添加数字键盘键,但是用手管理位置键会很麻烦。除了手动管理所有按钮之外,我不知道是否有更简单的方法为其余的键执行此操作。对于虚拟密钥的完整列表:http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx