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
