题
我是linux编程的新手。:-)
我只是想知道我的程序是否(使用 C 语言)可以立即捕获Linux中的每一个击键,然后决定是否回显以及如何显示,就像telnet一样。
例如,如果用户敲击“A”,我希望程序显示“B”,如果他键入“B”,则需要“C”,等等。
听起来很有趣而且没用。我只是好奇而已。
解决方案
基本上,这在很大程度上取决于您如何立即定义。
这里有两个任务。第一个是禁用大多数 C 输入库中内置的常规按键回显。第二种是打印出新字符而不是旧字符。
在伪代码中。
echo(off);
while (capturing && charIsAvailable()) {
c = readOneChar();
if (c == '\n') {
capturing = false;
}
printf("%c", c++);
}
echo(on);
有许多系统通过通信来捕获按键操作。
- 键盘
- (可能)USB 总线
- CPU中断处理程序
- 操作系统
- X 窗口服务器进程
- 具有焦点的 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 进行编译
这里有一些支持链接:
该代码可以在互联网上找到,它是由 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;
}
编辑: 当然,如果你想获取 char 本身而不是 ascii 值,请更改为 char
代替 int
这可能有点过头了,但你可以使用游戏库,例如 sdl 为了实现这一点。