Logo Search packages:      
Sourcecode: wacom-tools version File versions

xidump.c

/*****************************************************************************
** xidump.c
**
** Copyright (C) 2003 - 2004 - John E. Joganic
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
** as published by the Free Software Foundation; either version 2
** of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
**
** REVISION HISTORY
**   2003-02-23 0.0.1 - created for GTK1.2
**   2003-03-07 0.0.2 - added input device code
**   2003-03-08 0.0.3 - added curses code
**   2003-03-21 0.0.4 - added conditional curses code
**   2003-03-21 0.5.0 - released in development branch
**   2003-04-07 0.5.1 - added pressure bar
**
****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#include <sys/time.h>
#include <math.h>

#define XIDUMP_VERSION "0.5.1"

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/*****************************************************************************
** XInput
*****************************************************************************/

#include <X11/Xlib.h>
#include <X11/extensions/XInput.h>
#include <X11/extensions/XIproto.h>

      enum
      {
            INPUTEVENT_KEY_PRESS,
            INPUTEVENT_KEY_RELEASE,
            INPUTEVENT_FOCUS_IN,
            INPUTEVENT_FOCUS_OUT,
            INPUTEVENT_BTN_PRESS,
            INPUTEVENT_BTN_RELEASE,
            INPUTEVENT_PROXIMITY_IN,
            INPUTEVENT_PROXIMITY_OUT,
            INPUTEVENT_MOTION_NOTIFY,
            INPUTEVENT_DEVICE_STATE_NOTIFY,
            INPUTEVENT_DEVICE_MAPPING_NOTIFY,
            INPUTEVENT_CHANGE_DEVICE_NOTIFY,
            INPUTEVENT_DEVICE_POINTER_MOTION_HINT,
            INPUTEVENT_DEVICE_BUTTON_MOTION,
            INPUTEVENT_DEVICE_BUTTON1_MOTION,
            INPUTEVENT_DEVICE_BUTTON2_MOTION,
            INPUTEVENT_DEVICE_BUTTON3_MOTION,
            INPUTEVENT_DEVICE_BUTTON4_MOTION,
            INPUTEVENT_DEVICE_BUTTON5_MOTION,

            INPUTEVENT_MAX
      };

      int gnDevListCnt = 0;
      XDeviceInfoPtr gpDevList = NULL;
      int gnLastXError = 0;
      int gnVerbose = 0;
      int gnSuppress = 4;
      int gnInputEvent[INPUTEVENT_MAX] = { 0 };

int ErrorHandler(Display* pDisp, XErrorEvent* pEvent)
{
      char chBuf[64];
      XGetErrorText(pDisp,pEvent->error_code,chBuf,sizeof(chBuf));
      fprintf(stderr,"X Error: %d %s\n", pEvent->error_code, chBuf);
      gnLastXError  = pEvent->error_code;
      return 0;
}

int GetLastXError(void)
{
      return gnLastXError;
}

Display* InitXInput(void)
{
      Display* pDisp;
      int nMajor, nFEV, nFER;

      pDisp = XOpenDisplay(NULL);
      if (!pDisp)
      {
            fprintf(stderr,"Failed to connect to X server.\n");
            return NULL;
      }

      XSetErrorHandler(ErrorHandler);

      XSynchronize(pDisp,1 /*sync on*/);
      
      if (!XQueryExtension(pDisp,INAME,&nMajor,&nFEV,&nFER))
      {
            fprintf(stderr,"Server does not support XInput extension.\n");
            XCloseDisplay(pDisp);
            return NULL;
      }

      return pDisp;
}

