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. */
9 #include <GL/vms_x_fix.h>
20 #include <X11/XInput.h>
22 #include <X11/extensions/XInput.h>
24 #include <X11/Xutil.h>
28 #include <mmsystem.h> /* Win32 Multimedia API header. */
34 int __glutNumDials
= 0;
35 int __glutNumSpaceballButtons
= 0;
36 int __glutNumButtonBoxButtons
= 0;
37 int __glutNumTabletButtons
= 0;
38 int __glutNumMouseButtons
= 3; /* Good guess. */
39 XDevice
*__glutTablet
= NULL
;
40 XDevice
*__glutDials
= NULL
;
41 XDevice
*__glutSpaceball
= NULL
;
43 int __glutHasJoystick
= 0;
44 int __glutNumJoystickButtons
= 0;
45 int __glutNumJoystickAxes
= 0;
48 typedef struct _Range
{
53 #define NUM_SPACEBALL_AXIS 6
54 #define NUM_TABLET_AXIS 2
55 #define NUM_DIALS_AXIS 8
57 Range __glutSpaceballRange
[NUM_SPACEBALL_AXIS
];
58 Range __glutTabletRange
[NUM_TABLET_AXIS
];
59 int *__glutDialsResolution
;
61 /* Safely assumes 0 is an illegal event type for X Input
63 int __glutDeviceMotionNotify
= 0;
64 int __glutDeviceButtonPress
= 0;
65 int __glutDeviceButtonPressGrab
= 0;
66 int __glutDeviceButtonRelease
= 0;
67 int __glutDeviceStateNotify
= 0;
70 normalizeTabletPos(int axis
, int rawValue
)
72 assert(rawValue
>= __glutTabletRange
[axis
].min
);
73 assert(rawValue
<= __glutTabletRange
[axis
].min
74 + __glutTabletRange
[axis
].range
);
75 /* Normalize rawValue to between 0 and 4000. */
76 return ((rawValue
- __glutTabletRange
[axis
].min
) * 4000) /
77 __glutTabletRange
[axis
].range
;
81 normalizeDialAngle(int axis
, int rawValue
)
83 /* XXX Assumption made that the resolution of the device is
84 number of clicks for one complete dial revolution. This
85 is true for SGI's dial & button box. */
86 return (rawValue
* 360.0) / __glutDialsResolution
[axis
];
90 normalizeSpaceballAngle(int axis
, int rawValue
)
92 assert(rawValue
>= __glutSpaceballRange
[axis
].min
);
93 assert(rawValue
<= __glutSpaceballRange
[axis
].min
+
94 __glutSpaceballRange
[axis
].range
);
95 /* Normalize rawValue to between -1800 and 1800. */
96 return ((rawValue
- __glutSpaceballRange
[axis
].min
) * 3600) /
97 __glutSpaceballRange
[axis
].range
- 1800;
101 normalizeSpaceballDelta(int axis
, int rawValue
)
103 assert(rawValue
>= __glutSpaceballRange
[axis
].min
);
104 assert(rawValue
<= __glutSpaceballRange
[axis
].min
+
105 __glutSpaceballRange
[axis
].range
);
106 /* Normalize rawValue to between -1000 and 1000. */
107 return ((rawValue
- __glutSpaceballRange
[axis
].min
) * 2000) /
108 __glutSpaceballRange
[axis
].range
- 1000;
112 queryTabletPos(GLUTwindow
* window
)
119 state
= XQueryDeviceState(__glutDisplay
, __glutTablet
);
121 for (i
= 0; i
< state
->num_classes
; i
++) {
122 #if defined(__cplusplus) || defined(c_plusplus)
123 switch (any
->c_class
) {
125 switch (any
->class) {
128 v
= (XValuatorState
*) any
;
129 if (v
->num_valuators
< 2)
131 if (window
->tabletPos
[0] == -1)
132 window
->tabletPos
[0] = normalizeTabletPos(0, v
->valuators
[0]);
133 if (window
->tabletPos
[1] == -1)
134 window
->tabletPos
[1] = normalizeTabletPos(1, v
->valuators
[1]);
136 any
= (XInputClass
*) ((char *) any
+ any
->length
);
139 XFreeDeviceState(state
);
143 tabletPosChange(GLUTwindow
* window
, int first
, int count
, int *data
)
145 int i
, value
, genEvent
= 0;
147 for (i
= first
; i
< first
+ count
; i
++) {
151 value
= normalizeTabletPos(i
, data
[i
- first
]);
152 if (value
!= window
->tabletPos
[i
]) {
153 window
->tabletPos
[i
] = value
;
159 if (window
->tabletPos
[0] == -1 || window
->tabletPos
[1] == -1)
160 queryTabletPos(window
);
162 window
->tabletMotion(window
->tabletPos
[0], window
->tabletPos
[1]);
167 __glutProcessDeviceEvents(XEvent
* event
)
172 /* XXX Ugly code fan out. */
174 /* Can't use switch/case since X Input event types are
177 if (__glutDeviceMotionNotify
&& event
->type
== __glutDeviceMotionNotify
) {
178 XDeviceMotionEvent
*devmot
= (XDeviceMotionEvent
*) event
;
180 window
= __glutGetWindow(devmot
->window
);
183 && devmot
->deviceid
== __glutTablet
->device_id
184 && window
->tabletMotion
) {
185 tabletPosChange(window
, devmot
->first_axis
, devmot
->axes_count
,
187 } else if (__glutDials
188 && devmot
->deviceid
== __glutDials
->device_id
190 int i
, first
= devmot
->first_axis
, count
= devmot
->axes_count
;
192 for (i
= first
; i
< first
+ count
; i
++)
194 normalizeDialAngle(i
, devmot
->axis_data
[i
- first
]));
195 } else if (__glutSpaceball
196 && devmot
->deviceid
== __glutSpaceball
->device_id
) {
197 /* XXX Assume that space ball motion events come in as
198 all the first 6 axes. Assume first 3 axes are XYZ
199 translations; second 3 axes are XYZ rotations. */
200 if (devmot
->first_axis
== 0 && devmot
->axes_count
== 6) {
201 if (window
->spaceMotion
)
203 normalizeSpaceballDelta(0, devmot
->axis_data
[0]),
204 normalizeSpaceballDelta(1, devmot
->axis_data
[1]),
205 normalizeSpaceballDelta(2, devmot
->axis_data
[2]));
206 if (window
->spaceRotate
)
208 normalizeSpaceballAngle(3, devmot
->axis_data
[3]),
209 normalizeSpaceballAngle(4, devmot
->axis_data
[4]),
210 normalizeSpaceballAngle(5, devmot
->axis_data
[5]));
215 } else if (__glutDeviceButtonPress
216 && event
->type
== __glutDeviceButtonPress
) {
217 XDeviceButtonEvent
*devbtn
= (XDeviceButtonEvent
*) event
;
219 window
= __glutGetWindow(devbtn
->window
);
222 && devbtn
->deviceid
== __glutTablet
->device_id
223 && window
->tabletButton
224 && devbtn
->first_axis
== 0
225 && devbtn
->axes_count
== 2) {
226 tabletPosChange(window
, devbtn
->first_axis
, devbtn
->axes_count
,
228 window
->tabletButton(devbtn
->button
, GLUT_DOWN
,
229 window
->tabletPos
[0], window
->tabletPos
[1]);
230 } else if (__glutDials
231 && devbtn
->deviceid
== __glutDials
->device_id
232 && window
->buttonBox
) {
233 window
->buttonBox(devbtn
->button
, GLUT_DOWN
);
234 } else if (__glutSpaceball
235 && devbtn
->deviceid
== __glutSpaceball
->device_id
236 && window
->spaceButton
) {
237 window
->spaceButton(devbtn
->button
, GLUT_DOWN
);
241 } else if (__glutDeviceButtonRelease
242 && event
->type
== __glutDeviceButtonRelease
) {
243 XDeviceButtonEvent
*devbtn
= (XDeviceButtonEvent
*) event
;
245 window
= __glutGetWindow(devbtn
->window
);
248 && devbtn
->deviceid
== __glutTablet
->device_id
249 && window
->tabletButton
250 && devbtn
->first_axis
== 0
251 && devbtn
->axes_count
== 2) {
252 tabletPosChange(window
, devbtn
->first_axis
, devbtn
->axes_count
,
254 window
->tabletButton(devbtn
->button
, GLUT_UP
,
255 window
->tabletPos
[0], window
->tabletPos
[1]);
256 } else if (__glutDials
257 && devbtn
->deviceid
== __glutDials
->device_id
258 && window
->buttonBox
) {
259 window
->buttonBox(devbtn
->button
, GLUT_UP
);
260 } else if (__glutSpaceball
261 && devbtn
->deviceid
== __glutSpaceball
->device_id
262 && window
->spaceButton
) {
263 window
->spaceButton(devbtn
->button
, GLUT_UP
);
273 memset(&info
, 0, sizeof(JOYINFOEX
));
274 info
.dwSize
= sizeof(JOYINFOEX
);
275 info
.dwFlags
= JOY_RETURNALL
;
277 if (joyGetPosEx(JOYSTICKID1
,&info
) != JOYERR_NOERROR
) {
278 __glutHasJoystick
= 1;
279 joyGetDevCaps(JOYSTICKID1
, &joyCaps
, sizeof(joyCaps
));
280 __glutNumJoystickButtons
= joyCaps
.wNumButtons
;
281 __glutNumJoystickAxes
= joyCaps
.wNumAxes
;
283 __glutHasJoystick
= 0;
284 __glutNumJoystickButtons
= 0;
285 __glutNumJoystickAxes
= 0;
292 static GLUTeventParser eventParser
=
293 {__glutProcessDeviceEvents
, NULL
};
296 addDeviceEventParser(void)
298 static Bool been_here
= False
;
303 __glutRegisterEventParser(&eventParser
);
309 static Bool been_here
= False
;
312 XExtensionVersion
*version
;
313 XDeviceInfoPtr device_info
, device
;
318 int num_dev
= 0, btns
= 0, dials
= 0;
328 version
= XGetExtensionVersion(__glutDisplay
, "XInputExtension");
329 /* Ugh. XInput extension API forces annoying cast of a pointer
330 to a long so it can be compared with the NoSuchExtension
331 value (#defined to 1). */
332 if (version
== NULL
|| ((long) version
) == NoSuchExtension
) {
337 device_info
= XListInputDevices(__glutDisplay
, &num_dev
);
339 for (i
= 0; i
< num_dev
; i
++) {
340 /* XXX These are SGI names for these devices;
341 unfortunately, no good standard exists for standard
342 types of X input extension devices. */
344 device
= &device_info
[i
];
345 any
= (XAnyClassPtr
) device
->inputclassinfo
;
347 if (!__glutSpaceball
&& !strcmp(device
->name
, "spaceball")) {
350 for (j
= 0; j
< device
->num_classes
; j
++) {
351 #if defined(__cplusplus) || defined(c_plusplus)
352 switch (any
->c_class
) {
354 switch (any
->class) {
357 b
= (XButtonInfoPtr
) any
;
358 btns
= b
->num_buttons
;
361 v
= (XValuatorInfoPtr
) any
;
362 /* Sanity check: at least 6 valuators? */
363 if (v
->num_axes
< NUM_SPACEBALL_AXIS
)
365 a
= (XAxisInfoPtr
) ((char *) v
+ sizeof(XValuatorInfo
));
366 for (k
= 0; k
< NUM_SPACEBALL_AXIS
; k
++, a
++) {
367 __glutSpaceballRange
[k
].min
= a
->min_value
;
368 __glutSpaceballRange
[k
].range
= a
->max_value
- a
->min_value
;
372 any
= (XAnyClassPtr
) ((char *) any
+ any
->length
);
375 __glutSpaceball
= XOpenDevice(__glutDisplay
, device
->id
);
376 if (__glutSpaceball
) {
377 __glutNumSpaceballButtons
= btns
;
378 addDeviceEventParser();
381 } else if (!__glutDials
&& !strcmp(device
->name
, "dial+buttons")) {
384 for (j
= 0; j
< device
->num_classes
; j
++) {
385 #if defined(__cplusplus) || defined(c_plusplus)
386 switch (any
->c_class
) {
388 switch (any
->class) {
391 b
= (XButtonInfoPtr
) any
;
392 btns
= b
->num_buttons
;
395 v
= (XValuatorInfoPtr
) any
;
396 /* Sanity check: at least 8 valuators? */
397 if (v
->num_axes
< NUM_DIALS_AXIS
)
400 __glutDialsResolution
= (int *) malloc(sizeof(int) * dials
);
401 a
= (XAxisInfoPtr
) ((char *) v
+ sizeof(XValuatorInfo
));
402 for (k
= 0; k
< dials
; k
++, a
++) {
403 __glutDialsResolution
[k
] = a
->resolution
;
407 any
= (XAnyClassPtr
) ((char *) any
+ any
->length
);
410 __glutDials
= XOpenDevice(__glutDisplay
, device
->id
);
412 __glutNumButtonBoxButtons
= btns
;
413 __glutNumDials
= dials
;
414 addDeviceEventParser();
417 } else if (!__glutTablet
&& !strcmp(device
->name
, "tablet")) {
420 for (j
= 0; j
< device
->num_classes
; j
++) {
421 #if defined(__cplusplus) || defined(c_plusplus)
422 switch (any
->c_class
) {
424 switch (any
->class) {
427 b
= (XButtonInfoPtr
) any
;
428 btns
= b
->num_buttons
;
431 v
= (XValuatorInfoPtr
) any
;
432 /* Sanity check: exactly 2 valuators? */
433 if (v
->num_axes
!= NUM_TABLET_AXIS
)
435 a
= (XAxisInfoPtr
) ((char *) v
+ sizeof(XValuatorInfo
));
436 for (k
= 0; k
< NUM_TABLET_AXIS
; k
++, a
++) {
437 __glutTabletRange
[k
].min
= a
->min_value
;
438 __glutTabletRange
[k
].range
= a
->max_value
- a
->min_value
;
442 any
= (XAnyClassPtr
) ((char *) any
+ any
->length
);
445 __glutTablet
= XOpenDevice(__glutDisplay
, device
->id
);
447 __glutNumTabletButtons
= btns
;
448 addDeviceEventParser();
451 } else if (!strcmp(device
->name
, "mouse")) {
452 for (j
= 0; j
< device
->num_classes
; j
++) {
453 #if defined(__cplusplus) || defined(c_plusplus)
454 if (any
->c_class
== ButtonClass
) {
456 if (any
->class == ButtonClass
) {
458 b
= (XButtonInfoPtr
) any
;
459 __glutNumMouseButtons
= b
->num_buttons
;
461 any
= (XAnyClassPtr
) ((char *) any
+ any
->length
);
466 XFreeDeviceList(device_info
);
469 __glutNumMouseButtons
= GetSystemMetrics(SM_CMOUSEBUTTONS
);
471 /* X Input extension might be supported, but only if there is
472 a tablet, dials, or spaceball do we claim devices are
474 support
= __glutTablet
|| __glutDials
|| __glutSpaceball
;
479 __glutUpdateInputDeviceMask(GLUTwindow
* window
)
482 /* 5 (dial and buttons) + 5 (tablet locator and buttons) + 5
483 (Spaceball buttons and axis) = 15 */
484 XEventClass eventList
[15];
491 if (window
->tabletMotion
) {
492 DeviceMotionNotify(__glutTablet
, __glutDeviceMotionNotify
,
493 eventList
[numEvents
]);
496 if (window
->tabletButton
) {
497 DeviceButtonPress(__glutTablet
, __glutDeviceButtonPress
,
498 eventList
[numEvents
]);
500 DeviceButtonPressGrab(__glutTablet
, __glutDeviceButtonPressGrab
,
501 eventList
[numEvents
]);
503 DeviceButtonRelease(__glutTablet
, __glutDeviceButtonRelease
,
504 eventList
[numEvents
]);
507 if (window
->tabletMotion
|| window
->tabletButton
) {
508 DeviceStateNotify(__glutTablet
, __glutDeviceStateNotify
,
509 eventList
[numEvents
]);
515 DeviceMotionNotify(__glutDials
, __glutDeviceMotionNotify
,
516 eventList
[numEvents
]);
519 if (window
->buttonBox
) {
520 DeviceButtonPress(__glutDials
, __glutDeviceButtonPress
,
521 eventList
[numEvents
]);
523 DeviceButtonPressGrab(__glutDials
, __glutDeviceButtonPressGrab
,
524 eventList
[numEvents
]);
526 DeviceButtonRelease(__glutDials
, __glutDeviceButtonRelease
,
527 eventList
[numEvents
]);
530 if (window
->dials
|| window
->buttonBox
) {
531 DeviceStateNotify(__glutDials
, __glutDeviceStateNotify
,
532 eventList
[numEvents
]);
536 if (__glutSpaceball
) {
537 if (window
->spaceMotion
|| window
->spaceRotate
) {
538 DeviceMotionNotify(__glutSpaceball
, __glutDeviceMotionNotify
,
539 eventList
[numEvents
]);
542 if (window
->spaceButton
) {
543 DeviceButtonPress(__glutSpaceball
, __glutDeviceButtonPress
,
544 eventList
[numEvents
]);
546 DeviceButtonPressGrab(__glutSpaceball
, __glutDeviceButtonPressGrab
,
547 eventList
[numEvents
]);
549 DeviceButtonRelease(__glutSpaceball
, __glutDeviceButtonRelease
,
550 eventList
[numEvents
]);
553 if (window
->spaceMotion
|| window
->spaceRotate
|| window
->spaceButton
) {
554 DeviceStateNotify(__glutSpaceball
, __glutDeviceStateNotify
,
555 eventList
[numEvents
]);
560 if (window
->children
) {
561 GLUTwindow
*child
= window
->children
;
564 XChangeDeviceDontPropagateList(__glutDisplay
, child
->win
,
565 numEvents
, eventList
, AddToList
);
566 child
= child
->siblings
;
570 XSelectExtensionEvent(__glutDisplay
, window
->win
,
571 eventList
, numEvents
);
572 if (window
->overlay
) {
573 XSelectExtensionEvent(__glutDisplay
, window
->overlay
->win
,
574 eventList
, numEvents
);
577 /* X Input extension not supported; no chance for exotic
585 glutDeviceGet(GLenum param
)
589 case GLUT_HAS_KEYBOARD
:
591 /* Assume window system always has mouse and keyboard. */
593 case GLUT_HAS_SPACEBALL
:
594 return __glutSpaceball
!= NULL
;
595 case GLUT_HAS_DIAL_AND_BUTTON_BOX
:
596 return __glutDials
!= NULL
;
597 case GLUT_HAS_TABLET
:
598 return __glutTablet
!= NULL
;
599 case GLUT_NUM_MOUSE_BUTTONS
:
600 return __glutNumMouseButtons
;
601 case GLUT_NUM_SPACEBALL_BUTTONS
:
602 return __glutNumSpaceballButtons
;
603 case GLUT_NUM_BUTTON_BOX_BUTTONS
:
604 return __glutNumButtonBoxButtons
;
606 return __glutNumDials
;
607 case GLUT_NUM_TABLET_BUTTONS
:
608 return __glutNumTabletButtons
;
609 case GLUT_DEVICE_IGNORE_KEY_REPEAT
:
610 return __glutCurrentWindow
->ignoreKeyRepeat
;
612 case GLUT_DEVICE_KEY_REPEAT
:
614 XKeyboardState state
;
616 XGetKeyboardControl(__glutDisplay
, &state
);
617 return state
.global_auto_repeat
;
619 case GLUT_JOYSTICK_POLL_RATE
:
622 case GLUT_DEVICE_KEY_REPEAT
:
623 /* Win32 cannot globally disable key repeat. */
624 return GLUT_KEY_REPEAT_ON
;
625 case GLUT_JOYSTICK_POLL_RATE
:
626 return __glutCurrentWindow
->joyPollInterval
;
628 case GLUT_HAS_JOYSTICK
:
629 return __glutHasJoystick
;
630 case GLUT_JOYSTICK_BUTTONS
:
631 return __glutNumJoystickButtons
;
632 case GLUT_JOYSTICK_AXES
:
633 return __glutNumJoystickAxes
;
635 __glutWarning("invalid glutDeviceGet parameter: %d", param
);