Convert crlf->lf line endings.
[mesa.git] / src / glut / os2 / glut_input.cpp
index c517fe12490e46204b751b28c3d9f6e358646715..e65b691cb12838077c3ed555766682196538d505 100644 (file)
-\r
-/* Copyright (c) Mark J. Kilgard, 1994, 1997, 1998. */\r
-\r
-/* This program is freely distributable without licensing fees\r
-   and is provided without guarantee or warrantee expressed or\r
-   implied. This program is -not- in the public domain. */\r
-\r
-#include <assert.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-\r
-#include "glutint.h"\r
-#define POFIG 0\r
-#if POFIG\r
-\r
-int __glutNumDials = 0;\r
-int __glutNumSpaceballButtons = 0;\r
-int __glutNumButtonBoxButtons = 0;\r
-int __glutNumTabletButtons = 0;\r
-int __glutNumMouseButtons = 3;  /* Good guess. */\r
-XDevice *__glutTablet = NULL;\r
-XDevice *__glutDials = NULL;\r
-XDevice *__glutSpaceball = NULL;\r
-\r
-int __glutHasJoystick = 0;\r
-int __glutNumJoystickButtons = 0;\r
-int __glutNumJoystickAxes = 0;\r
-\r
-#if !defined(_WIN32)\r
-typedef struct _Range {\r
-  int min;\r
-  int range;\r
-} Range;\r
-\r
-#define NUM_SPACEBALL_AXIS     6\r
-#define NUM_TABLET_AXIS                2\r
-#define NUM_DIALS_AXIS         8\r
-\r
-Range __glutSpaceballRange[NUM_SPACEBALL_AXIS];\r
-Range __glutTabletRange[NUM_TABLET_AXIS];\r
-int *__glutDialsResolution;\r
-\r
-/* Safely assumes 0 is an illegal event type for X Input\r
-   extension events. */\r
-int __glutDeviceMotionNotify = 0;\r
-int __glutDeviceButtonPress = 0;\r
-int __glutDeviceButtonPressGrab = 0;\r
-int __glutDeviceButtonRelease = 0;\r
-int __glutDeviceStateNotify = 0;\r
-\r
-static int\r
-normalizeTabletPos(int axis, int rawValue)\r
-{\r
-  assert(rawValue >= __glutTabletRange[axis].min);\r
-  assert(rawValue <= __glutTabletRange[axis].min\r
-    + __glutTabletRange[axis].range);\r
-  /* Normalize rawValue to between 0 and 4000. */\r
-  return ((rawValue - __glutTabletRange[axis].min) * 4000) /\r
-    __glutTabletRange[axis].range;\r
-}\r
-\r
-static int\r
-normalizeDialAngle(int axis, int rawValue)\r
-{\r
-  /* XXX Assumption made that the resolution of the device is\r
-     number of clicks for one complete dial revolution.  This\r
-     is true for SGI's dial & button box. */\r
-  return (rawValue * 360.0) / __glutDialsResolution[axis];\r
-}\r
-\r
-static int\r
-normalizeSpaceballAngle(int axis, int rawValue)\r
-{\r
-  assert(rawValue >= __glutSpaceballRange[axis].min);\r
-  assert(rawValue <= __glutSpaceballRange[axis].min +\r
-    __glutSpaceballRange[axis].range);\r
-  /* Normalize rawValue to between -1800 and 1800. */\r
-  return ((rawValue - __glutSpaceballRange[axis].min) * 3600) /\r
-    __glutSpaceballRange[axis].range - 1800;\r
-}\r
-\r
-static int\r
-normalizeSpaceballDelta(int axis, int rawValue)\r
-{\r
-  assert(rawValue >= __glutSpaceballRange[axis].min);\r
-  assert(rawValue <= __glutSpaceballRange[axis].min +\r
-    __glutSpaceballRange[axis].range);\r
-  /* Normalize rawValue to between -1000 and 1000. */\r
-  return ((rawValue - __glutSpaceballRange[axis].min) * 2000) /\r
-    __glutSpaceballRange[axis].range - 1000;\r
-}\r
-\r
-static void\r
-queryTabletPos(GLUTwindow * window)\r
-{\r
-  XDeviceState *state;\r
-  XInputClass *any;\r
-  XValuatorState *v;\r
-  int i;\r
-\r
-  state = XQueryDeviceState(__glutDisplay, __glutTablet);\r
-  any = state->data;\r
-  for (i = 0; i < state->num_classes; i++) {\r
-#if defined(__cplusplus) || defined(c_plusplus)\r
-    switch (any->c_class) {\r
-#else\r
-    switch (any->class) {\r
-#endif\r
-    case ValuatorClass:\r
-      v = (XValuatorState *) any;\r
-      if (v->num_valuators < 2)\r
-        goto end;\r
-      if (window->tabletPos[0] == -1)\r
-        window->tabletPos[0] = normalizeTabletPos(0, v->valuators[0]);\r
-      if (window->tabletPos[1] == -1)\r
-        window->tabletPos[1] = normalizeTabletPos(1, v->valuators[1]);\r
-    }\r
-    any = (XInputClass *) ((char *) any + any->length);\r
-  }\r
-end:\r
-  XFreeDeviceState(state);\r
-}\r
-\r
-static void\r
-tabletPosChange(GLUTwindow * window, int first, int count, int *data)\r
-{\r
-  int i, value, genEvent = 0;\r
-\r
-  for (i = first; i < first + count; i++) {\r
-    switch (i) {\r
-    case 0:            /* X axis */\r
-    case 1:            /* Y axis */\r
-      value = normalizeTabletPos(i, data[i - first]);\r
-      if (value != window->tabletPos[i]) {\r
-        window->tabletPos[i] = value;\r
-        genEvent = 1;\r
-      }\r
-      break;\r
-    }\r
-  }\r
-  if (window->tabletPos[0] == -1 || window->tabletPos[1] == -1)\r
-    queryTabletPos(window);\r
-  if (genEvent)\r
-    window->tabletMotion(window->tabletPos[0], window->tabletPos[1]);\r
-}\r
-#endif /* !_WIN32 */\r
-\r
-static int\r
-__glutProcessDeviceEvents(XEvent * event)\r
-{\r
-#if !defined(_WIN32)\r
-  GLUTwindow *window;\r
-\r
-  /* XXX Ugly code fan out. */\r
-\r
-  /* Can't use switch/case since X Input event types are\r
-     dynamic. */\r
-\r
-  if (__glutDeviceMotionNotify && event->type == __glutDeviceMotionNotify) {\r
-    XDeviceMotionEvent *devmot = (XDeviceMotionEvent *) event;\r
-\r
-    window = __glutGetWindow(devmot->window);\r
-    if (window) {\r
-      if (__glutTablet\r
-        && devmot->deviceid == __glutTablet->device_id\r
-        && window->tabletMotion) {\r
-        tabletPosChange(window, devmot->first_axis, devmot->axes_count,\r
-          devmot->axis_data);\r
-      } else if (__glutDials\r
-          && devmot->deviceid == __glutDials->device_id\r
-        && window->dials) {\r
-        int i, first = devmot->first_axis, count = devmot->axes_count;\r
-\r
-        for (i = first; i < first + count; i++)\r
-          window->dials(i + 1,\r
-            normalizeDialAngle(i, devmot->axis_data[i - first]));\r
-      } else if (__glutSpaceball\r
-        && devmot->deviceid == __glutSpaceball->device_id) {\r
-        /* XXX Assume that space ball motion events come in as\r
-           all the first 6 axes.  Assume first 3 axes are XYZ\r
-           translations; second 3 axes are XYZ rotations. */\r
-        if (devmot->first_axis == 0 && devmot->axes_count == 6) {\r
-          if (window->spaceMotion)\r
-            window->spaceMotion(\r
-              normalizeSpaceballDelta(0, devmot->axis_data[0]),\r
-              normalizeSpaceballDelta(1, devmot->axis_data[1]),\r
-              normalizeSpaceballDelta(2, devmot->axis_data[2]));\r
-          if (window->spaceRotate)\r
-            window->spaceRotate(\r
-              normalizeSpaceballAngle(3, devmot->axis_data[3]),\r
-              normalizeSpaceballAngle(4, devmot->axis_data[4]),\r
-              normalizeSpaceballAngle(5, devmot->axis_data[5]));\r
-        }\r
-      }\r
-      return 1;\r
-    }\r
-  } else if (__glutDeviceButtonPress\r
-    && event->type == __glutDeviceButtonPress) {\r
-    XDeviceButtonEvent *devbtn = (XDeviceButtonEvent *) event;\r
-\r
-    window = __glutGetWindow(devbtn->window);\r
-    if (window) {\r
-      if (__glutTablet\r
-        && devbtn->deviceid == __glutTablet->device_id\r
-        && window->tabletButton\r
-        && devbtn->first_axis == 0\r
-        && devbtn->axes_count == 2) {\r
-        tabletPosChange(window, devbtn->first_axis, devbtn->axes_count,\r
-          devbtn->axis_data);\r
-        window->tabletButton(devbtn->button, GLUT_DOWN,\r
-          window->tabletPos[0], window->tabletPos[1]);\r
-      } else if (__glutDials\r
-          && devbtn->deviceid == __glutDials->device_id\r
-        && window->buttonBox) {\r
-        window->buttonBox(devbtn->button, GLUT_DOWN);\r
-      } else if (__glutSpaceball\r
-          && devbtn->deviceid == __glutSpaceball->device_id\r
-        && window->spaceButton) {\r
-        window->spaceButton(devbtn->button, GLUT_DOWN);\r
-      }\r
-      return 1;\r
-    }\r
-  } else if (__glutDeviceButtonRelease\r
-    && event->type == __glutDeviceButtonRelease) {\r
-    XDeviceButtonEvent *devbtn = (XDeviceButtonEvent *) event;\r
-\r
-    window = __glutGetWindow(devbtn->window);\r
-    if (window) {\r
-      if (__glutTablet\r
-        && devbtn->deviceid == __glutTablet->device_id\r
-        && window->tabletButton\r
-        && devbtn->first_axis == 0\r
-        && devbtn->axes_count == 2) {\r
-        tabletPosChange(window, devbtn->first_axis, devbtn->axes_count,\r
-          devbtn->axis_data);\r
-        window->tabletButton(devbtn->button, GLUT_UP,\r
-          window->tabletPos[0], window->tabletPos[1]);\r
-      } else if (__glutDials\r
-          && devbtn->deviceid == __glutDials->device_id\r
-        && window->buttonBox) {\r
-        window->buttonBox(devbtn->button, GLUT_UP);\r
-      } else if (__glutSpaceball\r
-          && devbtn->deviceid == __glutSpaceball->device_id\r
-        && window->spaceButton) {\r
-        window->spaceButton(devbtn->button, GLUT_UP);\r
-      }\r
-      return 1;\r
-    }\r
-  }\r
-#else\r
-  {\r
-    JOYINFOEX info;\r
-    JOYCAPS joyCaps;\r
-\r
-    memset(&info, 0, sizeof(JOYINFOEX)); \r
-    info.dwSize = sizeof(JOYINFOEX); \r
-    info.dwFlags = JOY_RETURNALL;\r
-\r
-    if (joyGetPosEx(JOYSTICKID1,&info) != JOYERR_NOERROR) {\r
-      __glutHasJoystick = 1;\r
-      joyGetDevCaps(JOYSTICKID1, &joyCaps, sizeof(joyCaps));\r
-      __glutNumJoystickButtons = joyCaps.wNumButtons;\r
-      __glutNumJoystickAxes = joyCaps.wNumAxes;\r
-    } else {\r
-      __glutHasJoystick = 0;\r
-      __glutNumJoystickButtons = 0;\r
-      __glutNumJoystickAxes = 0;\r
-    }\r
-  }\r
-#endif /* !_WIN32 */\r
-  return 0;\r
-}\r
-\r
-static GLUTeventParser eventParser =\r
-{__glutProcessDeviceEvents, NULL};\r
-\r
-static void\r
-addDeviceEventParser(void)\r
-{\r
-  static Bool been_here = False;\r
-\r
-  if (been_here)\r
-    return;\r
-  been_here = True;\r
-  __glutRegisterEventParser(&eventParser);\r
-}\r
-\r
-static int\r
-probeDevices(void)\r
-{\r
-  static Bool been_here = False;\r
-  static int support;\r
-#if !defined(_WIN32)\r
-  XExtensionVersion *version;\r
-  XDeviceInfoPtr device_info, device;\r
-  XAnyClassPtr any;\r
-  XButtonInfoPtr b;\r
-  XValuatorInfoPtr v;\r
-  XAxisInfoPtr a;\r
-  int num_dev = 0, btns = 0, dials = 0;\r
-  int i, j, k;\r
-#endif /* !_WIN32 */\r
-\r
-  if (been_here) {\r
-    return support;\r
-  }\r
-  been_here = True;\r
-\r
-#if !defined(_WIN32)\r
-  version = XGetExtensionVersion(__glutDisplay, "XInputExtension");\r
-  /* Ugh.  XInput extension API forces annoying cast of a pointer\r
-     to a long so it can be compared with the NoSuchExtension\r
-     value (#defined to 1). */\r
-  if (version == NULL || ((long) version) == NoSuchExtension) {\r
-    support = 0;\r
-    return support;\r
-  }\r
-  XFree(version);\r
-  device_info = XListInputDevices(__glutDisplay, &num_dev);\r
-  if (device_info) {\r
-    for (i = 0; i < num_dev; i++) {\r
-      /* XXX These are SGI names for these devices;\r
-         unfortunately, no good standard exists for standard\r
-         types of X input extension devices. */\r
-\r
-      device = &device_info[i];\r
-      any = (XAnyClassPtr) device->inputclassinfo;\r
-\r
-      if (!__glutSpaceball && !strcmp(device->name, "spaceball")) {\r
-        v = NULL;\r
-        b = NULL;\r
-        for (j = 0; j < device->num_classes; j++) {\r
-#if defined(__cplusplus) || defined(c_plusplus)\r
-          switch (any->c_class) {\r
-#else\r
-          switch (any->class) {\r
-#endif\r
-          case ButtonClass:\r
-            b = (XButtonInfoPtr) any;\r
-            btns = b->num_buttons;\r
-            break;\r
-          case ValuatorClass:\r
-            v = (XValuatorInfoPtr) any;\r
-            /* Sanity check: at least 6 valuators? */\r
-            if (v->num_axes < NUM_SPACEBALL_AXIS)\r
-              goto skip_device;\r
-            a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo));\r
-            for (k = 0; k < NUM_SPACEBALL_AXIS; k++, a++) {\r
-              __glutSpaceballRange[k].min = a->min_value;\r
-              __glutSpaceballRange[k].range = a->max_value - a->min_value;\r
-            }\r
-            break;\r
-          }\r
-          any = (XAnyClassPtr) ((char *) any + any->length);\r
-        }\r
-        if (v) {\r
-          __glutSpaceball = XOpenDevice(__glutDisplay, device->id);\r
-          if (__glutSpaceball) {\r
-            __glutNumSpaceballButtons = btns;\r
-            addDeviceEventParser();\r
-          }\r
-        }\r
-      } else if (!__glutDials && !strcmp(device->name, "dial+buttons")) {\r
-        v = NULL;\r
-        b = NULL;\r
-        for (j = 0; j < device->num_classes; j++) {\r
-#if defined(__cplusplus) || defined(c_plusplus)\r
-          switch (any->c_class) {\r
-#else\r
-          switch (any->class) {\r
-#endif\r
-          case ButtonClass:\r
-            b = (XButtonInfoPtr) any;\r
-            btns = b->num_buttons;\r
-            break;\r
-          case ValuatorClass:\r
-            v = (XValuatorInfoPtr) any;\r
-            /* Sanity check: at least 8 valuators? */\r
-            if (v->num_axes < NUM_DIALS_AXIS)\r
-              goto skip_device;\r
-            dials = v->num_axes;\r
-            __glutDialsResolution = (int *) malloc(sizeof(int) * dials);\r
-            a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo));\r
-            for (k = 0; k < dials; k++, a++) {\r
-              __glutDialsResolution[k] = a->resolution;\r
-            }\r
-            break;\r
-          }\r
-          any = (XAnyClassPtr) ((char *) any + any->length);\r
-        }\r
-        if (v) {\r
-          __glutDials = XOpenDevice(__glutDisplay, device->id);\r
-          if (__glutDials) {\r
-            __glutNumButtonBoxButtons = btns;\r
-            __glutNumDials = dials;\r
-            addDeviceEventParser();\r
-          }\r
-        }\r
-      } else if (!__glutTablet && !strcmp(device->name, "tablet")) {\r
-        v = NULL;\r
-        b = NULL;\r
-        for (j = 0; j < device->num_classes; j++) {\r
-#if defined(__cplusplus) || defined(c_plusplus)\r
-          switch (any->c_class) {\r
-#else\r
-          switch (any->class) {\r
-#endif\r
-          case ButtonClass:\r
-            b = (XButtonInfoPtr) any;\r
-            btns = b->num_buttons;\r
-            break;\r
-          case ValuatorClass:\r
-            v = (XValuatorInfoPtr) any;\r
-            /* Sanity check: exactly 2 valuators? */\r
-            if (v->num_axes != NUM_TABLET_AXIS)\r
-              goto skip_device;\r
-            a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo));\r
-            for (k = 0; k < NUM_TABLET_AXIS; k++, a++) {\r
-              __glutTabletRange[k].min = a->min_value;\r
-              __glutTabletRange[k].range = a->max_value - a->min_value;\r
-            }\r
-            break;\r
-          }\r
-          any = (XAnyClassPtr) ((char *) any + any->length);\r
-        }\r
-        if (v) {\r
-          __glutTablet = XOpenDevice(__glutDisplay, device->id);\r
-          if (__glutTablet) {\r
-            __glutNumTabletButtons = btns;\r
-            addDeviceEventParser();\r
-          }\r
-        }\r
-      } else if (!strcmp(device->name, "mouse")) {\r
-        for (j = 0; j < device->num_classes; j++) {\r
-#if defined(__cplusplus) || defined(c_plusplus)\r
-          if (any->c_class == ButtonClass) {\r
-#else\r
-          if (any->class == ButtonClass) {\r
-#endif\r
-            b = (XButtonInfoPtr) any;\r
-            __glutNumMouseButtons = b->num_buttons;\r
-          }\r
-          any = (XAnyClassPtr) ((char *) any + any->length);\r
-        }\r
-      }\r
-    skip_device:;\r
-    }\r
-    XFreeDeviceList(device_info);\r
-  }\r
-#else /* _WIN32 */\r
-  __glutNumMouseButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);\r
-#endif /* !_WIN32 */\r
-  /* X Input extension might be supported, but only if there is\r
-     a tablet, dials, or spaceball do we claim devices are\r
-     supported. */\r
-  support = __glutTablet || __glutDials || __glutSpaceball;\r
-  return support;\r
-}\r
-\r
-void\r
-__glutUpdateInputDeviceMask(GLUTwindow * window)\r
-{\r
-#if !defined(_WIN32)\r
-  /* 5 (dial and buttons) + 5 (tablet locator and buttons) + 5\r
-     (Spaceball buttons and axis) = 15 */\r
-  XEventClass eventList[15];\r
-  int rc, numEvents;\r
-\r
-  rc = probeDevices();\r
-  if (rc) {\r
-    numEvents = 0;\r
-    if (__glutTablet) {\r
-      if (window->tabletMotion) {\r
-        DeviceMotionNotify(__glutTablet, __glutDeviceMotionNotify,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-      }\r
-      if (window->tabletButton) {\r
-        DeviceButtonPress(__glutTablet, __glutDeviceButtonPress,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-        DeviceButtonPressGrab(__glutTablet, __glutDeviceButtonPressGrab,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-        DeviceButtonRelease(__glutTablet, __glutDeviceButtonRelease,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-      }\r
-      if (window->tabletMotion || window->tabletButton) {\r
-        DeviceStateNotify(__glutTablet, __glutDeviceStateNotify,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-      }\r
-    }\r
-    if (__glutDials) {\r
-      if (window->dials) {\r
-        DeviceMotionNotify(__glutDials, __glutDeviceMotionNotify,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-      }\r
-      if (window->buttonBox) {\r
-        DeviceButtonPress(__glutDials, __glutDeviceButtonPress,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-        DeviceButtonPressGrab(__glutDials, __glutDeviceButtonPressGrab,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-        DeviceButtonRelease(__glutDials, __glutDeviceButtonRelease,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-      }\r
-      if (window->dials || window->buttonBox) {\r
-        DeviceStateNotify(__glutDials, __glutDeviceStateNotify,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-      }\r
-    }\r
-    if (__glutSpaceball) {\r
-      if (window->spaceMotion || window->spaceRotate) {\r
-        DeviceMotionNotify(__glutSpaceball, __glutDeviceMotionNotify,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-      }\r
-      if (window->spaceButton) {\r
-        DeviceButtonPress(__glutSpaceball, __glutDeviceButtonPress,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-        DeviceButtonPressGrab(__glutSpaceball, __glutDeviceButtonPressGrab,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-        DeviceButtonRelease(__glutSpaceball, __glutDeviceButtonRelease,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-      }\r
-      if (window->spaceMotion || window->spaceRotate || window->spaceButton) {\r
-        DeviceStateNotify(__glutSpaceball, __glutDeviceStateNotify,\r
-          eventList[numEvents]);\r
-        numEvents++;\r
-      }\r
-    }\r
-#if 0\r
-    if (window->children) {\r
-      GLUTwindow *child = window->children;\r
-\r
-      do {\r
-        XChangeDeviceDontPropagateList(__glutDisplay, child->win,\r
-          numEvents, eventList, AddToList);\r
-        child = child->siblings;\r
-      } while (child);\r
-    }\r
-#endif\r
-    XSelectExtensionEvent(__glutDisplay, window->win,\r
-      eventList, numEvents);\r
-    if (window->overlay) {\r
-      XSelectExtensionEvent(__glutDisplay, window->overlay->win,\r
-        eventList, numEvents);\r
-    }\r
-  } else {\r
-    /* X Input extension not supported; no chance for exotic\r
-       input devices. */\r
-  }\r
-#endif /* !_WIN32 */\r
-}\r
-\r
-#endif //POFIG\r
-\r
-/* CENTRY */\r
-int GLUTAPIENTRY\r
-glutDeviceGet(GLenum param)\r
-{\r
-#if POFIG\r
-  probeDevices();\r
-#endif\r
-  switch (param) {\r
-  case GLUT_HAS_KEYBOARD:\r
-  case GLUT_HAS_MOUSE:\r
-    /* Assume window system always has mouse and keyboard. */\r
-    return 1;\r
-#if POFIG\r
-  case GLUT_HAS_SPACEBALL:\r
-    return __glutSpaceball != NULL;\r
-  case GLUT_HAS_DIAL_AND_BUTTON_BOX:\r
-    return __glutDials != NULL;\r
-  case GLUT_HAS_TABLET:\r
-    return __glutTablet != NULL;\r
-  case GLUT_NUM_MOUSE_BUTTONS:\r
-    return __glutNumMouseButtons;\r
-  case GLUT_NUM_SPACEBALL_BUTTONS:\r
-    return __glutNumSpaceballButtons;\r
-  case GLUT_NUM_BUTTON_BOX_BUTTONS:\r
-    return __glutNumButtonBoxButtons;\r
-  case GLUT_NUM_DIALS:\r
-    return __glutNumDials;\r
-  case GLUT_NUM_TABLET_BUTTONS:\r
-    return __glutNumTabletButtons;\r
-  case GLUT_DEVICE_IGNORE_KEY_REPEAT:\r
-    return __glutCurrentWindow->ignoreKeyRepeat;\r
-#ifndef _WIN32\r
-  case GLUT_DEVICE_KEY_REPEAT:\r
-    {\r
-      XKeyboardState state;\r
-\r
-      XGetKeyboardControl(__glutDisplay, &state);\r
-      return state.global_auto_repeat;\r
-    }\r
-  case GLUT_JOYSTICK_POLL_RATE:\r
-    return 0;\r
-#else\r
-  case GLUT_DEVICE_KEY_REPEAT:\r
-    /* Win32 cannot globally disable key repeat. */\r
-    return GLUT_KEY_REPEAT_ON;\r
-  case GLUT_JOYSTICK_POLL_RATE:\r
-    return __glutCurrentWindow->joyPollInterval;\r
-#endif\r
-  case GLUT_HAS_JOYSTICK:\r
-    return __glutHasJoystick;\r
-  case GLUT_JOYSTICK_BUTTONS:\r
-    return __glutNumJoystickButtons;\r
-  case GLUT_JOYSTICK_AXES:\r
-    return __glutNumJoystickAxes;\r
-#endif //POFIG\r
-  default:\r
-    __glutWarning("invalid glutDeviceGet parameter: %d", param);\r
-    return -1;\r
-  }\r
-}\r
-/* ENDCENTRY */\r
+
+/* Copyright (c) Mark J. Kilgard, 1994, 1997, 1998. */
+
+/* This program is freely distributable without licensing fees
+   and is provided without guarantee or warrantee expressed or
+   implied. This program is -not- in the public domain. */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "glutint.h"
+#define POFIG 0
+#if POFIG
+
+int __glutNumDials = 0;
+int __glutNumSpaceballButtons = 0;
+int __glutNumButtonBoxButtons = 0;
+int __glutNumTabletButtons = 0;
+int __glutNumMouseButtons = 3;  /* Good guess. */
+XDevice *__glutTablet = NULL;
+XDevice *__glutDials = NULL;
+XDevice *__glutSpaceball = NULL;
+
+int __glutHasJoystick = 0;
+int __glutNumJoystickButtons = 0;
+int __glutNumJoystickAxes = 0;
+
+#if !defined(_WIN32)
+typedef struct _Range {
+  int min;
+  int range;
+} Range;
+
+#define NUM_SPACEBALL_AXIS     6
+#define NUM_TABLET_AXIS                2
+#define NUM_DIALS_AXIS         8
+
+Range __glutSpaceballRange[NUM_SPACEBALL_AXIS];
+Range __glutTabletRange[NUM_TABLET_AXIS];
+int *__glutDialsResolution;
+
+/* Safely assumes 0 is an illegal event type for X Input
+   extension events. */
+int __glutDeviceMotionNotify = 0;
+int __glutDeviceButtonPress = 0;
+int __glutDeviceButtonPressGrab = 0;
+int __glutDeviceButtonRelease = 0;
+int __glutDeviceStateNotify = 0;
+
+static int
+normalizeTabletPos(int axis, int rawValue)
+{
+  assert(rawValue >= __glutTabletRange[axis].min);
+  assert(rawValue <= __glutTabletRange[axis].min
+    + __glutTabletRange[axis].range);
+  /* Normalize rawValue to between 0 and 4000. */
+  return ((rawValue - __glutTabletRange[axis].min) * 4000) /
+    __glutTabletRange[axis].range;
+}
+
+static int
+normalizeDialAngle(int axis, int rawValue)
+{
+  /* XXX Assumption made that the resolution of the device is
+     number of clicks for one complete dial revolution.  This
+     is true for SGI's dial & button box. */
+  return (rawValue * 360.0) / __glutDialsResolution[axis];
+}
+
+static int
+normalizeSpaceballAngle(int axis, int rawValue)
+{
+  assert(rawValue >= __glutSpaceballRange[axis].min);
+  assert(rawValue <= __glutSpaceballRange[axis].min +
+    __glutSpaceballRange[axis].range);
+  /* Normalize rawValue to between -1800 and 1800. */
+  return ((rawValue - __glutSpaceballRange[axis].min) * 3600) /
+    __glutSpaceballRange[axis].range - 1800;
+}
+
+static int
+normalizeSpaceballDelta(int axis, int rawValue)
+{
+  assert(rawValue >= __glutSpaceballRange[axis].min);
+  assert(rawValue <= __glutSpaceballRange[axis].min +
+    __glutSpaceballRange[axis].range);
+  /* Normalize rawValue to between -1000 and 1000. */
+  return ((rawValue - __glutSpaceballRange[axis].min) * 2000) /
+    __glutSpaceballRange[axis].range - 1000;
+}
+
+static void
+queryTabletPos(GLUTwindow * window)
+{
+  XDeviceState *state;
+  XInputClass *any;
+  XValuatorState *v;
+  int i;
+
+  state = XQueryDeviceState(__glutDisplay, __glutTablet);
+  any = state->data;
+  for (i = 0; i < state->num_classes; i++) {
+#if defined(__cplusplus) || defined(c_plusplus)
+    switch (any->c_class) {
+#else
+    switch (any->class) {
+#endif
+    case ValuatorClass:
+      v = (XValuatorState *) any;
+      if (v->num_valuators < 2)
+        goto end;
+      if (window->tabletPos[0] == -1)
+        window->tabletPos[0] = normalizeTabletPos(0, v->valuators[0]);
+      if (window->tabletPos[1] == -1)
+        window->tabletPos[1] = normalizeTabletPos(1, v->valuators[1]);
+    }
+    any = (XInputClass *) ((char *) any + any->length);
+  }
+end:
+  XFreeDeviceState(state);
+}
+
+static void
+tabletPosChange(GLUTwindow * window, int first, int count, int *data)
+{
+  int i, value, genEvent = 0;
+
+  for (i = first; i < first + count; i++) {
+    switch (i) {
+    case 0:            /* X axis */
+    case 1:            /* Y axis */
+      value = normalizeTabletPos(i, data[i - first]);
+      if (value != window->tabletPos[i]) {
+        window->tabletPos[i] = value;
+        genEvent = 1;
+      }
+      break;
+    }
+  }
+  if (window->tabletPos[0] == -1 || window->tabletPos[1] == -1)
+    queryTabletPos(window);
+  if (genEvent)
+    window->tabletMotion(window->tabletPos[0], window->tabletPos[1]);
+}
+#endif /* !_WIN32 */
+
+static int
+__glutProcessDeviceEvents(XEvent * event)
+{
+#if !defined(_WIN32)
+  GLUTwindow *window;
+
+  /* XXX Ugly code fan out. */
+
+  /* Can't use switch/case since X Input event types are
+     dynamic. */
+
+  if (__glutDeviceMotionNotify && event->type == __glutDeviceMotionNotify) {
+    XDeviceMotionEvent *devmot = (XDeviceMotionEvent *) event;
+
+    window = __glutGetWindow(devmot->window);
+    if (window) {
+      if (__glutTablet
+        && devmot->deviceid == __glutTablet->device_id
+        && window->tabletMotion) {
+        tabletPosChange(window, devmot->first_axis, devmot->axes_count,
+          devmot->axis_data);
+      } else if (__glutDials
+          && devmot->deviceid == __glutDials->device_id
+        && window->dials) {
+        int i, first = devmot->first_axis, count = devmot->axes_count;
+
+        for (i = first; i < first + count; i++)
+          window->dials(i + 1,
+            normalizeDialAngle(i, devmot->axis_data[i - first]));
+      } else if (__glutSpaceball
+        && devmot->deviceid == __glutSpaceball->device_id) {
+        /* XXX Assume that space ball motion events come in as
+           all the first 6 axes.  Assume first 3 axes are XYZ
+           translations; second 3 axes are XYZ rotations. */
+        if (devmot->first_axis == 0 && devmot->axes_count == 6) {
+          if (window->spaceMotion)
+            window->spaceMotion(
+              normalizeSpaceballDelta(0, devmot->axis_data[0]),
+              normalizeSpaceballDelta(1, devmot->axis_data[1]),
+              normalizeSpaceballDelta(2, devmot->axis_data[2]));
+          if (window->spaceRotate)
+            window->spaceRotate(
+              normalizeSpaceballAngle(3, devmot->axis_data[3]),
+              normalizeSpaceballAngle(4, devmot->axis_data[4]),
+              normalizeSpaceballAngle(5, devmot->axis_data[5]));
+        }
+      }
+      return 1;
+    }
+  } else if (__glutDeviceButtonPress
+    && event->type == __glutDeviceButtonPress) {
+    XDeviceButtonEvent *devbtn = (XDeviceButtonEvent *) event;
+
+    window = __glutGetWindow(devbtn->window);
+    if (window) {
+      if (__glutTablet
+        && devbtn->deviceid == __glutTablet->device_id
+        && window->tabletButton
+        && devbtn->first_axis == 0
+        && devbtn->axes_count == 2) {
+        tabletPosChange(window, devbtn->first_axis, devbtn->axes_count,
+          devbtn->axis_data);
+        window->tabletButton(devbtn->button, GLUT_DOWN,
+          window->tabletPos[0], window->tabletPos[1]);
+      } else if (__glutDials
+          && devbtn->deviceid == __glutDials->device_id
+        && window->buttonBox) {
+        window->buttonBox(devbtn->button, GLUT_DOWN);
+      } else if (__glutSpaceball
+          && devbtn->deviceid == __glutSpaceball->device_id
+        && window->spaceButton) {
+        window->spaceButton(devbtn->button, GLUT_DOWN);
+      }
+      return 1;
+    }
+  } else if (__glutDeviceButtonRelease
+    && event->type == __glutDeviceButtonRelease) {
+    XDeviceButtonEvent *devbtn = (XDeviceButtonEvent *) event;
+
+    window = __glutGetWindow(devbtn->window);
+    if (window) {
+      if (__glutTablet
+        && devbtn->deviceid == __glutTablet->device_id
+        && window->tabletButton
+        && devbtn->first_axis == 0
+        && devbtn->axes_count == 2) {
+        tabletPosChange(window, devbtn->first_axis, devbtn->axes_count,
+          devbtn->axis_data);
+        window->tabletButton(devbtn->button, GLUT_UP,
+          window->tabletPos[0], window->tabletPos[1]);
+      } else if (__glutDials
+          && devbtn->deviceid == __glutDials->device_id
+        && window->buttonBox) {
+        window->buttonBox(devbtn->button, GLUT_UP);
+      } else if (__glutSpaceball
+          && devbtn->deviceid == __glutSpaceball->device_id
+        && window->spaceButton) {
+        window->spaceButton(devbtn->button, GLUT_UP);
+      }
+      return 1;
+    }
+  }
+#else
+  {
+    JOYINFOEX info;
+    JOYCAPS joyCaps;
+
+    memset(&info, 0, sizeof(JOYINFOEX)); 
+    info.dwSize = sizeof(JOYINFOEX); 
+    info.dwFlags = JOY_RETURNALL;
+
+    if (joyGetPosEx(JOYSTICKID1,&info) != JOYERR_NOERROR) {
+      __glutHasJoystick = 1;
+      joyGetDevCaps(JOYSTICKID1, &joyCaps, sizeof(joyCaps));
+      __glutNumJoystickButtons = joyCaps.wNumButtons;
+      __glutNumJoystickAxes = joyCaps.wNumAxes;
+    } else {
+      __glutHasJoystick = 0;
+      __glutNumJoystickButtons = 0;
+      __glutNumJoystickAxes = 0;
+    }
+  }
+#endif /* !_WIN32 */
+  return 0;
+}
+
+static GLUTeventParser eventParser =
+{__glutProcessDeviceEvents, NULL};
+
+static void
+addDeviceEventParser(void)
+{
+  static Bool been_here = False;
+
+  if (been_here)
+    return;
+  been_here = True;
+  __glutRegisterEventParser(&eventParser);
+}
+
+static int
+probeDevices(void)
+{
+  static Bool been_here = False;
+  static int support;
+#if !defined(_WIN32)
+  XExtensionVersion *version;
+  XDeviceInfoPtr device_info, device;
+  XAnyClassPtr any;
+  XButtonInfoPtr b;
+  XValuatorInfoPtr v;
+  XAxisInfoPtr a;
+  int num_dev = 0, btns = 0, dials = 0;
+  int i, j, k;
+#endif /* !_WIN32 */
+
+  if (been_here) {
+    return support;
+  }
+  been_here = True;
+
+#if !defined(_WIN32)
+  version = XGetExtensionVersion(__glutDisplay, "XInputExtension");
+  /* Ugh.  XInput extension API forces annoying cast of a pointer
+     to a long so it can be compared with the NoSuchExtension
+     value (#defined to 1). */
+  if (version == NULL || ((long) version) == NoSuchExtension) {
+    support = 0;
+    return support;
+  }
+  XFree(version);
+  device_info = XListInputDevices(__glutDisplay, &num_dev);
+  if (device_info) {
+    for (i = 0; i < num_dev; i++) {
+      /* XXX These are SGI names for these devices;
+         unfortunately, no good standard exists for standard
+         types of X input extension devices. */
+
+      device = &device_info[i];
+      any = (XAnyClassPtr) device->inputclassinfo;
+
+      if (!__glutSpaceball && !strcmp(device->name, "spaceball")) {
+        v = NULL;
+        b = NULL;
+        for (j = 0; j < device->num_classes; j++) {
+#if defined(__cplusplus) || defined(c_plusplus)
+          switch (any->c_class) {
+#else
+          switch (any->class) {
+#endif
+          case ButtonClass:
+            b = (XButtonInfoPtr) any;
+            btns = b->num_buttons;
+            break;
+          case ValuatorClass:
+            v = (XValuatorInfoPtr) any;
+            /* Sanity check: at least 6 valuators? */
+            if (v->num_axes < NUM_SPACEBALL_AXIS)
+              goto skip_device;
+            a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo));
+            for (k = 0; k < NUM_SPACEBALL_AXIS; k++, a++) {
+              __glutSpaceballRange[k].min = a->min_value;
+              __glutSpaceballRange[k].range = a->max_value - a->min_value;
+            }
+            break;
+          }
+          any = (XAnyClassPtr) ((char *) any + any->length);
+        }
+        if (v) {
+          __glutSpaceball = XOpenDevice(__glutDisplay, device->id);
+          if (__glutSpaceball) {
+            __glutNumSpaceballButtons = btns;
+            addDeviceEventParser();
+          }
+        }
+      } else if (!__glutDials && !strcmp(device->name, "dial+buttons")) {
+        v = NULL;
+        b = NULL;
+        for (j = 0; j < device->num_classes; j++) {
+#if defined(__cplusplus) || defined(c_plusplus)
+          switch (any->c_class) {
+#else
+          switch (any->class) {
+#endif
+          case ButtonClass:
+            b = (XButtonInfoPtr) any;
+            btns = b->num_buttons;
+            break;
+          case ValuatorClass:
+            v = (XValuatorInfoPtr) any;
+            /* Sanity check: at least 8 valuators? */
+            if (v->num_axes < NUM_DIALS_AXIS)
+              goto skip_device;
+            dials = v->num_axes;
+            __glutDialsResolution = (int *) malloc(sizeof(int) * dials);
+            a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo));
+            for (k = 0; k < dials; k++, a++) {
+              __glutDialsResolution[k] = a->resolution;
+            }
+            break;
+          }
+          any = (XAnyClassPtr) ((char *) any + any->length);
+        }
+        if (v) {
+          __glutDials = XOpenDevice(__glutDisplay, device->id);
+          if (__glutDials) {
+            __glutNumButtonBoxButtons = btns;
+            __glutNumDials = dials;
+            addDeviceEventParser();
+          }
+        }
+      } else if (!__glutTablet && !strcmp(device->name, "tablet")) {
+        v = NULL;
+        b = NULL;
+        for (j = 0; j < device->num_classes; j++) {
+#if defined(__cplusplus) || defined(c_plusplus)
+          switch (any->c_class) {
+#else
+          switch (any->class) {
+#endif
+          case ButtonClass:
+            b = (XButtonInfoPtr) any;
+            btns = b->num_buttons;
+            break;
+          case ValuatorClass:
+            v = (XValuatorInfoPtr) any;
+            /* Sanity check: exactly 2 valuators? */
+            if (v->num_axes != NUM_TABLET_AXIS)
+              goto skip_device;
+            a = (XAxisInfoPtr) ((char *) v + sizeof(XValuatorInfo));
+            for (k = 0; k < NUM_TABLET_AXIS; k++, a++) {
+              __glutTabletRange[k].min = a->min_value;
+              __glutTabletRange[k].range = a->max_value - a->min_value;
+            }
+            break;
+          }
+          any = (XAnyClassPtr) ((char *) any + any->length);
+        }
+        if (v) {
+          __glutTablet = XOpenDevice(__glutDisplay, device->id);
+          if (__glutTablet) {
+            __glutNumTabletButtons = btns;
+            addDeviceEventParser();
+          }
+        }
+      } else if (!strcmp(device->name, "mouse")) {
+        for (j = 0; j < device->num_classes; j++) {
+#if defined(__cplusplus) || defined(c_plusplus)
+          if (any->c_class == ButtonClass) {
+#else
+          if (any->class == ButtonClass) {
+#endif
+            b = (XButtonInfoPtr) any;
+            __glutNumMouseButtons = b->num_buttons;
+          }
+          any = (XAnyClassPtr) ((char *) any + any->length);
+        }
+      }
+    skip_device:;
+    }
+    XFreeDeviceList(device_info);
+  }
+#else /* _WIN32 */
+  __glutNumMouseButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);
+#endif /* !_WIN32 */
+  /* X Input extension might be supported, but only if there is
+     a tablet, dials, or spaceball do we claim devices are
+     supported. */
+  support = __glutTablet || __glutDials || __glutSpaceball;
+  return support;
+}
+
+void
+__glutUpdateInputDeviceMask(GLUTwindow * window)
+{
+#if !defined(_WIN32)
+  /* 5 (dial and buttons) + 5 (tablet locator and buttons) + 5
+     (Spaceball buttons and axis) = 15 */
+  XEventClass eventList[15];
+  int rc, numEvents;
+
+  rc = probeDevices();
+  if (rc) {
+    numEvents = 0;
+    if (__glutTablet) {
+      if (window->tabletMotion) {
+        DeviceMotionNotify(__glutTablet, __glutDeviceMotionNotify,
+          eventList[numEvents]);
+        numEvents++;
+      }
+      if (window->tabletButton) {
+        DeviceButtonPress(__glutTablet, __glutDeviceButtonPress,
+          eventList[numEvents]);
+        numEvents++;
+        DeviceButtonPressGrab(__glutTablet, __glutDeviceButtonPressGrab,
+          eventList[numEvents]);
+        numEvents++;
+        DeviceButtonRelease(__glutTablet, __glutDeviceButtonRelease,
+          eventList[numEvents]);
+        numEvents++;
+      }
+      if (window->tabletMotion || window->tabletButton) {
+        DeviceStateNotify(__glutTablet, __glutDeviceStateNotify,
+          eventList[numEvents]);
+        numEvents++;
+      }
+    }
+    if (__glutDials) {
+      if (window->dials) {
+        DeviceMotionNotify(__glutDials, __glutDeviceMotionNotify,
+          eventList[numEvents]);
+        numEvents++;
+      }
+      if (window->buttonBox) {
+        DeviceButtonPress(__glutDials, __glutDeviceButtonPress,
+          eventList[numEvents]);
+        numEvents++;
+        DeviceButtonPressGrab(__glutDials, __glutDeviceButtonPressGrab,
+          eventList[numEvents]);
+        numEvents++;
+        DeviceButtonRelease(__glutDials, __glutDeviceButtonRelease,
+          eventList[numEvents]);
+        numEvents++;
+      }
+      if (window->dials || window->buttonBox) {
+        DeviceStateNotify(__glutDials, __glutDeviceStateNotify,
+          eventList[numEvents]);
+        numEvents++;
+      }
+    }
+    if (__glutSpaceball) {
+      if (window->spaceMotion || window->spaceRotate) {
+        DeviceMotionNotify(__glutSpaceball, __glutDeviceMotionNotify,
+          eventList[numEvents]);
+        numEvents++;
+      }
+      if (window->spaceButton) {
+        DeviceButtonPress(__glutSpaceball, __glutDeviceButtonPress,
+          eventList[numEvents]);
+        numEvents++;
+        DeviceButtonPressGrab(__glutSpaceball, __glutDeviceButtonPressGrab,
+          eventList[numEvents]);
+        numEvents++;
+        DeviceButtonRelease(__glutSpaceball, __glutDeviceButtonRelease,
+          eventList[numEvents]);
+        numEvents++;
+      }
+      if (window->spaceMotion || window->spaceRotate || window->spaceButton) {
+        DeviceStateNotify(__glutSpaceball, __glutDeviceStateNotify,
+          eventList[numEvents]);
+        numEvents++;
+      }
+    }
+#if 0
+    if (window->children) {
+      GLUTwindow *child = window->children;
+
+      do {
+        XChangeDeviceDontPropagateList(__glutDisplay, child->win,
+          numEvents, eventList, AddToList);
+        child = child->siblings;
+      } while (child);
+    }
+#endif
+    XSelectExtensionEvent(__glutDisplay, window->win,
+      eventList, numEvents);
+    if (window->overlay) {
+      XSelectExtensionEvent(__glutDisplay, window->overlay->win,
+        eventList, numEvents);
+    }
+  } else {
+    /* X Input extension not supported; no chance for exotic
+       input devices. */
+  }
+#endif /* !_WIN32 */
+}
+
+#endif //POFIG
+
+/* CENTRY */
+int GLUTAPIENTRY
+glutDeviceGet(GLenum param)
+{
+#if POFIG
+  probeDevices();
+#endif
+  switch (param) {
+  case GLUT_HAS_KEYBOARD:
+  case GLUT_HAS_MOUSE:
+    /* Assume window system always has mouse and keyboard. */
+    return 1;
+#if POFIG
+  case GLUT_HAS_SPACEBALL:
+    return __glutSpaceball != NULL;
+  case GLUT_HAS_DIAL_AND_BUTTON_BOX:
+    return __glutDials != NULL;
+  case GLUT_HAS_TABLET:
+    return __glutTablet != NULL;
+  case GLUT_NUM_MOUSE_BUTTONS:
+    return __glutNumMouseButtons;
+  case GLUT_NUM_SPACEBALL_BUTTONS:
+    return __glutNumSpaceballButtons;
+  case GLUT_NUM_BUTTON_BOX_BUTTONS:
+    return __glutNumButtonBoxButtons;
+  case GLUT_NUM_DIALS:
+    return __glutNumDials;
+  case GLUT_NUM_TABLET_BUTTONS:
+    return __glutNumTabletButtons;
+  case GLUT_DEVICE_IGNORE_KEY_REPEAT:
+    return __glutCurrentWindow->ignoreKeyRepeat;
+#ifndef _WIN32
+  case GLUT_DEVICE_KEY_REPEAT:
+    {
+      XKeyboardState state;
+
+      XGetKeyboardControl(__glutDisplay, &state);
+      return state.global_auto_repeat;
+    }
+  case GLUT_JOYSTICK_POLL_RATE:
+    return 0;
+#else
+  case GLUT_DEVICE_KEY_REPEAT:
+    /* Win32 cannot globally disable key repeat. */
+    return GLUT_KEY_REPEAT_ON;
+  case GLUT_JOYSTICK_POLL_RATE:
+    return __glutCurrentWindow->joyPollInterval;
+#endif
+  case GLUT_HAS_JOYSTICK:
+    return __glutHasJoystick;
+  case GLUT_JOYSTICK_BUTTONS:
+    return __glutNumJoystickButtons;
+  case GLUT_JOYSTICK_AXES:
+    return __glutNumJoystickAxes;
+#endif //POFIG
+  default:
+    __glutWarning("invalid glutDeviceGet parameter: %d", param);
+    return -1;
+  }
+}
+/* ENDCENTRY */