int ListDevices(Display* pDisp, const char* pszDeviceName)
{
      int i, j, k;
      XDeviceInfoPtr pDev;
      XAnyClassPtr pClass;

      /* get list of devices */
      if (!gpDevList)
      {
            gpDevList = (XDeviceInfoPtr) XListInputDevices(pDisp, &gnDevListCnt);
            if (!gpDevList)
            {
                  fprintf(stderr,"Failed to get input device list.\n");
                  return 1;
            }
      }

      for (i=0; i<gnDevListCnt; ++i)
      {
            pDev = gpDevList + i;

            /* if device name is specified, skip other devices */
            if (pszDeviceName && strcasecmp(pDev->name, pszDeviceName))
                  continue;

            printf("%-30s %s\n",
                        pDev->name,
                        (pDev->use == 0) ? "disabled" :
                        (pDev->use == IsXKeyboard) ? "keyboard" :
                        (pDev->use == IsXPointer) ? "pointer" :
                        (pDev->use == IsXExtensionDevice) ? "extension" :
                              "unknown");

            if (gnVerbose)
            {
                  pClass = pDev->inputclassinfo;
                  for (j=0; j<pDev->num_classes; ++j)
                  {
                        switch (pClass->class)
                        {
                              case ButtonClass:
                              {
                                    XButtonInfo* pBtn = (XButtonInfo*)pClass;
                                    printf("    btn: num=%d\n",pBtn->num_buttons);
                                    break;
                              }
      
                              case FocusClass:
                              {
                                    printf("  focus:\n");
                                    break;
                              }

                              case KeyClass:
                              {
                                    XKeyInfo* pKey = (XKeyInfo*)pClass;
                                    printf("    key: min=%d, max=%d, num=%d\n",
                                                pKey->min_keycode,
                                                pKey->max_keycode,
                                                pKey->num_keys);
                                    break;
                              }

                              case ValuatorClass:
                              {
                                    XValuatorInfoPtr pVal = (XValuatorInfoPtr)pClass;
                                    printf("    val: axes=%d mode=%s buf=%ld\n",
                                                pVal->num_axes,
                                                pVal->mode == Absolute ? "abs" :
                                                pVal->mode == Relative ? "rel" : "unk",
                                                pVal->motion_buffer);
                                    for (k=0; k<pVal->num_axes; ++k)
                                    {
                                          printf("    axis[%d]: res=%d, max=%d, max=%d\n",
                                                k, /* index */
                                                pVal->axes[k].resolution,
                                                pVal->axes[k].min_value,
                                                pVal->axes[k].max_value);
                                    }
                                    break;
                              }
      
                              default:
                                    printf("  unk: class=%lu\n",pClass->class);
                        }
      
                        /* skip to next record */
                        pClass = (XAnyClassPtr)((char*)pClass + pClass->length);
                  }
                  printf("\n");
            }
      }

      return 0;
}

XDeviceInfoPtr GetDevice(Display* pDisp, const char* pszDeviceName)
{
      int i;

      /* get list of devices */
      if (!gpDevList)
      {
            gpDevList = (XDeviceInfoPtr) XListInputDevices(pDisp, &gnDevListCnt);
            if (!gpDevList)
            {
                  fprintf(stderr,"Failed to get input device list.\n");
                  return NULL;
            }
      }

      /* find device by name */
      for (i=0; i<gnDevListCnt; ++i)
      {
            if (strcasecmp(gpDevList[i].name,pszDeviceName) == 0)
                  return gpDevList + i;
      }

      return NULL;
}

static const char* GetEventName(int nType)
{
      static char xchBuf[64];

      switch (nType)
      {
            case KeyPress: return "KeyPress";
            case KeyRelease: return "KeyRelease";
            case ButtonPress: return "ButtonPress";
            case ButtonRelease: return "ButtonRelease";
            case MotionNotify: return "MotionNotify";
            case EnterNotify: return "EnterNotify";
            case LeaveNotify: return "LeaveNotify";
            case FocusIn: return "FocusIn";
            case FocusOut: return "FocusOut";
            case KeymapNotify: return "KeymapNotify";
            case Expose: return "Expose";
            case GraphicsExpose: return "GraphicsExpose";
            case NoExpose: return "NoExpose";
            case VisibilityNotify: return "VisibilityNotify";
            case CreateNotify: return "CreateNotify";
            case DestroyNotify: return "DestroyNotify";
            case UnmapNotify: return "UnmapNotify";
            case MapNotify: return "MapNotify";
            case MapRequest: return "MapRequest";
            case ReparentNotify: return "ReparentNotify";
            case ConfigureNotify: return "ConfigureNotify";
            case ConfigureRequest: return "ConfigureRequest";
            case GravityNotify: return "GravityNotify";
            case ResizeRequest: return "ResizeRequest";
            case CirculateNotify: return "CirculateNotify";
            case CirculateRequest: return "CirculateRequest";
            case PropertyNotify: return "PropertyNotify";
            case SelectionClear: return "SelectionClear";
            case SelectionRequest: return "SelectionRequest";
            case SelectionNotify: return "SelectionNotify";
            case ColormapNotify: return "ColormapNotify";
            case ClientMessage: return "ClientMessage";
            case MappingNotify: return "MappingNotify";

            default:
            if (nType == gnInputEvent[INPUTEVENT_KEY_PRESS])
                  return "XIKeyPress";
            else if (nType == gnInputEvent[INPUTEVENT_KEY_RELEASE])
                  return "XIKeyRelease";
            else if (nType == gnInputEvent[INPUTEVENT_FOCUS_IN])
                  return "XIFocusIn";
            else if (nType == gnInputEvent[INPUTEVENT_FOCUS_OUT])
                  return "XIFocusOut";
            else if (nType == gnInputEvent[INPUTEVENT_BTN_PRESS])
                  return "XIButtonPress";
            else if (nType == gnInputEvent[INPUTEVENT_BTN_RELEASE])
                  return "XIButtonRelease";
            else if (nType == gnInputEvent[INPUTEVENT_PROXIMITY_IN])
                  return "XIProximityIn";
            else if (nType == gnInputEvent[INPUTEVENT_PROXIMITY_OUT])
                  return "XIProximityOut";
            else if (nType == gnInputEvent[INPUTEVENT_MOTION_NOTIFY])
                  return "XIMotionNotify";
            else if (nType == gnInputEvent[INPUTEVENT_DEVICE_STATE_NOTIFY])
                  return "XIDeviceStateNotify";
            else if (nType == gnInputEvent[INPUTEVENT_DEVICE_MAPPING_NOTIFY])
                  return "XIDeviceMappingNotify";
            else if (nType == gnInputEvent[INPUTEVENT_CHANGE_DEVICE_NOTIFY])
                  return "XIChangeDeviceNotify";
            else if (nType == gnInputEvent[INPUTEVENT_DEVICE_POINTER_MOTION_HINT])
                  return "XIDevicePointerMotionHint";
            else if (nType == gnInputEvent[INPUTEVENT_DEVICE_BUTTON_MOTION])
                  return "XIDeviceButtonMotion";
            else if (nType == gnInputEvent[INPUTEVENT_DEVICE_BUTTON1_MOTION])
                  return "XIDeviceButton1Motion";
            else if (nType == gnInputEvent[INPUTEVENT_DEVICE_BUTTON2_MOTION])
                  return "XIDeviceButton2Motion";
            else if (nType == gnInputEvent[INPUTEVENT_DEVICE_BUTTON3_MOTION])
                  return "XIDeviceButton3Motion";
            else if (nType == gnInputEvent[INPUTEVENT_DEVICE_BUTTON4_MOTION])
                  return "XIDeviceButton4Motion";
            else if (nType == gnInputEvent[INPUTEVENT_DEVICE_BUTTON5_MOTION])
                  return "XIDeviceButton5Motion";
      }

      snprintf(xchBuf,sizeof(xchBuf),"Event_%d",nType);
      return xchBuf;
}


