Noitidart
Noitidart

Reputation: 37318

Mouse events callback

I was using WinAPI SetWindowsHookEx and OS X objective-c [NSEvent addLocalMonitorForEventsMatchingMask:handler:] which both set up a callback and then i run the event loop endlessly and the callback triggers whenver it needs.

I insert this hook into just my process/application (but it would be cool if I could do system wide as well). As users do mouse combinations I track them, and if a combination matches a certain pattern, it blocks the last mouse event and does a certain function.

I was wondering what would be the x11 equivalent?

I found this topic: X11 Mouse Movement Event

But that seems to monitor absolutely all events, and he's just filtering out the mouse ones. This one is also a locking non-callback method, which is ok because i'm running this code from a dedicated thread. But ideally I would prefer a callback method because my main thread has to send messages to this thread like about the active window changing, and if its stuck in a loop it will never let up to get that active window change message.

Upvotes: 5

Views: 3158

Answers (1)

Aaron Digulla
Aaron Digulla

Reputation: 328770

You will probably have to patch the kernel for this if you want this to work globally. Some background.

I'm not sure about OS X but Windows is a very insecure OS. For example, every process can install a hook via SetWindowsHookEx and monitor the mouse and keyboard - it's basically a key logger. A few years ago, no anti virus tool would report this. I don't know how it is today.

But at the core, Windows is a cooperative OS. That means the GUI runs the computer. The application which has control (= the active one) gets all the events. If the application locks up, Windows locks up (mouse and keyboard are dead). If you click in another window and the active application says "No", then the new window doesn't become active. I remember that something was done to make things better but that's one of the reasons why Windows was so unstable in the past - one bug in some app and the whole system becomes buggy.

On Unix, the kernel doesn't care about the UI (which comes with it's own bag of problems). Instead, there is a program (a normal process) called the X server. From the kernel point of view, this program isn't any different from the others. The kernel handles mouse and keyboard. If X locks up, the keyboard still works (so you can switch to a text console, for example).

That means X reads devices like /dev/input/mice (which merges all mouse events from all the mice that are currently connected to your computer). Your keyboard is somewhere under /dev/input/by-id/. These devices are maintained be the kernel and used by X. X is just a customer here. Kernel as control.

If a program uses the X library, that means it creates a socket connection to the X server. The server processes the mouse and keyboard events sent by the kernel devices. These are turned into XEvent structures and send to the client. Rendering happens in the server, the client sends drawing commands to the server.

Which makes it hard to take control of mouse and keyboard from an X client - it's pretty far away from the source. If you create artificial events, they get flagged as "synthetic" and most programs ignore those - they are a security threat.

The devices listed above can only be read by root, so it's also not easy to listen to everything that the user does.

All in all, if you want to do this for all programs on the X display, you will need a programming running as root and probably a kernel module which allows you to inject events and expose them as a new event device under /dev/input/. And you need to configure X to listen to your new device. And even then, I don't think you can cancel events from other devices, just add your own.

If you need this just for a single application, then things are much easier. First, you need to add an event listener to all the windows which you create. In the handler, you can then analyze the mouse movements. Use the necessary Button*Mask and *MotionMask bits to get the events that you need.

If you don't care about security, you can then make your application accept synthetic events and just inject your new events. The problem is that X has no concept of "cancel event". You may be able to use the event propagation rules to achieve what you want; see "Propagation of Device Events" on this page: http://menehune.opt.wfu.edu/Kokua/Irix_6.5.21_doc_cd/usr/share/Insight/library/SGI_bookshelves/SGI_Developer/books/XLib_PG/sgi_html/ch08.html

You should probably also read chapter 2 which gives an overview of X.

One more thing: X is not thread safe. You must not call X functions from outside of the main thread. If you do, you'll get errors or your program will crash.

Related:

Upvotes: 6

Related Questions