Основы программирования в Linux
<i>}</i>Сохраните эту программу как menu5.с.
Как это работает
Переписанная функция
выводит то же меню, что и в предыдущих примерах, но подпрограммы вывода изменены так, чтобы можно было воспользоваться характеристиками из базы данныхgetchoice. Если вы хотите видеть на экране сообщение "You have chosen:" дольше, чем одно мгновение перед очисткой экрана и подготовкой его к следующему выбору пункта меню, добавьте в функциюterminfoвызовmain:sleepdo {choice = getchoice("Please select an action", menu, input, output);printf("\nYou have chosen: %c\n", choice);<i> sleep(1);</i>} while (choice != 'q');Последняя функция в этой программе
включает в себя вызов функцииchar_to_terminal, которую мы упоминали в главе 3.putcВ завершение этой главы бегло рассмотрим пример определения нажатий клавиш.
Обнаружение нажатий клавиш
Пользователи, программировавшие в ОС MS-DOS, часто ищут в ОС Linux эквивалент функции
, которая определяет, была ли нажата клавиша, без реального ее считывания. К сожалению, их поиски оказываются безуспешными, поскольку прямого аналога нет. Программисты в среде UNIX не ощущают этого отсутствия, т.к. UNIX запрограммирована так, что программы очень редко (если когда-либо вообще) озабочены ожиданием события. Поскольку это обычный способ примененияkbhit, ее нехватка редко ощущается в системах UNIX и Linux.kbhitОднако, когда вы переносите программы из MS-DOS, часто удобно эмулировать функцию
, которую можно применять на деле в неканоническом режиме ввода (упражнение 5.7).kbhitУпражнение 5.7. Исключительно ваша собственнаяkbhit1. Начните со стандартной заголовочной информации и пары структур для установки параметров терминала.
применяется для проверки нажатия клавиши. Далее описываются функции, которые будут использоваться позже:peek_character#include <stdio.h>#include <stdlib.h>#include <termios.h>#include <term.h>#include <curses.h>#include <unistd.h>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. Если нажата клавиша <q>, функцияkbhitвосстанавливает нормальный режим и программа завершается:close_keyboardint main() {int ch = 0;init_keyboard();while (ch != 'q') {printf("looping\n");sleep(1);if (kbhit()) {ch = readch();printf("you hit %c\n", ch);}}close_keyboard();exit(0);}3. Функции
иinit_keyboardнастраивают терминал в начале и конце программы:close_keyboardvoid 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. Нажатый символ считывается следующей функцией
, которая затем восстанавливает значение -1 переменнойreadchдля выполнения следующего цикла:peek_characterint readch() {char ch;if (peek_character != -1) {ch = peek_character;peek_character = -1;return ch;}read(0, &ch, 1);