C++, как одновременно выполнять ввод и вывод (LINUX/MAC) без ncurses

я пытаюсь заставить ввод и вывод работать одновременно, но без того, чтобы вывод не испортил это. Я заставил его работать с Windows, но не с Linux/Mac (для получения строки с терминала, чтобы я мог распечатать ее под выбранным выводимым текстом)

код:

#include <iostream>
#include <string>
#include <thread>
#include <atomic>
#include <chrono>

#if defined(_WIN32)
#include <windows.h>
#include <conio.h>
#elif defined(__unix__) || defined(__APPLE__)
//libraries needed
#endif

using namespace std;

void ReadCin(atomic<bool>& run)
{
    string buffer;

    while (run.load())
    {
        getline(cin, buffer);

        if (buffer == "Quit")
        {
            run.store(false);
        }
    }
}

string get_terminal_line()
{
    string line;

#if defined(_WIN32)
    HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    if (GetConsoleScreenBufferInfo(hStdOut, &csbi))
    {
        DWORD dwSize = csbi.dwSize.X;
        COORD cursorPos = csbi.dwCursorPosition;
        cursorPos.X = 0;
        SetConsoleCursorPosition(hStdOut, cursorPos);

        for (DWORD i = 0; i < dwSize; ++i)
        {
            char ch;
            DWORD charsRead;
            if (ReadConsoleOutputCharacterA(hStdOut, &ch, 1, cursorPos, &charsRead))
            {
                line += ch;
                cursorPos.X++;
            }
            else
            {
                break;
            }
        }

        SetConsoleCursorPosition(hStdOut, csbi.dwCursorPosition);
    }

#elif defined(__unix__) || defined(__APPLE__)
    //here
#endif

    size_t end = line.find_last_not_of(' ');
    if (end != string::npos)
    {
        line.erase(end + 1);
    }
    else
    {
        line.clear();
    }

    return line;
}

void PrintNewLine(atomic<bool>& run)
{
    while (run.load())
    {
        this_thread::sleep_for(chrono::seconds(2));

        string line = get_terminal_line();

        cout << "\33[2K\rNew line printed every 10 seconds" << endl;

        bool is_space = true;

        for (size_t length = 0; length != line.length(); length++)
        {
            if (isspace(line[length]) == false)
            {
                is_space = false;
                break;
            }
        }

        if (is_space == false)
        {
            cout << line;
        }
    }
}

int main()
{
    atomic<bool> run(true);
    thread cinThread(ReadCin, ref(run));
    thread printThread(PrintNewLine, ref(run));

    while (run.load())
    {
      //idk what to put here, so i'm just gonna leave it empty
    }

    run.store(false);
    cinThread.join();
    printThread.join();

    return 0;
}

Я хочу, чтобы это работало с Mac и Linux (следовательно, макрос определен выше), который просто получает строку с терминала.

Если вы не хотите использовать ncurses, вам придется реализовать это самостоятельно... получайте удовольствие.

tink 17.08.2024 01:49

Если вы не хотите использовать ncurses, вы можете написать свои собственные функции, которые делают ровно столько, сколько нужно для работы ваших платформ. Это будет небольшое подмножество ncurses, поскольку ncurses работает на удивительно большом наборе терминалов. И тогда вы сможете обнаружить все функции, которые вам нужно создать (вместо того, чтобы они уже были написаны и отлажены в ncurses).

Eljay 17.08.2024 01:50

Я имею в виду, что большую часть работы я уже сделал, мне просто нужна помощь с Linux/Mac (поскольку я с ними менее знаком)

changethis1 17.08.2024 01:52

Ваш подход (чтение буфера консоли) не будет работать в средах, отличных от Windows. Извини. И, к сожалению, идея одновременного взаимодействия нескольких потоков с пользовательским терминалом также имеет проблемы и может вас укусить. Он просто не предназначен для такого использования. Вы просто хотите, чтобы в нижнем углу было что-то вроде часов или что-то в этом роде, пока пользователь (медленно) вводит данные в другом месте экрана?

Dúthomhas 17.08.2024 02:20

Я просто хочу печатать текст на терминале без его печати поверх ранее набранной строки, чтобы пользователь мог продолжать вводить в него данные, как ncurses. Должен быть способ, если ncurses может это сделать. github.com/mirror/ncurses

