如何在linux中立即捕获关键笔划?

Yis*_*ang 7 c linux scancodes

可能重复:
什么等同于Linux中的getch()和getche()?

我是linux编程的新手.:-)

我只是想知道我的程序(使用C语言)是否可以立即捕获linux中的每一个键击,然后决定是否回显它以及如何显示它,就像telnet一样.

例如,如果用户敲击"A",我希望程序显示"B",如果他输入"B",则需要"C",依此类推.

听起来很有趣也没用.我只是好奇.

Edw*_*uck 12

基本上,它在很大程度上取决于您如何立即定义.

这里有两个任务.第一种是禁用大多数C输入库中内置的常规键回显.第二种是打印出新角色而不是旧角色.

在伪代码中.

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

有许多系统正在进行通信以捕获按键.

  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);
Run Code Online (Sandbox Code Playgroud)

即使这不是立竿见影的.要立即获得,您需要更接近源,这最终意味着内核模块(它仍然不如键盘微控制器那么直接,这不像交换机实际关闭的那样立即).在源和目的地之间有足够的项目,最终可以注意到差异,然而,在实践中,这些代码已经被寻求性能和灵活性之间的最佳权衡的人们进行了大量工作.

  • 这听起来很棒,还有很多东西需要学习. (3认同)
  • @UniMouS总是有,并且stdin输入处理被这样的好库包裹起来,你真的无法理解封面后面有多少东西,直到你必须做一些特别的事情. (3认同)

小智 5

该代码可以在互联网上找到,来自kermi3c-board

#include <termios.h>
#include <unistd.h>
#include <stdio.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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:当然,如果您想获取 char 本身而不是 ascii 值,请更改为char而不是int


Chi*_*era 5

埃德温巴克提供了一个很好的答案.这是另一种使用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);
}
Run Code Online (Sandbox Code Playgroud)

使用gcc code.c编译-o code -lncurses

以下是一些支持链接:

ncurses noecho和其他 - 手册
ncurses编程HOWTO