2016-12-03 2 views
0

Я делаю двумерную игру типа искателя подземелья для класса. Я пытаюсь получить пользовательский ввод, не требуя нажатия клавиши ввода. В частности, я хочу использовать w s s как направленные клавиши для перемещения по 2D-массиву.Getch() несовместим с функцией отображения в linux C++

Я пробовал использовать библиотеку ncurses, но в настоящее время она работает с моей функцией отображения (я считаю, что при использовании endl).

Обычно моя плата отображается будет выглядеть так:
ххх
ххх
ххх

Но при использовании Гечи() из библиотеки Ncurses моей плата выглядит следующим образом:
ххх
..... .xxx
............ xxx

Есть ли способ использовать getch() из библиотеки curses, не мешая моей функции печати?

void ParkBoard::print() { 
displayMessage(); 
for (int i = 0; i < getSize(); i++) { 
    cout << " "; 
    for (int j = 0; j < getSize(); j++) { 
     if (j == 0) { 
      parkBoard[i][j]->display(); 
     } 
     else { 
      cout << " "; 
      parkBoard[i][j]->display(); 
     } 
    } 
    cout << endl; 
} 

ответ

2

ncurses ожидает, что он имеет полный контроль над терминалом дисплея. Вы используете ncurses для ввода, но все же извергаете вывод до std::cout.

Это не сработает. По крайней мере, не без серьезного взлома.

ncurses - это все или ничего. Либо вы используете ncurses для ввода, либо для вывода терминала, либо используете что-то еще полностью.

Но есть гораздо проще решение, так как все, что вы пытаетесь сделать, это «принимать пользовательский ввод, не требуя клавишу ввода, чтобы нажать»:

  1. Просто поместите дескриптор файла 0 в неблокирующем режиме , и читать с fd 0 с использованием read() (поскольку std::cin потребует слишком много няни, когда он читает из неблокирующего файлового дескриптора).

См. Справочную страницу fcntl(2), и найдите O_NONBLOCK. Затем:

  1. Установите терминал в неканоническом режиме, отключив флаг ICANON. См. Справочную страницу termios(3). Это то, что делает ncurses, чтобы получить доступ к сырым нажатиям клавиш.

Вам нужно будет немного поработать, чтобы восстановить терминал в каноническом режиме, если программа прервана, чтобы вернуться в оболочку в режиме «здорового» терминала.

+0

Я никогда раньше не использовал файловый дескриптор. Я пытаюсь понять, как настроить его, но я немного потерян. Таким образом, он не должен читать ввод из файла, это может быть просто нажатие клавиш? Кроме того, это правильная настройка: ssize_t read (int fd, void * buf, size_t count); – Kazuo

+1

Вам не нужно ничего устанавливать. Файловый дескриптор 0, стандартный ввод, наследуется процессом. –

1

короткий: нет

долго:

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

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

При инициализации проклятий он сохраняет копию входных и выходных режимов терминала, которые вы можете временно переключить на/с помощью вызовов curses reset_shell_mode и reset_prog_mode. Используйте эти, а не специальные вызовы termios, чтобы избежать запутывания проклятий.

Кроме терминалов режимов, есть выход буферизации по адресу. Если вы написали что-то на стандартный вывод, используя cout, сделайте флеш этого потока, прежде чем переключиться обратно на проклятия. При переключении с проклятий на cout, do a refresh в проклятиях, чтобы убедиться, что экран находится в известном состоянии.

В то время как вы можете использовать newterm для определения фактических выходных потоков проклятий (и сделать их отличными от cout и cin), вы все равно должны использовать интерфейс проклятья для надежного использования библиотеки.