ADAM'S WEB PRESENCE

10 October 2006

Sending fake keypress events to an X11 window

Filed under: 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

23 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

  14. Comment by Antonio — 28 December 2008 @ 11:03 am

    Thanks Adam!

    > But what I need is to be able to do is set keyboard focus
    Feel free to correct me, what I’m using now is:

    /*
    * Window_With_Name: routine to locate a window with a given name on a display.
    * If no window with the given name is found, 0 is returned.
    * If more than one window has the given name, the first
    * one found will be returned. Only top and its subwindows
    * are looked at. Normally, top should be the RootWindow.
    */
    Window
    Window_With_Name(Display *display, Window top, const char *name)
    {
    Window *children, dummy;
    unsigned int nchildren;
    unsigned int i;
    Window w=0;
    char *window_name;

    if (XFetchName(display, top, &window_name) && !strcmp(window_name, name))
    return(top);

    if (!XQueryTree(display, top, &dummy, &dummy, &children, &nchildren))
    return(0);

    for (i=0; i<nchildren; i++) {
    w = Window_With_Name(display, children[i], name);
    if (w)
    break;
    }
    if (children) XFree ((char *)children);
    return(w);
    }

    int
    main(int argc, char *argv[])
    {
    display = XOpenDisplay(0);
    if (!display)
    exit(EXIT_FAILURE);

    Window window_root = DefaultRootWindow(display);
    if (!window_root)
    exit(EXIT_FAILURE);

    Window window_found = Window_With_Name(display, window_root, “put here the name of the window”);

    if (window_found)
    {
    XSetInputFocus(display, window_found, RevertToNone, CurrentTime);

    // Send keys to window_found

  15. Comment by Antonio — 7 February 2009 @ 11:27 pm

    With the method of the last comment you can automate any application (sending “keypresses” to its window).

    This method needs that the window is not minimized, maybe some hacker can find a method that is valid even if the window is minimized.

  16. Comment by Benjamin — 12 February 2009 @ 11:15 am

    Oh man, you are a hero!

    Thank you very much for this excellent code. I have been searching for this for hours!

    Best regards,
    Benjamin

  17. Comment by Andrei — 28 February 2009 @ 11:27 am

    I’ve been searching for several hours trying to find something like this, thank you very much.

    For some reason this doesn’t seem to send the key event to the focused window (a urxvt terminal in my case), but I read at this website (http://www.handhelds.org/moin/moin.cgi/GeneratingSyntheticX11Events) that a key event generated in this way is tagged as fake and many programs ignore events with that tag. However, as the site suggests, the thing to do is use the XTest function instead. So, I made this small change:

    XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event);
    was changed to
    XTestFakeKeyEvent(event.display, event.keycode, True, CurrentTime);

    To complie this I had to do g++ -o XFakeKey XFakeKey.cpp -L/usr/X11R6/lib -lX11 -lXtst

    Now it works perfectly.

    Again, thank you.

  18. Comment by skande — 9 March 2009 @ 9:31 am

    Please , can you show me where can i document myself about X11 .
    I need documentation to develop a keylogger . THANKS

  19. Comment by n9986 — 28 March 2009 @ 12:37 pm

    Many thanks for this tutorial! Really helped clear up the concept. :)

  20. Comment by palcu — 8 May 2009 @ 7:53 pm

    This example was very useful,thanks very much!

  21. Comment by HyperHacker — 23 January 2010 @ 2:05 pm

    Very helpful, thank you.

    A word of warning to those who try to modify it: multiple calls to XOpenDisplay() with the same parameter return different handles; sending the press event with one handle and the release event with another will not work.

  22. Comment by jcl — 28 January 2010 @ 7:47 pm

    Nice code thanks at all
    it does not work for me @Antonio

    I can get the window handler if i set the focus i become a Parameter error

    X Error of failed request: BadMatch (invalid parameter attributes)
    Major opcode of failed request: 42 (X_SetInputFocus)
    Serial number of failed request: 156
    Current serial number in output stream: 157

    My Problem is after a localhost Webserver Update i will send a ctrl+f5 to firefox for reload it not works for me
    dbus and firefox as option the same

  23. Comment by Andy Balaam — 4 February 2010 @ 3:06 am

    Thanks Adam! Brilliant. I needed* to send an F5 to Empathy to make it show all chat windows after starting. This worked perfectly first time.

    * For some definition of “needed”.

RSS feed for comments on this post. TrackBack URI

Leave a comment


Powered by WordPress