355 500 произведений, 25 200 авторов.

Электронная библиотека книг » Нейл Мэтью » Основы программирования в Linux » Текст книги (страница 20)
Основы программирования в Linux
  • Текст добавлен: 21 сентября 2016, 17:59

Текст книги "Основы программирования в Linux"


Автор книги: Нейл Мэтью


Соавторы: Ричард Стоунс
сообщить о нарушении

Текущая страница: 20 (всего у книги 67 страниц)

Обнаружение нажатий клавиш

Пользователи, программировавшие в ОС MS-DOS, часто ищут в ОС Linux эквивалент функции kbhit, которая определяет, была ли нажата клавиша, без реального ее считывания. К сожалению, их поиски оказываются безуспешными, поскольку прямого аналога нет. Программисты в среде UNIX не ощущают этого отсутствия, т.к. UNIX запрограммирована так, что программы очень редко (если когда-либо вообще) озабочены ожиданием события. Поскольку это обычный способ применения kbhit, ее нехватка редко ощущается в системах UNIX и Linux.

Однако, когда вы переносите программы из MS-DOS, часто удобно эмулировать функцию kbhit, которую можно применять на деле в неканоническом режиме ввода (упражнение 5.7).

Упражнение 5.7. Исключительно ваша собственная kbhit

1. Начните со стандартной заголовочной информации и пары структур для установки параметров терминала. peek_character применяется для проверки нажатия клавиши. Далее описываются функции, которые будут использоваться позже:

#include

#include

#include

#include

#include

#include

static struct termios initial_settings, new_settings;

static int peek_character = -1;

void init_keyboard();

void close_keyboard();

int kbhit();

int readch();

2. Функция main вызывает функцию init_keyboard для настройки терминала, затем выполняет цикл один раз в секунду, каждый раз вызывая в нем функцию kbhit. Если нажата клавиша , функция close_keyboard восстанавливает нормальный режим и программа завершается:

int main() {

 int ch = 0;

 init_keyboard();

 while (ch != 'q') {

  printf(«loopingn»);

  sleep(1);

  if (kbhit()) {

   ch = readch();

   printf(«you hit %cn», ch);

  }

 }

 close_keyboard();

 exit(0);

}

3. Функции init_keyboard и close_keyboard настраивают терминал в начале и конце программы:

void init_keyboard() {

 tcgetattr(0, &initial_settings);

 new_settings = initial_settings;

 new_settings.c_lflag &= ~ICANON;

 new_settings.c_lflag &= ~ECHO;

 new_settings.c_lflag &= ~ISIG;

 new_settings.c_cc[VMIN] = 1;

 new_settings.c_cc[VTIME] = 0;

 tcsetattr(0, TCSANOW, &new_settings);

}

void close_keyboard() {

 tcsetattr(0, TCSANOW, &initial_settings);

}

4. Теперь функция, проверяющая нажатие клавиши:

int kbhit() {

 char ch;

 int nread;

 if (peek_character != -1) return 1;

 new_settings.c_cc[VMIN] = 0;

 tcsetattr(0, TCSANOW, &new_settings);

 nread = read(0, sch, 1);

 newrsettings.c_cc[VMIN] = 1;

 tcsetattr(0, TCSANOW, &new_settings);

 if (nread == 1) {

  peek_character = ch;

  return 1;

 }

 return 0;

}

5. Нажатый символ считывается следующей функцией readch, которая затем восстанавливает значение -1 переменной peek_character для выполнения следующего цикла:

int readch() {

 char ch;

 if (peek_character != -1) {

  ch = peek_character;

  peek_character = -1;

  return ch;

 }

 read(0, &ch, 1);

 return ch;

}

Когда вы выполните программу (kbhit.c), то получите следующий вывод:

$ ./kbhit

looping

looping

looping

you hit h

looping

looping

looping

you hit d

looping

you hit q

$

Как это работает

Терминал настраивается в функции init_keyboard на считывание одного символа (MIN=1, TIME=0). Функция kbhit изменяет это поведение на проверку ввода и его немедленный возврат (MIN=0, TIME=0) и затем восстанавливает исходные установки перед завершением.

