我正在尝试编写自己的“键盘驱动程序”(实际上没有编写内核模块),
通过抓取键盘,我认为是用户空间中最低级别的抽象:/dev/input/event*
。
如果您更改ioctl(fd, EVIOCGRAB, UNGRAB)
的第一个错误,以下代码会抓取
到ioctl(fd, EVIOCGRAB, GRAB)
。
// gcc main.c -o main
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <linux/input.h>
#include <fcntl.h>
#include <errno.h>
#define EXIT_KEY KEY_ESC
#define UNGRAB 0
#define GRAB 1
const char* kbd_device = "/dev/input/event4";
// ------------------------------------------------------------------------------------------------
int main(void){
int fd = open(kbd_device, O_RDONLY);
if(fd == -1){
printf("Cannot open %s. %s.\n", kbd_device, strerror(errno));
return -1;
}
if(ioctl(fd, EVIOCGRAB, UNGRAB))
printf("Couldn't grab %s. %s.\n", kbd_device, strerror(errno));
else
printf("Grabbed %s!\n", kbd_device);
while(1){
struct input_event event;
read(fd, &event, sizeof(event));
if (event.type == EV_KEY && event.value >= 0 && event.value <= 2){
printf("%d %3d\n", event.value, event.code);
if(event.code == EXIT_KEY){
ioctl(fd, EVIOCGRAB, UNGRAB);
close(fd);
return 0;
}
}
}
}
gcc main.c -o main && sudo ./main
,一切都会按预期运行。sudo ./main
,则终端会不停地向下滚动,就像按住RETURN键一样。为什么会这样?
/dev/input/event4
恰好是键盘我正在尝试编写一个键盘“驱动程序”,它既适用于X,也适用于X(例如TTY)。
我理解X11的键盘库/扩展名是XKB。我认为TTY的键盘库是linux/divers/tty/vt/keyboard.c
(source),
它使用的初始键盘映射位于linux/drivers/tty/vt/defkeymap.map
(source),可以使用loadkeys
(来源here)对其进行修改。如果我错了,请纠正我。
答案 0 :(得分:5)
键入
时gcc main.c -o main && sudo ./main ↵
GCC需要一些时间,所以↵键已经在./main
运行时释放。
键入
时sudo ./main ↵
终端按下↵后立即向shell发送换行符,然后开始执行./main
。然后你的程序会看到↵释放的事件,但不是你的终端,因为你的程序已经抓住了输入设备。因此,对于终端,它看起来像↵,因此它继续产生换行符。
答案 1 :(得分:1)
这个问题已经被回答了,但是它仍然不能很好地解决这个问题。
我前一段时间实现的驱动程序也存在同样的问题,该驱动程序也需要捕获键盘。
我无法找到一种方法来强制内核在捕获设备之前识别出设备中的密钥释放,因此解决方案包括在您检测到所有密钥已被释放之前不抓取设备。可以通过在打开设备之前并抓住它之前用EVIOCGKEY ioctl监视设备来实现。
OBS:请注意,read
循环中看似虚假的while
函数是必要的,以避免繁忙的等待,这样循环将在输入设备发生每个事件后进行循环。另外请注意,必须将文件描述符配置为阻止I / O(默认设置)。
void waitReleaseAll(int fd) {
struct input_event evt;
unsigned char key_b[KEY_MAX/8 + 1];
int i, nothing;
while ( 1 ) {
memset(key_b, 0, sizeof(key_b));
ioctl(fd, EVIOCGKEY(sizeof(key_b)), key_b);
for ( nothing = 1 , i = 0 ; i < KEY_MAX/8 + 1 ; i++ ) {
if ( key_b[i] != 0 ) { nothing = 0; break; }
}
if ( nothing ) break;
read(fd, &evt, sizeof(evt));
}
printf("All keys are now released\n");
}
答案 2 :(得分:0)
要解决您的问题,您应该在代码中使用SIGINT
来识别用户的Ctrl-C
击键。
SIGNAL
实施例static volatile sig_atomic_t stop = 0;
static void interrupt_handler(int sig)
{
stop = 1;
} // Outside of the main function.
int main(int argc, char *argv[])
{
signal(SIGINT, interrupt_handler);
while (!stop) {
//your code
}
exit(0);
}