X RECORD extension example

/*
 * To enable record extension in Xorg/XFree86, add the following  line in
 * Section "Module"
 *     Load         "record"
 */

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlibint.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/keysymdef.h>
#include <X11/keysym.h>
#include <X11/extensions/record.h>
#include <X11/extensions/XTest.h>

/* for this struct, refer to libxnee */
typedef union {
  unsigned char    type ;
  xEvent           event ;
  xResourceReq     req   ;
  xGenericReply    reply ;
  xError           error ;
  xConnSetupPrefix setup;
} XRecordDatum;

/*
 * FIXME: We need define a private struct for callback function,
 * to store cur_x, cur_y, data_disp, ctrl_disp etc.
 */
Display *data_disp = NULL;
Display *ctrl_disp = NULL;

/* stop flag */
int stop = 0;

void event_callback (XPointer, XRecordInterceptData*);

int main (int argc, char **argv)
{
  ctrl_disp = XOpenDisplay (NULL);
  data_disp = XOpenDisplay (NULL);

  if (!ctrl_disp || !data_disp) {
    fprintf (stderr, "Error to open local display!\n");
    exit (1);
  }


  /*


   * we must set the ctrl_disp to sync mode, or, when we the enalbe


   * context in data_disp, there will be a fatal X error !!!


   */

  XSynchronize(ctrl_disp,True);

  int major, minor;
  if (!XRecordQueryVersion (ctrl_disp, &major, &minor)) {
    fprintf (stderr, "RECORD extension not supported on this X server!\n");
    exit (2);
  }
 
  printf ("RECORD extension for local server is version is %d.%d\n", major, minor);

  XRecordRange  *rr;
  XRecordClientSpec  rcs;
  XRecordContext   rc;

  rr = XRecordAllocRange ();
  if (!rr) {
    fprintf (stderr, "Could not alloc record range object!\n");
    exit (3);
  }

  rr->device_events.first = KeyPress;
  rr->device_events.last = MotionNotify;
  rcs = XRecordAllClients;

  rc = XRecordCreateContext (ctrl_disp, 0, &rcs, 1, &rr, 1);
  if (!rc) {
    fprintf (stderr, "Could not create a record context!\n");
    exit (4);
  }
 
  if (!XRecordEnableContextAsync (data_disp, rc, event_callback, NULL)) {
    fprintf (stderr, "Cound not enable the record context!\n");
    exit (5);
  }

  while (stop != 1) {
    XRecordProcessReplies (data_disp);
  }

  XRecordDisableContext (ctrl_disp, rc);
  XRecordFreeContext (ctrl_disp, rc);
  XFree (rr);
 
  XCloseDisplay (data_disp);
  XCloseDisplay (ctrl_disp);
  return 0;
}

void event_callback(XPointer priv, XRecordInterceptData *hook)
{
  /* FIXME: we need use XQueryPointer to get the first location */
  static int cur_x = 0;
  static int cur_y = 0;

  if (hook->category != XRecordFromServer) {
    XRecordFreeData (hook);
    return;
  }

  XRecordDatum *data = (XRecordDatum*) hook->data;

  int event_type = data->type;

  BYTE btncode, keycode;
  btncode = keycode = data->event.u.u.detail;

  int rootx = data->event.u.keyButtonPointer.rootX;
  int rooty = data->event.u.keyButtonPointer.rootY;
  int time = hook->server_time;

  switch (event_type) {
  case KeyPress:
    /* if escape is pressed, stop the loop and clean up, then exit */
    if (keycode == 9) stop = 1;

    /* Note: you should not use data_disp to do normal X operations !!!*/
    printf ("KeyPress: \t%s", XKeysymToString(XKeycodeToKeysym(ctrl_disp, keycode, 0)));
    break;
  case KeyRelease:
    printf ("KeyRelease: \t%s", XKeysymToString(XKeycodeToKeysym(ctrl_disp, keycode, 0)));
    break;
  case ButtonPress:
    printf ("ButtonPress: \t%d, rootX=%d, rootY=%d", btncode, cur_x, cur_y);
    break;
  case ButtonRelease:
    printf ("ButtonRelease: \t%d, rootX=%d, rootY=%d", btncode, cur_x, cur_y);
    break;
  case MotionNotify:
    printf ("MouseMove: \trootX=%d, rootY=%d",rootx, rooty);
    cur_x = rootx;
    cur_y = rooty;
    break;
  case CreateNotify:
    break;
  case DestroyNotify:
    break;
  case NoExpose:
    break;
  case Expose:
    break;
  default:
    break;
  }

  printf (", time=%d\n", time);

  XRecordFreeData (hook);
}

