我正在编写一个本质上基于字符的程序,但在 xterm 中运行,并且想使用鼠标向上/向下滚动和左键单击作为键盘向上/向下箭头和返回的同义词,只是为了一点额外的用户便利。
我有一个 select()
,所有输入 fdset 都工作正常,并且正在异步捕获原始输入(无论如何看起来是这样)。但是我在明确解释 input_event 结构中的类型、代码、值成员时遇到了一些麻烦。 /usr/include/linux/input.h
似乎有一些 EV,我看到了
EV_REL=0x02
(鼠标移动时的相对位置)EV_MSC=0x04
(杂项)用于所有其他鼠标操作。
问题 1:这是否普遍适用???我没有成功地用谷歌搜索任何具体的内容。
但除了 EV 之外,我在 /usr/include/
中没有看到任何代码和值。我的实验显示了以下内容,我进一步询问以下所有内容是否(普遍)正确。或者更好的是,关于这些东西的(权威的)文档在哪里?我原以为用谷歌搜索会很容易,但找不到答案。
任何一个 Action 似乎都会生成两个或三个单独的 input_event,最后一个(第二个或第三个)是类型 = 代码 = 值 = 0 的“预告片”。我在下面将 input_event 写为三元组(类型、代码、值)...
对于左键单击,您会得到三个事件:(4,4,589825),(1,272,1),(0,0,0)。对于左键单击释放,您将获得:(4,4,589825),(1,272,0),(0,0,0)。这一切都正确吗? 589825 到底是什么东西???
对于向上滚动轮,您会得到两个事件:(2,8,1),(0,0,0)。对于向下滚动轮,您将得到:(2,8,-1),(0,0,0)。 (普遍)正确,又一次?
我并不特别关心右键单击或鼠标移动,我只是忽略它们。那么我可以对前面的内容进行硬编码(使用一些#define'ed 符号),还是更像 termcap,它在某种程度上依赖于设备功能?而且,再一次,这些东西在哪里真实记录?谢谢。
编辑下面关于 NominalAnimal 的/dev/input/mice 的评论
正如 NominalAnimal 在他出色的回答中所建议的(再次感谢,Nominal),我正在阅读/dev/input/event16,这是我通过查看/proc/bus/input/devices 文件得出的。我想要(并且仍然想要)更一般地编写代码,但是尝试读取/dev/input/mice 每次读取仅返回三个字节,而不是包含 input_event 结构的 16 个字节。至少那是我做的时候发生的事情。而且我想不出任何方法来“解码”这些字节以告诉我“event16”。
所以我最初会问这个问题,但我想我已经说得够多了:有什么方法可以从/dev/input/mice 获取我现在从/dev/input/event16 获取的所有数据?或者有没有办法以编程方式确定哪个/dev/input/event?是在初始化期间用于鼠标(不解析该/proc/文件)?
最佳答案
您也可以使用旧式鼠标接口(interface)(/dev/mouse
、/dev/input/mouseN
,或者从连接到机器的所有鼠标,/dev/input/mice
)。您确实需要将设备切换到四字节 ImPS 协议(protocol)以支持所有三个按钮和滚轮,但这很简单:只需写入六个字节 0xf3, 200, 0xf3, 100, 0xf3, 80
, 并读取 ACK 字节 (0xfa
)。
考虑以下示例程序。您可以指定它应该从中读取的 mousedev 设备;如果未指定,则默认为 /dev/input/mice
:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
static const size_t mousedev_seq_len = 6;
static const unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
static volatile sig_atomic_t done = 0;
static void handle_done(int signum)
{
done = 1;
}
static int install_done(const int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = handle_done;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
static int bytetoint(const unsigned char c)
{
if (c < 128)
return c;
else
return c - 256;
}
int main(int argc, char *argv[])
{
unsigned char buffer[4];
ssize_t len;
const char *devpath = "/dev/input/mice";
int devfd;
int wasleft, wasmiddle, wasright;
if (argc < 1 || argc > 2 || (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s -h | --help\n", argv[0]);
fprintf(stderr, " %s /dev/input/mouseX\n", argv[0]);
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
if (argc == 2)
devpath = argv[1];
if (install_done(SIGINT) ||
install_done(SIGTERM) ||
install_done(SIGHUP)) {
fprintf(stderr, "Cannot install signal handlers: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
/* Open the mouse. */
do {
devfd = open(devpath, O_RDWR | O_NOCTTY);
} while (devfd == -1 && errno == EINTR);
if (devfd == -1) {
fprintf(stderr, "Cannot open %s: %s.\n", devpath, strerror(errno));
return EXIT_FAILURE;
}
/* Switch the mouse to ImPS/2 protocol. */
if (write(devfd, mousedev_imps_seq, mousedev_seq_len) != (ssize_t)mousedev_seq_len) {
fprintf(stderr, "Cannot switch to ImPS/2 protocol.\n");
close(devfd);
return EXIT_FAILURE;
}
if (read(devfd, buffer, sizeof buffer) != 1 || buffer[0] != 0xFA) {
fprintf(stderr, "Failed to switch to ImPS/2 protocol.\n");
close(devfd);
return EXIT_FAILURE;
}
/* IntelliMouse protocol uses four byte reports:
* Bit 7 6 5 4 3 2 1 0
* --------+-----+-----+-----+-----+-----+-----+-----+-----
* Byte 0 | 0 0 Neg-Y Neg-X 1 Mid Right Left
* Byte 1 | X X X X X X X X
* Byte 2 | Y Y Y Y Y Y Y Y
* Byte 3 | W W W W W W W W
*
* XXXXXXXX, YYYYYYYY, and WWWWWWWW are 8-bit two's complement values
* indicating changes in x-coordinate, y-coordinate, and scroll wheel.
* That is, 0 = no change, 1..127 = positive change +1 to +127,
* and 129..255 = negative change -127 to -1.
*
* Left, Right, and Mid are the three button states, 1 if being depressed.
* Neg-X and Neg-Y are set if XXXXXXXX and YYYYYYYY are negative, respectively.
*/
fprintf(stderr, "Mouse device %s opened successfully.\n", devpath);
fprintf(stderr, "Press CTRL+C (or send INT, TERM, or HUP signal to process %d) to exit.\n",
(int)getpid());
fflush(stderr);
wasleft = 0;
wasmiddle = 0;
wasright = 0;
while (!done) {
int x, y, wheel, left, middle, right;
len = read(devfd, buffer, 4);
if (len == -1) {
if (errno == EINTR)
continue;
fprintf(stderr, "%s.\n", strerror(errno));
break;
} else
if (len != 4 || !(buffer[0] & 0x08)) {
/* We are only interested in four-byte reports,
* that have bit 3 set in the first byte. */
fprintf(stderr, "Warning: Ignored a %d-byte report.\n", (int)len);
continue;
}
/* Unpack. */
left = buffer[0] & 1;
middle = buffer[0] & 4;
right = buffer[0] & 2;
x = bytetoint(buffer[1]);
y = bytetoint(buffer[2]);
wheel = bytetoint(buffer[3]);
/* Describe: */
if (x)
printf(" x%+d", x);
if (y)
printf(" y%+d", y);
if (wheel)
printf(" w%+d", wheel);
if (left && !wasleft)
printf(" LeftDown");
else
if (left && wasleft)
printf(" Left");
else
if (!left && wasleft)
printf(" LeftUp");
if (middle && !wasmiddle)
printf(" MiddleDown");
else
if (middle && wasmiddle)
printf(" Middle");
else
if (!middle && wasmiddle)
printf(" MiddleUp");
if (right && !wasright)
printf(" RightDown");
else
if (right && wasright)
printf(" Right");
else
if (!right && wasright)
printf(" RightUp");
printf("\n");
fflush(stdout);
wasleft = left;
wasmiddle = middle;
wasright = right;
}
/* Done. */
close(devfd);
return EXIT_SUCCESS;
}
这是我的机器(和一个便宜的 Logitech 鼠标)上的输出片段。 x
表示x坐标的变化,y
表示y坐标的变化,w
表示车轮状态的变化,等等。
Mouse device /dev/input/mice opened successfully.
Press CTRL+C (or send INT, TERM, or HUP signal to process 10356) to exit.
x-1
x-1 y-1
x-1
x-2
x-1 y-1
x-1
x-1
x-1 y-1
y+1
y+1
y+1
RightDown
x-1 Right
x-2 y+1 Right
x-2 Right
x-1 Right
y+1 Right
x-1 Right
x-2 Right
x-1 Right
x-2 Right
x-1 Right
y+1 Right
x-1 Right
x-2 Right
x-1 Right
RightUp
y-1
y-1
LeftDown
y-1 Left
x+1 Left
x+1 Left
x+1 Left
x+1 Left
LeftUp
w+1
w+1
w-1
w-2
w-1
w+1
w+1
w+2
w+1
w+1
w+1
w+1
w-1
w-1
w-1
w-1
w-1
w-1
w-1
w-1
关于c - 鼠标 Action 的input_event成员解释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38197517/