How to Listen for Mouse Events in Linux

How to capture and modify mouse events in linux?

My problem was solved using python-evdev

Turns out it's quite simple. Just grab mouse and create another uinput to write desired event.

import evdev
from evdev import ecodes

key=ecodes.KEY_LEFTSHIFT
kb=evdev.InputDevice('/dev/input/event1') # keybord
mouse=evdev.InputDevice('/dev/input/event3') # mouse
dummy=evdev.UInput.from_device(mouse)
hwheel=evdev.UInput({ecodes.EV_REL:[ecodes.REL_HWHEEL]})
mouse.grab()
for event in mouse.read_loop():
if event.type==ecodes.EV_REL and event.code==ecodes.REL_WHEEL and key in kb.active_keys():
hwheel.write(ecodes.EV_REL, ecodes.REL_HWHEEL, event.value)
hwheel.write(ecodes.EV_SYN, ecodes.SYN_REPORT, 0)
else:
dummy.write_event(event)

Mouse event handling in Linux?

If you make the event device descriptors nonblocking (by opening them with the O_NONBLOCK flag), you can very easily use `poll() to wait until one of them has events you can read.

Consider the following example program, example.c:

#define  _POSIX_C_SOURCE  200809L
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/input.h>
#include <termios.h>
#include <poll.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

/* Maximum number of input sources, including the terminal. */
#ifndef MAX_INPUTS
#define MAX_INPUTS 32
#endif

/* Maximum wait for events, in milliseconds (1000 ms = 1 second). */
#ifndef INTERVAL_MS
#define INTERVAL_MS 100
#endif

int main(int argc, char *argv[])
{
unsigned char keys[16];
struct input_event event;
struct termios config, oldconfig;
struct pollfd src[MAX_INPUTS];
size_t srcs, i, done;
ssize_t n;
int arg, nsrcs;

if (!isatty(STDIN_FILENO)) {
fprintf(stderr, "Standard input is not a terminal.\n");
return EXIT_FAILURE;
}

/* Save old terminal configuration. */
if (tcgetattr(STDIN_FILENO, &oldconfig) == -1 ||
tcgetattr(STDIN_FILENO, &config) == -1) {
fprintf(stderr, "Cannot get terminal settings: %s.\n", strerror(errno));
return EXIT_FAILURE;
}

/* Set new terminal configuration. */
config.c_iflag &= ~(IGNBRK | BRKINT | PARMRK);
config.c_lflag &= ~(ICANON | ISIG | ECHO | IEXTEN | TOSTOP);
config.c_cc[VMIN] = 0;
config.c_cc[VTIME] = 0;
config.c_cc[VSTART] = 0;
config.c_cc[VSTOP] = 0;
if (tcsetattr(STDIN_FILENO, TCSANOW, &config) == -1) {
const int saved_errno = errno;
tcsetattr(STDIN_FILENO, TCSANOW, &oldconfig);
fprintf(stderr, "Cannot set terminal settings: %s.\n", strerror(saved_errno));
return EXIT_FAILURE;
}

/* The very first input source is the terminal. */
src[0].fd = STDIN_FILENO;
src[0].events = POLLIN;
src[0].revents = 0;
srcs = 1;

/* Add input devices from command line. */
for (arg = 1; arg < argc; arg++) {
int fd;

fd = open(argv[arg], O_RDONLY | O_NOCTTY | O_NONBLOCK);
if (fd == -1) {
fprintf(stderr, "Skipping input device %s: %s.\n", argv[arg], strerror(errno));
continue;
}

if (srcs >= MAX_INPUTS) {
fprintf(stderr, "Too many event sources.\n");
return EXIT_FAILURE;
}

/* Optional: Grab input device, so only we receive its events. */
ioctl(fd, EVIOCGRAB, 1);

src[srcs].fd = fd;
src[srcs].events = POLLIN;
src[srcs].revents = 0;
srcs++;
}

printf("Ready. Press Q to exit.\n");
fflush(stdout);

done = 0;
while (!done) {

nsrcs = poll(src, srcs, INTERVAL_MS);
if (nsrcs == -1) {
if (errno == EINTR)
continue;
fprintf(stderr, "poll(): %s.\n", strerror(errno));
break;
}

/* Terminal is not an input source. */
if (src[0].revents & POLLIN) {
n = read(src[0].fd, keys, sizeof keys);
if (n > 0) {
for (i = 0; i < n; i++) {
if (keys[i] == 'q' || keys[i] == 'Q')
done = 1;
if (keys[i] >= 32 && keys[i] <= 126)
printf("Key '%c' = 0x%02x = %u pressed\n", keys[i], keys[i], keys[i]);
else
if (keys[i])
printf("Key '\\%03o' = 0x%02x = %u pressed\n", keys[i], keys[i], keys[i]);
else
printf("NUL key (0) pressed\n");
}
fflush(stdout);
}
src[0].revents = 0;
}

/* Check the other input sources. */
for (i = 1; i < srcs; i++) {
if (src[i].revents & POLLIN) {
while (1) {
n = read(src[i].fd, &event, sizeof event);
if (n != sizeof event)
break;

if (event.type == EV_KEY && event.code == BTN_LEFT) {
if (event.value > 0)
printf("Left mouse button pressed\n");
else
printf("Left mouse button released\n");
}

if (event.type == EV_KEY && event.code == BTN_RIGHT) {
if (event.value > 0)
printf("Right mouse button pressed\n");
else
printf("Right mouse button released\n");
}
}
fflush(stdout);
}
src[i].revents = 0;
}
}

/* Close input devices. */
for (i = 1; i < srcs; i++)
close(src[i].fd);

/* Restore terminal settings. */
tcsetattr(src[0].fd, TCSAFLUSH, &oldconfig);

printf("All done.\n");
return EXIT_SUCCESS;
}

Compile it using e.g.

gcc -Wall -O2 example.c -o example

and run it using e.g.

sudo ./example /dev/input/event5

where /dev/input/event5 is a mouse event device. Note that you can read /sys/class/input/event5/device/name to find out the name of the device (as far as the kernel knows it; these are the same names evtest shows when run as root).

If you are not sure, you can always run

for N in /sys/class/input/event*/device/name ; do 
DEV="${N%%/device/name}" ; DEV="/dev/${DEV##/sys/class/}" ;
NAME="$(cat "$N" 2>/dev/null)" ;
printf "%s: %s\n" "$DEV" "$NAME" ;
done

in a Bash or Dash or a POSIX shell, to see what event devices you can try.

The example program above must be run from a terminal or console, because it also takes input from the terminal. It sets the terminal into nonblocking non-canonical mode, where it can receive individual keypresses. Do note that some keypresses, like cursor and function keys, are actually several characters long, beginning with an ESC (\033).


It is also common to split that input event loop into a separate thread. It is just a dozen or so lines more, but the "problem" then becomes how the separate thread informs the main (or other) threads that new input events/commands have arrived. The non-blocking poll() approach above is usually easier to implement in a very robust, straightforward manner.

How can I capture mouseevents and keyevents using python in background on linux

I guess, you might use python bindings for evdev: http://packages.python.org/evdev/index.html. In tutorial they give an example for keyboard, but it should be similar for mouse events:

>>> from evdev import InputDevice, categorize, ecodes
>>> from select import select
>>> dev = InputDevice('/dev/input/event1')

>>> print(dev)
device /dev/input/event1, name "Dell Dell USB Keyboard", phys "usb-0000:00:12.1-2/input0"

>>> while True:
... r,w,x = select([dev], [], [])
... for event in dev.read():
... if event.type == ecodes.EV_KEY:
... print(categorize(event))
... # hitting a and holding space
key event at 1337016188.396030, 30 (KEY_A), down
key event at 1337016188.492033, 30 (KEY_A), up
key event at 1337016189.772129, 57 (KEY_SPACE), down
key event at 1337016190.275396, 57 (KEY_SPACE), hold
key event at 1337016190.284160, 57 (KEY_SPACE), up

Linux /dev/input/event*: lost mouse movement events

I found a solution: if we set a flat profile for pointer acceleration the coordinates shown by the code exactly match the display width/height. I tried to move the pointer over a well defined pixel on my Desktop background and I always receive the same value.

So the problem was the mouse acceleration profile

How to detect mouse click in python 3 on linux?

you can handle mouse input using the lib PyUserInput (code sample from github) :

from pymouse import PyMouseEvent

def fibo():
a = 0
yield a
b = 1
yield b
while True:
a, b = b, a+b
yield b

class Clickonacci(PyMouseEvent):
def __init__(self):
PyMouseEvent.__init__(self)
self.fibo = fibo()

def click(self, x, y, button, press):
'''Print Fibonacci numbers when the left click is pressed.'''
if button == 1:
if press:
print(self.fibo.next())
else: # Exit if any other mouse button used
self.stop()

C = Clickonacci()
C.run()

otherwise, you can do it with the Xlib lib : Python Xlib catch/send mouseclick



Related Topics



Leave a reply



Submit