Как создать цикл на C++, который запускает счетчик времени и одновременно позволяет пользователю вводить данные (неблокирующий пользовательский ввод)

Итак, что я пытаюсь сделать, так это создать функцию на C++, которая позволяет пользователю вводить что угодно и что угодно в строку в течение заданного промежутка времени (скажем, десять минут (или даже одну)) (и СОХРАНЯЙТЕ все, что они ввели, кстати. Я пытаюсь разработать игру, чтобы помочь участникам NaNoWriMo или авторам в целом подтолкнуть их к написанию, поэтому важно сохранить все) и then не позволяет добавлять входящие данные. Сначала это звучало просто, но пять часов гугления доказали обратное.

Во-первых, я подумал, что могу просто добавлять несколько раз, пока не истечет время или что-то в этом роде. Наблюдать:

int main() //testing
{
    string str;
    string app = " ";
    getline(cin, app);

    for (int i = 0; i <= 3; i++)
    {
        Sleep(5000);
        cout << i << endl;
        str = " ";
        getline(cin, str);
        app.append(str);
    }

    cout << app;
}

Но потом я понял, да,, что цикл не будет проверять условие снова, пока пользователь не нажмет Enter. Надоедливый. То же самое с моей умной идеей персонажа. Мне нужен был цикл, который обновлялся бы с каждым введенным символом (или с каждой прошедшей секундой), независимо от того, сколько времени потребуется пользователю, чтобы ввести еще один.

Итак, тогда я подумал: «Ну, останавливаться в каждом месте и обновлять время должно работать достаточно хорошо, да?»

Именно тогда я начал обнаруживать, что C++ плохо работает с разбором строк или чтением ввода по мере его поступления. Я подумал о добавлении каждого символа, так как с ним довольно легко найти пробел, но он все еще ждет пользователя.

Разочарованный, я задался вопросом, есть ли способ запустить программу одновременно с получением пользовательского ввода, чтобы когда время истекло (используя time(null), проходит время time(null) и вычитая два переменные для получения прошедших секунд).

Оказывается, есть! (Я знал, что должен быть, учитывая все компьютерные программы и игры, использующие этот принцип, но я новичок в программировании (в прошлую среду я изучил функции, чтобы дать вам представление), поэтому я не знал, что.)

Первыми функциями, на которые я наткнулся, были curses и ncurses, но я быстро обнаружил, что это действительно неподходящий вариант для того, что я хочу сделать (поскольку я слышал, что cout делает довольно забавные вещи).

Затем я наткнулся на kbhit, который распознает нажатие клавиш на клавиатуре. Этот блог кажется многообещающим, и, вероятно, то, что я хочу сделать, но я не уверен, на каком языке это написано. . . все, что я знаю, это то, что он плохо работает с моей C++ IDE. Я понятия не имею, как заставить его хорошо работать с C++.

Итак, повторение того, что я хотел бы:

Цикл, который содержит одновременное выполнение счетчика времени и пользовательского ввода (в строку), но завершается (перестает позволять пользователю вводить дальнейшие данные в строку) по истечении времени. (Все без выполнения забавные вещи к остальной части моей программы, как ncurses.)

Дополнительно: я запускаю Windows 8 (проклятие моего существования) и использую Code::Blocks в качестве своей IDE.

Или, если у вас есть, где-то на этот вопрос уже был дан ответ. Это на самом деле было бы здорово. Я бы чувствовал себя глупо, если бы не смог его найти.

(Вот несколько мест, которые я посмотрел по пути:

Ввод данных пользователем во время работы программы

Как читать ввод из стандартного ввода, пока не будет нажат пробел или табуляция?

Захват символов из стандартного ввода без ожидания введите для нажатия )

(Игра, которую я пытаюсь создать (которая еще совсем не за горами, я начал ее прошлой ночью), если вам интересно: https://github.com/Rowan-Law/Dungeon-Crawl/blob/master/Source%20Code )


person Mars Enyalios    schedule 22.02.2015    source источник
comment
В стандартном C++, когда std::cin ожидает, пока пользователь нажмет Enter, вы не сможете его прервать. Все, что вы можете сделать, это проверить прошедшее время после того, как пользователь нажал клавишу ввода (для этого вам даже не нужна многопоточность). Если вам нужен больший контроль над низкоуровневыми операциями, связанными с вводом текста на консоли, вам нужно сообщить нам, какую ОС и компилятор вы используете.   -  person Christian Hackl    schedule 22.02.2015
comment
И кстати, если вам нужен такой большой контроль, то вы, вероятно, скоро захотите переключиться на программу с графическим интерфейсом.   -  person Christian Hackl    schedule 22.02.2015
comment
ReadConsoleInput может делайте то, что вам кажется нужным в Windows.   -  person Retired Ninja    schedule 22.02.2015


Ответы (3)


Вот как вы можете получить довольно близкое приближение к тому, что вы хотите в С++ 17, используя многопоточность. Единственная загвоздка в том, что пользователь все еще может печатать после истечения срока, просто он не будет сохранен.

#include <atomic>
#include <chrono>
#include <iostream>
#include <istream>
#include <mutex>
#include <ostream>
#include <string>
#include <thread>

std::atomic_bool done = false;
std::mutex cout_mutex{};

void Timing(std::chrono::seconds length) {
    auto start = std::chrono::steady_clock::now();
    auto end = start + length;
    auto now = std::chrono::steady_clock::now();
    while(now < end) {
        now = std::chrono::steady_clock::now();
        done = false;
    }
    done = true;
    {
        std::scoped_lock<std::mutex> lock(cout_mutex);
        std::cout << "\nTime's up! Any unsaved input will be lost." << std::endl;
    }
}

int main() {
    std::string str{};
    std::string app{};

    using namespace std::literals::chrono_literals;
    //This can be any duration you want.
    std::thread t = std::thread(Timing, 30s);
    t.detach();
    while(!done) {
        std::getline(std::cin, str);
        if(!done) {
            app.append(str + '\n');
        }
    }
    std::cout << app;
}
person Casey    schedule 02.12.2018

Вы, вероятно, захотите создать поток для времени, а затем просто обновлять строку до тех пор, пока поток времени не вернется

person Joe    schedule 22.02.2015

Многопоточность — это решение. На базовом уровне консольные приложения C++, использующие std::cin, обновляются только при входе (как указали и я, и Кристиан Хакл), поэтому без потоковой передачи то, что я хотел сделать, невозможно.

Я знаю, что этот вопрос довольно старый, но я надеюсь, что этот ответ сэкономит кому-то другому новичку кучу времени на поиски в Интернете ответа, которого не существует!

person Mars Enyalios    schedule 02.12.2018