Команда IT специалистов выполнит подготовку инфраструктуры для вашего бизнеса.
Внедрение самых передовых решений и технологий.
Поддержка и сопровождение ваших сервисов.
Выполнение работ под "ключ", от покупки сервера, до настройки автоматизации процессов. 8(977)608-78-62 adm@nixm.ru
Внедрение самых передовых решений и технологий.
Поддержка и сопровождение ваших сервисов.
Выполнение работ под "ключ", от покупки сервера, до настройки автоматизации процессов. 8(977)608-78-62 adm@nixm.ru
Перевод терминала в не канонический режим работы
Перевод терминала в не канонический режим работы
В линукс существует понятие "канонический" и
"не канонический" режим работы терминала. Канонический
подразумевает использование буфера, тоесть вводимые
с клавиатуры знаки будут буферизироваться до нажатия
клавиши "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
...
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." - Alan Kay
Re: Перевод терминала в не канонический режим работы
А ещё, может окажется полезным в тему: Разработка программных проектов в Linux (глава "Расширенные операции ввода-вывода", стр. 273).nezabudka писал(а):Перепишим программу выполняющую все самостоятельно не обращаясь за
помощью к утилитам командной строки.
Ну и для полноты картины ... есть такая библиотека ncurses - это классика UNIX начиная с самых древних BSD, на ней сделано множество широкоизвестных используемых проектов Linux. ncurses и переводит терминал в некононический режим, и обеспечивает прямое позиционирование курсора, и посимвольный ввод/вывод ... и мн. других вещей. И когда окажется необходимым посимвольный ввод, то (хорошо понимая режимы ввода/вывода и termios) - лучше использовать ncurses.
Re: Перевод терминала в не канонический режим работы
Вот как красиво выглядит практически полновесный визуальный редактор экрана (такой, как мог бы служить основой текстового редактора):Olej писал(а):И когда окажется необходимым посимвольный ввод, то (хорошо понимая режимы ввода/вывода и termios) - лучше использовать ncurses.
Код: Выделить всё
#include <signal.h>
#include <stdlib.h>
#include <ncurses.h>
void handler( int signo ) {
endwin(); // завершение работы с ncurses
exit( 0 );
};
int main( int argc,char *argv[] ) {
signal( SIGINT, handler );
initscr(); // инициализация (должна быть выполнена перед использованием ncurses)
int c, y, x, my, mx;
getmaxyx( stdscr, my, mx );
move( my / 2, mx / 2 ); // перемещение курсора в стандартном экране y=10 x=30
noecho();
keypad( stdscr, TRUE );
while( ( c = getch() ) != KEY_F( 3 ) ) {
getyx( stdscr, y, x );
if( c == KEY_RESIZE ) {
getmaxyx( stdscr, my, mx );
continue;
}
switch( c ) {
case KEY_UP: move( y > 0 ? --y : y, x ); break;
case KEY_DOWN: move( y < my ? ++y : y, x ); break;
case KEY_LEFT: move( y, x > 0 ? --x : x ); break;
case KEY_RIGHT: move( y, x < mx ? ++x : x ); break;
case KEY_BACKSPACE: if( x > 1 ) {
move( y, x - 1 );
addch( ' ' );
move( y, x - 1 );
break;
}
case KEY_DC: addch( ' ' ); break;
default:
addch( c );
break;
}
}
endwin();
return 0;
}
Всего то!
Re: Перевод терминала в не канонический режим работы
Вот такой вот аналог программы получается с библиотекой ncurses:
При компиляции укажем библиотеку для линковщика:
Olej. Вы привели пример кода с управлением в окне при помощи стрелок. Подскажите при помощи чего
можно было бы реализовать управление в стиле vim, тоесть простого перемещение курсора по экрану
без отображения символов.
Код: Выделить всё
#include <ncurses.h>
int main()
{
char ch;
initscr();
cbreak();
while(ch != 'q')
{
ch = getch();
printw("%c ", ch);
}
endwin();
return 0;
}
Код: Выделить всё
gcc -Wall -O3 -o prog prog.c -lncurses
можно было бы реализовать управление в стиле vim, тоесть простого перемещение курсора по экрану
без отображения символов.
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." - Alan Kay
Re: Перевод терминала в не канонический режим работы
Я не сильно понял что такое "без отображения символов" (не помню уже vim), но вот это и есть без отображения:nezabudka писал(а): Вы привели пример кода с управлением в окне при помощи стрелок. Подскажите при помощи чего
можно было бы реализовать управление в стиле vim, тоесть простого перемещение курсора по экрану
без отображения символов.
Код: Выделить всё
noecho();
Код: Выделить всё
keypad( stdscr, TRUE );
Re: Перевод терминала в не канонический режим работы
2 полезных ссылки по ncurses:nezabudka писал(а): Подскажите при помощи чего
http://alexber220.narod.ru/ncurses/
http://alexber220.narod.ru/ncurses/page2.htm
Только читать - аккуратно, там парень в залихватскости своей много неточностей пишет ... но как подсказка - годится.
А дальше: /usr/include/ncurses.h - там большинство вопросов можно разобрать из заголовков, определений и комментариев.
Re: Перевод терминала в не канонический режим работы
Я имела ввиду аналогичную работу приведенной ниже программы только с использованием
библиотеки ncurses. Клавиши управления курсором в стиле vim "h j k l"
библиотеки ncurses. Клавиши управления курсором в стиле vim "h j k l"
Код: Выделить всё
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
int main (void) {
struct termios savetty, tty;
char ch;
int x = 0, y = 0;
if( !isatty( 0 ) ) {
fprintf( stderr, "stdin not terminal\n" );
exit( EXIT_FAILURE );
};
tcgetattr( 0, &tty ); // получили состояние терминала
savetty = tty;
tty.c_lflag &= ~( ICANON | ECHO | ISIG );
tty.c_cc[ VMIN ] = 1;
tcsetattr( 0, TCSAFLUSH, &tty ); // изменили состояние терминала
printf( "%c[2J", 27 ); // очистили экран
fflush( stdout );
printf( "%c[%d;%dH", 27, y, x ); // установили курсор в позицию
fflush( stdout );
for( ; ; ) {
read( 0, &ch, 1 );
if( ch == 'q' ) break;
switch( ch ) {
case 'k':
printf( "%c[1A", 27 );
break;
case 'j':
printf( "%c[1B", 27 );
break;
case 'l':
printf( "%c[1C", 27 );
break;
case 'h':
printf( "%c[1D", 27 );
break;
};
fflush( stdout );
};
tcsetattr( 0, TCSAFLUSH, &savetty ); // восстановили состояние терминала
printf( "\n" );
exit( EXIT_SUCCESS );
Последний раз редактировалось nezabudka 26 июл 2016, 23:39, всего редактировалось 2 раза.
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." - Alan Kay
Re: Перевод терминала в не канонический режим работы
В самом примитивном виде полный аналог вашего фрагмента будет так:nezabudka писал(а):Я имела ввиду аналогичную работу приведенной ниже программы только с использованием
библиотеки ncurses. Клавиши управления курсором в стиле vim "h j k l"
Код: Выделить всё
#include <ncurses.h>
int main( int argc,char *argv[] ) {
initscr(); // инициализация
int c, y, x;
move( 10, 30 ); // перемещение курсора
noecho();
while( ( c = getch() ) != 'q' ) {
getyx( stdscr, y, x );
switch( c ) {
case 'k': move( --y, x ); break;
case 'j': move( ++y, x ); break;
case 'h': move( y, --x ); break;
case 'l': move( y, ++x ); break;
}
}
endwin();
return 0;
}
Re: Перевод терминала в не канонический режим работы
Код: Выделить всё
#include <ncurses.h>
int main(void)
{
initscr();
noecho();
cbreak();
int y,x;
char ch;
y=20;
x=40;
move(y,x);
curs_set(0);
while(ch != 'q')
{
ch = getch();
switch(ch)
{
case 'j':
{
y=y+1;
move (y,x);
printw("*");
refresh();
break;
}
case 'k':
{
y=y-1;
move (y,x);
printw("*");
refresh();
break;
}
case 'l':
{
x=x+1;
move(y,x);
printw("*");
refresh();
break;
}
case 'h':
{
x=x-1;
move (y,x);
printw("*");
refresh();
break;
}
}
}
endwin();
return 0;
}
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." - Alan Kay
Re: Перевод терминала в не канонический режим работы
Когда сильно выпивши, то эхо гулко и многократно слышится, и отзывается внутри черепной коробки на любой малейший звук нестерпимым эхом...Шпак Дмитрий писал(а): А можног вопрос? ТЫ слышала про эхо? Я пока чуть выпивший, не стал вникать.