/*
 * 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);
}

评论:

Hey, Care to explain what that code does and how to compile it. I tried to compile it in Linux (Mandrake 10.1), but unsuccessful.

发表于 Amjidanutpan Ramanujam 在 2005年02月22日, 11:16 上午 CST #

g++ record.cpp -I/usr/X11R6/include -L/usr/X11R6/lib -lXtst

发表于 yongsun 在 2005年03月10日, 08:29 下午 CST #

Did you tryied with XRecordEnableContext (not asynchronous processing)? I'm having trouble disabling the context from another thread.

发表于 Toader Mihai Claudiu 在 2005年03月30日, 07:30 下午 CST #

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.

发表于 yongsun 在 2005年04月01日, 12:33 上午 CST #

#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;

发表于 yongsun 在 2005年04月01日, 12:38 上午 CST #

发表一条评论:
该日志评论功能被禁用了。

This blog copyright 2009 by yongsun