Обратите внимание на то, что вы должны считать символ нажатой клавиши, но сохраняете его локально, готовые вернуть символ в вызывающую программу по ее требованию.

Виртуальные консоли

ОС Linux предоставляет средство, называемое виртуальными консолями. Экран, клавиатуру и мышь одного ПК может использовать ряд терминальных устройств, доступных на этом компьютере. Обычно установка ОС Linux рассчитана на использование от 8 до 12 виртуальных консолей. Виртуальные консоли становятся доступными благодаря символьным устройствам /dev/ttyN, где N – номер, начинающийся с 1.

Если вы регистрируетесь в вашей системе Linux в текстовом режиме, как только система активизируется, вам будет предложено регистрационное приглашение. Далее вы регистрируетесь с помощью имени пользователя и пароля. В этот момент используемое вами устройство – первая виртуальная консоль, терминальное устройство /dev/tty1.

С помощью команд who и ps вы можете увидеть, кто зарегистрировался и какие командная оболочка и программы выполняются на этой виртуальной консоли:

$ who

neil tty1 Mar 8 18:27

$ ps -e

 PID TTY      TIME CMD

1092 tty1 00:00:00 login

1414 tty1 00:00:00 bash

1431 tty1 00:00:00 emacs

Из этого укороченного вывода видно, что пользователь neil зарегистрировался и запустил редактор Emacs на консоли ПК, устройстве /dev/tty1.

Обычно ОС Linux запускается с процессом getty, выполняющимся на первых шести виртуальных консолях, поэтому есть возможность зарегистрироваться шесть раз, используя одни и те же экран, клавиатуру и мышь. Увидеть эти процессы можно с помощью и команды ps:

$ ps -а

 PID TTY      TIME CMD

1092 tty1 00:00:00 login

1093 tty2 00:00:00 mingetty

1094 tty3 00:00:00 mingetty

1095 tty4 00:00:00 mingetty

1096 tty5 00:00:00 mingetty

1097 tty6 00:00:00 mingetty

В этом выводе представлен стандартный вариант программы getty для обслуживания консоли в системе SUSE, mingetty, выполняющийся на пяти следующих виртуальных консолях и ожидающий регистрации пользователя.

Переключаться между виртуальными консолями можно с помощью комбинации клавиш ++N>, где N – номер виртуальной консоли, на которую вы хотите переключиться. Таким образом, для того чтобы перейти на вторую виртуальную консоль, нажмите ++, и ++, чтобы вернуться на первую консоль. (При переключении из регистрации в текстовом режиме, а не графическом, также работает комбинация клавиш +N>.)

Если в Linux запущена регистрация в графическом режиме, либо с помощью программы startx илн менеджера экранов xdm, на первой свободной консоли, обычно /dev/tty7, стартует графическая оболочка X Window System. Переключиться с нее на текстовую, консоль вы сможете с помощью комбинации клавиш ++N>, а вернуться с помощью ++.

В ОС Linux можно запустить более одного сеанса X. Если вы сделаете это, скажем, с помощью следующей команды

$ startx – :1

Linux запустит сервер X на следующей свободной виртуальной консоли, в данном случае на /dev/tty8, и переключаться между ними вы сможете с помощью комбинаций клавиш ++ и ++.

Во всех остальных отношениях виртуальные консоли ведут себя как обычные терминалы, описанные в этой главе. Если процесс обладает достаточными правами, виртуальные консоли можно открывать, считывать с них данные, писать на них информацию точно так же, как в случае обычного терминала.

Псевдотерминалы

У многих UNIX-подобных систем, включая Linux, есть средство, именуемое псевдотерминалом. Это устройства, очень похожие на терминалы, которые мы использовали в данной главе, за исключением того, что у них нет связанного с ними оборудования. Они могут применяться для предоставления терминалоподобного интерфейса другим программам.

Например, с помощью псевдотерминалов возможно создание двух программ, играющих друг с другом в шахматы, не взирая на тот факт, что сами по себе программы проектировались для взаимодействия посредством терминала с человеком-игроком. Приложение, действующее как посредник, передает ходы одной программы другой и обратно. Оно применяет псевдотерминалы, чтобы обмануть программы и заставить их вести себя нормально при отсутствии терминала.