/*****************************************************************************
** FORMAT
*****************************************************************************/

typedef enum
{
      FORMATTYPE_DEFAULT,
      FORMATTYPE_ACCELERATION
} FORMATTYPE;

typedef struct _FORMAT FORMAT;
struct _FORMAT
{
      const char* pszName;
      FORMATTYPE type;
};

      FORMAT gFormats[] =
      {
            { "default", FORMATTYPE_DEFAULT },
            { "accel", FORMATTYPE_ACCELERATION },
            { NULL }
      };

/*****************************************************************************
** UI
*****************************************************************************/

typedef struct _UI UI;
struct _UI
{
      const char* pszName;
      int (*Init)(void);
      void (*Term)(void);
      int (*Run)(Display* pDisp, XDeviceInfo* pDevInfo, FORMATTYPE fmt);
};

/*****************************************************************************
** GTK UI
*****************************************************************************/

#if WCM_ENABLE_GTK12 || WCM_ENABLE_GTK20
#define USE_GTK 1
#include <gtk/gtk.h>

static int GTKInit(void)
{
      return 1;
}

static void GTKTerm(void)
{
}

static int GTKRun(Display* pDisp, XDeviceInfo* pDevInfo, FORMATTYPE fmt)
{
      return 1;
}

      UI gGTKUI = { "gtk", GTKInit, GTKTerm, GTKRun };
#else
#define USE_GTK 0
#endif

/*****************************************************************************
** Curses UI
*****************************************************************************/

#if WCM_ENABLE_NCURSES
#define USE_NCURSES 1
#include <wacscrn.h>

      int gbCursesInit = 0;

static void CursesTerm(void)
{
      if (gbCursesInit)
      {
            wacscrn_term();
            gbCursesInit = 0;
      }
}

static int CursesInit(void)
{
      if (!gbCursesInit)
      {
            gbCursesInit = 1;
            wacscrn_init();
            atexit(CursesTerm);
      }
      return 0;
}

