Linux でキーストロークをすぐにキャプチャするにはどうすればよいですか?[重複]

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

  •  13-12-2019
  •  | 
  •  

質問

重複の可能性:
Linux の getch() と getche() に相当するものは何ですか?

私は Linux プログラミングの初心者です。:-)

私のプログラム(を使用して C 言語) は、Linux ですべてのキー ストロークを即座にキャプチャし、Telnet と同様に、それをエコーするかどうか、および表示方法を決定できます。

たとえば、ユーザーが「A」を入力した場合はプログラムに「B」を表示させ、「B」を入力した場合は「C」を表示するようにします。

それは面白くて役に立たないように聞こえます。ただ興味があるのです。

役に立ちましたか?

解決

基本的に、それはすぐにどのように定義するかに大きく依存します。

ここには 2 つのタスクがあります。1 つ目は、ほとんどの C 入力ライブラリに組み込まれている通常のキー エコーを無効にすることです。2 つ目は、古い文字の代わりに新しい文字を出力することです。

疑似コードで。

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

キーの押下を捕捉するために通信するシステムは数多くあります。

  1. キーボード
  2. (おそらく) USB バス
  3. CPU割り込みハンドラ
  4. オペレーティングシステム
  5. X ウィンドウ サーバー プロセス
  6. フォーカスのある X の「ウィンドウ」。

最後のステップは、X サーバーからイベントを取得して処理する連続ループを実行するプログラムを使用して行われます。このプログラムを特定の方法 (キーが押された時間の長さを取得する) で拡張したい場合は、「生の」キーボード イベントが必要であることを他のプログラムに伝える必要があります。これは、実際には完全に「調理された」ものを受け取るわけではないことを意味します。 」の文字。その結果、どのキーが上下にあるのか、どのくらいの長さなのかを追跡し、プログラム内の奇妙なメタ キーの動作をすべて処理する必要があります (これは「a」ではなく「A」です。 シフト ダウンしているなど)。

正規および非正規など、考慮すべき他の処理モードもあります。これは、イベントを行指向のチャンク (ライン イベント) で受信するか文字指向のチャンク (文字イベント) で受信するかを制御します。これもまた、上流プログラムに下流クライアントの要件を認識させる必要があるため、多少複雑になります。

環境についてある程度理解できたので、文字出力を抑制するために必要な実際のコードをもう一度見てみましょう。

// 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 およびその他 - man ページ
ncurses プログラミングのハウツー

このコードはインターネットで見つけることができます。 kermi3 Cボードから

#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

やりすぎかもしれませんが、次のようなゲームライブラリを使用できます。 sdl それを達成するために。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top