ADAM'S WEB PRESENCE

10 October 2006

Sending fake keypress events to an X11 window

Filed under: Bizarre Stuff, Nerd Notes — adam @ 12:43 pm

This C++ example code will send a cursor-down event to the currently focussed window. It can easily be modified to send other key events. It would be a good starting point to write a virtual keyboard or remote control application.

// Send a fake keystroke event to an X window.
// by Adam Pierce - http://www.doctort.org/adam/
// This is public domain software. It is free to use by anyone for any purpose.

#include <X11/Xlib.h>
#include <X11/keysym.h>

// The key code to be sent.
// A full list of available codes can be found in /usr/include/X11/keysymdef.h
#define KEYCODE XK_Down

// Function to create a keyboard event
XKeyEvent createKeyEvent(Display *display, Window &win,
                           Window &winRoot, bool press,
                           int keycode, int modifiers)
{
   XKeyEvent event;

   event.display     = display;
   event.window      = win;
   event.root        = winRoot;
   event.subwindow   = None;
   event.time        = CurrentTime;
   event.x           = 1;
   event.y           = 1;
   event.x_root      = 1;
   event.y_root      = 1;
   event.same_screen = True;
   event.keycode     = XKeysymToKeycode(display, keycode);
   event.state       = modifiers;

   if(press)
      event.type = KeyPress;
   else
      event.type = KeyRelease;

   return event;
}

main()
{
// Obtain the X11 display.
   Display *display = XOpenDisplay(0);
   if(display == NULL)
      return -1;

// Get the root window for the current display.
   Window winRoot = XDefaultRootWindow(display);

// Find the window which has the current keyboard focus.
   Window winFocus;
   int    revert;
   XGetInputFocus(display, &winFocus, &revert);

// Send a fake key press event to the window.
   XKeyEvent event = createKeyEvent(display, winFocus, winRoot, true, KEYCODE, 0);
   XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event);

// Send a fake key release event to the window.
   event = createKeyEvent(display, winFocus, winRoot, false, KEYCODE, 0);
   XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event);

// Done.
   XCloseDisplay(display);
   return 0;
}

To compile it, you need to type this:

g++ -o XFakeKey XFakeKey.cpp -L/usr/X11R6/lib -lX11

13 Comments »

  1. Comment by Neeraj — 19 March 2007 @ 11:33 pm

    It is very good and very simple to understand example.

  2. Comment by ok — 29 March 2007 @ 6:08 am

    YES!!!

    Finally I found what I looked for (I almost 7 hours searching the web for this little example!).

    Adam Pierce - you are my hero!!!

    Thanks Thanks Thanks

    :) ;)

  3. Comment by adam — 29 March 2007 @ 10:23 am

    Thank you all for the positive comments. I also spent hours trying to find something like this and ended up having to write it myself.

  4. Comment by Thanks — 24 June 2007 @ 5:31 pm

    It’s nice example.

  5. Comment by Nick — 7 October 2007 @ 8:59 am

    Brilliant, I have thought for ages that there must be a way to do this programmatically but had real trouble finding it actually written out somewhere online.

    Thanks a lot.

  6. Comment by Ewald — 19 May 2008 @ 2:00 am

    Excellent example. However, one thing should be noted:
    I found out you have to request the focus window for every new key event you send

    getfocus(), keypress(), keyrelease() will not work
    while
    getfocus(), keypress(), getfocus(), keyrelease() works perfectly.

  7. Comment by Michael — 22 June 2008 @ 1:26 am

    nice! i searched 10 hours for something like this in QT4, but now i use this.

  8. Comment by Windsor Schmidt — 27 August 2008 @ 10:06 am

    Thanks, just what I needed!

  9. Comment by Johen — 3 September 2008 @ 12:38 am

    How about hotkeys like CTRL+L. How can I simulate it?

  10. Comment by adam — 3 September 2008 @ 9:45 am

    Try setting the “modifiers” parameter of the createKeyEvent function with values like XK_Shift_L or XK_Meta_L. See /usr/include/X11/keysymdef.h for a list of possible values.

  11. Comment by Izkata — 3 October 2008 @ 10:52 am

    FYI for those who don’t know, you can run ‘xev’ in a terminal to get keycodes - it opens a small window while it runs, then information on all keypresses are output to the terminal. For example: I typed “hi”

    KeyPress event, serial 23, synthetic NO, window 0×4c00001,
    root 0×59, subw 0×0, time 153093161, (423,461), root:(424,491),
    state 0×10, keycode 43 (keysym 0×68, h), same_screen YES,
    XLookupString gives 1 bytes: (68) “h”
    XmbLookupString gives 1 bytes: (68) “h”
    XFilterEvent returns: False

    KeyRelease event, serial 26, synthetic NO, window 0×4c00001,
    root 0×59, subw 0×0, time 153093232, (423,461), root:(424,491),
    state 0×10, keycode 43 (keysym 0×68, h), same_screen YES,
    XLookupString gives 1 bytes: (68) “h”
    XFilterEvent returns: False

    KeyPress event, serial 26, synthetic NO, window 0×4c00001,
    root 0×59, subw 0×0, time 153093374, (423,461), root:(424,491),
    state 0×10, keycode 31 (keysym 0×69, i), same_screen YES,
    XLookupString gives 1 bytes: (69) “i”
    XmbLookupString gives 1 bytes: (69) “i”
    XFilterEvent returns: False

    KeyRelease event, serial 26, synthetic NO, window 0×4c00001,
    root 0×59, subw 0×0, time 153093434, (423,461), root:(424,491),
    state 0×10, keycode 31 (keysym 0×69, i), same_screen YES,
    XLookupString gives 1 bytes: (69) “i”
    XFilterEvent returns: False

    So, keycode 43 is ‘h’ and 31 is ‘i’ - *on my keyboard*. It may or may not be different for you.. I’m not really sure.

    In any case, this should help a lot. I’ve been having troubles with Super and CTRL getting stuck on this new laptop somehow, so maybe I can use this to force a key-release…

  12. Comment by Kevin — 17 October 2008 @ 11:54 am

    Wow! Thanks Adam! This is invaluable. I just used XFakeKey to talk to my “headless firefox” inside of xvfb. The down clicks are working, the screenshots are changing!! Very exciting.

  13. Comment by Scott Carlson — 1 November 2008 @ 4:27 pm

    This has got me one step closer. But what I need is to be able to do is set keyboard focus on an already open window (in this case firefox), and then hit a key. how do you change window focus? I’ve Googled and not found a simple way yet. Oh and I’m trying to do it in Ruby but if you point me to a lib or just a C example I’ll probly find a method to bind to it.
    Thanks and fine work Adam

RSS feed for comments on this post. TrackBack URI

Leave a comment


Powered by WordPress