Подтвердить что ты не робот

Входная панель в нижней части консоли в C

Окно внизу

Некоторые приложения, такие как vim, mutt, aptitude, содержат

  • верхний раздел окна для вывода и
  • нижний раздел для ввода пользователем или для отображения состояния.

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

Actions  Undo  Package  Resolver  Search  Options  Views  Help
C-T: Menu  ?: Help  q: Quit  u: Update  g: Download/Install/Remove Pkgs



                                                                            |
                                                                            |
                                                                            |
                                                                            |
                                                                            |
                            ┌─────────────┐                                 |
                            │Loading cache│                                 |
                            └─────────────┘                                 |
                                                                            |
                                                                            |
                                                                            |
                                                                            |
                                                                            |
                                                                            |    
                                                                            |
--------------------------------------------------------------------------- |
Initialising package states                                            100% |

+-------------------------------------------------------+
| some output here                                      |
|                                                       |
|                                                       |
|                                                       |
|                                                       |
|                                                       |
|-------------------------------------------------------+
|:input here                                            |
+-------------------------------------------------------+

Учебник Ncurses не упоминает, что это очевидно.

Запрос на "c print to {window, screen, terminal, console} bottom" в StackOverflow или в поисковой системе не помогает.

Можно ли это сделать на C программно?

Отбрасывание ввода

В то время как некоторые из приведенных ниже решений могут перемещать символ в заданную позицию, существует проблема, что может потребоваться отменить ввод пользователя, а не оставить его на экране. Как и в случае vim, набрав ":w" и нажав Enter, не оставит на экране ":w".

Update. Это можно найти здесь: Как удалить текст после getstr() С++ ncurses

Оконный фокус - НЕОПРЕДЕЛЕННАЯ ЧАСТЬ ПРОБЛЕМЫ

Пока вы вводите ввод в нижней части окна, а текст в верхней части изменяется, мы видим проблему перемещения фокуса назад. Это отсутствует в решениях по состоянию на 29 декабря.


Обновление 1. Просто попробуйте

  • запомнить предыдущую позицию курсора, затем
  • отобразить вывод, а затем
  • восстановить позицию

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

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

Реализация этого будет связана с некоторой межпроцессной связью, и если есть другие решения, они могут быть предпочтительнее.

Похожие

4b9b3361

Ответ 1

Используя стандартные библиотеки, нет способа сделать это; используя ncurses, как вы уже сказали, это легко возможно; Я думаю, этот учебник объясняет это довольно хорошо.

Ответ 2

Используя escape-последовательность ANSI, можно управлять положением курсора:

void gotoxy(int x, int y) {
    printf("\033[%d;%dH",x,y);
}

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

Ответ 3

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

Используйте termio для отключения канонического режима.

Пример кода (здесь) покажет вам, как настроить такой входной цикл. Этот пример "опросы и сны", который может означать задержку, если вы не уменьшите сон. Также я думаю, что вы можете использовать termio для установки тайм-аута (подождите секунду и не возвращайте "нет ввода" или дайте мне вход СЕЙЧАС, если он поступит раньше). Но если вы действительно собираетесь контролировать другой процесс, опрос может быть более гибким вариантом. Вы можете действительно опробовать 30 раз в секунду и жить с процессором .00001%, который он вызовет, но вам понравится простота и ошибка. предотвращение.

Избегайте нескольких потоков и процессов, таких как чума

Вам не нужно использовать 2 процесса/нити, если единственная проблема, которую вы пытаетесь решить, - это тот факт, что getch() блокирует. Это потребовалось бы, если бы было невозможно предотвратить блокировку входных функций. "Canonical" (основанный на правилах) означает, что всевозможные полезные "правила" действуют, например: "не вводите ввод в программу до тех пор, пока не будет нажата ENTER". Для полноэкранного консольного приложения вы хотите отключить все правила и сделать все сами.

Поместите основной поток, отвечающий за окно...

... Затем вы можете просто использовать ansi escape csi codes, чтобы поместить курсор обратно туда, где вы хотите. Предостережение: вы не можете писать в правом нижнем углу экрана. Все будет прокручиваться.

В программировании MS-окон есть раздражающая вещь, где только поток, создающий окно, может безопасно обновлять его. На самом деле есть причина для этого. Если вы говорите о консоли или системе окон. рано или поздно, если у вас есть несколько потоков/обработки, попавших на одно устройство вывода, вы прервите escape-последовательность (или вам придется сделать дополнительный код для управления этим, что плохо), боритесь за выходной порт и т.д. вам нужен один поток для управления выходом.