static int CursesRun(Display* pDisp, XDeviceInfo* pDevInfo, FORMATTYPE fmt)
{
      int i, j, k, bDown, nBtn;
      int nRow=0, nPressRow, nProxRow, nFocusRow, nButtonRow,
                  nKeyRow, nValRow;
      int nMaxPress=100, nMinPress=0;
      int bStylus = 0;
      char chBuf[1024];
      XEvent event;
      XAnyEvent* pAny;
      XValuatorInfoPtr pValInfo = NULL;
      XAnyClassPtr pClass;

      /* Identify program and version */
      wacscrn_standout();
      for (i=0; i<80; ++i) wacscrn_output(nRow,i," ");
      wacscrn_output(nRow,0,"xidump v" XIDUMP_VERSION);
      wacscrn_normal();
      nRow += 2;

      /* get class info */
      pClass = pDevInfo->inputclassinfo;
      for (j=0; j<pDevInfo->num_classes; ++j)
      {
            switch (pClass->class)
            {
                  case ValuatorClass:
                        pValInfo = (XValuatorInfoPtr)pClass;
                        break;
            }
      
            /* skip to next record */
            pClass = (XAnyClassPtr)((char*)pClass + pClass->length);
      }

      snprintf(chBuf,sizeof(chBuf),"InputDevice: %s",pDevInfo->name);
      wacscrn_output(nRow,0,chBuf);
      nRow += 1;

      /* display valuator related info */
      if (pValInfo)
      {
            snprintf(chBuf,sizeof(chBuf),"Valuators: %s   Axes: %d  Buffer: %ld",
                        pValInfo->mode == Absolute ? "Absolute" :
                        pValInfo->mode == Relative ? "Relative" : "Unknown",
                        pValInfo->num_axes,
                        pValInfo->motion_buffer);
            wacscrn_output(nRow,0,chBuf);
            nRow += 2;
            nValRow = nRow;
            nRow += 6;

            wacscrn_output(nValRow+1 ,0,"     data:");
            wacscrn_output(nValRow+2 ,0,"      min:");
            wacscrn_output(nValRow+3 ,0,"      max:");
            wacscrn_output(nValRow+4 ,0,"      res:");

            /* retain pressure range for pressure bar */
            nMaxPress = pValInfo->axes[2].max_value;
            nMinPress = pValInfo->axes[2].min_value;

            /* should be a better way to identify the stylus */
            if ((pValInfo->axes[3].min_value == -64) &&
                  (pValInfo->axes[4].min_value == -64))
                  bStylus = 1;

            for (k=0; k<pValInfo->num_axes && k<6; ++k)
            {
                  wacscrn_output(nValRow,12 + k * 10,
                        k == 0 ? " x-axis " :
                        k == 1 ? " y-axis " :
                        k == 2 ? "pressure" :
                        k == 3 ? (bStylus ? " x-tilt " : "rotation" ) :
                        k == 4 ? (bStylus ? " y-tilt " : "throttle" ) :
                        k == 5 ? "  wheel " : "  error ");

                  snprintf(chBuf,sizeof(chBuf),"%+06d",
                        pValInfo->axes[k].min_value);
                  wacscrn_output(nValRow+2,12 + k * 10, chBuf);
                  snprintf(chBuf,sizeof(chBuf),"%+06d",
                        pValInfo->axes[k].max_value);
                  wacscrn_output(nValRow+3,12 + k * 10, chBuf);
                  snprintf(chBuf,sizeof(chBuf),"%+06d",
                        pValInfo->axes[k].resolution);
                  wacscrn_output(nValRow+4,12 + k * 10, chBuf);
            }
      }
      else nValRow = 0;

      nPressRow = nRow++;
      nProxRow = nRow++;
      nFocusRow = nRow++;
      nButtonRow = nRow++;
      nKeyRow = nRow++;

      wacscrn_output(nProxRow,  0,"Proximity:");
      wacscrn_output(nFocusRow, 0,"    Focus:");
      wacscrn_output(nButtonRow,0,"  Buttons:");
      wacscrn_output(nKeyRow   ,0,"     Keys:");



      /* handle events */

      while (1)
      {
            wacscrn_refresh();
            XNextEvent(pDisp,&event);

            pAny = (XAnyEvent*)&event;
            /* printf("event: type=%s\n",GetEventName(pAny->type)); */

            if (pAny->type == gnInputEvent[INPUTEVENT_PROXIMITY_IN])
            {
                  wacscrn_standout();
                  wacscrn_output(nProxRow,12,"IN ");
                  wacscrn_normal();
            }
            else if (pAny->type == gnInputEvent[INPUTEVENT_PROXIMITY_OUT])
                  wacscrn_output(nProxRow,12,"OUT ");
            else if (pAny->type == gnInputEvent[INPUTEVENT_FOCUS_IN])
            {
                  wacscrn_standout();
                  wacscrn_output(nFocusRow,12,"IN ");
                  wacscrn_normal();
            }
            else if (pAny->type == gnInputEvent[INPUTEVENT_FOCUS_OUT])
                  wacscrn_output(nFocusRow,12,"OUT ");
            else if (pAny->type == gnInputEvent[INPUTEVENT_MOTION_NOTIFY])
            {
                  XDeviceMotionEvent* pMove = (XDeviceMotionEvent*)pAny;
                  if (!pValInfo)
                  {
                        wacscrn_output(23,0,"Unexpected valuator data received.");
                  }

                  for (k=0; k<pValInfo->num_axes && k<6; ++k)
                  {
                        snprintf(chBuf,sizeof(chBuf),"%+06d",pMove->axis_data[k]);
                        wacscrn_output(nValRow+1,12 + k * 10, chBuf);

                  }

                  /* pressure bar */
                  {
                        char* c;
                        int s, nPos;
                        wacscrn_standout();
                        nPos = pMove->axis_data[2];

                        if (nPos < nMinPress)
                        {
                              c = "<";
                              nPos = 78; /* want full bar */
                        }
                        else if (nPos > nMaxPress)
                        {
                              c = ">";
                              nPos = 78; /* want full bar */
                        }
                        else
                        {
                              c = "*";
                              nPos = (nPos - nMinPress) * 78;
                              nPos /= (nMaxPress - nMinPress);
                        }

                        for (s=0; s<nPos; ++s)
                              wacscrn_output(nPressRow,s,c);
                        wacscrn_normal();
                        for (; s<78; ++s)
                              wacscrn_output(nPressRow,s," ");
                  }
            }
            else if ((pAny->type == gnInputEvent[INPUTEVENT_BTN_PRESS]) ||
                        (pAny->type == gnInputEvent[INPUTEVENT_BTN_RELEASE]))
            {
                  XDeviceButtonEvent* pBtn = (XDeviceButtonEvent*)pAny;
                  bDown = (pAny->type == gnInputEvent[INPUTEVENT_BTN_PRESS]);
                  nBtn = pBtn->button;
                  if ((nBtn < 1) || (nBtn > 5)) nBtn=6;
                  snprintf(chBuf,sizeof(chBuf),"%d-%s",pBtn->button,
                              bDown ? "DOWN" : "UP  ");
                  if (bDown) wacscrn_standout();
                  wacscrn_output(nButtonRow,12 + (nBtn-1) * 10,chBuf);
                  if (bDown) wacscrn_normal();
            }
            else
            {
                  snprintf(chBuf,sizeof(chBuf),"%ld - %-60s",
                              time(NULL),
                              GetEventName(pAny->type));
                  wacscrn_output(22,0,chBuf);
            }
      }

      return 0;
}

      UI gCursesUI = { "curses", CursesInit, CursesTerm, CursesRun };

