Как я могу сразу захватить нажатие клавиши в Linux?[дубликат]

StackOverflow https://stackoverflow.com//questions/12710582

  •  13-12-2019
  •  | 
  •  

Вопрос

Возможный дубликат:
Что эквивалентно getch() и getche() в Linux?

Я новичок в программировании под Linux.:-)

Мне просто интересно, если моя программа (используя С язык) может мгновенно фиксировать каждое нажатие клавиши в Linux, а затем решать, отображать его или нет и как его отображать, точно так же, как telnet.

например, если пользователь нажимает «A», я хочу, чтобы программа отображала «B», если он набирает «B», требуется «C» и так далее.

Звучит смешно и бесполезно.Мне просто интересно.

Это было полезно?

Решение

По сути, это во многом зависит от того, как вы определите сразу.

Здесь есть две задачи.Первый — отключить регулярное эхо клавиш, встроенное в большинство библиотек ввода C.Второй — распечатать новый символ вместо старого.

В псевдокоде.

 echo(off);
 while (capturing && charIsAvailable()) {
   c = readOneChar();
   if (c == '\n') {
     capturing = false;
   }
   printf("%c", c++);
 }
 echo(on);

Существует ряд систем, взаимодействующих для захвата нажатия клавиши.

  1. Клавиатура
  2. (возможно) шина USB
  3. Обработчик прерываний процессора
  4. Операционная система
  5. Процесс сервера X Window
  6. «Окно» X, имеющее фокус.

Последний шаг выполняется с помощью программы, которая запускает непрерывный цикл, захватывающий события с X-сервера и обрабатывающий их.Если вы хотите расширить эту программу определенным образом (получить продолжительность нажатия клавиши), вам нужно сообщить другим программам, что вам нужны «сырые» события клавиатуры, а это означает, что вы на самом деле не будете получать полностью «готовые» события. " персонажи.В результате вам придется отслеживать, какие клавиши находятся вверху и внизу и как долго, а также обрабатывать все странные мета-ключи в вашей программе (это не «а», а «А», потому что сдвиг не работает и т. д.).

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

Теперь, когда у вас есть некоторое представление о вашей среде, давайте вернемся к реальному коду, необходимому для подавления вывода символов.

// define a terminal configuration data structure
struct termios term;

// copy the stdin terminal configuration into term
tcgetattr( fileno(stdin), &term );

// turn off Canonical processing in term
term.c_lflag &= ~ICANON;

// turn off screen echo in term
term.c_lflag &= ~ECHO;

// set the terminal configuration for stdin according to term, now
tcsetattr( fileno(stdin), TCSANOW, &term);


(fetch characters here, use printf to show whatever you like)

// turn on Canonical processing in term
term.c_lflag |= ICANON;

// turn on screen echo in term
term.c_lflag |= ECHO;

// set the terminal configuration for stdin according to term, now
tcsetattr( fileno(stdin), TCSANOW, &term);

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

Другие советы

Эдвин Бак дал отличный ответ.Вот еще одна альтернатива, которая использует ncurses что делает такие вещи немного проще и поддерживается почти во всех дистрибутивах Linux и других вариантах Unix.

#include <ncurses.h>

int main(int argc, char *argv[])
{
    int ch,c;
    initscr();
    cbreak();
    noecho();

    while( ch != 'q')
    {
        switch( c = getch() )
        {
            case 'a':
                ch = 'b';
            break;

            case 'b':
                ch = 'c';
            break;

            case 'c':
                ch = 'd';
            break;

            default:
                ch = c;                 
            break;
        }
        printw("%c",ch);
    }
    endwin();
    return(0);
}

скомпилировать с помощью gcc code.c -o code -lncurses

И вот несколько вспомогательных ссылок:

ncurses noecho и другие — справочная страница
ncurses программирование HOWTO

Этот код можно найти в Интернете, и он принадлежит kermi3 из c-board

#include <termios.h>
#include <unistd.h>

int mygetch(void)
{
    struct termios oldt,newt;
    int ch;
    tcgetattr( STDIN_FILENO, &oldt );
    newt = oldt;
    newt.c_lflag &= ~( ICANON | ECHO );
    tcsetattr( STDIN_FILENO, TCSANOW, &newt );
    ch = getchar();
    tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
    return ch;
}

РЕДАКТИРОВАТЬ: конечно, если вы хотите получить сам символ, а не значение ascii, измените его на char вместо int

это может быть излишним, но вы можете использовать игровые библиотеки, такие как сдл чтобы добиться этого.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top