NCURSES — это библиотека на языке Си, которая управляет процессом отправки серии байтов через терминал. Это довольно старый подход, но он широко используется даже сейчас, поскольку интернет работает точно так же: интернет пакеты тоже посылаются просто сериями байтов. Так что интернет — это своего рода «большой» терминал 🙂
Итак… NCURSES (1993) — переписанный старый несвободный терминал CURSES, который был сделан для разработки игры Rogue (1980).
В общем, фича курсОв (далее ударение не ставлю) — управление курсором терминала. Эта статья основана на руководстве tldp NCURSES и некоторых других ресурсах. Давайте начнем!
NCURSES базовые функции
initscr()
запуск терминала в режиме курсов: делает malloc() окна stdscr
raw()
переводит ввод в «сырой» режим, позволяя, например, отключить буфер ввода (не надо жать Enter
для ввода команды); отключает интерпретацию системой нажатых клавиш (в т.ч. специальных)
cbreak();
примерно тоже самое; но интерпретирует некоторые команды, вроде ctrl+c
noecho()
отключает вывод нажатых клавиш; противоположна echo()
; т.е. если юзер вводит что-то через getch() — это не будет отображено ан экране
keypad(stdscr, TRUE)
позволяет читать нажатия специальных клавиш типа стрелок, F1-F12 и проч.
printw("Hello")
выводит в stdscr в данных y,x координатах
addch()
выводит символ
addstr()
выводит строку
refresh()
обновляет терминал
halfdelay()
кулдаун после которого вводить будет нельзя
getyx()
координаты курсора
move()
перемещает курсор в y,x
getch()
пользовательский ввод. Как getchar(), но без буфера ввода (не надо жать Enter после ввода)
attrset()
/ attron()
/ attroff()
примеряет атрибут к вводу. Также можно артибуты в виде максоров назначать на вывод:
addch(char | A_BOLD | A_UNDERLINE);
endwin()
выходит из режима курсов, высвобождая память через free()
Вывод (output)
mvaddch()
переместить курсор в y,x и напечатать. По сути означает:
move(row,col); addch(ch);
waddch()
тож самое что и addch()
, но в текущем окне
mvwaddch()
перемещает и печатает в окне
Похожим образом работают:
printw()
mvprintw(int y, int x, const char *fmt, ...)
wprintw()
mvwprintw()
vwprintw()
добаваляется список аргументов из <varargs.h>
Также:
addstr()
mvaddstr()
waddstr()
mvwaddstr()
addnstr()
печатает n
символов на экран
getmaxyx(stdscr,row,col)
возвращает максимальное количество строк и столбцов текущего онка. Это не функция, а макрос, который определен в ncurses.h
Ввод (input)
getch()
получить ввод пользователя минуя буфер
scanw()
взять форматированный ввод; как scanf(), но mvscanw()
— умеет брать ввод из конкретной yx
getstr()
взять строку; как getch() - но берет до тех пор, пока не встретится \n
, CR
, EOF
etc. Возвращает указатель на строку.
Атрибуты (attributes)
attrset()
устанавливает атрибуты окна; полностью отменяет все атрибуты, которые окно имело ранее
attron()
/ attroff()
включает заданный ему атрибут разметки (цвета, формат текста и проч)
attr_set()
, attr_on
… так же, как и выше, но принимает параметры типа attr_t
standend()
алиас attrset(A_NORMAL)
; отключает все атрибуты и переводит в нормальный режим
attr_get()
получает текущие атрибуты и пару (pair) цветов для окна (для сканирования областей экрана)
chgat()
установка атрибутов для группы символов без перемещения курсора (изменяет атрибуты заданного количества символов, начиная с текущего местоположения курсора).
Похожее: wchgat()
, mvchgat()
etc
Пример: mvchgat(0, 0, -1, A_BLINK, 1, NULL);
- Первые два параметра задают позицию, с которой нужно начать работу
- Третий параметр — количество символов для обновления. -1 означает до конец строки
- Четвертый параметр — это обычный атрибут, который вы хотите придать символу
- Пятый параметр — индекс цвета. Это индекс, заданный во время init_pair(). Используйте 0, если вам не нужен цвет
- Шестой параметр всегда NULL
Окна (windows)
Стандартное окно — stdscr
, но мы можем создать больше различных окон, чтобы манипулировать частями экрана по отдельности.
create_newwin(height, width, starty, startx);
создать новое «окно» — абстракцию воображаемого окна, которым можно манипулировать независимо от других частей экрана. Она возвращает указатель на структуру WINDOW, который может быть передан в функции, связанные с окном (wprintw()
и проч).
box()
нарисовать границу вокруг окна. Использует специальные расширенные символы для ее рисования (пример, ACS_ULCORNER
).
delwin()
уничтожить окно (деаллоцирует память для структуры окна)
Цвета (colors)
start_color()
инициализировать цвета
has_colors()
проверка: может ли терминал поддерживать цвета
init_pair()
инициализировать цветовую пару (цвет переднего плана (для отрисовки символов) и цвет фона).
COLOR_PAIR()
позволяет использовать цвета; например, через attron()
init_color(<color name>, <R>, <G>, <B>)
изменить значения rgb для цветов, определенных curses изначально. Если ваш терминал не может изменить определения цветов, функция возвращает ошибку (ERR).
can_change_color()
проверяет, может ли терминал менять цвета. Возвращает 1, если он может это делать (т.е. можно выставить любой кастомный цвет при помощи трех чисел — RGB; выставляя интенсивность от 0 до 1000 каждое).
color_content()
/ pair_content()
найти цвет
Мышь (mouse interaction)
Мы рассмотрели взаимодействие с клавиатурой в первой главе (материал getch), поэтому давайте рассмотрим взаимодействие с мышью:
mousemask (mmask_t newmask, mmask_t *oldmask)
1-й аргумент — это события, которые вы хотите прослушивать (по умолчанию все события выключены).
2-й аргумент — старая маска событий.
Пример:
mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL);
Список событий:
BUTTON1_PRESSED нажать кнопку 1 BUTTON1_RELEASED отжать кнопку 1 BUTTON1_CLICKED кликнуть кнопкой 1 BUTTON1_DOUBLE_CLICKED дабл клик кнопкой 1 BUTTON1_TRIPLE_CLICKED тройное нажатие кнопкой 1 ... BUTTON4_TRIPLE_CLICKED тройное нажатие кнопкой 4 BUTTON_SHIFT был зажат Shift BUTTON_CTRL был зажат Ctrl BUTTON_ALT был зажат Alt ALL_MOUSE_EVENTS сообщать обо всех изменениях состояния кнопки REPORT_MOUSE_POSITION сообщать о движении мыши
getmouse()
получить событие мыши; возвращает событие в указатель, переданный ему; такая структура:
typedef struct { short id; /* Идентификатор для различения нескольких устройств */ int x, y, z; /* координаты события */ mmask_t bstate; /* биты состояния кнопки */ }
mouse_trafo()
/ wmouse_trafo()
преобразование координат мыши в относительные координаты экрана (см. curs_mouse()
)
mouseinterval()
функция устанавливает максимальное время (в тысячных долях секунды), которое может пройти между событиями нажатия и отпускания для того, чтобы они были распознаны как клик
Примечание: Похоже, что некоторые старые примеры кода для мыши в NCURSES работают немного глючно. Я тестировал в Ubuntu и Cygwin, и некоторые вещи не работали.
Манипуляции с экраном (screen manipulation)
getyx(win, y, x);
получает координаты текущего курсора в переменные y, x.
win
— указатель окна
y, x
координаты будут помещены в эти переменные
getparyx()
получает начальные координаты подокна относительно главного окна
getbegyx()
/ getmaxyx()
сохранить координаты начала и максимума текущего окна
scr_dump()
сброс содержимого экрана в файл, указанный в качестве аргумента
scr_restore()
восстановить дамп содержимого экрана
putwin()
/ getwin()
сохранение и восстановление окон
copywin()
копирует окно полностью в другое окно; принимает исходное и конечное окна в качестве параметров и в соответствии с заданным прямоугольником копирует прямоугольную область из исходного окна в конечное. Последний параметр определяет, нужно ли перезаписать или просто наложить содержимое на окно назначения. Если этот аргумент равен true, то копирование будет «неразрушающим».
Другие полезности (misc NCURSES stuff)
curs_set()
сделать курсор невидимым. Параметры:
0 невидимый / 1 нормальный / 2 очень видимый
Как временно выйти из режима Curses:
def_prog_mode()
сохраняет tty режим → endwin()
Вернуться: reset_prog_mode()
→ refresh()
Полезные библиотеки:
panel.h
Панельный объект — это окно, которое неявно рассматривается как часть колоды, включающей все остальные панельные объекты. Колода рассматривается как стопка, при этом верхняя панель полностью видна, а остальные панели могут быть или не быть скрыты в зависимости от их положения.
menu.h
расширение к базовому curses для создания меню. Сначала вы создаете пункты, а затем выводите меню на экран. После этого вся обработка ответов пользователя выполняется в элегантной функции menu_driver(), которая является рабочей лошадкой любой программы меню.
form.h
формы, созданные с полями с помощью new_field(); форма манипулируется с помощью form_driver() — для отправки запросов на перемещение фокуса в определенное поле, перемещение курсора в конец поля и т.д.
CDK (Curses Development Kit) https://invisible-island.net/cdk/
dialog.h
для создания диалоговых окон http://invisible-island.net/dialog/
Perl Curses Modules CURSES::FORM и CURSES::WIDGETS:
http://cpan.org/modules/01modules.index.html
Цвета по умолчанию
0. Черный
1. Синий
2. Зеленый
3. Голубой
4. Красный
5. Пурпурный
6. Браун
7. Белый (Светло-серый)
8. Ярко-черный (Серый)
9. Ярко-синий
10. Ярко-зеленый
11. Яркий голубой
12. Ярко-красный
13. Яркий пурпурный
14. Желтый
15. Ярко-белый
Ссылки по NCurses (англ.)
Гайд по NCurses https://tldp.org/HOWTO/NCURSES-Programming-HOWTO/
Мануал https://invisible-island.net/ncurses/man/index.html
FAQ https://invisible-island.net/ncurses/ncurses.faq.html
Обучалка https://invisible-island.net/ncurses/ncurses-intro.html
Другой вариант этой библиотеки — PDCurses, которая хорошо работает в Windows OS