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