我正在写一个基本上基于字符的程序,但是在xterm中运行,并希望使用鼠标滚轮向上/向下和左键单击作为键盘向上/向下和返回的同义词,仅用于一点额外的用户便利。
我有一个select()
,所有输入fdset工作正常,并且异步捕获原始输入正常(无论如何)。但是我有点麻烦地从input_event结构中明确地解释类型,代码,值成员。 /usr/include/linux/input.h
似乎有一些EV,我正在看
EV_REL=0x02
(移动鼠标时的相对位置)EV_MSC=0x04
(其他)。问题1:普遍存在吗?我没有成功地搜索任何有关它的内容。
但是除了EV之外,我在/usr/include/
中看不到代码,值。我的实验显示了以下内容,我进一步询问下面的所有内容是否(普遍)都是正确的。或者甚至更好,关于这些东西的哪些(权威)文档?我认为google很容易,但找不到答案。
任何一个动作似乎都会生成两个或三个单独的input_event,最后一个(第二个或第三个)是一个“预告片”,其类型= code = value = 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每次读取只返回三个字节,而不是16包含input_event结构。至少那是我做的时候发生在我身上的事情。我想不出任何方法来“解码”这些字节来告诉我“event16”。
所以我原本会问这个问题,但我觉得我已经说得够了:有没有办法从/ dev / input / event16获得/ dev / input / mice的所有数据?或者有没有办法以编程方式确定哪个/ dev / input / event?是初始化期间的鼠标(没有解析/ proc /文件)?
答案 0 :(得分:4)
您还可以使用旧式鼠标界面(/dev/mouse
,/dev/input/mouseN
或连接到本机的所有鼠标/dev/input/mice
)。您需要将设备切换为四字节ImPS协议以支持所有三个按钮和滚轮,但这很简单:只需写入六个字节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
答案 1 :(得分:2)
我假设您正在使用事件输入子系统(而不是/dev/input/mice
),因为您希望直接从特定鼠标中读取,而不是从连接到机器的任何鼠标中读取。
规范文档位于Linux内核的doc/Documentation/input/event-codes.txt(文档)中。该链接将您带到最新的网页。
type=EV_REL, code=REL_WHEEL, value=1
(2,8,1)表示(垂直)滚轮向前一个向前滚动。如果用户快速旋转滚轮,或者如果它是具有“快速”滚轮模式的可编程鼠标,则该值可能大于1.
type=EV_REL, code=REL_WHEEL, value=-1
(2,8,-1)表示(垂直)向后滚动一个滚轮。如果用户快速旋转滚轮,或者它是具有“快速”滚轮模式的可编程鼠标,则该值可能小于-1。
许多老鼠都有水平滚轮。它们的工作方式与垂直滚轮的工作方式相同,但代码为REL_HWHEEL
。
其他有趣的type=EV_REL
代码为REL_X
,REL_Y
,REL_Z
(相对移动,REL_Z
为“高度”或距离表格的距离为3D老鼠); REL_RX
,REL_RY
,REL_RZ
围绕每个轴旋转,适用于具有六轴加速度计的3D鼠标;和REL_DIAL
用于慢跑轮。
type=EV_KEY, code=BTN_MOUSE, value=1
(1,272,1)表示鼠标单击(左键单击多按钮鼠标),value=0
(1,272,0)表示释放。
code
也可以是任何其他KEY_
或BTN_
常量。发布时value
为零,按下为非零。
特别是,BTN_MOUSE=BTN_LEFT
,鼠标右键为BTN_RIGHT
,鼠标中键为BTN_MIDDLE
,侧键为BTN_SIDE
,额外按键为BTN_EXTRA
,任务按钮为BTN_TASK
,向前和向后按钮(如某些Logitech鼠标上的按钮)为BTN_FORWARD
和BTN_BACK
。
type=EV_MSC, code=MSC_SCAN
(4,4,value)为未通过USB / HID标准化的键/按钮事件提供键盘扫描码。我相信你可以忽略这些(它们通常是由于一些奇怪的原因,实际事件的重复,可能是向后兼容Windows)。
type=EV_SYN, code=SYN_REPORT
(0,0),是一个同步事件;这意味着此时输入事件状态已完全更新。
对于“同时”发生的事件,您会收到零个或多个输入记录,然后是type=EV_SYN, code=SYN_REPORT
(0,0)。
通常,HID设备将报告所有轴上的更改以及一个块中的所有按钮,然后是其中一个。这很有意义,因为我们希望我们的指针根据真实的运动而移动,而不仅仅是水平/垂直...它看起来很奇怪。
总的来说,这是Linux输入子系统,非常稳定;它不会改变。 (可以添加新的键,按钮等,但现有的键不应该更改。)LinuxJournal(2003年)的Linux输入子系统文章I和II仍然作为背景信息。
答案 2 :(得分:1)
注意:这只是NominalAnimal前面答案的后续内容,其中包含他的演示程序,演示了C语言中的低级鼠标处理。感谢,Nominal。
他的原始代码在我的盒子上完美运行,除了中下按钮。在开始意识到它是一种神器之前,我开始搞乱代码试图解决这个问题。 X使用Middle-down进行&#34;粘贴&#34;并且以某种方式(我仍然不完全理解)抓住前面的部分printf并在每次按下Middle-down时将它们重新粘贴到输出流中。每次通过while()循环开始时的fflush似乎已经修复了。现在按下Middle-down也可以正常工作(只要你的粘贴缓冲区空了)......
#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>
#define RECOGNIZED(s) { printf(s); fflush(stdout); recognized++; }
static const size_t mousedev_seq_len = 6;
static const unsigned char mousedev_imps_seq[] =
{ 0xf3, 200, 0xf3, 100, 0xf3, 80 };
static int bytetoint(const unsigned char c) {
return ( (c < 128? c : c-256) ); }
int main(int argc, char *argv[]) {
char *devpath = (argc>1?argv[1]:"/dev/input/mice");
int msglevel = (argc>2?atoi(argv[2]):3);
int devfd = (-1);
unsigned char buffer[4];
ssize_t len = (-1);
int nactions=0, wasleft=0, wasmiddle=0, wasright=0;
/* Open the mouse. */
fflush(NULL);
do { devfd = open(devpath, O_RDWR | O_NOCTTY);
} while (devfd == -1 && errno == EINTR);
if (devfd == -1) {
printf("Cannot open %s: %s.\n", devpath, strerror(errno));
goto end_of_job; }
/* Switch the mouse to ImPS/2 protocol. */
if (write(devfd, mousedev_imps_seq, mousedev_seq_len)
!= (ssize_t)mousedev_seq_len) {
printf("Cannot switch to ImPS/2 protocol.\n");
goto end_of_job; }
if (read(devfd, buffer, sizeof buffer) != 1 || buffer[0] != 0xFA) {
printf("Failed to switch to ImPS/2 protocol.\n");
goto end_of_job; }
printf("Mouse device %s opened successfully.\n", devpath);
printf("Press CTRL+C to exit.\n" /*, (int)getpid()*/ );
/* 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. */
while (1) {
int x, y, wheel, left, middle, right;
int recognized = 0;
nactions++;
fflush(stdout);
len = read(devfd, buffer, 4);
if (len == -1) {
if (errno == EINTR) continue;
printf("%s.\n", strerror(errno));
break; }
/* We are only interested in four-byte reports,
* that have bit 3 set in the first byte. */
if (len != 4 || !(buffer[0] & 0x08)) {
printf("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]);
if ( msglevel >= 1 ) {
printf("(%d) buffer=%02x,%02x,%02x,%02x"
", xy=%d,%d, lmrw=%d,%d,%d,%d: ",
nactions, buffer[0],buffer[1],buffer[2],buffer[3],
x,y, left,middle,right,wheel); fflush(stdout); }
/* --- Describe: --- */
if (x) { RECOGNIZED(" x"); printf("%+d", x); }
if (y) { RECOGNIZED(" y"); printf("%+d", y); }
if (wheel) { RECOGNIZED(" w"); printf("%+d", wheel); }
if (left && !wasleft) { RECOGNIZED(" LeftDown"); }
else if (left && wasleft) { RECOGNIZED(" Left"); }
else if (!left && wasleft) { RECOGNIZED(" LeftUp"); }
if (middle && !wasmiddle) { RECOGNIZED(" MiddleDown"); }
else if (middle && wasmiddle) { RECOGNIZED(" Middle"); }
else if (!middle && wasmiddle) { RECOGNIZED(" MiddleUp"); }
if (right && !wasright) { RECOGNIZED(" RightDown"); }
else if (right && wasright) { RECOGNIZED(" Right"); }
else if (!right && wasright) { RECOGNIZED(" RightUp"); }
printf(" (recognized %d)\n",recognized);
wasleft=left; wasmiddle=middle; wasright=right;
} /* --- end-of-while(1) --- */
/* Done. */
end_of_job: if ( devfd!=(-1) ) close(devfd);
fflush(NULL);
return EXIT_SUCCESS;
} /* --- end-of-main() --- */
几行演示输出......
Mouse device /dev/input/mice opened successfully.
Press CTRL+C to exit.
(1) buffer=0c,00,00,00, xy=0,0, lmrw=0,4,0,0: MiddleDown (recognized 1)
(2) buffer=08,00,00,00, xy=0,0, lmrw=0,0,0,0: MiddleUp (recognized 1)
(3) buffer=0c,00,00,00, xy=0,0, lmrw=0,4,0,0: MiddleDown (recognized 1)
(4) buffer=08,00,00,00, xy=0,0, lmrw=0,0,0,0: MiddleUp (recognized 1)
(5) buffer=09,00,00,00, xy=0,0, lmrw=1,0,0,0: LeftDown (recognized 1)
(6) buffer=08,00,00,00, xy=0,0, lmrw=0,0,0,0: LeftUp (recognized 1)
(7) buffer=09,00,00,00, xy=0,0, lmrw=1,0,0,0: LeftDown (recognized 1)
(8) buffer=08,00,00,00, xy=0,0, lmrw=0,0,0,0: LeftUp (recognized 1)
(9) buffer=0a,01,00,00, xy=1,0, lmrw=0,0,2,0: x+1 RightDown(recognized 2)
(10) buffer=08,00,00,00, xy=0,0, lmrw=0,0,0,0: RightUp (recognized 1)
(11) buffer=0a,00,00,00, xy=0,0, lmrw=0,0,2,0: RightDown (recognized 1)
(12) buffer=08,00,00,00, xy=0,0, lmrw=0,0,0,0: RightUp (recognized 1)
(13) buffer=18,ff,00,00, xy=-1,0, lmrw=0,0,0,0: x-1 (recognized 1)
(14) buffer=18,ff,00,00, xy=-1,0, lmrw=0,0,0,0: x-1 (recognized 1)
(15) buffer=18,fe,00,00, xy=-2,0, lmrw=0,0,0,0: x-2 (recognized 1)
(16) buffer=18,fd,00,00, xy=-3,0, lmrw=0,0,0,0: x-3 (recognized 1)
(17) buffer=18,fd,00,00, xy=-3,0, lmrw=0,0,0,0: x-3 (recognized 1)
答案 3 :(得分:1)
下面是Nominal Animal之前代码的另一个版本,重新计入用户可调用函数mouseread(),它提供所有必要功能打开/关闭/读取/解释鼠标事件,如Nominal Animal&#所示39;上面的演示程序。而不是剪切和粘贴(下面的一些评论未对齐,可能是由于stackexchange选项卡设置),我还在http://www.forkosh.com/mouseread.c
放置了副本/****************************************************************************
*
* Copyright(c) 2016-2016, John Forkosh Associates, Inc. All rights reserved.
* http://www.forkosh.com mailto: john@forkosh.com
* --------------------------------------------------------------------------
* This file is mouseread.c, which is free software.
* You may redistribute and/or modify mouseread.c under the
* terms of the GNU General Public License, version 3 or later,
* as published by the Free Software Foundation.
* mouseread.c is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY, not even the implied warranty of MERCHANTABILITY.
* See the GNU General Public License for specific details.
* By using mouseread.c, you warrant that you have read, understood
* and agreed to these terms and conditions, and that you possess the legal
* right and ability to enter into this agreement and to use mouseread.c
* in accordance with it.
* To read the GNU General Public License, version 3, point your
* browser to http://www.gnu.org/licenses/ or write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
* --------------------------------------------------------------------------
*
* Purpose: o mouseread.c, licensed under the gpl, reads and interprets
* mouse events for the calling application-level program
* (see Notes below for further usage instructions).
* Thanks: mouseread.c is based on code supplied by
* Nominal Animal <question@nominal-animal.net>
* ( AKA Jouko Orava <jouko.orava@iki.fi> )
* in http://stackoverflow.com/questions/38197517/
*
* Functions: The following "table of contents" lists each function
* comprising mouseread.c in the order it appears in this file.
* See individual function entry points for specific comments
* about its purpose, calling sequence, side effects, etc.
* =============================================================
* --- primary user-callable function ---
* mouseread(action) open/close/read/etc mouse
* --- helper (static in this module) functions ---
* mouseopen(void) open mouse device
* mouseget(fd) read and interpret mouse device
* --- main() test driver ---
* #if defined(TESTMOUSEREAD)
* main(argc,argv) test driver
* #endif
* =============================================================
*
* Source: mouseread.c
*
* --------------------------------------------------------------------------
* Notes o See individual function entry points for specific comments
* about the purpose, calling sequence, side effects, etc
* of each mouseread.c function listed above.
* o compile as
* cc yourprogram.c mouseread.c -o yourprogram
* or for test driver
* cc -DTESTMOUSEREAD mouseread.c -o mouseread
* o mouseread() opens /dev/input/mice by default
* make sure /dev/input/mice is chmod o+rw,
* or else mouseread() will fail. To use another device,
* cc -DMOUSEDEV=\"/dev/input/mouse0\" etc.
* (which must also be chmod o+rw)
* o in yourprogram.c write the two lines
* #define _MOUSEHEADERS
* #include "mouseread.c"
* to get the defined symbols for recognized mouseread() actions.
* there's no separate mouseread.h file.
* o --- usage instructions ---
* Initialization:
* First make sure to follow the instructions immediately
* above to include the header information defining recognized
* mouseread() actions.
* Then the basic declaration your program should contain
* is of the form
* int fd=(-1), result=(-1), mouseread(int);
* And initialization consists of the single line
* fd = mouseread(_MOUSE_OPEN);
* which should be issued just once, and which returns
* the file descriptor of the open()'ed MOUSEDEV, or -1=error.
* You can combine declaration/initialization into one line
* int result=(-1), mouseread(int), fd=mouseread(_MOUSE_OPEN);
* And you won't need fd unless issuing a select(), or using
* it with other non-blocking i/o mechanisms, etc.
* Action _MOUSE_GET:
* result = mouseread(_MOUSE_GET);
* reads the next queued mouse event, returning
* +1=successful read, -1=some_i/o_error.
* The nature of that event is determined by interrogations
* performed by the following calls. You can issue as many
* of these calls as you like against the current event.
* The next event isn't read until you issue
* the next _MOUSE_GET action.
* Action _MOUSE_LEFT:
* result = mouseread(_MOUSE_LEFT);
* interrogates the left mouse button, returning
* 0 = button was up, and button remains up,
* +1 = button was up, and was just pressed down,
* -1 = button was down, and was just released,
* 99 = button was down, and remains down.
* Actions _MOUSE_RIGHT, _MOUSE_MIDDLE:
* result = mouseread(_MOUSE_RIGHT);
* result = mouseread(_MOUSE_MIDDLE);
* interrogates the right or middle mouse button, returning
* the same results as above for _MOUSE_LEFT.
* Action _MOUSE_X:
* result = mouseread(_MOUSE_X);
* 0 = no x-axis movement,
* +1,+2,+3,+etc = right x-axis movement by 1,2,3,etc pixels
* -1,-2,-3,-etc = left x-axis movement by 1,2,3,etc pixels
* Action _MOUSE_Y:
* result = mouseread(_MOUSE_Y);
* 0 = no y-axis movement,
* +1,+2,+3,+etc = up y-axis movement by 1,2,3,etc pixels
* -1,-2,-3,-etc = down y-axis movement by 1,2,3,etc pixels
* Action _MOUSE_WHEEL:
* result = mouseread(_MOUSE_WHEEL);
* 0 = no wheel movement,
* +1,+2,+3,+etc = down wheel movement by 1,2,3,etc pixels
* -1,-2,-3,-etc = up wheel movement by 1,2,3,etc pixels
* note: +/- for wheel has opposite meaning as for y-axis
* (that appears to be the standard).
* Exit:
* Just issue the single call
* mousread(_MOUSE_CLOSE);
* --------------------------------------------------------------------------
* Revision History:
* 07/05/16 J.Forkosh Installation.
* 07/09/16 J.Forkosh Most recent revision
*
****************************************************************************/
/* ---
* header information: no mouseread.h file, instead...
* #define _MOUSEHEADERS
* #include "mouseread.c"
* ----------------------------------------------------------------------- */
/* --- recognized mousread() actions --- */
#define _MOUSE_GET (128) /* read (wait for) next mouse event */
#define _MOUSE_OPEN (1) /* initialize mouse */
#define _MOUSE_CLOSE ((_MOUSE_OPEN)+1) /* close mouse device file */
#define _MOUSE_LEFT ((_MOUSE_CLOSE)+1) /* +1,-1,0 if left pressed,released */
#define _MOUSE_RIGHT ((_MOUSE_LEFT)+1) /* +1,-1,0 if right pressed,released*/
#define _MOUSE_MIDDLE ((_MOUSE_RIGHT)+1)/* +1,-1,0 if middle pressed,released*/
#define _MOUSE_X ((_MOUSE_MIDDLE)+1) /* +,-,0 right,left x-axis movement */
#define _MOUSE_Y ((_MOUSE_X)+1) /* +,-,0 up,down y-axis movement */
#define _MOUSE_WHEEL ((_MOUSE_Y)+1) /* +,-,0 down,up wheel movement */
/* note: the LEFT,RIGHT,MIDDLE have an additional return value 99
if the corresponding button was pressed down and remains pressed down */
/* --- end-of-header-information --- */
#if !defined(_MOUSEHEADERS)
/* -------------------------------------------------------------------------
Possibly device/installation-dependent constants
-------------------------------------------------------------------------- */
#if !defined(MOUSESTRING)
/* string to switch mouse to ImPS/2 protocol,
* unsigned char mousestring[] = {0xf3,200, 0xf3,100, 0xf3,80};... */
#define MOUSESTRING "\xf3\xc8\xf3\x64\xf3\x50"
#endif
#if !defined(MOUSEDEV)
/* must be chmod 666, i.e., o+rw... */
#define MOUSEDEV "/dev/input/mice"
#endif
/* -------------------------------------------------------------------------
standard headers
-------------------------------------------------------------------------- */
#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>
/* -------------------------------------------------------------------------
helper functions
-------------------------------------------------------------------------- */
#define bytetoint(c) ( ( ((int)(c)) < 128? ((int)(c)) : ((int)(c))-256 ) )
static int mouseopen(void); /* open mouse device file */
static int mouseget(int); /* get mouse device */
/* -------------------------------------------------------------------------
global data -- read/interpreted by mouseget(), returned to user by mouseread()
-------------------------------------------------------------------------- */
static int x=0,y=0,wheel=0, left=0,right=0,middle=0; /* coord,button states */
static int wasleft=0, wasright=0, wasmiddle=0; /* previous button states */
/* ==========================================================================
* Function: mouseread ( int action )
* Purpose: open/read/close mouse device
* --------------------------------------------------------------------------
* Arguments: action (I) int specifying action,
* see Notes comments above for complete
* usage instructions.
* --------------------------------------------------------------------------
* Returns: ( int ) result of action (see Notes above)
* --------------------------------------------------------------------------
* Notes: o caller can |OR (or +add) _MOUSE_GET to any interrogation
* request to read the next packet >>before<< checking, e.g.,
* instead of: mouseread(_MOUSE_GET); mouseread(_MOUSE_LEFT);
* just write: mouseread(_MOUSE_GET|_MOUSE_LEFT);
* You can >>only<< OR (or +add) _MOUSE_GET with one other action.
* o _MOUSE_GET will first perform a _MOUSE_OPEN if the mouse
* device has not already been open()'ed. But you won't get
* back the mouse fd. So if you need that for a select() or
* other purpose, make sure to issue a separate _MOUSE_OPEN
* and save the returned fd.
* ======================================================================= */
/* --- entry point --- */
int mouseread ( int action ) {
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
static int fd = (-1); /* fd of mouse device file after open */
int isget = 0; /* set true if _MOUSE_GET requested */
int result = (-1); /* result of action, -1=error */
/* -------------------------------------------------------------------------
check if _MOUSE_GET has been |or'ed or +added to action
-------------------------------------------------------------------------- */
if ( action >= _MOUSE_GET ) { /* _MOUSE_GET requested */
isget = 1; /* set flag to call mouseget() */
action -= _MOUSE_GET; } /* any remaining action */
/* -------------------------------------------------------------------------
open/close mouse device
-------------------------------------------------------------------------- */
if ( action == _MOUSE_OPEN ) { /* open request */
if ( fd == (-1) ) /* not yet opened */
fd = mouseopen(); /* try to open it */
result = fd; /* return fd to caller */
/* --- re-init global variables --- */
x=y=wheel=0; left=right=middle=0; /* reset coord,button states */
wasleft=wasright=wasmiddle = 0; /* reset previous button states */
} /* --- end-of-if(action==_MOUSE_OPEN) --- */
if ( action == _MOUSE_CLOSE ) { /* close request */
if ( fd != (-1) ) /* opened */
close(fd); /* close it */
fd = (-1); /* reset fd to signal closed */
result = 1; /* signal success to caller */
} /* --- end-of-if(action==_MOUSE_CLOSE) --- */
/* -------------------------------------------------------------------------
read mouse device
-------------------------------------------------------------------------- */
if ( isget ) { /* read mouse event */
if ( fd == (-1) ) /* caller maybe forgot _MOUSE_OPEN */
fd = mouseopen(); /* try to open it */
if ( fd != (-1) ) /* opened */
result = mouseget(fd); /* read */
result = 1; /* signal success to caller */
} /* --- end-of-if(action==_MOUSE_GET) --- */
/* -------------------------------------------------------------------------
determine current state of mouse buttons
-------------------------------------------------------------------------- */
/* --- left button --- */
if ( action == _MOUSE_LEFT ) { /* check left mouse button */
result = 0; /* left button up and remains up */
if (left && !wasleft) result=(+1); /* left button pressed down */
else if (left && wasleft) result=99; /* left down and remains down */
else if (!left && wasleft) result=(-1); /* left button released */
} /* --- end-of-if(action==_MOUSE_LEFT) --- */
/* --- right button --- */
if ( action == _MOUSE_RIGHT ) { /* check right mouse button */
result = 0; /* right button up and remains up */
if (right && !wasright) result=(+1); /* right button pressed down */
else if (right && wasright) result=99; /* right down and remains down */
else if (!right && wasright) result=(-1); /* right button released */
} /* --- end-of-if(action==_MOUSE_RIGHT) --- */
/* --- middle button --- */
if ( action == _MOUSE_MIDDLE ) { /* check middle mouse button */
result = 0; /* middle button up and remains up */
if (middle && !wasmiddle) result=(+1); /* middle button pressed down */
else if (middle && wasmiddle) result=99; /* middle down and remains down */
else if (!middle && wasmiddle) result=(-1); /* middle button released */
} /* --- end-of-if(action==_MOUSE_MIDDLE) --- */
/* -------------------------------------------------------------------------
determine current x,y,z(wheel)-axis movements
-------------------------------------------------------------------------- */
if ( action == _MOUSE_X ) { /* check for x-axis movement */
result = x; /* 0=none, or +/- x-axis movement */
} /* --- end-of-if(action==_MOUSE_X) --- */
if ( action == _MOUSE_Y ) { /* check for y-axis movement */
result = y; /* 0=none, or +/- y-axis movement */
} /* --- end-of-if(action==_MOUSE_Y) --- */
if ( action == _MOUSE_WHEEL ) { /* check for z-axis/wheel movement */
result = wheel; /* 0=none, or +/- wheel movement */
} /* --- end-of-if(action==_MOUSE_WHEEL) --- */
end_of_job:
return ( result ); /* result of action back to caller */
} /* --- end-of-function mouseread() --- */
/* ==========================================================================
* Function: mouseopen ( void )
* Purpose: open mouse device
* --------------------------------------------------------------------------
* Arguments: void (I) no args
* --------------------------------------------------------------------------
* Returns: ( int ) fd of open()'ed mouse, or -1=error
* --------------------------------------------------------------------------
* Notes: o MOUSEDEV, e.g., "/dev/input/mice", must be chmod o+rw
* ======================================================================= */
/* --- entry point --- */
static int mouseopen ( void ) {
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
char *mousedev = MOUSEDEV; /* path to mouse device file */
unsigned char *mousestring = MOUSESTRING; /* ImPS/2 initialization string */
unsigned char mbuffer[4]={0,0,0,0}; /* read to check initialization */
int mwrtlen=strlen(mousestring), /* #initialization bytes to write */
mrdlen = (-1); /* #bytes read from mouse device */
int fd = (-1); /* fd of open()'ed device, -1=error */
/* --- open the mouse device file --- */
do { fd = open(mousedev, O_RDWR | O_NOCTTY); /* open for read/write */
} while ( fd==(-1) && errno==EINTR ); /* retry if interrupted */
if ( fd==(-1) ) goto end_of_job; /* failed to open mouse device file */
/* --- switch mouse to ImPS/2 protocol --- */
if ( write(fd,mousestring,mwrtlen) == mwrtlen ) /* write the request, */
mrdlen = read(fd,mbuffer,4); /* read the reply */
if ( mrdlen != 1 || mbuffer[0] != 0xFA) { /* check for success, */
close(fd); fd=(-1); goto end_of_job; } /* if failed then die :) */
/* --- back to caller --- */
end_of_job:
return ( fd ); /* fd or -1=error back to caller */
} /* --- end-of-function mouseopen() --- */
/* ==========================================================================
* Function: mouseget ( int fd )
* Purpose: read and interpret mouse device
* --------------------------------------------------------------------------
* Arguments: fd (I) fd of open()'ed mouse device file
* --------------------------------------------------------------------------
* Returns: ( int ) get status
* --------------------------------------------------------------------------
* Notes: o 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.
* ======================================================================= */
/* --- entry point --- */
static int mouseget ( int fd ) {
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
unsigned char mbuffer[4]={0,0,0,0}; /* read buffer */
int mrdlen = (-1); /* #bytes read from mouse device */
int status = (-1); /* i/o status */
/* --- reset previous button states --- */
wasleft=left; wasmiddle=middle; wasright=right; /* previous button states */
/* -------------------------------------------------------------------------
read four bytes into mbuffer
-------------------------------------------------------------------------- */
/* --- read --- */
if ( fd == (-1) ) goto end_of_job; /* invalid/not_open fd */
do { mrdlen = read(fd,mbuffer,4); /* read four-byte protocol */
} while ( mrdlen==(-1) && errno==EINTR ); /* retry if interrupted */
if ( mrdlen == (-1) ) goto end_of_job; /* return -1 error if read failed */
/* --- only interested in four-byte reports with bit 3 set in 1st byte --- */
if ( mrdlen != 4 || !(mbuffer[0] & 0x08)) { /* unwanted packet */
status=0; goto end_of_job; } /* signal 0="nothing" to caller */
/* -------------------------------------------------------------------------
interpret the fields of the four-byte report packet
-------------------------------------------------------------------------- */
x=y=wheel=0; left=right=middle=0; /* reset global coord,button states */
left = mbuffer[0] & 1; /* bit#0 (low-order bit) of 1st byte */
right = mbuffer[0] & 2; /* bit#1 of 1st byte */
middle = mbuffer[0] & 4; /* bit#2 of 1st byte */
x = bytetoint(mbuffer[1]); /* 2nd byte */
y = bytetoint(mbuffer[2]); /* 3rd byte */
wheel = bytetoint(mbuffer[3]); /* 4th byte */
/* --- back to caller --- */
status = 1; /* success */
end_of_job:
return ( status ); /* read status */
} /* --- end-of-function mouseget() --- */
#endif /* --- #if !defined(_MOUSEHEADERS) --- */
#if defined(TESTMOUSEREAD)
/* ==========================================================================
* Function: main ( int argc, char *argv[] )
* Purpose: test driver for mouseread()
* --------------------------------------------------------------------------
* Arguments: argc (I) (int) containing the usual... unused
* argv (I) (char **) containing... unused
* --------------------------------------------------------------------------
* Returns: ( int ) exit(1) status
* --------------------------------------------------------------------------
* Notes: o exercises mouseread(), compile as
* cc -DTESTMOUSEREAD mouseread.c -o mouseread
* ======================================================================= */
/* --- entry point --- */
int main ( int argc, char *argv[] ) {
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
int msglevel = (argc>1?atoi(argv[1]):3); /* currently unused */
int mouseread(int), fd = mouseread(_MOUSE_OPEN);
int result=0, nactions=0;
/* -------------------------------------------------------------------------
interrogate mouse
-------------------------------------------------------------------------- */
if ( fd < 0 ) { /* probably forgot to chmod o+rw */
if(msglevel>0) printf("Unable to open %s\n",MOUSEDEV); goto end_of_job; }
if(msglevel>0) printf("Move,click,etc mouse. Ctrl-C to exit...\n");
while ( 1 ) {
nactions++;
printf("(%d) ",nactions);
result = mouseread(_MOUSE_GET|_MOUSE_X); /*GET the next queued mouse event*/
if (result!=0) printf(" x%+d", result); /* | and check for x-axis movement*/
result = mouseread(_MOUSE_Y); /* check for y-axis movement */
if (result!=0) printf(" y%+d", result); /* 0=none, + = up, - = down */
result = mouseread(_MOUSE_WHEEL); /* check for wheel movement */
if (result!=0) printf(" w%+d", result); /* 0=none, + = up, - = down */
result = mouseread(_MOUSE_LEFT); /* check left button */
if (result!=0) printf( " %s", /* see Notes for return values */
(result==1?"LEFT-PRESSED":(result<0?"LEFT-RELEASED":"LEFT-DOWN")) );
result = mouseread(_MOUSE_RIGHT); /* check right button */
if (result!=0) printf( " %s",
(result==1?"RIGHT-PRESSED":(result<0?"RIGHT-RELEASED":"RIGHT-DOWN")) );
result = mouseread(_MOUSE_MIDDLE); /* check middle button */
if (result!=0) printf( " %s",
(result==1?"MIDDLE-PRESSED":(result<0?"MIDDLE-RELEASED":"MIDDLE-DOWN")) );
printf("\n"); fflush(stdout); /* ready to GET next event */
} /* --- end-of-while(1) --- */
end_of_job:
mouseread(_MOUSE_CLOSE);
exit(1);
} /* --- end-of-function main() --- */
#endif /* --- #if defined(TESTMOUSEREAD) --- */
/* =======================================================================
END-OF-FILE MOUSEREAD.C
========================================================================== */