#else /* WCM_ENABLE_NCURSES */
#define USE_NCURSES 0
#endif /* !WCM_ENABLE_NCURSES */

/*****************************************************************************
** Raw UI
*****************************************************************************/

static int RawInit(void)
{
      return 0;
}

static void RawTerm(void)
{
}

static int RawRunDefault(Display* pDisp, XDeviceInfo* pDevInfo)
{
      XEvent event;
      XAnyEvent* pAny;
      struct timeval tv;
      double dStart, dNow;

      gettimeofday(&tv,NULL);
      dStart = tv.tv_sec + (double)tv.tv_usec / 1E6;

      while (1)
      {
            XNextEvent(pDisp,&event);

            pAny = (XAnyEvent*)&event;
            /* printf("event: type=%s\n",GetEventName(pAny->type)); */

            /* display time */
            gettimeofday(&tv,NULL);
            dNow = tv.tv_sec + (double)tv.tv_usec / 1E6;
            printf("%.8f: ",(dNow - dStart));

            if (pAny->type == gnInputEvent[INPUTEVENT_PROXIMITY_IN])
                  printf("Proximity In\n");
            else if (pAny->type == gnInputEvent[INPUTEVENT_PROXIMITY_OUT])
                  printf("Proximity Out\n");
            else if (pAny->type == gnInputEvent[INPUTEVENT_FOCUS_IN])
                  printf("Focus In\n");
            else if (pAny->type == gnInputEvent[INPUTEVENT_FOCUS_OUT])
                  printf("Focus Out\n");
            else if (pAny->type == gnInputEvent[INPUTEVENT_MOTION_NOTIFY])
            {
                  XDeviceMotionEvent* pMove = (XDeviceMotionEvent*)pAny;
                  printf("Motion: x=%+6d y=%+6d p=%4d tx=%+4d ty=%+4d w=%+5d\n",
                              pMove->axis_data[0],
                              pMove->axis_data[1],
                              pMove->axis_data[2],
                              pMove->axis_data[3],
                              pMove->axis_data[4],
                              pMove->axis_data[5]);
            }
            else if ((pAny->type == gnInputEvent[INPUTEVENT_BTN_PRESS]) ||
                        (pAny->type == gnInputEvent[INPUTEVENT_BTN_RELEASE]))
            {
                  XDeviceButtonEvent* pBtn = (XDeviceButtonEvent*)pAny;
                  printf("Button: %d %s\n",pBtn->button,
                              pAny->type == gnInputEvent[INPUTEVENT_BTN_PRESS] ?
                                    "DOWN" : "UP");
            }
            else
            {
                  printf("Event: %s\n",GetEventName(pAny->type));
            }

            /* flush data to terminal */
            fflush(stdout);
      }

      return 0;
}

