Перевод терминала в не канонический режим работы
Добавлено: 25 июл 2016, 14:34
В линукс существует понятие "канонический" и
"не канонический" режим работы терминала. Канонический
подразумевает использование буфера, тоесть вводимые
с клавиатуры знаки будут буферизироваться до нажатия
клавиши "enter". В не канонический режим, в котором
кстати по умолчанию пребывает и консоль виндовс, мы
можем получить доступ несколькими путями. Во первых что это
нам дает. Давайте разберем это на примере скрипта bash.
Что бы получить ввод каждого символа с клавиатуры мы
в команду read подставим опцию -n со значением 1.
Теперь каждое нажатие на клавишу будет отправлять
значение символа сразу в программу. Здесь мы пока
не отключаем буферизованный ввод, а только определяем
размер буфера в один символ (1 или 2 байта в зависимости от локали).
Что бы выйти из программы достаточно нажать клавишу 'q'.
Давайте теперь соберем похужую программу на Си работающую
пока в режиме канонического терминала, тоесть
в режиме по умолчанию.
Скомпилируем программу с опциями выводящими на всякий
случай, даже небольшие предупреждения:
Можем запускать
Любую нажатую клавишу и символ перевода строки
программа будет повторять. Замечу, только однобайтовые
символы, тоесть аски, в латинской раскладке. Выход из
программы осуществляется так же по нажатию клавиши 'q'.
Что бы эта программа считывала сразу воодимые символы,
не дожидаясь нажатия клавиши "enter" можно в командной
строке перед запуском нашей программы перевести терминал
в режим "не канонический". Но для начала сохраним прежнее
значение в переменную:
Теперь можно менять параметры:
Запустим нашу программу:
Теперь вывод появляется сразу же после нажатия на клавишу.
И так как мы теперь можем не нажимать клавишу "enter"
то и не поялвяются дублирующие невидимые занки перевода строки.
Нажмем клавишу 'q' и выйдем из программы, а терминал
переведем в нормальный режим восстановив первоначальные
его параметры:
Что бы программа работала так по умолчанию и мы могли перед каждым
ее запуском не менять в ручную настройки терминала вызовем
в программе утилиту stty через специальную функцию system()
Это очень просто но хочу заметить что вызывать в программе на Си
обертку с интефейсом командной строки далеко не продуктивно. Все это
можно проделать в ручную, вызывая по порядку необходимые функции.
Перепишим программу выполняющую все самостоятельно не обращаясь за
помощью к утилитам командной строки.
Выходим только по каманде 'q'. Если выйти через сигнал
прерывания Ctrl+C то терминал останется работать в не
каноническом режиме. Это относится и к предыдущей программе.
Тогда во избежание неприятностей просто закройте терминал и
откройте снова. Справку по всем функциям можно получить не
отходя от кассы, потому что язык Си это язык на котором написан linux.
Подставляем в вызове страницы мана только циферку 3:
"не канонический" режим работы терминала. Канонический
подразумевает использование буфера, тоесть вводимые
с клавиатуры знаки будут буферизироваться до нажатия
клавиши "enter". В не канонический режим, в котором
кстати по умолчанию пребывает и консоль виндовс, мы
можем получить доступ несколькими путями. Во первых что это
нам дает. Давайте разберем это на примере скрипта bash.
Что бы получить ввод каждого символа с клавиатуры мы
в команду read подставим опцию -n со значением 1.
Теперь каждое нажатие на клавишу будет отправлять
значение символа сразу в программу. Здесь мы пока
не отключаем буферизованный ввод, а только определяем
размер буфера в один символ (1 или 2 байта в зависимости от локали).
Код: Выделить всё
#!/usr/bin/env bash
while [[ $d != 'q' ]]; do
read -n 1 -s d
echo -ne "$d "
done
echo ""Давайте теперь соберем похужую программу на Си работающую
пока в режиме канонического терминала, тоесть
в режиме по умолчанию.
Код: Выделить всё
#include <stdio.h>
int main(void)
{
char ch;
while ((ch = getchar()) != 'q')
{
printf("%c\n", ch);
}
return 0;
}случай, даже небольшие предупреждения:
Код: Выделить всё
gcc -Wall -O3 -o prog prog.cКод: Выделить всё
./progпрограмма будет повторять. Замечу, только однобайтовые
символы, тоесть аски, в латинской раскладке. Выход из
программы осуществляется так же по нажатию клавиши 'q'.
Что бы эта программа считывала сразу воодимые символы,
не дожидаясь нажатия клавиши "enter" можно в командной
строке перед запуском нашей программы перевести терминал
в режим "не канонический". Но для начала сохраним прежнее
значение в переменную:
Код: Выделить всё
save_stty=$(stty -g)Код: Выделить всё
stty -icanonКод: Выделить всё
./progИ так как мы теперь можем не нажимать клавишу "enter"
то и не поялвяются дублирующие невидимые занки перевода строки.
Нажмем клавишу 'q' и выйдем из программы, а терминал
переведем в нормальный режим восстановив первоначальные
его параметры:
Код: Выделить всё
stty $save_sttyее запуском не менять в ручную настройки терминала вызовем
в программе утилиту stty через специальную функцию system()
Код: Выделить всё
#include <stdio.h>
#include <stdlib.h>
int main() {
int c;
system("stty -icanon -echo"); /* включаем неканонический ввод */
while ((c = getchar()) != 'q') {
printf("%c - %i\n", c, c);
}
system("stty icanon echo"); /* включаем канонический ввод */
return 0;
}
обертку с интефейсом командной строки далеко не продуктивно. Все это
можно проделать в ручную, вызывая по порядку необходимые функции.
Перепишим программу выполняющую все самостоятельно не обращаясь за
помощью к утилитам командной строки.
Код: Выделить всё
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
struct termios oldt, newt; //определяем переменные
int main() {
char ch;
tcgetattr(0, &oldt);
newt = oldt;
newt.c_lflag &= ~ICANON;
tcsetattr(0, TCSANOW, &newt);
while ((ch = getchar()) != 'q') {
printf("%c\n", ch);
}
tcsetattr(0, TCSANOW, &oldt);
return 0;
}
прерывания Ctrl+C то терминал останется работать в не
каноническом режиме. Это относится и к предыдущей программе.
Тогда во избежание неприятностей просто закройте терминал и
откройте снова. Справку по всем функциям можно получить не
отходя от кассы, потому что язык Си это язык на котором написан linux.
Подставляем в вызове страницы мана только циферку 3:
Код: Выделить всё
man 3 termios
man 3 tcgetattr
...