有没有一种方法可以在不按回车键的情况下获取用户输入?

13

我正在编写一款控制台游戏(吃豆人),我想知道如何在用户不按回车键的情况下获取用户输入。我在网上查找了一些关于_getch()的资料,但它显然已经过时了,除非有人自己构建头文件,否则无已知声明。由于我还是C++的新手,因此无法进行构建。

那么我该如何编写代码来实现这个目标呢?谢谢。


1
Curses 游戏库支持像这样的函数:http://invisible-island.net/ncurses/man/curs_get_wch.3x.html。 - Hunter McMillen
你使用的平台是什么?Linux 还是 Windows? - Shiplu Mokaddim
3个回答

6
这对我很有用(我使用的是Linux):
#include <stdio.h>
#include <unistd.h>
#include <termios.h>

int main()
{
    struct termios old_tio, new_tio;
    unsigned char c;

    /* get the terminal settings for stdin */
    tcgetattr(STDIN_FILENO,&old_tio);

    /* we want to keep the old setting to restore them a the end */
    new_tio=old_tio;

    /* disable canonical mode (buffered i/o) and local echo */
    new_tio.c_lflag &=(~ICANON & ~ECHO);

    /* set the new settings immediately */
    tcsetattr(STDIN_FILENO,TCSANOW,&new_tio);

    do {
         c=getchar();
         printf("%d ",c);
    } while(c!='q');

    /* restore the former settings */
    tcsetattr(STDIN_FILENO,TCSANOW,&old_tio);

    return 0;
}

它使控制台无缓冲。

参考:http://shtrom.ssji.net/skb/getc.html


5

您可以使用conio.h库和函数_getch()以实时方式获取输入,还可以设置循环以获得多个输入。

#include<conio.h>
#include<iostream>
using namespace std;
int main()
{
    char n = 'a'; //Just to initialize it. 
    while(n != 'e') // Will exit if you press e.
    {
        n = _getch();
    }
}

conio.h 只存在于 WIN 的 cmd 中。 - dboy

1

允许进行本地文本编辑的Windows解决方案

#include <Windows.h>
#include <conio.h>

enum key_code
{
    KEY_QUIT = 3,
    KEY_BACKSPACE = 8,
    KEY_TAB = 9,
    KEY_RETURN = 13,
    KEY_ESCAPE = 27,
    KEY_SPACE = ' ',
    KEY_EXCLAMATION_POINT = '!',
    KEY_QUOTATION = '"',
    KEY_HASHTAG = '#',
    KEY_DOLLAR = '$',
    KEY_MODULUS = '%',
    KEY_AMPERSAND = '&',
    KEY_APOSTROPHE = '\'',
    KEY_LEFT_PAREN = '(',
    KEY_RIGHT_PAREN = ')',
    KEY_ASTERICK = '*',
    KEY_PLUS = '+',
    KEY_COMMA = ',',
    KEY_MINUS = '-',
    KEY_PERIOD = '.',
    KEY_FORWARD_SLASH = '/',
    KEY_0 = '0',
    KEY_1 = '1',
    KEY_2 = '2',
    KEY_3 = '3',
    KEY_4 = '4',
    KEY_5 = '5',
    KEY_6 = '6',
    KEY_7 = '7',
    KEY_8 = '8',
    KEY_9 = '9',
    KEY_COLON = ':',
    KEY_SEMICOLON = ';',
    KEY_LESS_THAN = '<',
    KEY_EQUALS = '=',
    KEY_GREATER_THAN = '>',
    KEY_QUESTION = '?',
    KEY_AT = '@',
    KEY_A = 'A',
    KEY_B = 'B',
    KEY_C = 'C',
    KEY_D = 'D',
    KEY_E = 'E',
    KEY_F = 'F',
    KEY_G = 'G',
    KEY_H = 'H',
    KEY_I = 'I',
    KEY_J = 'J',
    KEY_K = 'K',
    KEY_L = 'L',
    KEY_M = 'M',
    KEY_N = 'N',
    KEY_O = 'O',
    KEY_P = 'P',
    KEY_Q = 'Q',
    KEY_R = 'R',
    KEY_S = 'S',
    KEY_T = 'T',
    KEY_U = 'U',
    KEY_V = 'V',
    KEY_W = 'W',
    KEY_X = 'X',
    KEY_Y = 'Y',
    KEY_Z = 'Z',
    KEY_OPENING_SQR_BRACE = '[',
    KEY_BACKSLASH = '\\',
    KEY_CLOSING_SQR_BRACE = ']',
    KEY_EXP = '^',
    KEY_UNDERSCORE = '_',
    KEY_BACKTICK = '`',
    KEY_a = 'a',
    KEY_b = 'b',
    KEY_c = 'c',
    KEY_d = 'd',
    KEY_e = 'e',
    KEY_f = 'f',
    KEY_g = 'g',
    KEY_h = 'h',
    KEY_i = 'i',
    KEY_j = 'j',
    KEY_k = 'k',
    KEY_l = 'l',
    KEY_m = 'm',
    KEY_n = 'n',
    KEY_o = 'o',
    KEY_p = 'p',
    KEY_q = 'q',
    KEY_r = 'r',
    KEY_s = 's',
    KEY_t = 't',
    KEY_u = 'u',
    KEY_v = 'v',
    KEY_w = 'w',
    KEY_x = 'x',
    KEY_y = 'y',
    KEY_z = 'z',
    KEY_OPENING_CURLY_BRACE = '{',
    KEY_LINE = '|',
    KEY_CLOSING_CURLY_BRACE = '}',
    KEY_TILDA = '~',
    KEY_UP_ARROW,
    KEY_DOWN_ARROW,
    KEY_LEFT_ARROW,
    KEY_RIGHT_ARROW,
    KEY_DELETE,
    KEY_END,
    KEY_HOME,
};

