- •Глава 6
- •Int endwin(void);
- •Int instr(char *string);
- •Int innstr(char *string, int number_of_characters);
- •Int move(int new_y, int new_x);
- •Int leaveok(window *window_ptr, bool leave_flag);
- •Int delwin(window *window_to_delete);
- •Int wnoutrefresh(window *window_ptr);
- •Int doupdate(void);
- •Int start_y, int start_x);
- •Int delwin(window *window_to_delete);
- •Int keypad(window *window_ptr, bool keypad_on);
- •Int start_color(void);
- •Int init_pair(short pair_number, short foreground, short background);
- •Int color_pair(int pair_number);
- •Int pair_content(short pair_number, short *foreground, short *background);
- •Int init_color(short color_number, short red, short green, short blue);
- •Int prefresh(window *pad_ptr, int pad_row, int pad_column, int screen_row_min, int screen_col_min, int screen_row_max, int screen_соl_max);
Int instr(char *string);
Int innstr(char *string, int number_of_characters);
Функция
inch
должна быть всегда доступна, а функции
instr
и
innstr
не всегда поддерживаются. Функция
inch
возвращает символ из текущей позиции курсора на экране и данные о его атрибутах. Обратите внимание на то, что функция возвращает значение не
char
, a
chtype
, в то время как функции
instr
и
innstr
пишут в массивы с элементами типа
char
.
Очистка экрана
Существует четыре основных способа очистки области экрана:
#include <curses.h>
int erase (void);
int clear(void);
int clrtobot(void);
int clrtoeol(void);
Функция
erase
записывает пробелы во все позиции экрана. Функция
clear
, как и
erase
, очищает экран, но вызывает перерисовку экрана с помощью внутреннего вызова низкоуровневой функции clear
o
k, которая выполняет последовательность очистки экрана и новое отображение экрана при следующем вызове
refresh
.
Функция
clear
обычно применяет команду терминала, которая очищает весь экран, а не пытается стереть текущие непробельные символы во всех точках экрана. Это делает функцию
clear
надежным средством очистки экрана. Сочетание функции
clear
с последующей функцией
refresh
может обеспечить удобную команду перерисовки экрана в том случае, когда изображение на экране беспорядочно или испорчено каким-либо образом.
Функция
clrtobot
очищает экран, начиная с текущей позиции курсора и далее до конца экрана, а функция
clrtoeol
очищает экран, начиная с текущей позиции курсора до конца строки, в которой находится курсор.
Перемещение курсора
Для перемещения курсора применяется единственная функция с дополнительной командой, управляющей положением курсора после обновления экрана.
#include <curses.h>
Int move(int new_y, int new_x);
Int leaveok(window *window_ptr, bool leave_flag);
Функция
move
просто переносит позицию логического курсора в заданное место на экране. Напоминаем о том, что начало экранных координат (0, 0) находится в левом верхнем углу экрана. В большинстве версий библиотеки curses две глобальные целочисленные переменные,
LINES
и
COLUMNS
, определяют размер физического экрана и могут применяться для определения максимально допустимых значений параметров
new_y
и
new_x
. Вызов
move
сам по себе не приводит к перемещению физического курсора. Он только изменяет позицию на логическом экране, в которой появится следующий вывод. Если вы хотите, чтобы экранный курсор переместился немедленно после вызова функции move, вставьте следом за ним вызов функции
refresh
.
Функция
leaveok
устанавливает флаг, управляющий положением курсора на физическом экране после его обновления. По умолчанию флаг равен
false
, и после вызова
refresh
аппаратный курсор остается в той же точке экрана, что и логический курсор. Если флаг равен
true
, аппаратный курсор можно оставить в случайно выбранной точке экрана. Как правило, значение, устанавливаемое по умолчанию, предпочтительней, т.к. курсор остается в не лишенной смысла позиции.
Атрибуты символов
У всех символов, обрабатываемых curses, могут быть определенные атрибуты, управляющие способом отображения символа на экране при условии, что оборудование, применяемое для их отображения, поддерживает требуемый атрибут. Определены следующие атрибуты:
A_BLINK
,
A_BOLD
,
A_DIM
,
A_REVERSE
,
A_STANDOUT
и
A_UNDERLINE
. Вы можете использовать перечисленные далее функции для установки атрибутов по одному или все вместе.
#include <curses.h>
int attron(chtype attribute);
int attroff(chtype attribute);
int attrset(chtype attribute);
int standout(void);
int standend(void);
Функция
attrset
устанавливает атрибуты curses, функции
attron
и
attroff
включают и отключают заданные атрибуты, не портя остальные, а функции
standout
и
standend
обеспечивают более выразительный режим выделения или "лучший из всех" режим. На большинстве терминалов выбирается инверсия.
Выполните упражнение 6.2.
Упражнение 6.2. Перемещение, вставка и атрибуты
Теперь, когда вы знаете больше об управлении экраном, можно испытать более сложный пример moveadd.c. Вы включите несколько вызовов функций
refresh
и
sleep
в этот пример, чтобы на каждом шаге видеть, как выглядит экран. Обычно программы с использованием библиотеки curses стараются обновлять экран как можно реже, поскольку это не слишком высокопроизводительная операция. Программный код написан с некоторой долей искусственности для обеспечения большей наглядности.
1. Для начала вставьте несколько заголовочных файлов, определите несколько символьных массивов и указатель на них, а затем инициализируйте структуры библиотеки curses:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <curses.h>
int main() {
const char witch_one[] = " First Witch ";
const char witch_two[] = " Second Witch ";
const char *scan_ptr;
initscr();
2. Теперь для трех начальных текстовых фрагментов, которые появляются на экране через определенные интервалы, включите и отключите соответствующие флаги атрибутов;
move(5, 15);
attron(A_BOLD);
printw("%s", "Macbeth");
attroff(A_BOLD);
refresh();
sleep(1);
move(8, 15);
attron(A_STANDOUT);
printw("%s", "Thunder and Lightning");
attroff(A_STANDOUT);
refresh();
sleep(1);
move(10, 10);
printw("%s", "When shall we three meet again");
move(11, 23);
printw("%s", "In thunder, lightning, or in rain ?");
move(13, 10);
printw("%s", "When the hurlyburly's done, ");
move(14, 23);
printw("%s", "When the battle's lost and won.");
refresh();
sleep(1);
3. Действующие лица идентифицированы, и их имена выводятся посимвольно:
attron(A_DIM);
scan_ptr = witch_one + strlen(witch_one) - 1;
while (scan_ptr != witch_one) {
move(10, 10);
insch(*scan_ptr--);
}
scan_ptr = witch_two + strlen(witch_two) - 1;
while (scan_ptr != witch_two) {
move(13, 10);
insch(*scan_ptr--);
}
attroff(A_DIM);
refresh();
sleep(1);
4. В заключение переместите курсор в правый нижний угол экрана, а затем подготовьте и выполните завершение:
move(LINES - 1, COLS - 1);
refresh();
sleep(1);
endwin();
exit(EXIT_SUCCESS);
}
Когда вы выполните программу, заключительный экран будет выглядеть так, как показано на рис. 6.3. К сожалению, снимок экрана не дает полного впечатления и не показывает курсор, установленный в правом нижнем углу экрана. Эмулятор xterm может быть более подходящей средой для точного отображения программ, чем обычная консоль.
Рис. 6.3
Как это работает
После инициализации некоторых переменных и экрана с помощью библиотеки curses вы применили функции
move
для перемещения курсора по экрану. Посредством функций
attron
и
attroff
вы управляли атрибутами текста, выводимого в заданную точку экрана. Далее перед закрытием библиотеки curses и завершением программа продемонстрировала, как вставлять символы функцией
insch
.
Клавиатура
Наряду с предоставлением интерфейса, облегчающего управление экраном, библиотека curses также предлагает средства, облегчающие управление клавиатурой.
Режимы клавиатуры
Процедуры считывания с клавиатуры управляются режимами. Режимы устанавливаются с помощью следующих функций:
#include <curses.h>
int echo(void);
int noecho(void);
int cbreak(void);
int nocbreak(void);
int raw(void);
int noraw(void);
Функции
echo
и
noecho
просто включают и отключают отображение символов, набираемых на клавиатуре. Оставшиеся четыре функции управляют тем, как символы, набранные на терминале, становятся доступны программе с применением curses. Для того чтобы понять функцию
cbreak
, необходимо иметь представление о стандартном режиме ввода. Когда программа, использующая библиотеку curses, стартует с вызова функции
initscr
, устанавливается режим ввода, называемый режимом с обработкой (cooked mode). Это означает построчную обработку, т.е. ввод становится доступен программе после нажатия пользователем клавиши <Enter> (или <Return> на некоторых клавиатурах). Специальные символы на клавиатуре включены, поэтому набор соответствующих клавиатурных последовательностей может сгенерировать сигнал в программе. Управление потоком, если терминал запускается с терминала, также включено. Вызывая функцию
cbreak
, программа может установить режим ввода
cbreak
, в котором символы становятся доступными программе сразу после их набора, а не помещаются в буфер и передаются программе только после нажатия клавиши <Enter>. Как и в режиме с обработкой, специальные символы клавиатуры действуют, а простые клавиши, например <Backspace>, передаются для обработки непосредственно в программу, поэтому если вы хотите, чтобы нажатие клавиши <Backspace> приводило к привычным действиям, то вы должны запрограммировать их самостоятельно.
Вызов функции
raw
отключает обработку специальных символов, поэтому становится невозможной генерация сигналов или управление потоком с помощью набранных на клавиатуре специальных символьных последовательностей. Вызов функции
nocbreak
возвращает режим ввода в режим с обработкой символов, но режим обработки специальных символов не изменяет; вызов
noraw
восстанавливает и режим с обработкой, и обработку специальных символов.
Клавиатурный ввод
Чтение с клавиатуры — очень простая операция. К основным функциям чтения относятся следующие:
#include <curses.h>
int getch(void);
int getstr(char *string);
int getnstr(char *string, int number_of_characters);
int scanw(char *format, ...);
Все они действуют подобно своим аналогам, не входящим в библиотеку curses,
getchar
,
gets
и
scanf
. Обратите внимание на то, что у функции
getstr
нет возможности ограничить длину возвращаемой строки, поэтому применять ее следует с большой осторожностью. Если ваша версия библиотеки curses поддерживает функцию
getnstr
, позволяющую ограничить количество считываемых символов, всегда применяйте ее вместо функции
getstr
. Это очень напоминает поведение функций
gets
и
fgets
, с которыми вы познакомились в главе 3.
В упражнении 6.3 для демонстрации управления клавиатурой приведен пример короткой программы ipmode.c.
Упражнение 6.3. Режим клавиатуры и ввод
1. Наберите программу и включите в нее начальные вызовы библиотеки curses:
#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
#include <string.h>
#define PW_LEN 256
#define NAME_LEN 256
int main() {
char name[NAME_LEN];
char password[PW_LEN];
const char *real_password = "xyzzy";
int i = 0;
initscr();
move(5, 10);
printw("%s", "Please login:");
move(7, 10);
printw("%s", "User name: ");
getstr(name);
move(9, 10);
printw("%s", "Password: ");
refresh();
2. Когда пользователь вводит свой пароль, необходимо остановить отображение символов на экране. Далее сравните введенный пароль со строкой xyzzy:
cbreak();
noecho();
memset(password, '\0', sizeof(password));
while (i < PW_LEN) {
password[i] = getch();
if (password[i] == '\n') break;
move(8, 20 + i);
addch('*');
refresh();
i++;
}
3. В заключение восстановите отображение символов и выведите сообщение об успешном или неудачном завершении:
echo();
nocbreak();
move(11, 10);
if (strncmp(real_password, password, strlen(real_password)) == 0)
printw("%s", "Correct");
else printw("%s", "Wrong");
printw("%s", " password");
refresh();
sleep(2);
endwin();
exit(EXIT_SUCCESS);
}
Как это работает
Остановив отображение клавиатурного ввода и установив режим
cbreak
, вы выделяете область памяти, готовую к приему пароля. Каждый введенный символ пароля немедленно обрабатывается, и на экран выводится
*
в следующей позиции курсора. Вам необходимо каждый раз обновлять экран и сравнивать с помощью функции
strcmp
две строки: введенный и реальный пароли.
Примечание
Если вы пользуетесь очень старой версией библиотеки curses, вам, возможно, понадобится выполнить дополнительный вызов функции
refresh
перед вызовом функции
getstr
. В библиотеке ncurses вызов
getstr
обновляет экран автоматически.
Окна
До сих пор вы использовали терминал как средство полноэкранного вывода. Это вполне подходит для маленьких простых программ, но библиотека curses идет гораздо дальше. Вы можете на физическом экране одновременно отображать множество окон разных размеров. Многие из описанных в этом разделе функций поддерживаются в терминах стандарта X/Open так называемой "расширенной" версией curses. Но поскольку они поддерживаются библиотекой ncurses, не велика проблема сделать их доступными на большинстве платформ. Пора идти дальше и применить множественные окна. Вы увидите, как обобщаются до сих пор использовавшиеся команды и применяются в сценариях с множественными окнами.
Структура WINDOW
Несмотря на то, что мы уже упоминали стандартный экран
stdscr
, пока у вас не было необходимости в его применении, поскольку почти все рассматриваемые до сих пор функции полагали, что они работают на экране
stdscr
, и не требовалось передавать его как параметр.
stdscr
— это специальный случай структуры
WINDOW
, как stdout — специальный случай файлового потока. Обычно структура
WINDOW
объявляется в файле curses.h и, несмотря на то, что ее просмотр может быть очень поучителен, программы никогда не используют эту структуру напрямую, т.к. она может различаться в разных реализациях.
Вы можете создать и уничтожить окно с помощью вызовов функций newwin и delwin:
#include <curses.h>
WINDOW *newwin(int num_of_lines, int num_of_cols, int start_y, int start_x);