static int RawRunAccel(Display* pDisp, XDeviceInfo* pDevInfo)
{
      XEvent event;
      XAnyEvent* pAny;
      int prox=0, head=0, tail=0, points=0, prev=-1;
      int x[16], y[16];
      double d[16], dd[16], vx[16], vy[16], ax[16], ay[16],
            dx, dy, dvx, dvy, m, a;

      while (1)
      {
            XNextEvent(pDisp,&event);
            pAny = (XAnyEvent*)&event;

            if (pAny->type == gnInputEvent[INPUTEVENT_PROXIMITY_IN])
                  prox=1;
            else if (pAny->type == gnInputEvent[INPUTEVENT_PROXIMITY_OUT])
                  { prox=head=tail=points=0; prev=-1; }
            else if (pAny->type == gnInputEvent[INPUTEVENT_MOTION_NOTIFY])
            {
                  XDeviceMotionEvent* pMove = (XDeviceMotionEvent*)pAny;
                  x[head] = pMove->axis_data[0];
                  y[head] = pMove->axis_data[1];
                  d[head] = (double)pMove->time;

                  if (prev >= 0)
                  {
                        /* parametric deltas, velocity, and accel */
                        dx = x[head] - x[prev];
                        dy = y[head] - y[prev];

                        if ((abs(dx) < gnSuppress) &&
                              (abs(dy) >= gnSuppress)) continue;

                        dd[head] = d[head] - d[prev];
                        vx[head] = dd[head] ? (dx/dd[head]) : 0;
                        vy[head] = dd[head] ? (dy/dd[head]) : 0;
                        dvx = vx[head] - vx[prev];
                        dvy = vy[head] - vy[prev];
                        ax[head] = dd[head] ? (dvx/dd[head]) : 0;
                        ay[head] = dd[head] ? (dvy/dd[head]) : 0;
                  }
                  else
                  {
                        dx = dy = 0;
                        vx[head] = vy[head] = 0;
                        ax[head] = ay[head] = 0;
                  }

                  ++points;
                  prev = head;
                  head = (head + 1) % 16;
                  if (head == tail) tail = (head + 1) % 16;

                  /* compute magnitude and angle of velocity */
                  m = sqrt(vx[prev]*vx[prev] + vy[prev]*vy[prev]),
                  a = atan2(vx[prev], -vy[prev]);

                  printf("%8.0f: %4.0f "
                        "[%+4d %+4d] [%6.2f %6.2f] "
                        "[%+4.2f %+4.2f] (%6.2f %+3.0f)\n",
                        d[prev], dd[prev],
                        x[prev], y[prev],
                        vx[prev], vy[prev],
                        ax[prev], ay[prev],
                        m, a * 180 / M_PI);
            }

            /* flush data to terminal */
            fflush(stdout);
      }

      return 0;
}

static int RawRun(Display* pDisp, XDeviceInfo* pDevInfo, FORMATTYPE fmt)
{
      switch (fmt)
      {
            case FORMATTYPE_ACCELERATION:
                  return RawRunAccel(pDisp,pDevInfo);

            default:
                  return RawRunDefault(pDisp,pDevInfo);
      }
}

      UI gRawUI = { "raw", RawInit, RawTerm, RawRun };

/****************************************************************************/

      UI* gpUIs[] =
      {
            /* GTK UI */
            #if USE_GTK
      /*    &gGTKUI, */ /* not ready yet */
            #endif

            /* Curses UI */
            #if USE_NCURSES
            &gCursesUI,
            #endif

            /* Raw UI is always available */
            &gRawUI,
            NULL
      };

/****************************************************************************/

void Usage(int rtn)
{
      int nCnt;
      UI** ppUI;
      FORMAT* pFmt;
      FILE* f = rtn ? stderr : stdout;

      fprintf(f, "Usage: xidump [options] input_device\n"
                  "  -h, --help                - usage\n"
                  "  -v, --verbose             - verbose\n"
                  "  -V, --version             - version\n"
                  "  -l, --list                - list available input devices\n"
                  "  -s, --suppress value      - suppress changes less than value\n"
                  "  -f, --format format_type  - use specified format, see below\n"
                  "  -u, --ui ui_type          - use specified ui, see below\n"
                  "\n"
                  "Use --list option for input_device choices\n"
                  "UI types: ");

      /* output UI types */
      for (ppUI=gpUIs, nCnt=0; *ppUI!=NULL; ++ppUI, ++nCnt)
            fprintf(f, "%s%s", nCnt ? ", " : "", (*ppUI)->pszName);

      fprintf(f,"\nFormat types: ");

      /* output format types */
      for (pFmt=gFormats, nCnt=0; pFmt->pszName!=NULL; ++pFmt, ++nCnt)
            fprintf(f, "%s%s", nCnt ? ", " : "", pFmt->pszName);

      fprintf(f,"\n");
      exit(rtn);
}

void Version(void)
{
      fprintf(stdout,"%s\n",XIDUMP_VERSION);
}

void Fatal(const char* pszFmt, ...)
{
      va_list args;
      va_start(args,pszFmt);
      vfprintf(stderr,pszFmt,args);
      va_end(args);
      exit(1);
}

/****************************************************************************/

