user2314247
user2314247

Reputation: 81

How to detect mouse click events in all applications in X11?

I am using "XGrabPointer" to get the mouse click events when ever they occured in the active window.But my requirement is to detect the clicks globally i.e in any application on the X11 desktop. XGrabPointer blocks the active window so i can not move to other applications and detect the mouse click events.

Here are the codes:

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

int main(int argc, char **argv)
{
  Display *display;
  XEvent xevent;
  Window window;
  int grb;
  int scr;

  if( (display = XOpenDisplay(NULL)) == NULL )
    return -1;

  unsigned int t_new=0,t_prev=0,t_diff=0;
  scr = DefaultScreen(display);
  window = RootWindow(display, scr);

  while(1) {
    XGrabPointer(display,
                 window,
                 True,
                 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
                 GrabModeAsync,
                 GrabModeAsync,
                 None,
                 None,
                 CurrentTime);

    XAllowEvents(display,AsyncPointer, CurrentTime);
    XNextEvent(display, &xevent);

    switch (xevent.type) {
      case MotionNotify:{
        printf("motion event\n");
        break;
      }
      case ButtonPress:{
        switch (xevent.xbutton.button) {
          case 1:
            printf("Left Click\n");
            t_prev=t_new;
            printf("Click Occured      : [%d, %d]\n",
                   xevent.xbutton.x_root,
                   xevent.xbutton.y_root);
            break;
          case 2:
            printf("Grabed\n");
            printf("Middle Click\n");
            break;
          case 3:
            printf("Right Click\n");
            break;
          case 4:
            printf("Grabed\n");
            printf("Scroll UP\n");
            break;
          case 5:
            printf("Scroll Down\n");
            break;
        }
        break;
      }
    }
  }
  XUngrabPointer(display,CurrentTime);
  return 0;
}

Upvotes: 3

Views: 6170

Answers (1)

RareStrawbery
RareStrawbery

Reputation: 36

Couldn't find an answer on how to listen to mouse events in the background as well. It's impossible to do it with mouse grabbing and you won't be able to click anywhere outside of your program.

So the solution is to read linux's /dev/input/mice device for the raw mouse input (we want button clicks) and when a low-level event occur we query X server for mouse position (can't query mouse key presses from X this way).

Display *display;
Window root_window;
XEvent event;

display = XOpenDisplay(0);
root_window = DefaultRootWindow(display);

int fd, bytes;
unsigned char data[3];

const char *pDevice = "/dev/input/mice";

// Open Mouse
fd = open(pDevice, O_RDWR);
if (fd == -1) {
    printf("ERROR Opening %s\n", pDevice);
    return -1;
}

int left, middle, right;
while (1) {
    // Read Mouse
    bytes = read(fd, data, sizeof(data));

    if (bytes > 0) {
        left = data[0] & 0x1;
        right = data[0] & 0x2;
        middle = data[0] & 0x4;

        XQueryPointer(
                display,
                root_window,
                &event.xbutton.root,
                &event.xbutton.subwindow,
                &event.xbutton.x_root,
                &event.xbutton.y_root,
                &event.xbutton.x,
                &event.xbutton.y,
                &event.xbutton.state
            );

        printf("x=%d, y=%d, left=%d, middle=%d, right=%d\n", event.xmotion.x, event.xmotion.y, left, middle, right);
    }
}

Sample output

x=470, y=969, left=1, middle=0, right=0
x=470, y=969, left=0, middle=0, right=0
x=467, y=969, left=0, middle=4, right=0
x=463, y=969, left=0, middle=0, right=0
x=444, y=971, left=0, middle=0, right=2
x=441, y=971, left=0, middle=0, right=0

Upvotes: 1

Related Questions