5 thoughts on “X RECORD extension example

  1. I just tried the sync mode, it works fine. I just disable the context in event callback function. But I don't know whether it could work in multithread. Maybe, you can consider the context as a critical resource, you can disable the context only when the callback function is not in the calling stack.

  2. #include <stdio.h> #include <stdlib.h> #include <X11/Xlibint.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/cursorfont.h> #include <X11/keysymdef.h> #include <X11/keysym.h> #include <X11/extensions/record.h> #include <X11/extensions/XTest.h> /* for this struct, refer to libxnee */ typedef union { &nbsp; unsigned char&nbsp;&nbsp;&nbsp; type ; &nbsp; xEvent&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; event ; &nbsp; xResourceReq&nbsp;&nbsp;&nbsp;&nbsp; req&nbsp;&nbsp; ; &nbsp; xGenericReply&nbsp;&nbsp;&nbsp; reply ; &nbsp; xError&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; error ; &nbsp; xConnSetupPrefix setup; } XRecordDatum; /* &nbsp;* FIXME: We need define a private struct for callback function, &nbsp;* to store cur_x, cur_y, data_disp, ctrl_disp etc. &nbsp;*/ Display *data_disp = NULL; Display *ctrl_disp = NULL; XRecordRange&nbsp; *rr; XRecordClientSpec&nbsp; rcs; XRecordContext&nbsp;&nbsp; rc; void event_callback (XPointer, XRecordInterceptData*); int main (int argc, char **argv) { &nbsp; ctrl_disp = XOpenDisplay (NULL); &nbsp; data_disp = XOpenDisplay (NULL); &nbsp; if (!ctrl_disp || !data_disp) { &nbsp;&nbsp;&nbsp; fprintf (stderr, "Error to open local display!\n"); &nbsp;&nbsp;&nbsp; exit (1); &nbsp; } &nbsp; /* &nbsp;&nbsp; * we must set the ctrl_disp to sync mode, or, when we the enalbe &nbsp;&nbsp; * context in data_disp, there will be a fatal X error !!! &nbsp;&nbsp; */ &nbsp; XSynchronize(ctrl_disp,True); &nbsp; int major, minor; &nbsp; if (!XRecordQueryVersion (ctrl_disp, &amp;major, &amp;minor)) { &nbsp;&nbsp;&nbsp; fprintf (stderr, "RECORD extension not supported on this X server!\n"); &nbsp;&nbsp;&nbsp; exit (2); &nbsp; } &nbsp; &nbsp; printf ("RECORD extension for local server is version is %d.%d\n", major, minor); &nbsp; rr = XRecordAllocRange (); &nbsp; if (!rr) { &nbsp;&nbsp;&nbsp; fprintf (stderr, "Could not alloc record range object!\n"); &nbsp;&nbsp;&nbsp; exit (3); &nbsp; } &nbsp; rr->device_events.first = KeyPress; &nbsp; rr->device_events.last = MotionNotify; &nbsp; rcs = XRecordAllClients; &nbsp; rc = XRecordCreateContext (ctrl_disp, 0, &amp;rcs, 1, &amp;rr, 1); &nbsp; if (!rc) { &nbsp;&nbsp;&nbsp; fprintf (stderr, "Could not create a record context!\n"); &nbsp;&nbsp;&nbsp; exit (4); &nbsp; } &nbsp; &nbsp; if (!XRecordEnableContext (data_disp, rc, event_callback, NULL)) { &nbsp;&nbsp;&nbsp; fprintf (stderr, "Cound not enable the record context!\n"); &nbsp;&nbsp;&nbsp; exit (5); &nbsp; } &nbsp; XRecordFreeContext (ctrl_disp, rc); &nbsp; XFree (rr); &nbsp; &nbsp; XCloseDisplay (data_disp); &nbsp; XCloseDisplay (ctrl_disp); &nbsp; return 0; } void event_callback(XPointer priv, XRecordInterceptData *hook) { &nbsp; /* FIXME: we need use XQueryPointer to get the first location */ &nbsp; static int cur_x = 0; &nbsp; static int cur_y = 0; &nbsp; if (hook->category != XRecordFromServer) { &nbsp;&nbsp;&nbsp; XRecordFreeData (hook); &nbsp;&nbsp;&nbsp; return; &nbsp; } &nbsp; XRecordDatum *data = (XRecordDatum*) hook->data; &nbsp; int event_type = data->type; &nbsp; BYTE btncode, keycode; &nbsp; btncode = keycode = data->event.u.u.detail; &nbsp; int rootx = data->event.u.keyButtonPointer.rootX; &nbsp; int rooty = data->event.u.keyButtonPointer.rootY; &nbsp; int time = hook->server_time; &nbsp; switch (event_type) { &nbsp; case KeyPress: &nbsp;&nbsp;&nbsp; /* if escape is pressed, stop the loop and clean up, then exit */ &nbsp;&nbsp;&nbsp; if (keycode == 9) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XRecordDisableContext (ctrl_disp, rc); &nbsp;&nbsp;&nbsp; /* Note: you should not use data_disp to do normal X operations !!!*/ &nbsp;&nbsp;&nbsp; printf ("KeyPress: \t%s", XKeysymToString(XKeycodeToKeysym(ctrl_disp, keycode, 0))); &nbsp;&nbsp;&nbsp; break; &nbsp; case KeyRelease: &nbsp;&nbsp;&nbsp; printf ("KeyRelease: \t%s", XKeysymToString(XKeycodeToKeysym(ctrl_disp, keycode, 0))); &nbsp;&nbsp;&nbsp; break; &nbsp; case ButtonPress: &nbsp;&nbsp;&nbsp; printf ("ButtonPress: \t%d, rootX=%d, rootY=%d", btncode, cur_x, cur_y); &nbsp;&nbsp;&nbsp; break; &nbsp; case ButtonRelease: &nbsp;&nbsp;&nbsp; printf ("ButtonRelease: \t%d, rootX=%d, rootY=%d", btncode, cur_x, cur_y); &nbsp;&nbsp;&nbsp; break; &nbsp; case MotionNotify: &nbsp;&nbsp;&nbsp; printf ("MouseMove: \trootX=%d, rootY=%d",rootx, rooty); &nbsp;&nbsp;&nbsp; cur_x = rootx; &nbsp;&nbsp;&nbsp; cur_y = rooty; &nbsp;&nbsp;&nbsp; break; &nbsp; case CreateNotify: &nbsp;&nbsp;&nbsp; break; &nbsp; case DestroyNotify: &nbsp;&nbsp;&nbsp; break; &nbsp; case NoExpose: &nbsp;&nbsp;&nbsp; break; &nbsp; case Expose: &nbsp;&nbsp;&nbsp; break; &nbsp; default: &nbsp;&nbsp;&nbsp; break; &nbsp; } &nbsp; printf (", time=%d\n", time); &nbsp; XRecordFreeData (hook); } &nbsp;

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

To submit your comment, click the image below where it asks you to...
Clickcha - The One-Click Captcha