Linux 从 /dev/input 读取
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15949163/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Read from /dev/input
提问by szymon hrapkowicz
I have an USB RFID card reader which emulates keyboard.
So when i put an card to it i see the string on a terminal window -i.e. "0684a24bc1"
我有一个模拟键盘的 USB RFID 读卡器。因此,当我将卡片放入其中时,我会在终端窗口上看到字符串 - 即"0684a24bc1"
But i would like to read it in my C program.
There is no problem when i use: scanf("%s",buff);
但我想在我的 C 程序中阅读它。当我使用时没有问题:scanf("%s",buff);
But when i use below code i got a lot (about 500 bytes) not recognized data. Why? I would like to have non blocking read.
但是当我使用下面的代码时,我得到了很多(大约 500 字节)无法识别的数据。为什么?我想要非阻塞读取。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
int main(int argc, char ** argv) {
int fd;
char buf[256];
fd = open("/dev/input/event3", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
perror("open_port: Unable to open /dev/ttyAMA0 - ");
return(-1);
}
// Turn off blocking for reads, use (fd, F_SETFL, FNDELAY) if you want that
fcntl(fd, F_SETFL, 0);
}
while(1){
n = read(fd, (void*)buf, 255);
if (n < 0) {
perror("Read failed - ");
return -1;
} else if (n == 0) printf("No data on port\n");
else {
buf[n] = 'struct input_event {
struct timeval time;
unsigned short type;
unsigned short code;
unsigned int value; };
';
printf("%i bytes read : %s", n, buf);
}
sleep(1);
printf("i'm still doing something");
}
close(fd);
return 0;
}
回答by Hasturkun
According to the Linux input documentation, section 5, the /dev/input/eventX devices return data as following:
根据Linux 输入文档,第 5 节,/dev/input/eventX 设备返回数据如下:
You can use blocking and nonblocking reads, also select() on the /dev/input/eventX devices, and you'll always get a whole number of input events on a read. Their layout is:
struct input_event { struct timeval time; unsigned short type; unsigned short code; unsigned int value; };
'time' is the timestamp, it returns the time at which the event happened. Type is for example EV_REL for relative moment, EV_KEY for a keypress or release. More types are defined in include/linux/input.h.
'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete list is in include/linux/input.h.
'value' is the value the event carries. Either a relative change for EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for release, 1 for keypress and 2 for autorepeat.
您可以使用阻塞和非阻塞读取,也可以在 /dev/input/eventX 设备上使用 select(),并且每次读取时您将始终获得完整数量的输入事件。他们的布局是:
perror("open_port: Unable to open /dev/ttyAMA0 - ");
'time' 是时间戳,它返回事件发生的时间。例如,类型是 EV_REL 表示相对时刻,EV_KEY 表示按键或释放。更多类型在 include/linux/input.h 中定义。
'code' 是事件代码,例如 REL_X 或 KEY_BACKSPACE,同样完整的列表在 include/linux/input.h 中。
“价值”是事件携带的价值。EV_REL 的相对变化,EV_ABS 的绝对新值(操纵杆...),或者 EV_KEY 为 0 表示释放,1 表示按键,2 表示自动重复。
回答by ulidtko
Your code is clearly wrong at opening an event device under /dev/input/
. Even your error message is contradicting the choice:
您的代码在/dev/input/
. 甚至您的错误消息也与选择相矛盾:
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
int main(int argc, char *argv[])
{
int timeout_ms = 5000;
char input_dev[] = "/dev/input/event17##代码##";
int st;
int ret;
struct pollfd fds[1];
fds[0].fd = open(input_dev, O_RDONLY|O_NONBLOCK);
if(fds[0].fd<0)
{
printf("error unable open for reading '%s'\n",input_dev);
return(0);
}
const int input_size = 4096;
unsigned char input_data[input_size];
memset(input_data,0,input_size);
fds[0].events = POLLIN;
int exit_on_key_press_count = 10;
while(true)
{
ret = poll(fds, 1, timeout_ms);
if(ret>0)
{
if(fds[0].revents)
{
ssize_t r = read(fds[0].fd,input_data,input_size);
if(r<0)
{
printf("error %d\n",(int)r);
break;
}
else
{
printf("total bytes read %d/%d\n",(int)r,input_size);
for(int i = 0; i<r;i++)
{
printf("%02X ",(unsigned char)input_data[i]);
}
printf("\n");
memset(input_data,0,input_size);
exit_on_key_press_count--;
if(exit_on_key_press_count<1)
break;
}
}
else
{
printf("error\n");
}
}
else
{
printf("timeout\n");
}
}
close(fds[0].fd);
return 0;
}
Reads from /dev/input/eventN
files return binary data with event descriptions (like pointer moving or button presses), not text. Your probably want to open some sort of serial emulation device instead.
从/dev/input/eventN
文件读取返回带有事件描述(如指针移动或按钮按下)的二进制数据,而不是文本。您可能想要打开某种串行仿真设备。
回答by Rolas
$ sudo ./keypressed
$ sudo ./keypressed
total bytes read 72/4096
读取的总字节数 72/4096
35 49 C9 5C 00 00 00 00 38 27 0B 00 00 00 00 00 04 00 04 00 5A 00 07 00 35 49 C9 5C 00 00 00 00 38 27 0B 00 00 00 00 00 01 00 50 00 01 00 00 00 35 49 C9 5C 00 00 00 00 38 27 0B 00 00 00 00 00 00 00 00 00 00 00 00 00
35 49 C9 5C 00 00 00 00 38 27 0B 00 00 00 00 00 04 00 04 00 5A 00 07 00 35 49 C9 5C 00 00 00 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 C9 5C 00 00 00 00 38 27 0B 00 00 00 00 00 00 00 00 00 00 00 00 00
This is raw data, to convert to some key, I need to read 'Linux input documentation' link abave...
这是原始数据,要转换为某个键,我需要阅读以下“Linux 输入文档”链接...