home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / exampleCode / opengl / GLUT / lib / fglut / glut_input.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-11  |  16.5 KB  |  535 lines

  1. /* Copyright (c) Mark J. Kilgard, 1994. */
  2.  
  3. /* This program is freely distributable without licensing fees
  4.    and is provided without guarantee or warrantee expressed or
  5.    implied. This program is -not- in the public domain. */
  6. #include <assert.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10.  
  11. #include <X11/Xlib.h>
  12. #if defined(__vms)
  13. #include <X11/XInput.h>
  14. #else
  15. #include <X11/extensions/XInput.h>
  16. #endif
  17. #include <X11/Xutil.h>
  18.  
  19. #include "glutint.h"
  20.  
  21. int __glutNumDials = 0;
  22. int __glutNumSpaceballButtons = 0;
  23. int __glutNumButtonBoxButtons = 0;
  24. int __glutNumTabletButtons = 0;
  25. int __glutNumMouseButtons = 3;  /* Good guess. */
  26. XDevice *__glutTablet = NULL;
  27. XDevice *__glutDials = NULL;
  28. XDevice *__glutSpaceball = NULL;
  29.  
  30. typedef struct _Range {
  31.   int min;
  32.   int range;
  33. } Range;
  34.  
  35. #define NUM_SPACEBALL_AXIS    6
  36. #define NUM_TABLET_AXIS        2
  37. #define NUM_DIALS_AXIS        8
  38.  
  39. Range __glutSpaceballRange[NUM_SPACEBALL_AXIS];
  40. Range __glutTabletRange[NUM_TABLET_AXIS];
  41. int *__glutDialsResolution;
  42.  
  43. /* Safely assumes 0 is an illegal event type for X Input
  44.    extension events. */
  45. int __glutDeviceMotionNotify = 0;
  46. int __glutDeviceButtonPress = 0;
  47. int __glutDeviceButtonPressGrab = 0;
  48. int __glutDeviceButtonRelease = 0;
  49. int __glutDeviceStateNotify = 0;
  50.  
  51. static int
  52. normalizeTabletPos(int axis, int rawValue)
  53. {
  54.   assert(rawValue >= __glutTabletRange[axis].min);
  55.   assert(rawValue <= __glutTabletRange[axis].min + __glutTabletRange[axis].range);
  56.   /* Normalize rawValue to between 0 and 4000. */
  57.   return ((rawValue - __glutTabletRange[axis].min) * 4000) /
  58.     __glutTabletRange[axis].range;
  59. }
  60.  
  61. static int
  62. normalizeDialAngle(int axis, int rawValue)
  63. {
  64.   /* XXX Assumption made that the resolution of the device is
  65.      number of clicks for one complete dial revolution.  This
  66.      is true for SGI's dial & button box. */
  67.   return (rawValue * 360.0) / __glutDialsResolution[axis];
  68. }
  69.  
  70. static int
  71. normalizeSpaceballAngle(int axis, int rawValue)
  72. {
  73.   assert(rawValue >= __glutSpaceballRange[axis].min);
  74.   assert(rawValue <= __glutSpaceballRange[axis].min +
  75.     __glutSpaceballRange[axis].range);
  76.   /* normalize rawValue to between -1800 and 1800 */
  77.   return ((rawValue - __glutSpaceballRange[axis].min) * 3600) /
  78.     __glutSpaceballRange[axis].range - 1800;
  79. }
  80.  
  81. static int
  82. normalizeSpaceballDelta(int axis, int rawValue)
  83. {
  84.   assert(rawValue >= __glutSpaceballRange[axis].min);
  85.   assert(rawValue <= __glutSpaceballRange[axis].min +
  86.     __glutSpaceballRange[axis].range);
  87.   /* normalize rawValue to between -1000 and 1000 */
  88.   return ((rawValue - __glutSpaceballRange[axis].min) * 2000) /
  89.     __glutSpaceballRange[axis].range - 1000;
  90. }
  91.  
  92. static void
  93. queryTabletPos(GLUTwindow * window)
  94. {
  95.   XDeviceState *state;
  96.   XInputClass *any;
  97.   XValuatorState *v;
  98.   int i;
  99.  
  100.   state = XQueryDeviceState(__glutDisplay, __glutTablet);
  101.   any = state->data;
  102.   for (i = 0; i < state->num_classes; i++) {
  103.     switch (any->class) {
  104.     case ValuatorClass:
  105.       v = (XValuatorState *) any;
  106.       if (v->num_valuators < 2)
  107.         goto end;
  108.       if (window->tabletPos[0] == -1)
  109.         window->tabletPos[0] = normalizeTabletPos(0, v->valuators[0]);
  110.       if (window->tabletPos[1] == -1)
  111.         window->tabletPos[1] = normalizeTabletPos(1, v->valuators[1]);
  112.     }
  113.     any = (XInputClass *) ((char *) any + any->length);
  114.   }
  115. end:
  116.   XFreeDeviceState(state);
  117. }
  118.  
  119. static void
  120. tabletPosChange(GLUTwindow * window, int first, int count, int *data)
  121. {
  122.   int i, value, genEvent = 0;
  123.  
  124.   for (i = first; i < first + count; i++) {
  125.     switch (i) {
  126.     case 0:            /* X axis */
  127.     case 1:            /* Y axis */
  128.       value = normalizeTabletPos(i, data[i - first]);
  129.       if (value != window->tabletPos[i]) {
  130.         window->tabletPos[i] = value;
  131.         genEvent = 1;
  132.       }
  133.       break;
  134.     }
  135.   }
  136.   if (window->tabletPos[0] == -1 || window->tabletPos[1] == -1)
  137.     queryTabletPos(window);
  138.   if (genEvent)
  139.     window->tabletMotion(window->tabletPos[0], window->tabletPos[1]);
  140. }
  141.  
  142. int
  143. __glutProcessDeviceEvents(XEvent * event)
  144. {
  145.   GLUTwindow *window;
  146.  
  147.   /* XXX Ugly code fan out. */
  148.  
  149.   /* Can't use switch/case since X Input event types are
  150.      dynamic. */
  151.  
  152.   if (__glutDeviceMotionNotify && event->type == __glutDeviceMotionNotify) {
  153.     XDeviceMotionEvent *devmot = (XDeviceMotionEvent *) event;
  154.  
  155.     window = __glutGetWindow(devmot->window);
  156.     if (window) {
  157.       if (__glutTablet
  158.         && devmot->deviceid == __glutTablet->device_id
  159.         && window->tabletMotion) {
  160.         tabletPosChange(window, devmot->first_axis, devmot->axes_count,
  161.           devmot->axis_data);
  162.       } else if (__glutDials
  163.           && devmot->deviceid == __glutDials->device_id
  164.         && window->dials) {
  165.         int i, first = devmot->first_axis, count = devmot->axes_count;
  166.  
  167.         for (i = first; i < first + count; i++)
  168.           window->dials(i + 1, normalizeDialAngle(i, devmot->axis_data[i - first]));
  169.       } else if (__glutSpaceball
  170.         && devmot->deviceid == __glutSpaceball->device_id) {
  171.         /* XXX Assume that space ball motion events come in as
  172.            all the first 6 axes.  Assume first 3 axes are XYZ
  173.            translations; second 3 axes are XYZ rotations. */
  174.         if (devmot->first_axis == 0 && devmot->axes_count == 6) {
  175.           if (window->spaceMotion)
  176.             window->spaceMotion(normalizeSpaceballDelta(0, devmot->axis_data[0]),
  177.               normalizeSpaceballDelta(1, devmot->axis_data[1]),
  178.               normalizeSpaceballDelta(2, devmot->axis_data[2]));
  179.           if (window->spaceRotate)
  180.             window->spaceRotate(normalizeSpaceballAngle(3, devmot->axis_data[3]),
  181.               normalizeSpaceballAngle(4, devmot->axis_data[4]),
  182.               normalizeSpaceballAngle(5, devmot->axis_data[5]));
  183.         }
  184.       }
  185.       return 1;
  186.     }
  187.   } else if (__glutDeviceButtonPress && event->type == __glutDeviceButtonPress) {
  188.     XDeviceButtonEvent *devbtn = (XDeviceButtonEvent *) event;
  189.  
  190.     window = __glutGetWindow(devbtn->window);
  191.     if (window) {
  192.       if (__glutTablet
  193.         && devbtn->deviceid == __glutTablet->device_id
  194.         && window->tabletButton
  195.         && devbtn->first_axis == 0
  196.         && devbtn->axes_count == 2) {
  197.         tabletPosChange(window, devbtn->first_axis, devbtn->axes_count,
  198.           devbtn->axis_data);
  199.         window->tabletButton(devbtn->button, GLUT_DOWN,
  200.           window->tabletPos[0], window->tabletPos[1]);
  201.       } else if (__glutDials
  202.           && devbtn->deviceid == __glutDials->device_id
  203.         && window->buttonBox) {
  204.         window->buttonBox(devbtn->button, GLUT_DOWN);
  205.       } else if (__glutSpaceball
  206.           && devbtn->deviceid == __glutSpaceball->device_id
  207.         && window->spaceButton) {
  208.         window->spaceButton(devbtn->button, GLUT_DOWN);
  209.       }
  210.       return 1;
  211.     }
  212.   } else if (__glutDeviceButtonRelease && event->type == __glutDeviceButtonRelease) {
  213.     XDeviceButtonEvent *devbtn = (XDeviceButtonEvent *) event;
  214.  
  215.     window = __glutGetWindow(devbtn->window);
  216.     if (window) {
  217.       if (__glutTablet
  218.         && devbtn->deviceid == __glutTablet->device_id
  219.         && window->tabletButton
  220.         && devbtn->first_axis == 0
  221.         && devbtn->axes_count == 2) {
  222.         tabletPosChange(window, devbtn->first_axis, devbtn->axes_count,
  223.           devbtn->axis_data);
  224.         window->tabletButton(devbtn->button, GLUT_UP,
  225.           window->tabletPos[0], window->tabletPos[1]);
  226.       } else if (__glutDials
  227.           && devbtn->deviceid == __glutDials->device_id
  228.         && window->buttonBox) {
  229.         window->buttonBox(devbtn->button, GLUT_UP);
  230.       } else if (__glutSpaceball
  231.           && devbtn->deviceid == __glutSpaceball->device_id
  232.         && window->spaceButton) {
  233.         window->spaceButton(devbtn->button, GLUT_UP);
  234.       }
  235.       return 1;
  236.     }
  237.   }
  238.   return 0;
  239. }
  240.  
  241. static GLUTeventParser eventParser =
  242. {__glutProcessDeviceEvents, NULL};
  243.  
  244. static void
  245. addDeviceEventParser(void)
  246. {
  247.   static Bool been_here = False;
  248.  
  249.   if (been_here)
  250.     return;
  251.   been_here = True;
  252.   __glutRegisterEventParser(&eventParser);
  253. }
  254.  
  255. static int
  256. probeDevices(void)
  257. {
  258.   static Bool been_here = False;
  259.   static int support;
  260.   XExtensionVersion *version;
  261.   XDeviceInfoPtr device_info, device;
  262.   XAnyClassPtr any;
  263.   XButtonInfoPtr b;
  264.   XValuatorInfoPtr v;
  265.   XAxisInfoPtr a;
  266.   int num_dev, btns, dials;
  267.   int i, j, k;
  268.  
  269.   if (been_here) {
  270.     return support;
  271.   }
  272.   been_here = True;
  273.   version = XGetExtensionVersion(__glutDisplay, "XInputExtension");
  274.   if (version == NULL || ((int) version) == NoSuchExtension) {
  275.     support = 0;
  276.     return support;
  277.   }
  278.   XFree(version);
  279.   device_info = XListInputDevices(__glutDisplay, &num_dev);
  280.   if (device_info) {
  281.     for (i = 0; i < num_dev; i++) {
  282.       /* XXX These are SGI names for these devices;
  283.          unfortunately, no good standard exists for standard
  284.          types of X input extension devices. */
  285.  
  286.       device = &device_info[i];
  287.       any = (XAnyClassPtr) device->inputclassinfo;
  288.  
  289.       if (!__glutSpaceball && !strcmp(device->name, "spaceball")) {
  290.         v = NULL;
  291.         b = NULL;
  292.         for (j = 0; j < device->num_classes; j++) {
  293.           switch (any->class) {
  294.           case ButtonClass:
  295.             b = (XButtonInfoPtr) any;
  296.             btns = b->num_buttons;
  297.             break;
  298.           case ValuatorClass:
  299.             v = (XValuatorInfoPtr) any;
  300.             /* Sanity check: at least 6 valuators? */
  301.             if (v->num_axes < NUM_SPACEBALL_AXIS)
  302.               goto skip_device;
  303.             a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo));
  304.             for (k = 0; k < NUM_SPACEBALL_AXIS; k++, a++) {
  305.               __glutSpaceballRange[k].min = a->min_value;
  306.               __glutSpaceballRange[k].range = a->max_value - a->min_value;
  307.             }
  308.             break;
  309.           }
  310.           any = (XAnyClassPtr) ((char *) any + any->length);
  311.         }
  312.         if (v) {
  313.           __glutSpaceball = XOpenDevice(__glutDisplay, device->id);
  314.           if (__glutSpaceball) {
  315.             __glutNumSpaceballButtons = btns;
  316.             addDeviceEventParser();
  317.           }
  318.         }
  319.       } else if (!__glutDials && !strcmp(device->name, "dial+buttons")) {
  320.         v = NULL;
  321.         b = NULL;
  322.         for (j = 0; j < device->num_classes; j++) {
  323.           switch (any->class) {
  324.           case ButtonClass:
  325.             b = (XButtonInfoPtr) any;
  326.             btns = b->num_buttons;
  327.             break;
  328.           case ValuatorClass:
  329.             v = (XValuatorInfoPtr) any;
  330.             /* Sanity check: at least 8 valuators? */
  331.             if (v->num_axes < NUM_DIALS_AXIS)
  332.               goto skip_device;
  333.             dials = v->num_axes;
  334.             __glutDialsResolution = (int *) malloc(sizeof(int) * dials);
  335.             a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo));
  336.             for (k = 0; k < dials; k++, a++) {
  337.               __glutDialsResolution[k] = a->resolution;
  338.             }
  339.             break;
  340.           }
  341.           any = (XAnyClassPtr) ((char *) any + any->length);
  342.         }
  343.         if (v) {
  344.           __glutDials = XOpenDevice(__glutDisplay, device->id);
  345.           if (__glutDials) {
  346.             __glutNumButtonBoxButtons = btns;
  347.             __glutNumDials = dials;
  348.             addDeviceEventParser();
  349.           }
  350.         }
  351.       } else if (!__glutTablet && !strcmp(device->name, "tablet")) {
  352.         v = NULL;
  353.         b = NULL;
  354.         for (j = 0; j < device->num_classes; j++) {
  355.           switch (any->class) {
  356.           case ButtonClass:
  357.             b = (XButtonInfoPtr) any;
  358.             btns = b->num_buttons;
  359.             break;
  360.           case ValuatorClass:
  361.             v = (XValuatorInfoPtr) any;
  362.             /* Sanity check: exactly 2 valuators? */
  363.             if (v->num_axes != NUM_TABLET_AXIS)
  364.               goto skip_device;
  365.             a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo));
  366.             for (k = 0; k < NUM_TABLET_AXIS; k++, a++) {
  367.               __glutTabletRange[k].min = a->min_value;
  368.               __glutTabletRange[k].range = a->max_value - a->min_value;
  369.             }
  370.             break;
  371.           }
  372.           any = (XAnyClassPtr) ((char *) any + any->length);
  373.         }
  374.         if (v) {
  375.           __glutTablet = XOpenDevice(__glutDisplay, device->id);
  376.           if (__glutTablet) {
  377.             __glutNumTabletButtons = btns;
  378.             addDeviceEventParser();
  379.           }
  380.         }
  381.       } else if (!strcmp(device->name, "mouse")) {
  382.         for (j = 0; j < device->num_classes; j++) {
  383.           if (any->class == ButtonClass) {
  384.             b = (XButtonInfoPtr) any;
  385.             __glutNumMouseButtons = b->num_buttons;
  386.           }
  387.           any = (XAnyClassPtr) ((char *) any + any->length);
  388.         }
  389.       }
  390.     skip_device:;
  391.     }
  392.     XFreeDeviceList(device_info);
  393.   }
  394.   /* X Input extension might be supported, but only if there is
  395.      a tablet, dials, or spaceball do we claim devices are
  396.      supported. */
  397.   support = __glutTablet || __glutDials || __glutSpaceball;
  398.   return support;
  399. }
  400.  
  401. void
  402. __glutUpdateInputDeviceMask(GLUTwindow * window)
  403. {
  404.   /* 5 (dial and buttons) + 5 (tablet locator and buttons) + 5
  405.      (Spaceball buttons and axis) = 15 */
  406.   XEventClass eventList[15];
  407.   int rc, numEvents;
  408.  
  409.   rc = probeDevices();
  410.   if (rc) {
  411.     numEvents = 0;
  412.     if (__glutTablet) {
  413.       if (window->tabletMotion) {
  414.         DeviceMotionNotify(__glutTablet, __glutDeviceMotionNotify,
  415.           eventList[numEvents]);
  416.         numEvents++;
  417.       }
  418.       if (window->tabletButton) {
  419.         DeviceButtonPress(__glutTablet, __glutDeviceButtonPress,
  420.           eventList[numEvents]);
  421.         numEvents++;
  422.         DeviceButtonPressGrab(__glutTablet, __glutDeviceButtonPressGrab,
  423.           eventList[numEvents]);
  424.         numEvents++;
  425.         DeviceButtonRelease(__glutTablet, __glutDeviceButtonRelease,
  426.           eventList[numEvents]);
  427.         numEvents++;
  428.       }
  429.       if (window->tabletMotion || window->tabletButton) {
  430.         DeviceStateNotify(__glutTablet, __glutDeviceStateNotify,
  431.           eventList[numEvents]);
  432.         numEvents++;
  433.       }
  434.     }
  435.     if (__glutDials) {
  436.       if (window->dials) {
  437.         DeviceMotionNotify(__glutDials, __glutDeviceMotionNotify,
  438.           eventList[numEvents]);
  439.         numEvents++;
  440.       }
  441.       if (window->buttonBox) {
  442.         DeviceButtonPress(__glutDials, __glutDeviceButtonPress,
  443.           eventList[numEvents]);
  444.         numEvents++;
  445.         DeviceButtonPressGrab(__glutDials, __glutDeviceButtonPressGrab,
  446.           eventList[numEvents]);
  447.         numEvents++;
  448.         DeviceButtonRelease(__glutDials, __glutDeviceButtonRelease,
  449.           eventList[numEvents]);
  450.         numEvents++;
  451.       }
  452.       if (window->dials || window->buttonBox) {
  453.         DeviceStateNotify(__glutDials, __glutDeviceStateNotify,
  454.           eventList[numEvents]);
  455.         numEvents++;
  456.       }
  457.     }
  458.     if (__glutSpaceball) {
  459.       if (window->spaceMotion || window->spaceRotate) {
  460.         DeviceMotionNotify(__glutSpaceball, __glutDeviceMotionNotify,
  461.           eventList[numEvents]);
  462.         numEvents++;
  463.       }
  464.       if (window->spaceButton) {
  465.         DeviceButtonPress(__glutSpaceball, __glutDeviceButtonPress,
  466.           eventList[numEvents]);
  467.         numEvents++;
  468.         DeviceButtonPressGrab(__glutSpaceball, __glutDeviceButtonPressGrab,
  469.           eventList[numEvents]);
  470.         numEvents++;
  471.         DeviceButtonRelease(__glutSpaceball, __glutDeviceButtonRelease,
  472.           eventList[numEvents]);
  473.         numEvents++;
  474.       }
  475.       if (window->spaceMotion || window->spaceRotate || window->spaceButton) {
  476.         DeviceStateNotify(__glutSpaceball, __glutDeviceStateNotify,
  477.           eventList[numEvents]);
  478.         numEvents++;
  479.       }
  480.     }
  481. #if 0
  482.     if (window->children) {
  483.       GLUTwindow *child = window->children;
  484.  
  485.       do {
  486.         XChangeDeviceDontPropagateList(__glutDisplay, child->win,
  487.           numEvents, eventList, AddToList);
  488.         child = child->siblings;
  489.       } while (child);
  490.     }
  491. #endif
  492.     XSelectExtensionEvent(__glutDisplay, window->win,
  493.       eventList, numEvents);
  494.     if (window->overlay) {
  495.       XSelectExtensionEvent(__glutDisplay, window->overlay->win,
  496.         eventList, numEvents);
  497.     }
  498.   } else {
  499.     /* X Input extension not supported; no chance for exotic
  500.        input devices. */
  501.   }
  502. }
  503.  
  504. /* CENTRY */
  505. glutDeviceGet(GLenum param)
  506. {
  507.   probeDevices();
  508.   switch (param) {
  509.   case GLUT_HAS_KEYBOARD:
  510.   case GLUT_HAS_MOUSE:
  511.     /* Assume X always has mouse and keyboard. */
  512.     return 1;
  513.   case GLUT_HAS_SPACEBALL:
  514.     return __glutSpaceball != NULL;
  515.   case GLUT_HAS_DIAL_AND_BUTTON_BOX:
  516.     return __glutDials != NULL;
  517.   case GLUT_HAS_TABLET:
  518.     return __glutTablet != NULL;
  519.   case GLUT_NUM_MOUSE_BUTTONS:
  520.     return __glutNumMouseButtons;
  521.   case GLUT_NUM_SPACEBALL_BUTTONS:
  522.     return __glutNumSpaceballButtons;
  523.   case GLUT_NUM_BUTTON_BOX_BUTTONS:
  524.     return __glutNumButtonBoxButtons;
  525.   case GLUT_NUM_DIALS:
  526.     return __glutNumDials;
  527.   case GLUT_NUM_TABLET_BUTTONS:
  528.     return __glutNumTabletButtons;
  529.   default:
  530.     __glutWarning("invalid glutDeviceGet parameter: %d", param);
  531.     return -1;
  532.   }
  533. }
  534. /* ENDCENTRY */
  535.