, если, вам действительно интересно, что делает какой-то другой поток или процесс, просто проверьте его в своем главном контуре управления контуром. Например, у вас есть другой процесс, который вы просто хотите сообщить о его прогрессе, запустите его из своей программы и запишите его stdouput и посмотрите на это; другой поток, просто заблокируйте что-то общее, вы можете проверить свою процедуру опроса. Если это просто байт, и он используется только для статусов, даже не блокируйте эту чертову вещь. Вы можете бросить пару GOTO, просто чтобы показать свою индивидуальность: -)

caveat Я не знаю, что ncurses будет хорошо играть с вами, если вы вручную возитесь с termio? Я предполагаю, что он хочет сделать это сам. Никогда не пробовал смешивать. Если ваше приложение просто, вы можете сделать это самостоятельно без помощи, особенно если вы можете бороться с ncurses в том, что хотите. Я не эксперт в тех приложениях, которые вы упоминаете, но я бы поспорил, что они микроменеджмент все.

Ответ 4

У меня была аналогичная проблема несколько недель назад при написании IRC-клиента, который работает в терминале. Я написал его, используя библиотеку Windows conio, но я уверен, что это должно быть применимо к проклятиям. Идея заключается в том, что вывод консоли обрабатывается одним потоком, а вход в консоль обрабатывается в отдельном потоке. В принципе, все, что вам нужно, это цикл, который подталкивает возврат getch() к FIFO с мьютированием, который работает в течение всего времени программы. В потоке отображения вы можете вызывать нажатия клавиш FIFO и обрабатывать их, как вам нравится. Вы не можете использовать стандартную функцию, например fgets(), но это очень надежное решение вашей проблемы. Я могу предоставить полный (беспорядочный) источник по запросу.

Изменить: хорошо, ну вот соответствующий код из FIFO:

bool keyqueuewriting = false;
std::deque<int> keyqueue;
void grabkey( void* in )
{
    int t;
    while( true ){
        t = getch();
        #ifdef _WIN32
        if( t == 224 || t == 0 )
        {
            t += getch() << 8;
        }
        #else
            int off = 8;
            if( t == 27 ){
                int e = getch();
                t += e << off;
                off += 8;
                while( e ==91 || (e >= '0' && e <= '9') || e == ';' )
                {
                    e = getch();
                    t += e << off;
                    off += 8;
                }
            }
        #endif
        while( keyqueuewriting ){}
        keyqueuewriting = true;
        keyqueue.push_back( t );
        keyqueuewriting = false;
    }
}

И обработка:

while( keyqueuewriting ){}
keyqueuewriting = true;
while( keyqueue.size() > 0 )
{
    shouldsleep = false;
    int t = keyqueue.front();
    keyqueue.pop_front();
    switch( t )
    {
        case K_BACKSPACE:
            if( pos > 0 ){
                for( int i = pos-1; input[i] != 0; i++ ){input[i] = input[i+1];}
                movecursorback( 1 );
                pos -= 1;

                } break;
        case K_LEFT: if( pos > 0 ){ movecursorback( 1 ); pos -= 1; } break;
        case K_RIGHT: if( input[pos] != 0 ) {movecursorforward( 1 ); pos += 1;} break;
        case K_HOME: { gotoxy(0,SCREENHIG-1); pos = 0; } break;
        case K_END: { int a = strlen( input ); /*gotoxy( 79,39 );*/ pos = a;} break;
        case 3: exit(3); break;

        default: if( t >= 0x20 && t < 0x80 ){
                int a = strlen( input );
                if( a > 998 )
                    a = 998;
                int deadcode = 1;
                input[999] = 0;
                for( int i = a+1; i > pos; i-- ){input[i] = input[i-1];}
                input[ pos ] = t;
                movecursorforward( 1 );
                pos++;
                } break;
    }
    change = bufpos[curroom] - bufprev;
    if( pos > 998 ) pos = 998;
    if( pos - mescroll < 1 ) {mescroll += (pos-mescroll-1); gotoxy( pos-mescroll, SCREENHIG-1 );}
    if( pos - mescroll > 78 ) {mescroll += (pos-mescroll-78); gotoxy( pos-mescroll, SCREENHIG-1 );}
    if( mescroll < 0 ) {mescroll = 0; gotoxy( 0, SCREENHIG-1 ); }
    savexy();
    gotoxy( 0, SCREENHIG-1 );
    char y = (input+mescroll)[79];
    (input+mescroll)[79] = 0;
    printf( "%s   ", input+mescroll );
    (input+mescroll)[79] = y;

    returntosaved();
    change2 = change;
    bufprev = bufpos[curroom];
}
keyqueuewriting = false;

Да, он использует std:: deque. Это должно быть единственной спецификой С++. Просто замените его на C-совместимый FIFO.

Весь клиент может найти здесь. Да, он компилируется в Linux, но он не работает. Я никогда не беспокоился о том, как использовать ncurses, прежде чем я начну работать над ним.