struct handle
{
    HANDLE console;
    DWORD old_mode;

    handle() : console{GetStdHandle(STD_OUTPUT_HANDLE)}
    {
        GetConsoleMode(console, &old_mode);
        SetConsoleMode(console, old_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
    }

    handle(const handle&) = delete;
    handle& operator=(const handle&) = delete;

    COORD get_cursor_pos() const
    {
        CONSOLE_SCREEN_BUFFER_INFO screen{};
        GetConsoleScreenBufferInfo(console, &screen);
        return screen.dwCursorPosition;
    }

    void set_pos(COORD pos) const
    {
        SetConsoleCursorPosition(console, pos);
    }

    void write(const WCHAR* sequence) const
    {
        DWORD written = 0;
        WriteConsoleW(console, sequence, (DWORD)wcslen(sequence), &written, nullptr);
    }

    void clear_screen() const
    {
        write(L"\x1b[2J");
        set_pos({0, 0});
    }

    ~handle()
    {
        SetConsoleMode(console, old_mode);
    }
};

key_code input()
{
    int c = _getch();
    // if it is a special key and there is another key to be handled
    if (c == 224 && _kbhit())
    {
        c = _getch();
        switch (c)
        {
        case 75:
            return KEY_LEFT_ARROW;
        case 77:
            return KEY_RIGHT_ARROW;
        case 72:
            return KEY_UP_ARROW;
        case 80:
            return KEY_DOWN_ARROW;
        case 83:
            return KEY_DELETE;
        case 79:
            return KEY_END;
        case 71:
            return KEY_HOME;
        }
    }
    return static_cast<key_code>(c);
}

struct handler
{
    std::wstring text;

    handle console;

    // holds initial cursor position
    COORD cursor_init;

    // holds position that the console cursor is for editing
    size_t cursor;

    bool finished;

    handler() : text{}, console{}, cursor{}, finished{true}
    {
    }

    void run()
    {
        if (finished)
        {
            text.clear();
            cursor_init = console.get_cursor_pos();
            cursor = 0;
            finished = false;
        }

        key_code code;

        // show cursor
        console.write(L"\x1b[?25h");
        console.set_pos({static_cast<short>(cursor_init.X + cursor), cursor_init.Y});

        code = input();
        switch (code)
        {
        case KEY_BACKSPACE:
            if (cursor > 0)
            {
                text.erase(text.begin() + cursor - 1);
                --cursor;
            }
            break;
        case KEY_DELETE:
            if (cursor < text.size())
                text.erase(text.begin() + cursor);
            break;
        case KEY_LEFT_ARROW:
            if (cursor > 0)
                --cursor;
            break;
        case KEY_RIGHT_ARROW:
            if (cursor < text.size())
                ++cursor;
            break;
        case KEY_HOME:
            cursor = 0;
            break;
        case KEY_END:
            cursor = text.size();
            break;
        case KEY_RETURN:
        case KEY_QUIT:
            finished = true;
        case KEY_UP_ARROW:
        case KEY_DOWN_ARROW:
        case KEY_ESCAPE:
            return;
        default:
            text.insert(text.begin() + cursor, static_cast<char>(code));
            ++cursor;
        }

        // move cursor to beginning of line
        console.set_pos(cursor_init);
        // clear line
        console.write(L"\x1b[0K");

        console.write(text.data());
        console.set_pos({static_cast<short>(cursor_init.X + cursor), cursor_init.Y});

        // hide cursor
        console.write(L"\x1b[?25l");
    }
};

// get_input returns true if input is finished (newline is entered)
bool get_input(std::wstring& str)
{
    static handler h;

    h.run();

    str = h.text;

    return h.finished;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接