int Run(Display* pDisp, UI* pUI, FORMATTYPE fmt, const char* pszDeviceName)
{
      int nRtn;
      XDevice* pDev;
      XDeviceInfoPtr pDevInfo;
      Window wnd;
      int nEventListCnt = 0;
      XEventClass eventList[32];
      XEventClass cls;

      /* create a window to receive events */
      wnd = XCreateWindow(pDisp,
                  DefaultRootWindow(pDisp), /* parent */
                  0,0,100,100, /* placement */
                  0, /* border width */
                  0, /* depth */
                  InputOnly, /* class */
                  CopyFromParent, /* visual */
                  0, /* valuemask */
                  NULL); /* attributes */

      /* mapping appears to be necessary */
      XMapWindow(pDisp,wnd);

      /* get the device by name */
      pDevInfo = GetDevice(pDisp,pszDeviceName);
      if (!pDevInfo)
      {
            fprintf(stderr,"Unable to find input device '%s'\n",pszDeviceName);
            XDestroyWindow(pDisp,wnd);
            return 1;
      }

      /* open device */
      pDev = XOpenDevice(pDisp,pDevInfo->id);
      if (!pDev)
      {
            fprintf(stderr,"Unable to open input device '%s'\n",pszDeviceName);
            XDestroyWindow(pDisp,wnd);
            return 1;
      }

      /* key events */
      DeviceKeyPress(pDev,gnInputEvent[INPUTEVENT_KEY_PRESS],cls);
      if (cls) eventList[nEventListCnt++] = cls;
      DeviceKeyRelease(pDev,gnInputEvent[INPUTEVENT_KEY_RELEASE],cls);
      if (cls) eventList[nEventListCnt++] = cls;

      /* focus events */
      DeviceFocusIn(pDev,gnInputEvent[INPUTEVENT_FOCUS_IN],cls);
      if (cls) eventList[nEventListCnt++] = cls;
      DeviceFocusOut(pDev,gnInputEvent[INPUTEVENT_FOCUS_OUT],cls);
      if (cls) eventList[nEventListCnt++] = cls;

      /* button events */
      DeviceButtonPress(pDev,gnInputEvent[INPUTEVENT_BTN_PRESS],cls);
      if (cls) eventList[nEventListCnt++] = cls;
      DeviceButtonRelease(pDev,gnInputEvent[INPUTEVENT_BTN_RELEASE],cls);
      if (cls) eventList[nEventListCnt++] = cls;

      /* proximity events */
      ProximityIn(pDev,gnInputEvent[INPUTEVENT_PROXIMITY_IN],cls);
      if (cls) eventList[nEventListCnt++] = cls;
      ProximityOut(pDev,gnInputEvent[INPUTEVENT_PROXIMITY_OUT],cls);
      if (cls) eventList[nEventListCnt++] = cls;

      /* motion events */
      DeviceMotionNotify(pDev,gnInputEvent[INPUTEVENT_MOTION_NOTIFY],cls);
      if (cls) eventList[nEventListCnt++] = cls;

      /* device state */
      DeviceStateNotify(pDev,gnInputEvent[INPUTEVENT_DEVICE_STATE_NOTIFY],cls);
      if (cls) eventList[nEventListCnt++] = cls;
      DeviceMappingNotify(pDev,
                  gnInputEvent[INPUTEVENT_DEVICE_MAPPING_NOTIFY],cls);
      if (cls) eventList[nEventListCnt++] = cls;
      ChangeDeviceNotify(pDev,gnInputEvent[INPUTEVENT_CHANGE_DEVICE_NOTIFY],cls);
      if (cls) eventList[nEventListCnt++] = cls;

#if 0
      /* this cuts the motion data down - not sure if this is useful */
      DevicePointerMotionHint(pDev,
                  gnInputEvent[INPUTEVENT_DEVICE_POINTER_MOTION_HINT],cls);
      if (cls) eventList[nEventListCnt++] = cls;
#endif

      /* button motion */
      DeviceButtonMotion(pDev,
                  gnInputEvent[INPUTEVENT_DEVICE_BUTTON_MOTION],cls);
      if (cls) eventList[nEventListCnt++] = cls;
      DeviceButton1Motion(pDev,
                  gnInputEvent[INPUTEVENT_DEVICE_BUTTON1_MOTION],cls);
      if (cls) eventList[nEventListCnt++] = cls;
      DeviceButton2Motion(pDev,
                  gnInputEvent[INPUTEVENT_DEVICE_BUTTON2_MOTION],cls);
      if (cls) eventList[nEventListCnt++] = cls;
      DeviceButton3Motion(pDev,
                  gnInputEvent[INPUTEVENT_DEVICE_BUTTON3_MOTION],cls);
      if (cls) eventList[nEventListCnt++] = cls;
      DeviceButton4Motion(pDev,
                  gnInputEvent[INPUTEVENT_DEVICE_BUTTON4_MOTION],cls);
      if (cls) eventList[nEventListCnt++] = cls;
      DeviceButton5Motion(pDev,
                  gnInputEvent[INPUTEVENT_DEVICE_BUTTON5_MOTION],cls);
      if (cls) eventList[nEventListCnt++] = cls;

      /* specify which events to report */
      /* XSelectInput(pDisp,wnd,0x00FFFFFF ^ PointerMotionHintMask); */
      /* XSelectExtensionEvent(pDisp,wnd,eventList,nEventListCnt); */

      /* grab device - work whether pointer is in active window or not */
      XGrabDevice(pDisp,pDev,wnd,
                  0, /* no owner events */
                  nEventListCnt, eventList, /* events */
                  GrabModeAsync, /* don't queue, give me whatever you got */
                  GrabModeAsync, /* same */
                  CurrentTime);

      /* fire up the UI */
      if ((nRtn=pUI->Init()) != 0)
            fprintf(stderr,"failed to initialize UI\n");
      else
      {
            if ((nRtn=pUI->Run(pDisp,pDevInfo,fmt)) != 0)
                  fprintf(stderr,"failed to run UI\n");
            pUI->Term();
      }

      XUngrabDevice(pDisp,pDev,CurrentTime);
      XCloseDevice(pDisp,pDev);
      XDestroyWindow(pDisp,wnd);

      return nRtn;
}