changethis1 17.08.2024 02:30

ncurses довольно чистый и эффективный. Если бы я хотел знать, как сделать это правильно, не используя ncurses, я бы посмотрел, как ncurses выполняет эту работу. Скорее всего, если вы попытаетесь отойти слишком далеко от их подхода, вы чаще будете стрелять себе в ногу.

user4581301 17.08.2024 02:43

есть ли какие-либо предложения о том, как я могу сделать это на С++?

changethis1 17.08.2024 02:55

Моя система Windows в настоящее время не работает, поэтому я не могу запустить ваш код, чтобы точно увидеть, как он себя ведет. Расскажите нам, чего именно вы пытаетесь достичь визуально, и мы, возможно, сможем предложить что-то полезное. Однако если вам нужен необработанный ввод, скорее всего, лучше всего использовать NCurses.

Dúthomhas 17.08.2024 03:13

Я не уверен, как я смогу объяснить это визуально, но я постараюсь изо всех сил. строка курсора (из терминала) сначала копируется и сохраняется перед печатью новой строки. Когда новая строка собирается быть напечатанной, она заменяет (строку курсора), сначала очищая строку курсора, а затем печатая себя на той же строке. тогда предыдущая строка курсора печатается после новой строки.

changethis1 17.08.2024 03:22

это останавливает печать, прерывая введенный текст в терминале, если в него не вносилось никаких изменений (если это все пробелы), то предыдущая строка не печатается

changethis1 17.08.2024 03:26

Похоже, вам нужна «оторванная» линия, которая используется для строк состояния (или ввода), в то время как другие строки выше (или ниже) могут продолжать прокручиваться?

Dúthomhas 17.08.2024 03:33

хотите, чтобы я скомпилировал пример в x86, чтобы вы могли использовать Wine с терминалом в качестве примера, если вы используете Linux, извините, что неясно, не знаю, как это объяснить

changethis1 17.08.2024 04:00

@changethis1 для справки: ваша программа не будет работать в обычном Wine. Для этого понадобится wineconsole, который эмулирует консоль Windows… с помощью ncurses.

spectras 17.08.2024 06:28

я не использую ncurses...

changethis1 17.08.2024 08:15

о, ты имеешь в виду на винной консоли, разве это не вариант?

changethis1 17.08.2024 08:16

хмммммммммм Я тоже нашел это: stackoverflow.com/questions/55414228/…

changethis1 17.08.2024 08:36

вау, я только что понял, что могу взять его посимвольно, который набран, и сохранить его обратно в строку, а затем, когда это произойдет, просто перепечатать его снова для max/linux... Я думаю, это было возможно и легко

changethis1 17.08.2024 08:42

зачем все это было необходимо?!

changethis1 17.08.2024 08:42

в любом случае, я закончил код, спасибо за предложения...

changethis1 17.08.2024 08:50
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
19
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В Linux вы управляете вводом/выводом терминала с помощью функции tcsetattr, которая позволяет вам контролировать различные вещи, которые происходят в ядре/драйверах между вашей программой и терминалом.

Если я понимаю, о чем вы спрашиваете, вы хотите отключить автоматическое эхо ввода с клавиатуры, чтобы вы могли правильно позиционировать его при выводе. Вы делаете это с помощью флага ECHO:

#include <termios.h>

  :

     struct termios term;
     tcgetattr(0, &term);    // get the setting on the terminal connected to stdin
     term.c_lflag &= ~ECHO;  // turn off the ECHO flag
     tcsetattr(0, TCSANOW, &term);

Теперь ввод с клавиатуры будет «тихим» — не будет отображаться на экране, поэтому, если вы хотите, чтобы ввод был виден, вам придется вывести его самостоятельно. Если вы хотите иметь возможность получать (и, таким образом, отображать и видеть) нажатия клавиш до нажатия Enter, вам также необходимо очистить бит ICANON для канонической обработки ввода:

term.c_lflag &= ~(ECHO|ICANON);  // turn off echo and canonical input

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

спасибо, я думаю, но я уже нашел решение, которое работает для меня

changethis1 17.08.2024 08:52

Другие вопросы по теме