2 /* Copyright (c) Mark J. Kilgard, 1994, 1997, 1998. */
4 /* This program is freely distributable without licensing fees
5 and is provided without guarantee or warrantee expressed or
6 implied. This program is -not- in the public domain. */
17 int __glutNumDials
= 0;
18 int __glutNumSpaceballButtons
= 0;
19 int __glutNumButtonBoxButtons
= 0;
20 int __glutNumTabletButtons
= 0;
21 int __glutNumMouseButtons
= 3; /* Good guess. */
22 XDevice
*__glutTablet
= NULL
;
23 XDevice
*__glutDials
= NULL
;
24 XDevice
*__glutSpaceball
= NULL
;
26 int __glutHasJoystick
= 0;
27 int __glutNumJoystickButtons
= 0;
28 int __glutNumJoystickAxes
= 0;
31 typedef struct _Range
{
36 #define NUM_SPACEBALL_AXIS 6
37 #define NUM_TABLET_AXIS 2
38 #define NUM_DIALS_AXIS 8
40 Range __glutSpaceballRange
[NUM_SPACEBALL_AXIS
];
41 Range __glutTabletRange
[NUM_TABLET_AXIS
];
42 int *__glutDialsResolution
;
44 /* Safely assumes 0 is an illegal event type for X Input
46 int __glutDeviceMotionNotify
= 0;
47 int __glutDeviceButtonPress
= 0;
48 int __glutDeviceButtonPressGrab
= 0;
49 int __glutDeviceButtonRelease
= 0;
50 int __glutDeviceStateNotify
= 0;
53 normalizeTabletPos(int axis
, int rawValue
)
55 assert(rawValue
>= __glutTabletRange
[axis
].min
);
56 assert(rawValue
<= __glutTabletRange
[axis
].min
57 + __glutTabletRange
[axis
].range
);
58 /* Normalize rawValue to between 0 and 4000. */
59 return ((rawValue
- __glutTabletRange
[axis
].min
) * 4000) /
60 __glutTabletRange
[axis
].range
;
64 normalizeDialAngle(int axis
, int rawValue
)
66 /* XXX Assumption made that the resolution of the device is
67 number of clicks for one complete dial revolution. This
68 is true for SGI's dial & button box. */
69 return (rawValue
* 360.0) / __glutDialsResolution
[axis
];
73 normalizeSpaceballAngle(int axis
, int rawValue
)
75 assert(rawValue
>= __glutSpaceballRange
[axis
].min
);
76 assert(rawValue
<= __glutSpaceballRange
[axis
].min
+
77 __glutSpaceballRange
[axis
].range
);
78 /* Normalize rawValue to between -1800 and 1800. */
79 return ((rawValue
- __glutSpaceballRange
[axis
].min
) * 3600) /
80 __glutSpaceballRange
[axis
].range
- 1800;
84 normalizeSpaceballDelta(int axis
, int rawValue
)
86 assert(rawValue
>= __glutSpaceballRange
[axis
].min
);
87 assert(rawValue
<= __glutSpaceballRange
[axis
].min
+
88 __glutSpaceballRange
[axis
].range
);
89 /* Normalize rawValue to between -1000 and 1000. */
90 return ((rawValue
- __glutSpaceballRange
[axis
].min
) * 2000) /
91 __glutSpaceballRange
[axis
].range
- 1000;
95 queryTabletPos(GLUTwindow
* window
)
102 state
= XQueryDeviceState(__glutDisplay
, __glutTablet
);
104 for (i
= 0; i
< state
->num_classes
; i
++) {
105 #if defined(__cplusplus) || defined(c_plusplus)
106 switch (any
->c_class
) {
108 switch (any
->class) {
111 v
= (XValuatorState
*) any
;
112 if (v
->num_valuators
< 2)
114 if (window
->tabletPos
[0] == -1)
115 window
->tabletPos
[0] = normalizeTabletPos(0, v
->valuators
[0]);
116 if (window
->tabletPos
[1] == -1)
117 window
->tabletPos
[1] = normalizeTabletPos(1, v
->valuators
[1]);
119 any
= (XInputClass
*) ((char *) any
+ any
->length
);
122 XFreeDeviceState(state
);
126 tabletPosChange(GLUTwindow
* window
, int first
, int count
, int *data
)
128 int i
, value
, genEvent
= 0;
130 for (i
= first
; i
< first
+ count
; i
++) {
134 value
= normalizeTabletPos(i
, data
[i
- first
]);
135 if (value
!= window
->tabletPos
[i
]) {
136 window
->tabletPos
[i
] = value
;
142 if (window
->tabletPos
[0] == -1 || window
->tabletPos
[1] == -1)
143 queryTabletPos(window
);
145 window
->tabletMotion(window
->tabletPos
[0], window
->tabletPos
[1]);
150 __glutProcessDeviceEvents(XEvent
* event
)
155 /* XXX Ugly code fan out. */
157 /* Can't use switch/case since X Input event types are
160 if (__glutDeviceMotionNotify
&& event
->type
== __glutDeviceMotionNotify
) {
161 XDeviceMotionEvent
*devmot
= (XDeviceMotionEvent
*) event
;
163 window
= __glutGetWindow(devmot
->window
);
166 && devmot
->deviceid
== __glutTablet
->device_id
167 && window
->tabletMotion
) {
168 tabletPosChange(window
, devmot
->first_axis
, devmot
->axes_count
,
170 } else if (__glutDials
171 && devmot
->deviceid
== __glutDials
->device_id
173 int i
, first
= devmot
->first_axis
, count
= devmot
->axes_count
;
175 for (i
= first
; i
< first
+ count
; i
++)
177 normalizeDialAngle(i
, devmot
->axis_data
[i
- first
]));
178 } else if (__glutSpaceball
179 && devmot
->deviceid
== __glutSpaceball
->device_id
) {
180 /* XXX Assume that space ball motion events come in as
181 all the first 6 axes. Assume first 3 axes are XYZ
182 translations; second 3 axes are XYZ rotations. */
183 if (devmot
->first_axis
== 0 && devmot
->axes_count
== 6) {
184 if (window
->spaceMotion
)
186 normalizeSpaceballDelta(0, devmot
->axis_data
[0]),
187 normalizeSpaceballDelta(1, devmot
->axis_data
[1]),
188 normalizeSpaceballDelta(2, devmot
->axis_data
[2]));
189 if (window
->spaceRotate
)
191 normalizeSpaceballAngle(3, devmot
->axis_data
[3]),
192 normalizeSpaceballAngle(4, devmot
->axis_data
[4]),
193 normalizeSpaceballAngle(5, devmot
->axis_data
[5]));
198 } else if (__glutDeviceButtonPress
199 && event
->type
== __glutDeviceButtonPress
) {
200 XDeviceButtonEvent
*devbtn
= (XDeviceButtonEvent
*) event
;
202 window
= __glutGetWindow(devbtn
->window
);
205 && devbtn
->deviceid
== __glutTablet
->device_id
206 && window
->tabletButton
207 && devbtn
->first_axis
== 0
208 && devbtn
->axes_count
== 2) {
209 tabletPosChange(window
, devbtn
->first_axis
, devbtn
->axes_count
,
211 window
->tabletButton(devbtn
->button
, GLUT_DOWN
,
212 window
->tabletPos
[0], window
->tabletPos
[1]);
213 } else if (__glutDials
214 && devbtn
->deviceid
== __glutDials
->device_id
215 && window
->buttonBox
) {
216 window
->buttonBox(devbtn
->button
, GLUT_DOWN
);
217 } else if (__glutSpaceball
218 && devbtn
->deviceid
== __glutSpaceball
->device_id
219 && window
->spaceButton
) {
220 window
->spaceButton(devbtn
->button
, GLUT_DOWN
);
224 } else if (__glutDeviceButtonRelease
225 && event
->type
== __glutDeviceButtonRelease
) {
226 XDeviceButtonEvent
*devbtn
= (XDeviceButtonEvent
*) event
;
228 window
= __glutGetWindow(devbtn
->window
);
231 && devbtn
->deviceid
== __glutTablet
->device_id
232 && window
->tabletButton
233 && devbtn
->first_axis
== 0
234 && devbtn
->axes_count
== 2) {
235 tabletPosChange(window
, devbtn
->first_axis
, devbtn
->axes_count
,
237 window
->tabletButton(devbtn
->button
, GLUT_UP
,
238 window
->tabletPos
[0], window
->tabletPos
[1]);
239 } else if (__glutDials
240 && devbtn
->deviceid
== __glutDials
->device_id
241 && window
->buttonBox
) {
242 window
->buttonBox(devbtn
->button
, GLUT_UP
);
243 } else if (__glutSpaceball
244 && devbtn
->deviceid
== __glutSpaceball
->device_id
245 && window
->spaceButton
) {
246 window
->spaceButton(devbtn
->button
, GLUT_UP
);
256 memset(&info
, 0, sizeof(JOYINFOEX
));
257 info
.dwSize
= sizeof(JOYINFOEX
);
258 info
.dwFlags
= JOY_RETURNALL
;
260 if (joyGetPosEx(JOYSTICKID1
,&info
) != JOYERR_NOERROR
) {
261 __glutHasJoystick
= 1;
262 joyGetDevCaps(JOYSTICKID1
, &joyCaps
, sizeof(joyCaps
));
263 __glutNumJoystickButtons
= joyCaps
.wNumButtons
;
264 __glutNumJoystickAxes
= joyCaps
.wNumAxes
;
266 __glutHasJoystick
= 0;
267 __glutNumJoystickButtons
= 0;
268 __glutNumJoystickAxes
= 0;
275 static GLUTeventParser eventParser
=
276 {__glutProcessDeviceEvents
, NULL
};
279 addDeviceEventParser(void)
281 static Bool been_here
= False
;
286 __glutRegisterEventParser(&eventParser
);
292 static Bool been_here
= False
;
295 XExtensionVersion
*version
;
296 XDeviceInfoPtr device_info
, device
;
301 int num_dev
= 0, btns
= 0, dials
= 0;
311 version
= XGetExtensionVersion(__glutDisplay
, "XInputExtension");
312 /* Ugh. XInput extension API forces annoying cast of a pointer
313 to a long so it can be compared with the NoSuchExtension
314 value (#defined to 1). */
315 if (version
== NULL
|| ((long) version
) == NoSuchExtension
) {
320 device_info
= XListInputDevices(__glutDisplay
, &num_dev
);
322 for (i
= 0; i
< num_dev
; i
++) {
323 /* XXX These are SGI names for these devices;
324 unfortunately, no good standard exists for standard
325 types of X input extension devices. */
327 device
= &device_info
[i
];
328 any
= (XAnyClassPtr
) device
->inputclassinfo
;
330 if (!__glutSpaceball
&& !strcmp(device
->name
, "spaceball")) {
333 for (j
= 0; j
< device
->num_classes
; j
++) {
334 #if defined(__cplusplus) || defined(c_plusplus)
335 switch (any
->c_class
) {
337 switch (any
->class) {
340 b
= (XButtonInfoPtr
) any
;
341 btns
= b
->num_buttons
;
344 v
= (XValuatorInfoPtr
) any
;
345 /* Sanity check: at least 6 valuators? */
346 if (v
->num_axes
< NUM_SPACEBALL_AXIS
)
348 a
= (XAxisInfoPtr
) ((char *) v
+ sizeof(XValuatorInfo
));
349 for (k
= 0; k
< NUM_SPACEBALL_AXIS
; k
++, a
++) {
350 __glutSpaceballRange
[k
].min
= a
->min_value
;
351 __glutSpaceballRange
[k
].range
= a
->max_value
- a
->min_value
;
355 any
= (XAnyClassPtr
) ((char *) any
+ any
->length
);
358 __glutSpaceball
= XOpenDevice(__glutDisplay
, device
->id
);
359 if (__glutSpaceball
) {
360 __glutNumSpaceballButtons
= btns
;
361 addDeviceEventParser();
364 } else if (!__glutDials
&& !strcmp(device
->name
, "dial+buttons")) {
367 for (j
= 0; j
< device
->num_classes
; j
++) {
368 #if defined(__cplusplus) || defined(c_plusplus)
369 switch (any
->c_class
) {
371 switch (any
->class) {
374 b
= (XButtonInfoPtr
) any
;
375 btns
= b
->num_buttons
;
378 v
= (XValuatorInfoPtr
) any
;
379 /* Sanity check: at least 8 valuators? */
380 if (v
->num_axes
< NUM_DIALS_AXIS
)
383 __glutDialsResolution
= (int *) malloc(sizeof(int) * dials
);
384 a
= (XAxisInfoPtr
) ((char *) v
+ sizeof(XValuatorInfo
));
385 for (k
= 0; k
< dials
; k
++, a
++) {
386 __glutDialsResolution
[k
] = a
->resolution
;
390 any
= (XAnyClassPtr
) ((char *) any
+ any
->length
);
393 __glutDials
= XOpenDevice(__glutDisplay
, device
->id
);
395 __glutNumButtonBoxButtons
= btns
;
396 __glutNumDials
= dials
;
397 addDeviceEventParser();
400 } else if (!__glutTablet
&& !strcmp(device
->name
, "tablet")) {
403 for (j
= 0; j
< device
->num_classes
; j
++) {
404 #if defined(__cplusplus) || defined(c_plusplus)
405 switch (any
->c_class
) {
407 switch (any
->class) {
410 b
= (XButtonInfoPtr
) any
;
411 btns
= b
->num_buttons
;
414 v
= (XValuatorInfoPtr
) any
;
415 /* Sanity check: exactly 2 valuators? */
416 if (v
->num_axes
!= NUM_TABLET_AXIS
)
418 a
= (XAxisInfoPtr
) ((char *) v
+ sizeof(XValuatorInfo
));
419 for (k
= 0; k
< NUM_TABLET_AXIS
; k
++, a
++) {
420 __glutTabletRange
[k
].min
= a
->min_value
;
421 __glutTabletRange
[k
].range
= a
->max_value
- a
->min_value
;
425 any
= (XAnyClassPtr
) ((char *) any
+ any
->length
);
428 __glutTablet
= XOpenDevice(__glutDisplay
, device
->id
);
430 __glutNumTabletButtons
= btns
;
431 addDeviceEventParser();
434 } else if (!strcmp(device
->name
, "mouse")) {
435 for (j
= 0; j
< device
->num_classes
; j
++) {
436 #if defined(__cplusplus) || defined(c_plusplus)
437 if (any
->c_class
== ButtonClass
) {
439 if (any
->class == ButtonClass
) {
441 b
= (XButtonInfoPtr
) any
;
442 __glutNumMouseButtons
= b
->num_buttons
;
444 any
= (XAnyClassPtr
) ((char *) any
+ any
->length
);
449 XFreeDeviceList(device_info
);
452 __glutNumMouseButtons
= GetSystemMetrics(SM_CMOUSEBUTTONS
);
454 /* X Input extension might be supported, but only if there is
455 a tablet, dials, or spaceball do we claim devices are
457 support
= __glutTablet
|| __glutDials
|| __glutSpaceball
;
462 __glutUpdateInputDeviceMask(GLUTwindow
* window
)
465 /* 5 (dial and buttons) + 5 (tablet locator and buttons) + 5
466 (Spaceball buttons and axis) = 15 */
467 XEventClass eventList
[15];
474 if (window
->tabletMotion
) {
475 DeviceMotionNotify(__glutTablet
, __glutDeviceMotionNotify
,
476 eventList
[numEvents
]);
479 if (window
->tabletButton
) {
480 DeviceButtonPress(__glutTablet
, __glutDeviceButtonPress
,
481 eventList
[numEvents
]);
483 DeviceButtonPressGrab(__glutTablet
, __glutDeviceButtonPressGrab
,
484 eventList
[numEvents
]);
486 DeviceButtonRelease(__glutTablet
, __glutDeviceButtonRelease
,
487 eventList
[numEvents
]);
490 if (window
->tabletMotion
|| window
->tabletButton
) {
491 DeviceStateNotify(__glutTablet
, __glutDeviceStateNotify
,
492 eventList
[numEvents
]);
498 DeviceMotionNotify(__glutDials
, __glutDeviceMotionNotify
,
499 eventList
[numEvents
]);
502 if (window
->buttonBox
) {
503 DeviceButtonPress(__glutDials
, __glutDeviceButtonPress
,
504 eventList
[numEvents
]);
506 DeviceButtonPressGrab(__glutDials
, __glutDeviceButtonPressGrab
,
507 eventList
[numEvents
]);
509 DeviceButtonRelease(__glutDials
, __glutDeviceButtonRelease
,
510 eventList
[numEvents
]);
513 if (window
->dials
|| window
->buttonBox
) {
514 DeviceStateNotify(__glutDials
, __glutDeviceStateNotify
,
515 eventList
[numEvents
]);
519 if (__glutSpaceball
) {
520 if (window
->spaceMotion
|| window
->spaceRotate
) {
521 DeviceMotionNotify(__glutSpaceball
, __glutDeviceMotionNotify
,
522 eventList
[numEvents
]);
525 if (window
->spaceButton
) {
526 DeviceButtonPress(__glutSpaceball
, __glutDeviceButtonPress
,
527 eventList
[numEvents
]);
529 DeviceButtonPressGrab(__glutSpaceball
, __glutDeviceButtonPressGrab
,
530 eventList
[numEvents
]);
532 DeviceButtonRelease(__glutSpaceball
, __glutDeviceButtonRelease
,
533 eventList
[numEvents
]);
536 if (window
->spaceMotion
|| window
->spaceRotate
|| window
->spaceButton
) {
537 DeviceStateNotify(__glutSpaceball
, __glutDeviceStateNotify
,
538 eventList
[numEvents
]);
543 if (window
->children
) {
544 GLUTwindow
*child
= window
->children
;
547 XChangeDeviceDontPropagateList(__glutDisplay
, child
->win
,
548 numEvents
, eventList
, AddToList
);
549 child
= child
->siblings
;
553 XSelectExtensionEvent(__glutDisplay
, window
->win
,
554 eventList
, numEvents
);
555 if (window
->overlay
) {
556 XSelectExtensionEvent(__glutDisplay
, window
->overlay
->win
,
557 eventList
, numEvents
);
560 /* X Input extension not supported; no chance for exotic
570 glutDeviceGet(GLenum param
)
576 case GLUT_HAS_KEYBOARD
:
578 /* Assume window system always has mouse and keyboard. */
581 case GLUT_HAS_SPACEBALL
:
582 return __glutSpaceball
!= NULL
;
583 case GLUT_HAS_DIAL_AND_BUTTON_BOX
:
584 return __glutDials
!= NULL
;
585 case GLUT_HAS_TABLET
:
586 return __glutTablet
!= NULL
;
587 case GLUT_NUM_MOUSE_BUTTONS
:
588 return __glutNumMouseButtons
;
589 case GLUT_NUM_SPACEBALL_BUTTONS
:
590 return __glutNumSpaceballButtons
;
591 case GLUT_NUM_BUTTON_BOX_BUTTONS
:
592 return __glutNumButtonBoxButtons
;
594 return __glutNumDials
;
595 case GLUT_NUM_TABLET_BUTTONS
:
596 return __glutNumTabletButtons
;
597 case GLUT_DEVICE_IGNORE_KEY_REPEAT
:
598 return __glutCurrentWindow
->ignoreKeyRepeat
;
600 case GLUT_DEVICE_KEY_REPEAT
:
602 XKeyboardState state
;
604 XGetKeyboardControl(__glutDisplay
, &state
);
605 return state
.global_auto_repeat
;
607 case GLUT_JOYSTICK_POLL_RATE
:
610 case GLUT_DEVICE_KEY_REPEAT
:
611 /* Win32 cannot globally disable key repeat. */
612 return GLUT_KEY_REPEAT_ON
;
613 case GLUT_JOYSTICK_POLL_RATE
:
614 return __glutCurrentWindow
->joyPollInterval
;
616 case GLUT_HAS_JOYSTICK
:
617 return __glutHasJoystick
;
618 case GLUT_JOYSTICK_BUTTONS
:
619 return __glutNumJoystickButtons
;
620 case GLUT_JOYSTICK_AXES
:
621 return __glutNumJoystickAxes
;
624 __glutWarning("invalid glutDeviceGet parameter: %d", param
);