Эта глава имеет дело с вводом/выводом символов на экран. Когда мы говорим "символ", то подразумеваем композицию пикселов, которая может меняться в зависимости от таблицы представлений символов (charset). Ваша графическая карта уже предлагает одну или более таких таблиц и по умолчанию работает в текстовом (charset) режиме, потому что текст обрабатывается быстрее, чем пиксельная графика. Терминалы можно использовать лучше, чем как простые и скучные текстовые дисплеи. Рассмотрим, как использовать специальные возможности, которые предлагает терминал Linux, особенно консоль Linux.
В следующих разделах мы рассмотрим, как пользоваться различными пакетами доступа к терминалу. В Linux мы имеем GNU-версию termcap и можем пользоваться ncurses вместо curses.
Функции printf(...) в libc обеспечивают форматированный вывод и позволяют трансформировать аргументы.
format содержит два типа объектов:
Форматная информация должна начинаться с %, за которым следуют значения для формата, дальше идет символ для трансляции (чтобы напечатать знак %, используйте %%). Возможны следующие значения для формата:
Возможные значения для трансформации смотри в таблице 8.1.
\
0). Вы должны
захватить достаточно памяти для s!
Символ | Форматируется в |
d,i | int signed, десятиричный |
o | int unsigned, восьмеричный, без предваряющего 0 |
x,X | int unsigned, шестнадцатиричный, без предваряющего 0x |
u | int unsigned, десятиричный |
c | int (unsigned) одиночный символ |
s | char * до \0 |
f | double как [-]mmm.ddd |
e,E | double как [-]m.dddddde+xx, [-]m.dddddde-xx |
g,G | double использует %e или %f когда нужно |
p | void * |
n | int * |
% | % |
Таблица 8.1: Libc: трансформации printf
Точно так же, как printf(...) для форматированного вывода, Вы можете использовать scanf(...) для форматированного ввода.
format может содержать правила форматирования аргументов (см. таблицу 8.2. Он может также включать:
Таблица 8.2: Libc: правила scanf
перед d,i,n,o,u,x может стоять h, если указатель short
то же для l, если указатель long
l также может быть перед e,f,g, если указатель double
L может стоять перед e,f,g, если указатель long double
Библиотека termcap это API для базы данных termcap, которая находится в /etc/termcap. Библиотечные функции позволяют:
Программы, использующие библиотеку termcap должны включать
termcap.h и собираться с:
gcc [flags] files -ltermcap
Функции termcap терминально-независимые программы, но дают программисту только низкоуровневый доступ к терминалу. Для пакета более высокого уровня потребуется curses или ncurses.
Что касается buffer, то в GNU-версии Linux termcap не нужно захватывать память. В других версиях вам придется выделить 2048 байт (прежде buffer требовал 1024 байта, но сейчас размер удвоился).
tgetent(...) возвращает 1 в случае успеха и 0 когда база данных найдена, но не имеет точки входа для TERM. Другие ошибки возвращают различные значения.
Следующий пример объясняет как использовать tgetent(...):
#define buffer 0
char *termtype=getenv("TERM");
int ok;
ok=tgetent(buffer,termtype);
if (ok==1)
/* все нормально, мы имеем вход */
else if(ok==0)
/* Что-то не так с TERM
* проверим сначала termtype, затем базу данных termcap
*/
else
/* Глобальная ошибка */
По умолчанию termcap использует /etc/termcap как базу данных. Если переменная среды TERMCAP установлена, например, в $HOME/mytermcap, то все функции будут пользоваться mytermcap вместо /etc/termcap. Без начального слэша в TERMCAP определенное значение понимается как имя для терминала.
Каждый фрагмент информации называется свойством (capability). Каждое свойство это двухсимвольный код, за каждым двухсимвольным кодом стоит значение свойства. Возможны следующие типы свойств:
Каждое свойство связано с единственным типом значений (co всегда числовой, hc всегда флаг, а st всегда строка). Три типа значений и три типа функций, их запрашивающих. char *name двухсимвольный код свойства.
5i | принтер не имеет эха на экране |
am | автоматические границы, что означает автоматическое форматирование строки |
bs | Crtl-H представляет backspace |
bw | backspace на левой границе переносит строку на правую границу предыдущей |
da | вывести сохраненное над текущим экраном |
db | вывести сохраненное под текущим экраном |
eo | пробел стирает литеру на позиции курсора |
es | esc-последовательности и специальные символы работают в строке состояния |
gn | родовое устройство |
hc | это терминал твердой копии (hardcopy terminal) |
HC | курсор плохо видно, когда он не на последней линии |
hs | присутствует линия статуса |
hz | терминал не может напечатать тильды (tilde characters) |
in | терминал вставляет нули вместо пробелов на пустые места |
km | терминал имеет мета клавишу |
mi | режим вставки для курсора |
ms | режим стандартного вывода/подчеркивания для курсора |
NP | нет символов-заполнителей |
NR | ti не обращает teos, терминал может забивать ошибки |
ul | терминал подчеркивает, но ошибки забивать не может |
xb | сбой, вызванный столпотворением, F1 посылает ESCAPE, F2 посылает ^C |
xn | сбой новой строки/соединения строк |
xo | терминал использует xon/xoff протокол |
xs | текст, напечатанный поверх выделенного, будет выделен |
xt | сбой телевизионного луча, неверная табуляция и странный режим выделения |
co | число столбцов |
dB | приостановка на милисекунды для возврата на терминалах твердой копии |
dC | приостановка на милисекунды для перевода каретки на терминалах твердой копии |
dF | приостановка на милисекунды для заполнения страницы на терминалах твердой копии |
dN | приостановка на милисекунды для новой линии на терминалах твердой копии |
dT | приостановка на милисекунды для табуляции на терминалах твердой копии |
dV | приостановка на милисекунды для вертикальной табуляции на терминалах твердой копии |
it | раница между позициями табуляции |
lh | высота мягких меток |
lm | линии памяти |
lw | ширина |
li | число линий |
Nl | число мягких меток |
pb | наименьшая граница, когда требуется дозаполнение |
sg | сбой режима выделения |
ug | сбой режима подчеркивания |
vt | номер виртуального терминала |
ws | ширина линии статуса, если она отлична от ширины экрана |
!1 | клавиша сохранения в верхнем регистре |
!2 | клавиша подвешивания в верхнем регистре |
!3 | клавиша undo в верхнем регистре |
#1 | клавиша помощи в верхнем регистре |
#2 | клавиша home в верхнем регистре |
#3 | клавиша ввода в верхнем регистре |
#4 | клавиша курсор влево в верхнем регистре |
%0 | клавиша redo |
%1 | клавиша помощи |
%2 | клавиша пометки |
%3 | клавиша сообщения |
%4 | клавиша перемещения |
%5 | клавиша следующего объекта |
%6 | клавиша открытия |
%7 | клавиша опций |
%8 | клавиша предыдущего объекта |
%9 | клавиша печати |
%a | клавиша сообщения в верхнем регистре |
%b | клавиша перемещения в верхнем регистре |
%c | клавиша следующего объекта в верхнем регистре |
%d | клавиша опций в верхнем регистре |
%e | клавиша предыдущего объекта в верхнем регистре |
%f | клавиша печати в верхнем регистре |
%g | клавиша redo в верхнем регистре |
%h | клавиша перестановки в верхнем регистре |
%i | клавиша курсор-вправо в верхнем регистре |
%j | клавиша продолжения в верхнем регистре |
&0 | клавиша cancel в верхнем регистре |
&1 | клавиша ссылки |
&2 | клавиша обновления |
&3 | клавиша перестановки |
&4 | клавиша перезапуска |
&5 | клавиша продолжения |
&6 | клавиша сохранения |
&7 | клавиша подвешивания |
&8 | клавиша undo |
&9 | клавиша начала в верхнем регистре |
*0 | клавиша поиска в верхнем регистре |
*1 | клавиша команды в верхнем регистре |
*2 | клавиша копирования в верхнем регистре |
*3 | клавиша создания в верхнем регистре |
*4 | клавиша удаления символа в верхнем регистре |
*5 | клавиша удаления строки в верхнем регистре |
*6 | клавиша выделения |
*7 | клавиша конца в верхнем регистре |
*8 | клавиша очистки линии в верхнем регистре |
*9 | клавиша выхода в верхнем регистре |
0 | клавиша поиска1 клавиша начала |
2 | клавиша cancel |
3 | клавиша закрытия |
4 | клавиша команды |
5 | клавиша копирования |
6 | клавиша создания |
7 | клавиша конца |
8 | клавиша ввода/посылки |
9 | клавиша выхода |
al | клавиша вставки одной линии |
AL | клавиша вставки %1 линий |
ac | цвет блока символов, отображаемых в другой таблице символов |
ae | конец множества символов из альтернативной таблицы |
as | начало блока символов в альтернативной таблице |
bc | backspace, если не ^H |
bl | символ звонка |
bt | переход к предыдущему месту табуляции |
cb | очистка от начала линии до курсора |
cc | странный командный символ |
cd | очистка до конца экрана |
ce | очистка до конца линии |
ch | перемещение курсора горизонтально до столбца %1 |
cl | очистка экрана, курсор помещается в начало |
cm | курсор перемещается на строку %1 и колонку %2 (на экране) |
CM | курсор перемещается на строку %1 и колонку %2 (в памяти) |
cr | возврат каретки |
cs | область прокрутки от строки %1 до строки %2 |
ct | очистка табуляций |
cv | вертикальное движение курсора до строки %1 |
dc | удаление 1 символа |
DC | удаление %1 символов |
dl | удаление 1 строки |
DL | удаление %1 строк |
dm | начало режима удаления |
do | курсор на 1 линию вниз |
DO | курсор на %1 линию вниз |
ds | убрать строку статуса |
eA | активирование альтернативной символьной таблицы |
ec | удаление %1 символов начиная с позиции курсора |
ed | конец режима удаления |
ei | конец режима вставки |
ff | символ дозаполнения экрана на терминалах твердой копии |
fs | возврат символа на его позицию перед переходом на строку статуса |
F1 | строка послана функциональной клавишей F11 |
... | ... |
F9 | строка послана функциональной клавишей F19 |
FA | строка послана функциональной клавишей F20 |
... ... | |
FZ | строка послана функциональной клавишей F45 |
Fa | строка послана функциональной клавишей F46 |
... ... | |
Fr | строка послана функциональной клавишей F63 |
hd | перемещение курсора на пол-линии вниз |
ho | курсор в начало |
hu | перемещение курсора на пол-линии вверх |
i1 | инициализация строки 1 в начале сеанса |
i3 | инициализация строки 3 в начале сеанса |
is | инициализация строки 2 в начале сеанса |
ic | вставка 1 символа |
IC | вставка %1 символов |
if | файл инициализации |
im | начало режима вставки |
ip | вставка времени и необходимых специальных символов после вставки |
iP | программа инициализации |
K1 | верхняя левая клавиша на keypad |
K2 | центральная клавиша на keypad |
K3 | верхняя правая клавиша на keypad |
K4 | нижняя левая клавиша на keypad |
K5 | нижняя правая клавиша на keypad |
k0 | функциональная клавиша 0 |
... | ... |
k9 | функциональная клавиша 9 |
k; | функциональная клавиша 10 |
ka | клавиша очистки всех табуляций |
kA | клавиша вставки линии |
kb | клавиша backspace |
kB | клавиша возврата к предыдущему месту табуляции |
kC | клавиша очистки экрана |
kd | клавиша down |
kD | клавиша удаления символа под курсором |
ke | отключение keypad |
kE | клавиша очистки до конца строки |
kh | клавиша курсор home |
kH | клавиша курсор home+down |
kI | вставка символа/клавиша режима вставки |
kl | клавиша курсор left |
kL | клавиша удаления строки |
kM | Mклавиша выхода из режима вставки |
kN | клавиша следующей страницы |
kP | клавиша предыдущей страницы |
kr | клавиша курсор right |
kR | клавиша прокрутки назад/вверх |
ks | включение keypad |
kS | клавиша очистки до конца экрана |
kt | клавиша очистки данной табуляции |
kT | клавиша установки табуляции на этом месте |
ku | клавиша курсор up |
l0 | метка для нулевой функциональной клавиши, если не f0 |
l1 | метка для первой функциональной клавиши, если не f1 |
l2 | метка для второй функциональной клавиши, если не f2 |
... | |
la | метка для десятой функциональной клавиши, если не f10 |
le | курсор влево на 1 символ |
ll | перемещение курсора в нижний левый угол |
LE | курсор влево на %1 символов |
LF | отключение мягких меток |
LO | включение мягких меток |
mb | начало мерцания |
MC | очистка мягких границ |
md | начало режима верхнего регистра |
me | конец всех режимов типа so, us, mb, md, mr |
mh | начало полуяркого режима |
mk | начало темного режима (символы не видны) |
ML | установка левой мягкой границы |
mm | вход терминала в метарежим |
mo | выход терминала из метарежима |
mp | включение защищенного атрибута |
mr | начало режима обращения (reverse mode) |
MR | установка правой мягкой границы |
nd | курсор на 1 символ влево |
nw | команда возврата каретки |
pc | символ-заполнитель |
pf | отключение принтера |
pk | программная клавиша %1 для посылки строки %2, если нажата пользователем |
pl | программная клавиша %1 для исполнения строки %2 в локальном режиме |
pn | программная мягкая метка %1 для отображения строки %2 |
po | подключение принтера |
pO | подключение принтера для %1 (<256) байт |
ps | печать содержимого экрана на принтере |
px | программная клавиша %1 для посылки строки %2 в компьютер |
r1 | сброс строки 1, установка нормальных режимов |
r2 | сброс строки 2, установка нормальных режимов |
r3 | сброс строки 3, установка нормальных режимов |
RA | отключение автоматических границ |
rc | восстановление сохраненной позиции курсора |
rf | сброс строки имени файла |
RF | требование ввода с терминала |
RI | курсор вправо на %1 символов |
rp | повторение символа %1 %2 раз |
rP | заполнение после присланного символа в режиме замены |
rs | сброс строки |
RX | выключение XON/XOFF управления |
sa | установка атрибутов %1 %2 %3 %4 %5 %6 %7 %8 %9 |
SA | включение автоматических границ |
sc | сохранение позиции курсора |
se | конец режима стандартного вывода |
sf | нормальная прокрутка на одну строку |
SF | нормальная прокрутка на %1 строк |
so | начало режима стандартного вывода |
sr | обратная прокрутка |
SR | прокрутка назад на %1 строк |
st | установка табуляции во всех строках в данной колонке |
SX | включение XON/XOFF управления |
ta | перемещение к следующей табуляции физического устройства |
tc | чтение в описании терминала с другой точки входа |
te | конец программы, использующей движение курсора |
ti | начало программы, использующей движение курсора |
ts | перемещение курсора на столбец %1 строки статуса |
uc | подчеркивание символа под курсором и движение курсора вправо |
ue | конец подчеркивания |
up | курсор на 1 строку вверх |
UP | курсор на %1 строк вверх |
us | начало подчеркивания |
vb | видимый звонок |
ve | нормальный видимый курсор |
vi | невидимый курсор |
vs | курсор стандартного вывода |
wi | установка окна со строки %1 до строки %2 и столбцов с %3 до %4 |
XF | символ XOFF, если не ^S |
В этом разделе будем пользоваться следующей терминологией:
Обычно программа, использующая ncurses, выглядит так:
#include
Подключение ncurses.h определит переменные и типы для ncurses, такие как WINDOW, и прототипы функций. Автоматически подключатся stdio.h, stdarg.h, termios.h и unctrl.h.
initscr() используется для инициализации структур данных ncurses и для чтения файла terminfo. Будет захвачена память под stdscr и curscr. Если произойдет ошибка, то initscr вернет ERR. В противном случае возвращается указатель на stdscr. Кроме этого, экран будет очищен и будут проинициализированы LINES и COLS.
endwin() очистит все выделенные ресурсы ncurses и восстановит режимы tty, какими они были до вызова initscr(). Функция endwin() должна вызываться перед любой другой функцией из библиотеки ncurses и перед выходом из вашей программы. Если вы хотите использовать для вывода более чем один терминал, используйте newterm(...) вместо initscr().
Компилируйте программу посредством:
gcc [flags] files -lncurses
Вы можете устанавливать любые флаги (см. gcc(1)). Если путь к
ncurses.h изменился, вы должны включить следующую строку, иначе
ncurses.h, nterm.h, termcap.h и unctrl.h не будут найдены:
-I/usr/include/ncurses
Другие возможные в Linux флаги: O2 скажет gcc произвести некоторую оптимизацию; -ansi: для ANSI си-кода; -Wall выведет все предупреждения; -m486 оптимизирует код для Intel 486 (можно и для Intel 386).
Библиотека ncurses находится в /usr/lib. Существует 3 версии библиотеки:
Структуры данных для экрана называются windows и определены в ncurses.h. Окно это нечто типа символьного массива в памяти, которым программист может манипулировать без вывода на терминал. При помощи newwin(...) вы можете создать другие окна.
Чтобы оптимально обновить физический терминал, ncurses имеет другое окно, curscr. Это изображение, реально выводимое на экран. Для отображения stdscr на экране используется функция refresh(). После этого ncurses обновит curscr и физический терминал содержимым stdscr. Библиотечные функции произведут внутреннюю оптимизацию для процесса обновления, поэтому вы можете менять различные окна и затем обновлять экран сразу самым оптимальным способом.
Функциями ncurses вы можете работать со структурой данных window. Функции, начинающиеся с w, позволяют назначать окно window, тогда как остальные обычно имеют дело с stdscr. Функции, начинающиеся с mv, прежде всего переместят курсор на позицию y,x.
Символы имеют тип chtype, который является long unsigned int , чтобы сохранять дополнительную информацию о себе (атрибуты и т.д.).
Библиотека ncurses использует базу данных terminfo. Обычно она находится в usr/lib/terminfo/, и ncurses обращается туда за локальными определениями терминала. Если вы хотите проверить некоторые другие определения для терминала, не исправляя первоначальную terminfo, установите соответственно переменную среды TERMINFO. Эта переменная будет протестирована ncurses, и вместо usr/lib/terminfo/ сохранятся ваши определения.
Текущей версией ncurses является (на момент написания книги) 1.8.6.
В конце этого раздела вы найдете обзорную таблицу для BSD-Curses, ncurses и Sun-OS 5.4 curses.
initscr() прочитает terminfo файл и установит структуры данных
ncurses, выделит память для curscr и stdscr и проинициализирует переменные
LINES и COLS значениями, соответствующими вашему терминалу. Будет возвращен
указатель на stdscr или ERR в случае ошибки. Вам НЕ нужно
инициализировать указатель.
stdscr=initscr();
поскольку initscr() сделает это за вас. Если возвращен ERR, ваша
программа должна завершиться, поскольку ни одна функция ncurses не
будет работать:
if (!(initscr()))
{
fprintf(stderr,"type: initscr() failed\n\n");
exit (1);
}
Дополнительный вызов refresh() после endwin() восстановит содержимое терминала, отображавшееся до вызова initscr() (visual-mode), в противном случае экран будет очищен (non-visual-mode).
Окна могут быть созданы, уничтожены, перемещены, скопированы, задублированы и т.д.
0 begx
| |
0 | | COLS
- - - - -------|-------------------------|------->
| | ncols |
begy | |<. . . . . . . . . . . .>|
- - - -|- - - -|-------------------------|
| ^| |
| .| |
| .| |
|nlines.| newwin(nlines, ncols, |
| .| begy, begx) |
| v| |
|- - - -|-------------------------|
LINES |
v
Рисунок 8.1: Ncurses: схема для newwin
Верхний левый угол нашего окна находится в строке 10 в колонке 10; окно имеет 10 строк и 60 колонок. Если nlines равна нулю, окно будет иметь (LINES-begy) строк. Точно так же, если ncols равна нулю, то окно будет иметь (COLS-begx) колонок.
Когда мы вызываем newwin(...) с нулевыми аргументами:
WINDOW *mywin;
mywin=newwin(0,0,0,0);
открытое окно получает размеры экрана.
При помощи LINES и COLS мы можем открыть окно на
середине экрана, какую бы размерность оно ни имело:
#define MYLINE (int) ((LINES-22)/2)
#define MYCOL ((COLS-70)/2)
#define MYLINES 22
#define MYCOLS 70
...
WINDOW *win;
...
if(!(initscr())){
fprintf(stderr, "type: iniscr() failed\n\n");
exit(1);
}
...
if ((LINES<22)||(COLS<70)){
fprintf(stderr, "screen too small\n\n");
endwin(); exit (1);
}
win=newwin(MYLINES,MYCOLS,MYLINE,MYCOL);
Откроется окно с 22 строками и 70 колонками в середине экрана. Проверьте размер экрана перед тем, как открывать окно. Консоль Linux имеет не менее 25 строк и 80 колонок, но на Х-терминалах это может не выполняться (их размеры изменяемы).
С другой стороны, используйте LINES и COLS, чтобы
поместить два окна в один экран:
#define MYROWS (int) (LINES/2+LINES/4)
#define MYCOLS (int) (COLS/2+COLS/4)
#define LEFTROW (int) ((LINES-MYROWS)/2)
#define LEFTCOL (int) (((COLS-2)-MYCOLS)/2)
#define RIGHTROW (int) (LEFTROW)
#define RIGHTCOL (int) (LEFTROW+2+MYCOLS)
#define WCOLS (int) (MYCOLS/2)
...
WINDOW *leftwin, *rightwin;
...
leftwin=newwin(MYROWS, WCOLS, LEFTROW, LEFTCOL);
rightwin=newwin(MYROWS, WCOLS, RIGHTROW, RIGHTCOL);
...
Подробнее смотрите screen.c в директории с примерами.
begx и begy относятся не к origwin, а к экрану.
\
0"). Функции, начинающиеся с
w, заносят str в окно win, остальные в stdscr.
Функции с n пишут n символов строки str. Если
n равен -1, будет записана вся строка str.
В libc printf() используется для форматированного вывода. Вы можете определять выводимую строку и включать в нее переменные различных типов. Подробнее смотрите раздел 8.1.1.
vwprintw(...) требует подключения varargs.h.
y и x координаты, на которые переместится курсор перед вставкой str; n это число вставляемых символов (n=0 вводит чистую строку).
y и x координаты, на которые курсор переместится перед удалением.
Код символа | Позиция | По умолчанию |
tl | левая верхняя | ACS_ULCORNER |
ts | верхняя сторона | ACS_HLINE |
tr | правая верхняя | ACS_URCORNER |
ls | левая сторона | ACS_VLINE |
rs | правая сторона | ACS_VLINE |
bl | левая нижняя | ACS_LLCORNER |
bs | нижняя сторона | ACS_HLINE |
br | правая нижняя | ACS_LRCORNER |
rt | правая средняя | ACS_RTEE |
lt | левая средняя | ACS_LTEE |
tt | верхняя средняя | ACS_TTEE |
bt | нижняя средняя | ACS_BTEE |
Таблица 8.3: Ограничительные символы Ncurses
Рисунок 8.2: Символы бокса в ncurses.
tl ts tt ts tr
|------------|------------|
| |
ls| | |rs
| |
| | |
lt|- - - - - - - - - - - - -|rt
| | |
| |
ls| | |rs
| |
|------------|------------|
bl bs bt bs br
С включенной keypad(...) при нажатии функциональной клавиши getch() вернет код, определенный в ncurses.h как макрос KEY_*. При нажатии ESCAPE (который может быть началом функциональной клавиши) ncurses запустит односекундный таймер. Если остаток не получен в течение этой секунды, то возвращается ESCAPE, иначе значение функциональной клавиши. При необходимости секундный таймер можно отключить через notimeout().
Поговорим об использовании опций окна и режимов терминала.
Прежде всего, под Linux следует подключить keypad. Это позволит пользоваться цифровым блоком и клавишами перемещения курсора на клавиатуре ПК.
Теперь имеется 2 основных типа ввода:
Для первого случая мы установим следующие опции и режимы, и цикл
while сработает корректно:
char c;
noecho();
timeout(-1);
nonl();
cbreak();
keypad(stdscr,TRUE);
while(c=getch()){
switch(c){
case 'q': your_quit_function();
default: break;
}
}
Эта программа повиснет до нажатия клавиши. Если нажата q, мы вызываем your_quit_function(), иначе ждем другого ввода.
Выражение switch может быть расширено по нашему желанию. Макросы
KEY_* служат для учета специальных клавиш. Например,
KEY_UP KEY_RIGHT KEY_A1 KEY_B2 KEY_C1
KEY_DOWN KEY_LEFT KEY_A3 KEY_C3
для клавиш перемещения курсора. Для просмотра файла цикл может выглядеть
примерно так:
int loop=TRUE;
char c;
enum{UP,DOWN,RIGHT,LEFT};
noecho();
timeout(-1);
nonl();
cbreak();
keypad(stdscr,TRUE);
while(loop==TRUE){
c=getch();
switch(c){
case KEY_UP:
case 'u':
case 'U': scroll_s(UP);
break;
case KEY_DOWN:
case 'd':
case 'D': scroll_s(DOWN);
break;
case KEY_LEFT:
case 'l':
case 'L': scroll_s(LEFT);
break;
case KEY_RIGHT:
case 'r':
case 'R': scroll_s(RIGHT);
break;
case 'q':
case 'Q': loop=FALSE;
default: break;
}
}
Для второго случая, нам достаточно установить echo(), и символы, набираемые пользователем, будут напечатаны на экране. Место печати задается функциями move(...) или wmove(...).
Или вы можете открыть окно с маской (выделяемой другими цветами)
и попросить пользователя ввести строку:
WINDOW *maskwin;
WINDOW *mainwin;
char *ptr=(char *)malloc(255);
...
mainwin=newwin(3,37,9,21);
maskwin=newwin(1,21,10,35);
...
werase(mainwin);
werase(maskwin);
...
box(mainwin,0,0)
mvwaddstr(mainwin,1,2,"Inputstring:");
...
wnoutrefresh(mainwin);
wnoutrefresh(maskwin);
doupdate();
...
mvwgetstr(maskwin,0,0,ptr);
...
delwin(maskwin);
delwin(mainwin);
endwin();
free(ptr);
Более подробно см. input.c в каталоге примеров.
void NewClear(WINDOW *win)
{
int y,x;
for (y = 0; y <= win -> _maxy; y++)
for (x = 0; x <= win -> _maxx; x++)
(chtype *) win-> _line[y][x] = ' '|win-> _attrs;
win -> _curx = win -> _cury = 0;
touchwin(win);
}
Проблема состоит в том, что ncurses иногда делает совершенно
бесполезными атрибуты окна, когда заполняет экран пробелами. Если в
lib_clrtoeol.c BLANK определен как
#define BLANK ' '|A_NORMAL,
то другие атрибуты окна теряются, пока идет стирание строки.
Как написано в обзоре, окна ncurses есть отображения в памяти. Это означает, что любое изменение окна не отражается на физическом экране до тех пор, пока не будет произведено обновление. Это оптимизирует вывод на экран, поскольку вы получаете возможность совершать множество действий, а затем лишь единожды вызвать обновление, чтобы напечатать его на экране. В противном случае на терминале отражалось бы каждое изменение, что ухудшало бы исполнение ваших программ.
Допустим, мы имеем следующую программу с двумя окнами. Мы
изменяем оба окна, меняя несколько линий текста. Напишем
cgangewin(win) с wrefresh(win).
main() changewin(WINDOW *win)
{ {
WINDOW *win1,*win2; ... /* здесь мы изменяем */
... ... /* строки */
changewin(win1); wrefresh(win);
changewin(win2); return;
... }
}
Тогда ncurses обновит терминал дважды, а это замедлит исполнение
нашей программы. Благодаря doupdate() мы изменим changewin(win)
и нашу основную функцию, добившись этим лучшего исполнения.
main() changewin(WINDOW *win)
{ {
WINDOW *win1,*win2; ... /* здесь мы изменяем */
... ... /* строки */
changewin(win1); wnoutrefresh(win);
changewin(win2); return;
doupdate(); }
...
}
wtouchln() захватит n линий, начинающихся в y. Если change соответствует TRUE, то линии захватываются, в противном случае нет (изменяются или не изменяются).
untouchwin(win) пометит окно win как неизмененное со времени последнего вызова refresh().
Атрибуты это специальные возможности терминала, применяемые во время печати символов на экран. Символы могут быть напечататы жирно, могут быть подчеркнуты, могут мигать и т.д. В ncurses вы имеете возможность включать или отключать атрибуты для достижения наилучшего внешнего вида вывода. Возможные атрибуты перечислены в нижеследующей таблице.
Определение | Атрибут |
A_ATTRIBUTES | маска для атрибутов (chtype) |
A_NORMAL | нормальный, переустановка всего остального |
A_STANDOUT | наиболее яркий режим |
A_UNDERLINE | подчеркивание |
A_REVERSE | обратное изображение |
A_BLINK | мигание |
A_DIM | тусклый или полуяркий режим |
A_BOLD | четкий или очень яркий режим |
A_ALTCHARSET | использование альтернативной символьной таблицы |
A_INVIS | невидимый режим |
A_PROTECT | не понял |
A_CHARTEXT | маска для действующих символов (chtype) |
A_COLOR | маска для цвета |
COLOR_PAIR(n) | установка цветовой пары n |
PAIR_NUMBER(a) | получение цветовой пары, лежащей в атрибуте a |
Ncurses определяет 8 цветов, которыми вы можете пользоваться на терминале с цветовой поддержкой. Сначала проинициализируйте цветовые структуры данных посредством start_color(), затем проверьте возможности терминала при помощи has_colors(). start_color() будет инициализировать COLORS, наибольшее количество цветов, поддерживаемых терминалом, и COLOR_PAIR, максимальное число цветовых пар, которые вы можете определить.
Определение | Цвет |
COLOR_BLACK | черный |
COLOR_RED | красный |
COLOR_GREEN | зеленый |
COLOR_YELLOW | желтый |
COLOR_BLUE | синий |
COLOR_MAGENTA | пурпурный |
COLOR_CYAN | голубой |
COLOR_WHITE | белый |
Атрибуты могут быть совмещены '|' (OR), поэтому вы можете получить четкий мерцающий вывод при помощи A_BOLD|A_BLINK
Если вы установите окно с атрибутом attr, все символы, напечатанные в этом окне, приобретут это свойство и будут его сохранять до изменения вами атрибута. Это не будет утеряно при прокрутке или движении окна и т.п.
Будьте осторожны с цветами, если вы пишете программы для ncurses и BSD curses, так как BSD curses не имеет цветовой поддержки. (Точно так же не имеют цветовой поддержки старые версии SYS V). Поэтому, если вы компилируете для обеих библиотек, придется использовать операции #ifdef.
init_pair(1,COLOR_RED,COLOR_BLUE);
Теперь вызовем wattr(...) для установки новой пары цветов для
win:
wattr(win,COLOR_PAIR(1));
Или соединим цветовые пары с другими атрибутами, например:
wattr(win,A_BOLD|COLOR_PAIR(1));
wattr(win1,A_STANDOUT|COLOR_PAIR(1));
Первый вызов установит цветовую пару и атрибут BOLD, второй подключит режим
STANDOUT, и вы получите светлый красный на синем экране.
Как комбинировать атрибуты и цвета? Некоторые терминалы, как
консоли в Linux, имеют цвета, а некоторые нет (xterm, vs100 и
т.д.). Следующий код решит эту проблему:
void CheckColor(WINDOW *win1, WINDOW *win2)
{
start_color();
if (has_colors()){
/* Хорошо, у нас есть цвета, определяем цветовые пары для
* цветов переднего и заднего плана
*/
init_pair(1,COLOR_BLUE,COLOR_WHITE);
init_pair(2,COLOR_WHITE,COLOR_RED);
/* теперь используем уже определенные цветовые пары для окон */
wattrset(win1,COLOR_PAIR(2));
wattrset(win2,COLOR_PAIR(1));
}
else
{
/* Нет цвета (может быть vt100 или xterm). Ладно, будем
* пользоваться вместо этого черно-белыми атрибутами.
*/
wattrset(win1,A_REVERSE);
wattrset(win2,A_BOLD);
}
return;
}
Прежде всего, функция CheckColor проинициализирует цвета при помощи start_color(). Затем has_colors() вернет TRUE, если текущий терминал имеет цвета. После этого вызывается ini_tpair(...) для соединения цветов переднего и заднего плана, и wattrset(...) для установки этих цветов в данном окне. Впрочем, чтобы установить атрибуты для черно-белого терминала, мы можем использовать только wattrset(...).
Чтобы получить цвета на xterm, лучший способ, найденный автором, это использовать ansi_xterm с надерганными элементами terminfo из Midnight Commander. Просто добудьте исходники ansi_xterm и Midnight Commander (mc-x.x.tar.gz). Потом скомпилируйте ansi_xterm и используйте tic с xterm.ti и vt100.ti из архива mc-x.x.tar.gz. Запустите ansi_xterm и протестируйте его.
При включенном scrollok(...) содержимое окна может быть прокручено при помощи нижеследующих функций. Замечание: оно будет прокручено и в случае, если вы напечатаете новую строку, находясь в последней строке окна, поэтому будьте осторожны со scrollok(...).)
Следующий код объяснит, как прокручивать текст на экране. Смотрите также type.c в директории примеров.
Мы хотим прокрутить текст в окне, имеющем 18 линий и 66 колонок. S[]
это массив символов с текстом. Max_s является номером последней
строки в S[]. Clear_line напечатает пробелы с текущей
позиции курсора до конца строки, используя текущие атрибуты окна (не
A_NORMAL, как это делает clrtoeol). Beg это последняя строка из
s[], изображенная на данный момент на экране. Scroll перечень
того, что должна сделать функция, показать NEXT или PREVious (следующую или
предыдущую) строку текста.
enum{PREV,NEXT};
void scroll_s(WINDOW *win, int scroll)
{
/* пробуем, должны ли мы прокрутить вниз и если что-нибудь есть,
* то прокрутить
*/
if((scroll==NEXT)&&(beg<=(max_s-18))){
/* одна строка вниз */
beg++;
/* задаем права на прокрутку */
scrollok(win, TRUE);
/* прокручиваем */
wscrl(win, +1);
/* отклоняем права на прокрутку */
scrollok(win, FALSE);
/* устанавливаем новую строку в последней линии */
mvwaddnstr(win,17,0,s[beg+17],66);
/* очищаем последнюю строку от последнего символа до конца
* строки. Иначе атрибуты не будут учтены.
*/
clear_line(66,win);
}
else if((scroll==PREV)&&(beg>0)){
beg--;
scrollok(win, TRUE);
wscrl(win, -1);
scrollok(win, FALSE);
mvwaddnstr(win,0,0,s[beg],66);
clear_line(66,win);
}
wrefresh(win);
return;
}
Последние шесть числовых свойств присутствуют в структуре term SYSV, но не задокументированы в man page. Комментарии взяты из заголовка этой структуры.
label_format | fln | Lf | ?? |
set_clock | sclk | SC Установка времени дня | |
display_clock | dclk | DK | Вывод времени дня на экран |
remove_clock | rmclk | RC | Удаление времени дня ?? |
create_window | cwin | CW | Определение окна #1 с параметрами от #2, #3 до #4 #5 |
goto_window | wingo | WG | Переход в окно #1 |
hangup | hup | HU | Положить трубку телефона |
dial_phone | dial | DI | Набрать номер телефона #1 |
quick_dial | qdial | QD | Набрать номер телефона #1 без дальнейшего повторения |
tone | tone | TO | Выбрать длинные гудки |
pulse | pulse | PU | Выбрать короткие гудки |
flash_hook | hook | fh | Нажать телефонную клавишу |
fixed_pause | pause | PA | Пауза на 2-3 секунды |
wait_tone | wait | WA | Ожидание ответного сигнала |
user0 | u0 | u0 | Пользовательская строка #0 |
user1 | u1 | u1 | Пользовательская строка #1 |
user2 | u2 | u2 | Пользовательская строка #2 |
user3 | u3 | u3 | Пользовательская строка #3 |
user4 | u4 | u4 | Пользовательская строка #4 |
user5 | u5 | u5 | Пользовательская строка #5 |
user6 | u6 | u6 | Пользовательская строка #6 |
user7 | u7 | u7 | Пользовательская строка #7 |
user8 | u8 | u8 | Пользовательская строка #8 |
user9 | u9 | u9 | Пользовательская строка #9 |
get_mouse | getm | Gm | Curses должна предоставить события от мыши |
key_mouse | kmous | Km | ?? |
mouse_info | minfo | Mi | Информация о состоянии мыши |
pc_term_options | pctrm | S6 | Опции терминала ПК |
req_mouse_pos | reqmp | RQ | Требование отчета о позиции мыши |
zero_motion | zerom | Zx | Следующий символ не двигается |