Одно время реализация псевдотерминалов (если вообще существовала) сильно зависела от конкретной системы. Сейчас они включены в стандарт Single UNIX Specification (единый стандарт UNIX) как UNIX98 Pseudo-Terminals (псевдотерминалы стандарта UNIX98) или PTY.

Резюме

В этой главе вы узнали о трех аспектах управления терминалом. В начале главы рассказывалось об обнаружении перенаправления и способах прямого диалога с терминалом в случае перенаправления дескрипторов стандартных файлов. Вы посмотрели на аппаратную модель терминала и немного познакомились с его историей. Затем вы узнали об общем терминальном интерфейсе и структуре termios, предоставляющей в ОС Linux возможность тонкого управления и манипулирования терминалом. Вы также увидели, как применять базу данных terminfo и связанные с ней функции для управления в аппаратно-независимом стиле выводом на экран, и познакомились с приемами мгновенного обнаружения нажатий клавиш. В заключение вы узнали о виртуальных консолях и псевдотерминалах.

Глава 6
Управление текстовыми экранами с помощью библиотеки curses

В главе 5 вы узнали, как улучшить управление вводом символов и как обеспечить вывод символов способом, не зависящим от особенностей конкретного терминала. Проблема использования общего терминального интерфейса (GTI или termios) и манипулирование escape-последовательностями с помощью tparm и родственных функций заключается в необходимости применения большого объема программного кода низкого уровня. Для многих программ предпочтительней интерфейс высокого уровня. Мы хотели бы иметь возможность просто рисовать на экране и применять библиотеку функций для автоматического отслеживания аппаратных характеристик терминала.

В этой главе вы узнаете именно о такой библиотеке, называемой curses. Стандарт curses очень важен как компромисс между простыми "строковыми" программами и полностью графическими (которые обычно труднее программировать) программами в графической оболочке X Window System, такими как GTK+/GNOME и Qt/KDE, В ОС Linux есть библиотека svgatib (Super VGA Library, библиотека низкоуровневой графики), но она не является стандартной библиотекой UNIX, поэтому обычно не доступна в других UNIX-подобных операционных системах.

Библиотека curses применяется во многих полноэкранных приложениях как довольно легкий и аппаратно-независимый способ разработки полноэкранных, хотя и символьных программ. Такие программы почти всегда легче писать с помощью библиотеки curses, чем непосредственно применять escape-последовательности. Эта библиотека также может управлять клавиатурой, обеспечивая легкий в использовании, не блокирующий режим ввода символов.

Вы можете столкнуться с тем, что несколько примеров из этой главы не всегда будут отображаться на простой консоли Linux так, как вы ожидали. Бывают случаи, когда сочетание библиотеки curses и определения консоли терминала получается немного не согласованным и приводит в результате к несколько странным компоновкам при использовании curses. Но если для отображения вывода применить графическую оболочку X Window System и окно xterm, все встанет на свои места.

В этой главе обсуждаются следующие темы:

□ применение библиотеки curses:

□ основные идеи curses;

□ управление базовыми вводом и выводом;

□ использование множественных окон;

□ применение режима дополнительной клавиатуры (keypad mode);

□ добавление цвета.

Мы закончим главу переработкой на языке С программы, управляющей коллекцией компакт-дисков, подытожив все, чему вы научились к этому моменту.

Компиляция с библиотекой curses

Библиотека curses получила свое название благодаря способности оптимизировать перемещение курсора и минимизировать необходимые обновления экрана, а следовательно, уменьшить количество символов, нуждающихся в пересылке на текстовый терминал. Несмотря на то, что сейчас количество символов вывода гораздо менее важно, чем во времена неинтеллектуальных терминалов и низкоскоростных модемов, библиотека curses выжила как полезное дополнение к набору инструментов программиста.

