Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

glut_input.c

Go to the documentation of this file.
00001 
00002 /* Copyright (c) Mark J. Kilgard, 1994. */
00003 
00004 /* This program is freely distributable without licensing fees
00005    and is provided without guarantee or warrantee expressed or
00006    implied. This program is -not- in the public domain. */
00007 
00008 #include <assert.h>
00009 #include <stdio.h>
00010 #include <stdlib.h>
00011 #include <string.h>
00012 
00013 #include <X11/Xlib.h>
00014 #if defined(__vms)
00015 #include <X11/XInput.h>
00016 #else
00017 #include <X11/extensions/XInput.h>
00018 #endif
00019 #include <X11/Xutil.h>
00020 
00021 #include "glutint.h"
00022 
00023 int __glutNumDials = 0;
00024 int __glutNumSpaceballButtons = 0;
00025 int __glutNumButtonBoxButtons = 0;
00026 int __glutNumTabletButtons = 0;
00027 int __glutNumMouseButtons = 3;  /* Good guess. */
00028 XDevice *__glutTablet = NULL;
00029 XDevice *__glutDials = NULL;
00030 XDevice *__glutSpaceball = NULL;
00031 
00032 typedef struct _Range {
00033   int min;
00034   int range;
00035 } Range;
00036 
00037 #define NUM_SPACEBALL_AXIS      6
00038 #define NUM_TABLET_AXIS         2
00039 #define NUM_DIALS_AXIS          8
00040 
00041 Range __glutSpaceballRange[NUM_SPACEBALL_AXIS];
00042 Range __glutTabletRange[NUM_TABLET_AXIS];
00043 int *__glutDialsResolution;
00044 
00045 /* Safely assumes 0 is an illegal event type for X Input
00046    extension events. */
00047 int __glutDeviceMotionNotify = 0;
00048 int __glutDeviceButtonPress = 0;
00049 int __glutDeviceButtonPressGrab = 0;
00050 int __glutDeviceButtonRelease = 0;
00051 int __glutDeviceStateNotify = 0;
00052 
00053 static int
00054 normalizeTabletPos(int axis, int rawValue)
00055 {
00056   assert(rawValue >= __glutTabletRange[axis].min);
00057   assert(rawValue <= __glutTabletRange[axis].min + __glutTabletRange[axis].range);
00058   /* Normalize rawValue to between 0 and 4000. */
00059   return ((rawValue - __glutTabletRange[axis].min) * 4000) /
00060     __glutTabletRange[axis].range;
00061 }
00062 
00063 static int
00064 normalizeDialAngle(int axis, int rawValue)
00065 {
00066   /* XXX Assumption made that the resolution of the device is
00067      number of clicks for one complete dial revolution.  This
00068      is true for SGI's dial & button box. */
00069   return (rawValue * 360.0) / __glutDialsResolution[axis];
00070 }
00071 
00072 static int
00073 normalizeSpaceballAngle(int axis, int rawValue)
00074 {
00075   assert(rawValue >= __glutSpaceballRange[axis].min);
00076   assert(rawValue <= __glutSpaceballRange[axis].min +
00077     __glutSpaceballRange[axis].range);
00078   /* normalize rawValue to between -1800 and 1800 */
00079   return ((rawValue - __glutSpaceballRange[axis].min) * 3600) /
00080     __glutSpaceballRange[axis].range - 1800;
00081 }
00082 
00083 static int
00084 normalizeSpaceballDelta(int axis, int rawValue)
00085 {
00086   assert(rawValue >= __glutSpaceballRange[axis].min);
00087   assert(rawValue <= __glutSpaceballRange[axis].min +
00088     __glutSpaceballRange[axis].range);
00089   /* normalize rawValue to between -1000 and 1000 */
00090   return ((rawValue - __glutSpaceballRange[axis].min) * 2000) /
00091     __glutSpaceballRange[axis].range - 1000;
00092 }
00093 
00094 static void
00095 queryTabletPos(GLUTwindow * window)
00096 {
00097   XDeviceState *state;
00098   XInputClass *any;
00099   XValuatorState *v;
00100   int i;
00101 
00102   state = XQueryDeviceState(__glutDisplay, __glutTablet);
00103   any = state->data;
00104   for (i = 0; i < state->num_classes; i++) {
00105     switch (any->class) {
00106     case ValuatorClass:
00107       v = (XValuatorState *) any;
00108       if (v->num_valuators < 2)
00109         goto end;
00110       if (window->tabletPos[0] == -1)
00111         window->tabletPos[0] = normalizeTabletPos(0, v->valuators[0]);
00112       if (window->tabletPos[1] == -1)
00113         window->tabletPos[1] = normalizeTabletPos(1, v->valuators[1]);
00114     }
00115     any = (XInputClass *) ((char *) any + any->length);
00116   }
00117 end:
00118   XFreeDeviceState(state);
00119 }
00120 
00121 static void
00122 tabletPosChange(GLUTwindow * window, int first, int count, int *data)
00123 {
00124   int i, value, genEvent = 0;
00125 
00126   for (i = first; i < first + count; i++) {
00127     switch (i) {
00128     case 0:            /* X axis */
00129     case 1:            /* Y axis */
00130       value = normalizeTabletPos(i, data[i - first]);
00131       if (value != window->tabletPos[i]) {
00132         window->tabletPos[i] = value;
00133         genEvent = 1;
00134       }
00135       break;
00136     }
00137   }
00138   if (window->tabletPos[0] == -1 || window->tabletPos[1] == -1)
00139     queryTabletPos(window);
00140   if (genEvent)
00141     window->tabletMotion(window->tabletPos[0], window->tabletPos[1]);
00142 }
00143 
00144 int
00145 __glutProcessDeviceEvents(XEvent * event)
00146 {
00147   GLUTwindow *window;
00148 
00149   /* XXX Ugly code fan out. */
00150 
00151   /* Can't use switch/case since X Input event types are
00152      dynamic. */
00153 
00154   if (__glutDeviceMotionNotify && event->type == __glutDeviceMotionNotify) {
00155     XDeviceMotionEvent *devmot = (XDeviceMotionEvent *) event;
00156 
00157     window = __glutGetWindow(devmot->window);
00158     if (window) {
00159       if (__glutTablet
00160         && devmot->deviceid == __glutTablet->device_id
00161         && window->tabletMotion) {
00162         tabletPosChange(window, devmot->first_axis, devmot->axes_count,
00163           devmot->axis_data);
00164       } else if (__glutDials
00165           && devmot->deviceid == __glutDials->device_id
00166         && window->dials) {
00167         int i, first = devmot->first_axis, count = devmot->axes_count;
00168 
00169         for (i = first; i < first + count; i++)
00170           window->dials(i + 1, normalizeDialAngle(i, devmot->axis_data[i - first]));
00171       } else if (__glutSpaceball
00172         && devmot->deviceid == __glutSpaceball->device_id) {
00173         /* XXX Assume that space ball motion events come in as
00174            all the first 6 axes.  Assume first 3 axes are XYZ
00175            translations; second 3 axes are XYZ rotations. */
00176         if (devmot->first_axis == 0 && devmot->axes_count == 6) {
00177           if (window->spaceMotion)
00178             window->spaceMotion(normalizeSpaceballDelta(0, devmot->axis_data[0]),
00179               normalizeSpaceballDelta(1, devmot->axis_data[1]),
00180               normalizeSpaceballDelta(2, devmot->axis_data[2]));
00181           if (window->spaceRotate)
00182             window->spaceRotate(normalizeSpaceballAngle(3, devmot->axis_data[3]),
00183               normalizeSpaceballAngle(4, devmot->axis_data[4]),
00184               normalizeSpaceballAngle(5, devmot->axis_data[5]));
00185         }
00186       }
00187       return 1;
00188     }
00189   } else if (__glutDeviceButtonPress && event->type == __glutDeviceButtonPress) {
00190     XDeviceButtonEvent *devbtn = (XDeviceButtonEvent *) event;
00191 
00192     window = __glutGetWindow(devbtn->window);
00193     if (window) {
00194       if (__glutTablet
00195         && devbtn->deviceid == __glutTablet->device_id
00196         && window->tabletButton
00197         && devbtn->first_axis == 0
00198         && devbtn->axes_count == 2) {
00199         tabletPosChange(window, devbtn->first_axis, devbtn->axes_count,
00200           devbtn->axis_data);
00201         window->tabletButton(devbtn->button, GLUT_DOWN,
00202           window->tabletPos[0], window->tabletPos[1]);
00203       } else if (__glutDials
00204           && devbtn->deviceid == __glutDials->device_id
00205         && window->buttonBox) {
00206         window->buttonBox(devbtn->button, GLUT_DOWN);
00207       } else if (__glutSpaceball
00208           && devbtn->deviceid == __glutSpaceball->device_id
00209         && window->spaceButton) {
00210         window->spaceButton(devbtn->button, GLUT_DOWN);
00211       }
00212       return 1;
00213     }
00214   } else if (__glutDeviceButtonRelease && event->type == __glutDeviceButtonRelease) {
00215     XDeviceButtonEvent *devbtn = (XDeviceButtonEvent *) event;
00216 
00217     window = __glutGetWindow(devbtn->window);
00218     if (window) {
00219       if (__glutTablet
00220         && devbtn->deviceid == __glutTablet->device_id
00221         && window->tabletButton
00222         && devbtn->first_axis == 0
00223         && devbtn->axes_count == 2) {
00224         tabletPosChange(window, devbtn->first_axis, devbtn->axes_count,
00225           devbtn->axis_data);
00226         window->tabletButton(devbtn->button, GLUT_UP,
00227           window->tabletPos[0], window->tabletPos[1]);
00228       } else if (__glutDials
00229           && devbtn->deviceid == __glutDials->device_id
00230         && window->buttonBox) {
00231         window->buttonBox(devbtn->button, GLUT_UP);
00232       } else if (__glutSpaceball
00233           && devbtn->deviceid == __glutSpaceball->device_id
00234         && window->spaceButton) {
00235         window->spaceButton(devbtn->button, GLUT_UP);
00236       }
00237       return 1;
00238     }
00239   }
00240   return 0;
00241 }
00242 
00243 static GLUTeventParser eventParser =
00244 {__glutProcessDeviceEvents, NULL};
00245 
00246 static void
00247 addDeviceEventParser(void)
00248 {
00249   static Bool been_here = False;
00250 
00251   if (been_here)
00252     return;
00253   been_here = True;
00254   __glutRegisterEventParser(&eventParser);
00255 }
00256 
00257 static int
00258 probeDevices(void)
00259 {
00260   static Bool been_here = False;
00261   static int support;
00262   XExtensionVersion *version;
00263   XDeviceInfoPtr device_info, device;
00264   XAnyClassPtr any;
00265   XButtonInfoPtr b;
00266   XValuatorInfoPtr v;
00267   XAxisInfoPtr a;
00268   int num_dev, btns, dials;
00269   int i, j, k;
00270 
00271   if (been_here) {
00272     return support;
00273   }
00274   been_here = True;
00275   version = XGetExtensionVersion(__glutDisplay, "XInputExtension");
00276   if (version == NULL || ((int) version) == NoSuchExtension) {
00277     support = 0;
00278     return support;
00279   }
00280   XFree(version);
00281   device_info = XListInputDevices(__glutDisplay, &num_dev);
00282   if (device_info) {
00283     for (i = 0; i < num_dev; i++) {
00284       /* XXX These are SGI names for these devices;
00285          unfortunately, no good standard exists for standard
00286          types of X input extension devices. */
00287 
00288       device = &device_info[i];
00289       any = (XAnyClassPtr) device->inputclassinfo;
00290 
00291       if (!__glutSpaceball && !strcmp(device->name, "spaceball")) {
00292         v = NULL;
00293         b = NULL;
00294         for (j = 0; j < device->num_classes; j++) {
00295           switch (any->class) {
00296           case ButtonClass:
00297             b = (XButtonInfoPtr) any;
00298             btns = b->num_buttons;
00299             break;
00300           case ValuatorClass:
00301             v = (XValuatorInfoPtr) any;
00302             /* Sanity check: at least 6 valuators? */
00303             if (v->num_axes < NUM_SPACEBALL_AXIS)
00304               goto skip_device;
00305             a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo));
00306             for (k = 0; k < NUM_SPACEBALL_AXIS; k++, a++) {
00307               __glutSpaceballRange[k].min = a->min_value;
00308               __glutSpaceballRange[k].range = a->max_value - a->min_value;
00309             }
00310             break;
00311           }
00312           any = (XAnyClassPtr) ((char *) any + any->length);
00313         }
00314         if (v) {
00315           __glutSpaceball = XOpenDevice(__glutDisplay, device->id);
00316           if (__glutSpaceball) {
00317             __glutNumSpaceballButtons = btns;
00318             addDeviceEventParser();
00319           }
00320         }
00321       } else if (!__glutDials && !strcmp(device->name, "dial+buttons")) {
00322         v = NULL;
00323         b = NULL;
00324         for (j = 0; j < device->num_classes; j++) {
00325           switch (any->class) {
00326           case ButtonClass:
00327             b = (XButtonInfoPtr) any;
00328             btns = b->num_buttons;
00329             break;
00330           case ValuatorClass:
00331             v = (XValuatorInfoPtr) any;
00332             /* Sanity check: at least 8 valuators? */
00333             if (v->num_axes < NUM_DIALS_AXIS)
00334               goto skip_device;
00335             dials = v->num_axes;
00336             __glutDialsResolution = (int *) malloc(sizeof(int) * dials);
00337             a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo));
00338             for (k = 0; k < dials; k++, a++) {
00339               __glutDialsResolution[k] = a->resolution;
00340             }
00341             break;
00342           }
00343           any = (XAnyClassPtr) ((char *) any + any->length);
00344         }
00345         if (v) {
00346           __glutDials = XOpenDevice(__glutDisplay, device->id);
00347           if (__glutDials) {
00348             __glutNumButtonBoxButtons = btns;
00349             __glutNumDials = dials;
00350             addDeviceEventParser();
00351           }
00352         }
00353       } else if (!__glutTablet && !strcmp(device->name, "tablet")) {
00354         v = NULL;
00355         b = NULL;
00356         for (j = 0; j < device->num_classes; j++) {
00357           switch (any->class) {
00358           case ButtonClass:
00359             b = (XButtonInfoPtr) any;
00360             btns = b->num_buttons;
00361             break;
00362           case ValuatorClass:
00363             v = (XValuatorInfoPtr) any;
00364             /* Sanity check: exactly 2 valuators? */
00365             if (v->num_axes != NUM_TABLET_AXIS)
00366               goto skip_device;
00367             a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo));
00368             for (k = 0; k < NUM_TABLET_AXIS; k++, a++) {
00369               __glutTabletRange[k].min = a->min_value;
00370               __glutTabletRange[k].range = a->max_value - a->min_value;
00371             }
00372             break;
00373           }
00374           any = (XAnyClassPtr) ((char *) any + any->length);
00375         }
00376         if (v) {
00377           __glutTablet = XOpenDevice(__glutDisplay, device->id);
00378           if (__glutTablet) {
00379             __glutNumTabletButtons = btns;
00380             addDeviceEventParser();
00381           }
00382         }
00383       } else if (!strcmp(device->name, "mouse")) {
00384         for (j = 0; j < device->num_classes; j++) {
00385           if (any->class == ButtonClass) {
00386             b = (XButtonInfoPtr) any;
00387             __glutNumMouseButtons = b->num_buttons;
00388           }
00389           any = (XAnyClassPtr) ((char *) any + any->length);
00390         }
00391       }
00392     skip_device:;
00393     }
00394     XFreeDeviceList(device_info);
00395   }
00396   /* X Input extension might be supported, but only if there is
00397      a tablet, dials, or spaceball do we claim devices are
00398      supported. */
00399   support = __glutTablet || __glutDials || __glutSpaceball;
00400   return support;
00401 }
00402 
00403 void
00404 __glutUpdateInputDeviceMask(GLUTwindow * window)
00405 {
00406   /* 5 (dial and buttons) + 5 (tablet locator and buttons) + 5
00407      (Spaceball buttons and axis) = 15 */
00408   XEventClass eventList[15];
00409   int rc, numEvents;
00410 
00411   rc = probeDevices();
00412   if (rc) {
00413     numEvents = 0;
00414     if (__glutTablet) {
00415       if (window->tabletMotion) {
00416         DeviceMotionNotify(__glutTablet, __glutDeviceMotionNotify,
00417           eventList[numEvents]);
00418         numEvents++;
00419       }
00420       if (window->tabletButton) {
00421         DeviceButtonPress(__glutTablet, __glutDeviceButtonPress,
00422           eventList[numEvents]);
00423         numEvents++;
00424         DeviceButtonPressGrab(__glutTablet, __glutDeviceButtonPressGrab,
00425           eventList[numEvents]);
00426         numEvents++;
00427         DeviceButtonRelease(__glutTablet, __glutDeviceButtonRelease,
00428           eventList[numEvents]);
00429         numEvents++;
00430       }
00431       if (window->tabletMotion || window->tabletButton) {
00432         DeviceStateNotify(__glutTablet, __glutDeviceStateNotify,
00433           eventList[numEvents]);
00434         numEvents++;
00435       }
00436     }
00437     if (__glutDials) {
00438       if (window->dials) {
00439         DeviceMotionNotify(__glutDials, __glutDeviceMotionNotify,
00440           eventList[numEvents]);
00441         numEvents++;
00442       }
00443       if (window->buttonBox) {
00444         DeviceButtonPress(__glutDials, __glutDeviceButtonPress,
00445           eventList[numEvents]);
00446         numEvents++;
00447         DeviceButtonPressGrab(__glutDials, __glutDeviceButtonPressGrab,
00448           eventList[numEvents]);
00449         numEvents++;
00450         DeviceButtonRelease(__glutDials, __glutDeviceButtonRelease,
00451           eventList[numEvents]);
00452         numEvents++;
00453       }
00454       if (window->dials || window->buttonBox) {
00455         DeviceStateNotify(__glutDials, __glutDeviceStateNotify,
00456           eventList[numEvents]);
00457         numEvents++;
00458       }
00459     }
00460     if (__glutSpaceball) {
00461       if (window->spaceMotion || window->spaceRotate) {
00462         DeviceMotionNotify(__glutSpaceball, __glutDeviceMotionNotify,
00463           eventList[numEvents]);
00464         numEvents++;
00465       }
00466       if (window->spaceButton) {
00467         DeviceButtonPress(__glutSpaceball, __glutDeviceButtonPress,
00468           eventList[numEvents]);
00469         numEvents++;
00470         DeviceButtonPressGrab(__glutSpaceball, __glutDeviceButtonPressGrab,
00471           eventList[numEvents]);
00472         numEvents++;
00473         DeviceButtonRelease(__glutSpaceball, __glutDeviceButtonRelease,
00474           eventList[numEvents]);
00475         numEvents++;
00476       }
00477       if (window->spaceMotion || window->spaceRotate || window->spaceButton) {
00478         DeviceStateNotify(__glutSpaceball, __glutDeviceStateNotify,
00479           eventList[numEvents]);
00480         numEvents++;
00481       }
00482     }
00483 #if 0
00484     if (window->children) {
00485       GLUTwindow *child = window->children;
00486 
00487       do {
00488         XChangeDeviceDontPropagateList(__glutDisplay, child->win,
00489           numEvents, eventList, AddToList);
00490         child = child->siblings;
00491       } while (child);
00492     }
00493 #endif
00494     XSelectExtensionEvent(__glutDisplay, window->win,
00495       eventList, numEvents);
00496     if (window->overlay) {
00497       XSelectExtensionEvent(__glutDisplay, window->overlay->win,
00498         eventList, numEvents);
00499     }
00500   } else {
00501     /* X Input extension not supported; no chance for exotic
00502        input devices. */
00503   }
00504 }
00505 
00506 glutDeviceGet(GLenum param)
00507 {
00508   probeDevices();
00509   switch (param) {
00510   case GLUT_HAS_KEYBOARD:
00511   case GLUT_HAS_MOUSE:
00512     /* Assume X always has mouse and keyboard. */
00513     return 1;
00514   case GLUT_HAS_SPACEBALL:
00515     return __glutSpaceball != NULL;
00516   case GLUT_HAS_DIAL_AND_BUTTON_BOX:
00517     return __glutDials != NULL;
00518   case GLUT_HAS_TABLET:
00519     return __glutTablet != NULL;
00520   case GLUT_NUM_MOUSE_BUTTONS:
00521     return __glutNumMouseButtons;
00522   case GLUT_NUM_SPACEBALL_BUTTONS:
00523     return __glutNumSpaceballButtons;
00524   case GLUT_NUM_BUTTON_BOX_BUTTONS:
00525     return __glutNumButtonBoxButtons;
00526   case GLUT_NUM_DIALS:
00527     return __glutNumDials;
00528   case GLUT_NUM_TABLET_BUTTONS:
00529     return __glutNumTabletButtons;
00530   default:
00531     __glutWarning("invalid glutDeviceGet parameter: %d", param);
00532     return -1;
00533   }
00534 }
 

Powered by Plone

This site conforms to the following standards: