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