Поскольку curses – это библиотека, для ее применения необходимо включить в программу заголовочный файл, объявления функций и макросы из соответствующей системной библиотеки. Существует несколько разных реализаций библиотеки curses. Первоначальная версия появилась в системе BSD UNIX и затем была включена в разновидности UNIX стиля System V прежде, чем была стандартизована группой X/Open. Система Linux использует вариант ncurses ("new curses") – свободно распространяемую версию System V Release 4.0 curses, разработанную для Linux. Эта реализация хорошо переносится на другие версии UNIX, хотя и содержит несколько непереносимых дополнительных функций. Есть даже версии библиотеки для MS-DOS и Windows. Если вы увидите, что библиотека curses, поставляемая с вашей версией системы UNIX, не поддерживает некоторые функции, попытайтесь получить копию альтернативной библиотеки ncurses. Обычно пользователи ОС Linux обнаруживают уже установленную библиотеку ncurses или, по крайней мере, ее компоненты, необходимые для выполнения программ на базе библиотеки curses. Если инструментальные библиотеки для нее заранее не установлены в вашем дистрибутиве (нет файла curses.h или файла библиотеки curses для редактирования связей), для большинства основных дистрибутивов их всегда можно найти в виде стандартного пакета с именем наподобие ibncurses5-dev.

Примечание

В стандарте X/Open определены два варианта curses: базовый и расширенный. Расширенный вариант библиотеки curses содержит разнородную кучу дополнительных функций, включая ряд функций для обработки многостолбцовых символов и подпрограммы управления цветом. Кроме приведенного далее в этой главе описания способов управления цветом, мы будем в основном привязаны к функциям базовой версии библиотеки.

При компиляции программ, использующих curses, следует подключить заголовочный файл curses.h и на этапе редактирования связей саму библиотеку с помощью аргумента -lcurses. Во многих системах Linux вы можете применять просто библиотеку curses, а потом обнаружить, что на самом деле вы пользуетесь усовершенствованной, более новой реализацией ncurses.

Для того чтобы проверить, как установлена библиотека curses в вашей системе, выполните команду