/*****************************************************************************
** main
*****************************************************************************/

int main(int argc, char** argv)
{
      int nRtn;
      int bList = 0;
      UI* pUI=NULL, **ppUI;
      FORMAT* pFmt;
      FORMATTYPE fmt=FORMATTYPE_DEFAULT;
      const char* pa;
      Display* pDisp = NULL;
      const char* pszDeviceName = NULL;

      ++argv;
      while ((pa = *(argv++)) != NULL)
      {
            if (pa[0] == '-')
            {
                  if ((strcmp(pa,"-h") == 0) || (strcmp(pa,"--help") == 0))
                        Usage(0);
                  else if ((strcmp(pa,"-v") == 0) || (strcmp(pa,"--verbose") == 0))
                        ++gnVerbose;
                  else if ((strcmp(pa,"-V") == 0) || (strcmp(pa,"--version") == 0))
                        { Version(); exit(0); }
                  else if ((strcmp(pa,"-l") == 0) || (strcmp(pa,"--list") == 0))
                        bList = 1;
                  else if ((strcmp(pa,"-f") == 0) || (strcmp(pa,"--format") == 0))
                  {
                        pa = *(argv++);
                        if (!pa) Fatal("Missing format argument\n");

                        /* find format by name */
                        for (pFmt = gFormats; pFmt->pszName!=NULL; ++pFmt)
                        {
                              if (strcmp(pa,pFmt->pszName) == 0)
                              {
                                    fmt = pFmt->type;
                                    break;
                              }
                        }

                        /* bad format type, die */
                        if (!pFmt->pszName)
                              Fatal("Unknown format option %s\n",pa);
                  }
                  else if ((strcmp(pa,"-s") == 0) || (strcmp(pa,"--suppress") == 0))
                  {
                        pa = *(argv++);
                        if (!pa) Fatal("Missing suppress argument\n");

                        gnSuppress = atoi(pa);
                        if (gnSuppress <= 0)
                              Fatal("Invalid suppress value\n");
                  }
                  else if ((strcmp(pa,"-u") == 0) || (strcmp(pa,"--ui") == 0))
                  {
                        pa = *(argv++);
                        if (!pa) Fatal("Missing ui argument\n");

                        /* find ui by name */
                        pUI = NULL;
                        for (ppUI = gpUIs; *ppUI!=NULL; ++ppUI)
                        {
                              if (strcmp(pa,(*ppUI)->pszName) == 0)
                                    pUI = *ppUI;
                        }

                        /* bad ui type, die */
                        if (!pUI)
                              Fatal("Unknown ui option %s; was it configured?\n",pa);
                  }
                  else
                        Fatal("Unknown option %s\n",pa);
            }
            else if (!pszDeviceName)
                  pszDeviceName = pa;
            else
                  Fatal("Unknown argument %s\n",pa);
      }

      /* device must be specified */
      if (!pszDeviceName && !bList)
      {
            fprintf(stderr,"input_device not specified\n");
            Usage(1);
      }

      /* default to first valid UI, if not specified */
      if (pUI == NULL)
            pUI = gpUIs[0];
      
      /* open connection to XServer with XInput */
      pDisp = InitXInput();
      if (!pDisp) exit(1);

      if (bList)
            nRtn = ListDevices(pDisp,pszDeviceName);
      else
            nRtn = Run(pDisp,pUI,fmt,pszDeviceName);

      /* release device list */
      if (gpDevList)
            XFreeDeviceList(gpDevList);

      XCloseDisplay(pDisp);

      return nRtn;
}

Generated by  Doxygen 1.6.0   Back to index