سؤال

I'm trying to get a non-blocking I/O on a Windows terminal application (windows only, sorry!).

What if I want to have a short input time in wich the user can press a button, but if he doesn't the input stops and the program continues?

For example:

A timer that counts from 1 to whatever that stops when the user presses a certain key: I should have a while loop, but if I do a getch or a getchar function it will stop the program, right?

I know I could use kbhit(); , but for the "program" I'm trying to make I need to know the input, not just IF THERE IS input! Are there any simple functions that would allow me to read like the last key in the keyboard buffer?

هل كانت مفيدة؟

المحلول

From the documentation for _kbhit():

The _kbhit function checks the console for a recent keystroke. If the function returns a nonzero value, a keystroke is waiting in the buffer. The program can then call _getch or _getche to get the keystroke.

So, in your loop:

while (true) {
    // ...
    if (_kbhit()) {
        char c = _getch();
        // act on character c in whatever way you want
    }
}

So, you can still use _getch(), but limit its use to only after _kbhit() says there is something waiting. That way it won't block.

نصائح أخرى

Here is how to make a non blocking call to stdin in windows by using the right API :

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>

void ErrorExit(LPSTR);
void KeyEventProc(KEY_EVENT_RECORD ker);

// Global variables are here for example, avoid that.
DWORD fdwSaveOldMode;
HANDLE hStdin;

void printToCoordinates(int x, int y, char* text)
{
    printf("\033[%d;%dH%s", y, x, text);
}

int main()
{
    printf("\033[H\033[J");
    int i = 0;
    char* s = "*";

    DWORD fdwMode, cNumRead;
    INPUT_RECORD irInBuf[128];
    DWORD bufferSize = 0;

    hStdin = GetStdHandle(STD_INPUT_HANDLE);

    // Just a check to ensure everything is fine at this state
    if (hStdin==INVALID_HANDLE_VALUE){
        printf("Invalid handle value.\n");
        exit(EXIT_FAILURE);
    }

    // Just a check to ensure everything is fine at this state
    if (! GetConsoleMode(hStdin, &fdwSaveOldMode) )
        ErrorExit("GetConsoleMode");

    // Those constants are documented on Microsoft doc
    // ENABLE_PROCESSED_INPUT allows you to use CTRL+C
    // (so it's not catched by ReadConsoleInput here)
    fdwMode = ENABLE_WINDOW_INPUT | ENABLE_PROCESSED_INPUT;
    if (! SetConsoleMode(hStdin, fdwMode) )
        ErrorExit("SetConsoleMode");


    while (i < 60) {
        // The goal of this program is to print a line of stars
        printToCoordinates(i, 5, s);
        i++;


        GetNumberOfConsoleInputEvents(hStdin, &bufferSize);

        // ReadConsoleInput block if the buffer is empty
        if (bufferSize > 0) {
            if (! ReadConsoleInput(
                    hStdin,      // input buffer handle
                    irInBuf,     // buffer to read into
                    128,         // size of read buffer
                    &cNumRead) ) // number of records read
                ErrorExit("ReadConsoleInput");

            // This code is not rock solid, you should iterate over
            // irInBuf to get what you want, the last event may not contain what you expect
            // Once again you'll find an event constant list on Microsoft documentation
            if (irInBuf[cNumRead-1].EventType == KEY_EVENT) {
                KeyEventProc(irInBuf[cNumRead-1].Event.KeyEvent);
                Sleep(2000);
            }
        }

        Sleep(100);
    }
    // Setting the console back to normal
    SetConsoleMode(hStdin, fdwSaveOldMode);
    CloseHandle(hStdin);

    printf("\nFIN\n");

    return 0;
}

void ErrorExit (LPSTR lpszMessage)
{
    fprintf(stderr, "%s\n", lpszMessage);

    // Restore input mode on exit.

    SetConsoleMode(hStdin, fdwSaveOldMode);

    ExitProcess(0);
}

void KeyEventProc(KEY_EVENT_RECORD ker)
{
    printf("Key event: \"%c\" ", ker.uChar.AsciiChar);

    if(ker.bKeyDown)
        printf("key pressed\n");
    else printf("key released\n");
}

Please notice this work in brand new Terminal application but not in CMD (due to termcaps used in the code) but it will compile and you can run it anyway.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top