ls -l /usr/include/*curses.h

для просмотра заголовочных файлов и

ls -l /usr/lib/lib*curses*

для проверки библиотечных файлов. Если вы увидите, что curses.h и ncurses.h – прямо связанные файлы, и существует файл библиотеки ncurses, то у вас есть возможность компилировать файлы из этой главы с помощью следующей команды:

$ gcc program. с -о program -lcurses

Если установка curses в вашей системе не использует автоматически ncurses, вы сможете явно задать использование ncurses, включив файл ncurses.h вместо файла curses.h и выполнив следующую команду:

$ gcc -I/usr/include/ncurses program.с -о program -lncurses

в которой опция -I задает каталог для поиска заголовочного файла.

Примечание

В загружаемом коде сценария Makefile предполагается, что в установленной у вас системе по умолчанию применяется библиотека curses, поэтому вы должны заменить его или откомпилировать вручную, если в вашей системе это не так.

Если вы точно не знаете, как установлена библиотека curses в вашей системе, обратитесь к страницам интерактивного справочного руководства, посвященным ncurses, или просмотрите другую интерактивную документацию; обычное место ее хранения – каталог /usr/share/doc/, в котором вы найдете каталог curses или ncurses часто с присоединенным в конце номером версии.

Терминология библиотеки curses и общие представления

Подпрограммы curses действуют на экранах, в окнах и вложенных окнах или подокнах. Экран – это устройство (обычно экран терминала, но может быть и экран эмулятора терминала xterm), на который вы записываете информацию. Он занимает все доступное пространство дисплея этого устройства, Если экран – окно терминала в графическом окне, то он представляет собой совокупность всех доступных символьных позиций в окне терминала. Всегда существует, по крайней мере, одно окно curses с именем stdscr, совпадающее по размеру с физическим экраном. Вы можете создавать дополнительные окна с размером, меньшим, чем размер экрана. Окна могут накладываться друг на друга и иметь много вложенных окон, но каждое из них всегда должно находиться внутри родительского окна.

Библиотека curses поддерживает две структуры данных, действующие как отображение экрана терминала: stdscr и curscr. Структура stdscr, наиболее важная из двух, обновляется, когда функции curses формируют вывод. Структура данных stdscr – «стандартный экран». Она действует во многом так же, как стандартный вывод stdout из библиотеки stdio. Эта структура – стандартное окно вывода в программах, использующих библиотеку curses. Структура curscr похожа на stdscr, но хранит внешний вид отображаемого в текущий момент экрана. Вывод, записанный в структуру stdscr, не появляется на экране до тех пор, пока программа не вызовет функцию refresh, в которой библиотека curses сравнивает содержимое stdscr (как должен выглядеть экран) со второй структурой curscr (как выглядит экран в данный момент). Затем curses использует различия между этими двумя структурами для обновления экрана.

Некоторым программам с использованием curses нужно знать, что библиотека поддерживает структуру stdscr, которая применяется в нескольких функциях curses как параметр. Однако действительная структура stdscr реализуется по-разному, и к ней никогда не следует обращаться напрямую. У программ с использованием curses практически нет нужды в применении структуры curscr.

Таким образом, процесс вывода символов в программе с применением curses выглядит следующим образом:

1. Используется функция библиотеки curses для обновления логического экрана.

2. Запрашивается у библиотеки curses обновление физического экрана с помощью функции refresh.

Преимущество двухшагового подхода помимо большей легкости при программировании – очень эффективный вариант обновления экрана curses. Это может быть не столь важно для экрана консоли, но становится существенным показателем, если программа выполняется через медленное сетевое соединение.

Программа с использованием curses выполнит множество вызовов функций вывода на логический экран, возможно, перемещая курсор по всему экрану для того, чтобы достичь нужной позиции вывода текста или рисования линий и рамок. На каком-то этапе пользователю потребуется увидеть весь этот вывод. Когда это произойдет (обычно во время вызова функции refresh), библиотека curses найдет оптимальный способ формирования физического экрана, соответствующего логическому. Применяя нужные характеристики терминала и оптимизируя перемещения курсора, curses часто обновляет экран, выводя гораздо меньше символов по сравнению со всеми операциями записи на экран, если бы они выполнялись немедленно.

Макет логического экрана – это символьный массив, упорядоченный по строкам и столбцам, с начальной позицией экрана (0, 0) в левом верхнем углу (рис. 6.1).

Рис. 6.1

Во всех функциях библиотеки curses применяются координаты со значением у (строки) перед значением х (столбцы). Каждая позиция хранит не только символ, расположенный в этом месте экрана, но и его атрибуты. Атрибуты, которые можно отобразить, зависят от физических характеристик терминала, но, как правило, они включают жирное начертание и подчеркивание символа. На консолях Linux вам также доступны негативное изображение и цвет, о которых речь пойдет далее в этой главе.

Поскольку библиотека curses нуждается в создании и удалении некоторых временных структур данных, все программы с использованием curses должны инициализировать библиотеку перед применением и затем разрешить ей восстановить первоначальные установки после ее применения. Делается это с помощью вызовов пары функций: initscr и endwin (упражнение 6.1).

Упражнение 6.1. Программа с использованием curses, выводящая приветствие

В этом примере вы напишите очень простую использующую curses программу screen1.c, чтобы показать эти и другие базовые функции в действии. Далее будут описаны их прототипы.

1. Вставьте заголовочный файл curses.h и в функцию main, включите вызовы для инициализации и возврата в исходное состояние библиотеки curses:

#include

#include

#include

int main() {

 initscr();

 ...

 endwin();

 exit(EXIT_SUCCESS);

}

2. Внутрь поместите код для перемещения курсора в точку (5, 15) на логическом экране, выведите приветствие "Hello World" и обновите реальный экран. В заключение примените вызов sleep(2) для того, чтобы приостановить выполнение программы на две секунды и просмотреть вывод на экран перед ее завершением:

move(5, 15);

printw(«%s», «Hello World»);

refresh();

sleep(2);

Пока программа выполняется, вы видите фразу "Hello World" в левом верхнем квадранте пустого экрана (рис. 6.2).

Рис. 6.2

Как это работает

Эта программа инициализирует библиотеку curses, перемещает курсор в заданную точку экрана и отображает некоторый текст. После короткой паузы она закрывает библиотеку и завершается.


    Ваша оценка произведения:

Популярные книги за неделю