Язык Си: основы Ncurses


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


Запись опубликована в рубрике С (Си). Добавьте в закладки постоянную ссылку.

Добавить комментарий

🇬🇧 Attention! Comments with URLs/email are not allowed.
🇷🇺 Комментарии со ссылками/email удаляются автоматически.