Harvey
Harvey

Reputation: 2222

Linux X11 C Want to know pointer motion anywhere on screen

I want to write a small window program that will display the pointer position (and other info) anywhere on the screen. I do not want to disrupt the normal use of the mouse in all the other programs running. Is there a way to "hook" pointer motion events, or how can I set up a timer event for polling the pointer position in my event loop?

Upvotes: 1

Views: 1637

Answers (1)

dho
dho

Reputation: 2370

I'd like to point you at the Xautolock code queryPointer function, which figures out the mouse position. If you dig around in main.c and diy.c, you should also get enough information about what is necessary to take action based on mouse mouse cursor position and idle timeouts.

Effectively, it just uses XQueryPointer to get the information. However, you should keep in mind that all mouse movements are relative, so you must keep state based on the initial position. Example code for this is found in another SO thread.

Edit

Since it's not apparently obvious from the Xautolock code, I cribbed the bits that do what I think you're looking for. This is a minimal set of code that just dumps the x / y coordinates to stdout. If you want them statically, you'll have to create and position a window to draw some text to. Polling with a resolution of 1ms as this code does, the program takes roughly 0.1% CPU on my machine (Intel(R) Core(TM) i7-4558U CPU @ 2.80GHz).

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/Xresource.h>

static Window root;

static void
query_pointer(Display *d)
{
  static int once;
  int i, x, y;
  unsigned m;
  Window w;

  if (once == 0) {
    once = 1;
    root = DefaultRootWindow(d);
  }

  if (!XQueryPointer(d, root, &root, &w, &x, &y, &i, &i, &m)) {
    for (i = -1; ++i < ScreenCount(d); ) {
      if (root == RootWindow(d, i)) {
        break;
      } 
    }
  }

  fprintf(stderr, "X: %d Y: %d\n", x, y);
}

static int
catchFalseAlarm(void)
{
  return 0;
}   

int 
main(void)
{
  XSetWindowAttributes attribs;
  Display* d;
  Window w;

  if (!(d = XOpenDisplay(0))) {
    fprintf (stderr, "Couldn't connect to %s\n", XDisplayName (0));
    exit (EXIT_FAILURE);
  }

  attribs.override_redirect = True;
  w = XCreateWindow(d, DefaultRootWindow (d), -1, -1, 1, 1, 0,
         CopyFromParent, InputOnly, CopyFromParent,
         CWOverrideRedirect, &attribs);
  XMapWindow(d, w);
  XSetErrorHandler((XErrorHandler )catchFalseAlarm);
  XSync (d, 0);

  for (;;) {
    query_pointer(d);
    usleep(1000);
  }

  return 0;
}

Upvotes: 3

Related Questions