glut_input.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:20k
源码类别:

GIS编程

开发平台:

Visual C++

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