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>
31 #include <mmsystem.h> /* Win32 Multimedia API header. */
37 int __glutNumDials
= 0;
38 int __glutNumSpaceballButtons
= 0;
39 int __glutNumButtonBoxButtons
= 0;
40 int __glutNumTabletButtons
= 0;
41 int __glutNumMouseButtons
= 3; /* Good guess. */
42 XDevice
*__glutTablet
= NULL
;
43 XDevice
*__glutDials
= NULL
;
44 XDevice
*__glutSpaceball
= NULL
;
46 int __glutHasJoystick
= 0;
47 int __glutNumJoystickButtons
= 0;
48 int __glutNumJoystickAxes
= 0;
51 typedef struct _Range
{
56 #define NUM_SPACEBALL_AXIS 6
57 #define NUM_TABLET_AXIS 2
58 #define NUM_DIALS_AXIS 8
60 Range __glutSpaceballRange
[NUM_SPACEBALL_AXIS
];
61 Range __glutTabletRange
[NUM_TABLET_AXIS
];
62 int *__glutDialsResolution
;
64 /* Safely assumes 0 is an illegal event type for X Input
66 int __glutDeviceMotionNotify
= 0;
67 int __glutDeviceButtonPress
= 0;
68 int __glutDeviceButtonPressGrab
= 0;
69 int __glutDeviceButtonRelease
= 0;
70 int __glutDeviceStateNotify
= 0;
73 normalizeTabletPos(int axis
, int rawValue
)
75 assert(rawValue
>= __glutTabletRange
[axis
].min
);
76 assert(rawValue
<= __glutTabletRange
[axis
].min
77 + __glutTabletRange
[axis
].range
);
78 /* Normalize rawValue to between 0 and 4000. */
79 return ((rawValue
- __glutTabletRange
[axis
].min
) * 4000) /
80 __glutTabletRange
[axis
].range
;
84 normalizeDialAngle(int axis
, int rawValue
)
86 /* XXX Assumption made that the resolution of the device is
87 number of clicks for one complete dial revolution. This
88 is true for SGI's dial & button box. */
89 return (rawValue
* 360.0) / __glutDialsResolution
[axis
];
93 normalizeSpaceballAngle(int axis
, int rawValue
)
95 assert(rawValue
>= __glutSpaceballRange
[axis
].min
);
96 assert(rawValue
<= __glutSpaceballRange
[axis
].min
+
97 __glutSpaceballRange
[axis
].range
);
98 /* Normalize rawValue to between -1800 and 1800. */
99 return ((rawValue
- __glutSpaceballRange
[axis
].min
) * 3600) /
100 __glutSpaceballRange
[axis
].range
- 1800;
104 normalizeSpaceballDelta(int axis
, int rawValue
)
106 assert(rawValue
>= __glutSpaceballRange
[axis
].min
);
107 assert(rawValue
<= __glutSpaceballRange
[axis
].min
+
108 __glutSpaceballRange
[axis
].range
);
109 /* Normalize rawValue to between -1000 and 1000. */
110 return ((rawValue
- __glutSpaceballRange
[axis
].min
) * 2000) /
111 __glutSpaceballRange
[axis
].range
- 1000;
115 queryTabletPos(GLUTwindow
* window
)
122 state
= XQueryDeviceState(__glutDisplay
, __glutTablet
);
124 for (i
= 0; i
< state
->num_classes
; i
++) {
125 #if defined(__cplusplus) || defined(c_plusplus)
126 switch (any
->c_class
) {
128 switch (any
->class) {
131 v
= (XValuatorState
*) any
;
132 if (v
->num_valuators
< 2)
134 if (window
->tabletPos
[0] == -1)
135 window
->tabletPos
[0] = normalizeTabletPos(0, v
->valuators
[0]);
136 if (window
->tabletPos
[1] == -1)
137 window
->tabletPos
[1] = normalizeTabletPos(1, v
->valuators
[1]);
139 any
= (XInputClass
*) ((char *) any
+ any
->length
);
142 XFreeDeviceState(state
);
146 tabletPosChange(GLUTwindow
* window
, int first
, int count
, int *data
)
148 int i
, value
, genEvent
= 0;
150 for (i
= first
; i
< first
+ count
; i
++) {
154 value
= normalizeTabletPos(i
, data
[i
- first
]);
155 if (value
!= window
->tabletPos
[i
]) {
156 window
->tabletPos
[i
] = value
;
162 if (window
->tabletPos
[0] == -1 || window
->tabletPos
[1] == -1)
163 queryTabletPos(window
);
165 window
->tabletMotion(window
->tabletPos
[0], window
->tabletPos
[1]);
170 __glutProcessDeviceEvents(XEvent
* event
)
175 /* XXX Ugly code fan out. */
177 /* Can't use switch/case since X Input event types are
180 if (__glutDeviceMotionNotify
&& event
->type
== __glutDeviceMotionNotify
) {
181 XDeviceMotionEvent
*devmot
= (XDeviceMotionEvent
*) event
;
183 window
= __glutGetWindow(devmot
->window
);
186 && devmot
->deviceid
== __glutTablet
->device_id
187 && window
->tabletMotion
) {
188 tabletPosChange(window
, devmot
->first_axis
, devmot
->axes_count
,
190 } else if (__glutDials
191 && devmot
->deviceid
== __glutDials
->device_id
193 int i
, first
= devmot
->first_axis
, count
= devmot
->axes_count
;
195 for (i
= first
; i
< first
+ count
; i
++)
197 normalizeDialAngle(i
, devmot
->axis_data
[i
- first
]));
198 } else if (__glutSpaceball
199 && devmot
->deviceid
== __glutSpaceball
->device_id
) {
200 /* XXX Assume that space ball motion events come in as
201 all the first 6 axes. Assume first 3 axes are XYZ
202 translations; second 3 axes are XYZ rotations. */
203 if (devmot
->first_axis
== 0 && devmot
->axes_count
== 6) {
204 if (window
->spaceMotion
)
206 normalizeSpaceballDelta(0, devmot
->axis_data
[0]),
207 normalizeSpaceballDelta(1, devmot
->axis_data
[1]),
208 normalizeSpaceballDelta(2, devmot
->axis_data
[2]));
209 if (window
->spaceRotate
)
211 normalizeSpaceballAngle(3, devmot
->axis_data
[3]),
212 normalizeSpaceballAngle(4, devmot
->axis_data
[4]),
213 normalizeSpaceballAngle(5, devmot
->axis_data
[5]));
218 } else if (__glutDeviceButtonPress
219 && event
->type
== __glutDeviceButtonPress
) {
220 XDeviceButtonEvent
*devbtn
= (XDeviceButtonEvent
*) event
;
222 window
= __glutGetWindow(devbtn
->window
);
225 && devbtn
->deviceid
== __glutTablet
->device_id
226 && window
->tabletButton
227 && devbtn
->first_axis
== 0
228 && devbtn
->axes_count
== 2) {
229 tabletPosChange(window
, devbtn
->first_axis
, devbtn
->axes_count
,
231 window
->tabletButton(devbtn
->button
, GLUT_DOWN
,
232 window
->tabletPos
[0], window
->tabletPos
[1]);
233 } else if (__glutDials
234 && devbtn
->deviceid
== __glutDials
->device_id
235 && window
->buttonBox
) {
236 window
->buttonBox(devbtn
->button
, GLUT_DOWN
);
237 } else if (__glutSpaceball
238 && devbtn
->deviceid
== __glutSpaceball
->device_id
239 && window
->spaceButton
) {
240 window
->spaceButton(devbtn
->button
, GLUT_DOWN
);
244 } else if (__glutDeviceButtonRelease
245 && event
->type
== __glutDeviceButtonRelease
) {
246 XDeviceButtonEvent
*devbtn
= (XDeviceButtonEvent
*) event
;
248 window
= __glutGetWindow(devbtn
->window
);
251 && devbtn
->deviceid
== __glutTablet
->device_id
252 && window
->tabletButton
253 && devbtn
->first_axis
== 0
254 && devbtn
->axes_count
== 2) {
255 tabletPosChange(window
, devbtn
->first_axis
, devbtn
->axes_count
,
257 window
->tabletButton(devbtn
->button
, GLUT_UP
,
258 window
->tabletPos
[0], window
->tabletPos
[1]);
259 } else if (__glutDials
260 && devbtn
->deviceid
== __glutDials
->device_id
261 && window
->buttonBox
) {
262 window
->buttonBox(devbtn
->button
, GLUT_UP
);
263 } else if (__glutSpaceball
264 && devbtn
->deviceid
== __glutSpaceball
->device_id
265 && window
->spaceButton
) {
266 window
->spaceButton(devbtn
->button
, GLUT_UP
);
276 memset(&info
, 0, sizeof(JOYINFOEX
));
277 info
.dwSize
= sizeof(JOYINFOEX
);
278 info
.dwFlags
= JOY_RETURNALL
;
280 if (joyGetPosEx(JOYSTICKID1
,&info
) != JOYERR_NOERROR
) {
281 __glutHasJoystick
= 1;
282 joyGetDevCaps(JOYSTICKID1
, &joyCaps
, sizeof(joyCaps
));
283 __glutNumJoystickButtons
= joyCaps
.wNumButtons
;
284 __glutNumJoystickAxes
= joyCaps
.wNumAxes
;
286 __glutHasJoystick
= 0;
287 __glutNumJoystickButtons
= 0;
288 __glutNumJoystickAxes
= 0;
295 static GLUTeventParser eventParser
=
296 {__glutProcessDeviceEvents
, NULL
};
300 addDeviceEventParser(void)
302 static Bool been_here
= False
;
307 __glutRegisterEventParser(&eventParser
);
314 static Bool been_here
= False
;
317 XExtensionVersion
*version
;
318 XDeviceInfoPtr device_info
, device
;
323 int num_dev
= 0, btns
= 0, dials
= 0;
333 version
= XGetExtensionVersion(__glutDisplay
, "XInputExtension");
334 /* Ugh. XInput extension API forces annoying cast of a pointer
335 to a long so it can be compared with the NoSuchExtension
336 value (#defined to 1). */
337 if (version
== NULL
|| ((long) version
) == NoSuchExtension
) {
342 device_info
= XListInputDevices(__glutDisplay
, &num_dev
);
344 for (i
= 0; i
< num_dev
; i
++) {
345 /* XXX These are SGI names for these devices;
346 unfortunately, no good standard exists for standard
347 types of X input extension devices. */
349 device
= &device_info
[i
];
350 any
= (XAnyClassPtr
) device
->inputclassinfo
;
352 if (!__glutSpaceball
&& !strcmp(device
->name
, "spaceball")) {
355 for (j
= 0; j
< device
->num_classes
; j
++) {
356 #if defined(__cplusplus) || defined(c_plusplus)
357 switch (any
->c_class
) {
359 switch (any
->class) {
362 b
= (XButtonInfoPtr
) any
;
363 btns
= b
->num_buttons
;
366 v
= (XValuatorInfoPtr
) any
;
367 /* Sanity check: at least 6 valuators? */
368 if (v
->num_axes
< NUM_SPACEBALL_AXIS
)
370 a
= (XAxisInfoPtr
) ((char *) v
+ sizeof(XValuatorInfo
));
371 for (k
= 0; k
< NUM_SPACEBALL_AXIS
; k
++, a
++) {
372 __glutSpaceballRange
[k
].min
= a
->min_value
;
373 __glutSpaceballRange
[k
].range
= a
->max_value
- a
->min_value
;
377 any
= (XAnyClassPtr
) ((char *) any
+ any
->length
);
380 __glutSpaceball
= XOpenDevice(__glutDisplay
, device
->id
);
381 if (__glutSpaceball
) {
382 __glutNumSpaceballButtons
= btns
;
383 addDeviceEventParser();
386 } else if (!__glutDials
&& !strcmp(device
->name
, "dial+buttons")) {
389 for (j
= 0; j
< device
->num_classes
; j
++) {
390 #if defined(__cplusplus) || defined(c_plusplus)
391 switch (any
->c_class
) {
393 switch (any
->class) {
396 b
= (XButtonInfoPtr
) any
;
397 btns
= b
->num_buttons
;
400 v
= (XValuatorInfoPtr
) any
;
401 /* Sanity check: at least 8 valuators? */
402 if (v
->num_axes
< NUM_DIALS_AXIS
)
405 __glutDialsResolution
= (int *) malloc(sizeof(int) * dials
);
406 a
= (XAxisInfoPtr
) ((char *) v
+ sizeof(XValuatorInfo
));
407 for (k
= 0; k
< dials
; k
++, a
++) {
408 __glutDialsResolution
[k
] = a
->resolution
;
412 any
= (XAnyClassPtr
) ((char *) any
+ any
->length
);
415 __glutDials
= XOpenDevice(__glutDisplay
, device
->id
);
417 __glutNumButtonBoxButtons
= btns
;
418 __glutNumDials
= dials
;
419 addDeviceEventParser();
422 } else if (!__glutTablet
&& !strcmp(device
->name
, "tablet")) {
425 for (j
= 0; j
< device
->num_classes
; j
++) {
426 #if defined(__cplusplus) || defined(c_plusplus)
427 switch (any
->c_class
) {
429 switch (any
->class) {
432 b
= (XButtonInfoPtr
) any
;
433 btns
= b
->num_buttons
;
436 v
= (XValuatorInfoPtr
) any
;
437 /* Sanity check: exactly 2 valuators? */
438 if (v
->num_axes
!= NUM_TABLET_AXIS
)
440 a
= (XAxisInfoPtr
) ((char *) v
+ sizeof(XValuatorInfo
));
441 for (k
= 0; k
< NUM_TABLET_AXIS
; k
++, a
++) {
442 __glutTabletRange
[k
].min
= a
->min_value
;
443 __glutTabletRange
[k
].range
= a
->max_value
- a
->min_value
;
447 any
= (XAnyClassPtr
) ((char *) any
+ any
->length
);
450 __glutTablet
= XOpenDevice(__glutDisplay
, device
->id
);
452 __glutNumTabletButtons
= btns
;
453 addDeviceEventParser();
456 } else if (!strcmp(device
->name
, "mouse")) {
457 for (j
= 0; j
< device
->num_classes
; j
++) {
458 #if defined(__cplusplus) || defined(c_plusplus)
459 if (any
->c_class
== ButtonClass
) {
461 if (any
->class == ButtonClass
) {
463 b
= (XButtonInfoPtr
) any
;
464 __glutNumMouseButtons
= b
->num_buttons
;
466 any
= (XAnyClassPtr
) ((char *) any
+ any
->length
);
471 XFreeDeviceList(device_info
);
474 __glutNumMouseButtons
= GetSystemMetrics(SM_CMOUSEBUTTONS
);
476 /* X Input extension might be supported, but only if there is
477 a tablet, dials, or spaceball do we claim devices are
479 support
= __glutTablet
|| __glutDials
|| __glutSpaceball
;
484 __glutUpdateInputDeviceMask(GLUTwindow
* window
)
487 /* 5 (dial and buttons) + 5 (tablet locator and buttons) + 5
488 (Spaceball buttons and axis) = 15 */
489 XEventClass eventList
[15];
496 if (window
->tabletMotion
) {
497 DeviceMotionNotify(__glutTablet
, __glutDeviceMotionNotify
,
498 eventList
[numEvents
]);
501 if (window
->tabletButton
) {
502 DeviceButtonPress(__glutTablet
, __glutDeviceButtonPress
,
503 eventList
[numEvents
]);
505 DeviceButtonPressGrab(__glutTablet
, __glutDeviceButtonPressGrab
,
506 eventList
[numEvents
]);
508 DeviceButtonRelease(__glutTablet
, __glutDeviceButtonRelease
,
509 eventList
[numEvents
]);
512 if (window
->tabletMotion
|| window
->tabletButton
) {
513 DeviceStateNotify(__glutTablet
, __glutDeviceStateNotify
,
514 eventList
[numEvents
]);
520 DeviceMotionNotify(__glutDials
, __glutDeviceMotionNotify
,
521 eventList
[numEvents
]);
524 if (window
->buttonBox
) {
525 DeviceButtonPress(__glutDials
, __glutDeviceButtonPress
,
526 eventList
[numEvents
]);
528 DeviceButtonPressGrab(__glutDials
, __glutDeviceButtonPressGrab
,
529 eventList
[numEvents
]);
531 DeviceButtonRelease(__glutDials
, __glutDeviceButtonRelease
,
532 eventList
[numEvents
]);
535 if (window
->dials
|| window
->buttonBox
) {
536 DeviceStateNotify(__glutDials
, __glutDeviceStateNotify
,
537 eventList
[numEvents
]);
541 if (__glutSpaceball
) {
542 if (window
->spaceMotion
|| window
->spaceRotate
) {
543 DeviceMotionNotify(__glutSpaceball
, __glutDeviceMotionNotify
,
544 eventList
[numEvents
]);
547 if (window
->spaceButton
) {
548 DeviceButtonPress(__glutSpaceball
, __glutDeviceButtonPress
,
549 eventList
[numEvents
]);
551 DeviceButtonPressGrab(__glutSpaceball
, __glutDeviceButtonPressGrab
,
552 eventList
[numEvents
]);
554 DeviceButtonRelease(__glutSpaceball
, __glutDeviceButtonRelease
,
555 eventList
[numEvents
]);
558 if (window
->spaceMotion
|| window
->spaceRotate
|| window
->spaceButton
) {
559 DeviceStateNotify(__glutSpaceball
, __glutDeviceStateNotify
,
560 eventList
[numEvents
]);
565 if (window
->children
) {
566 GLUTwindow
*child
= window
->children
;
569 XChangeDeviceDontPropagateList(__glutDisplay
, child
->win
,
570 numEvents
, eventList
, AddToList
);
571 child
= child
->siblings
;
575 XSelectExtensionEvent(__glutDisplay
, window
->win
,
576 eventList
, numEvents
);
577 if (window
->overlay
) {
578 XSelectExtensionEvent(__glutDisplay
, window
->overlay
->win
,
579 eventList
, numEvents
);
582 /* X Input extension not supported; no chance for exotic
590 glutDeviceGet(GLenum param
)
594 case GLUT_HAS_KEYBOARD
:
596 /* Assume window system always has mouse and keyboard. */
598 case GLUT_HAS_SPACEBALL
:
599 return __glutSpaceball
!= NULL
;
600 case GLUT_HAS_DIAL_AND_BUTTON_BOX
:
601 return __glutDials
!= NULL
;
602 case GLUT_HAS_TABLET
:
603 return __glutTablet
!= NULL
;
604 case GLUT_NUM_MOUSE_BUTTONS
:
605 return __glutNumMouseButtons
;
606 case GLUT_NUM_SPACEBALL_BUTTONS
:
607 return __glutNumSpaceballButtons
;
608 case GLUT_NUM_BUTTON_BOX_BUTTONS
:
609 return __glutNumButtonBoxButtons
;
611 return __glutNumDials
;
612 case GLUT_NUM_TABLET_BUTTONS
:
613 return __glutNumTabletButtons
;
614 case GLUT_DEVICE_IGNORE_KEY_REPEAT
:
615 return __glutCurrentWindow
->ignoreKeyRepeat
;
617 case GLUT_DEVICE_KEY_REPEAT
:
619 XKeyboardState state
;
621 XGetKeyboardControl(__glutDisplay
, &state
);
622 return state
.global_auto_repeat
;
624 case GLUT_JOYSTICK_POLL_RATE
:
627 case GLUT_DEVICE_KEY_REPEAT
:
628 /* Win32 cannot globally disable key repeat. */
629 return GLUT_KEY_REPEAT_ON
;
630 case GLUT_JOYSTICK_POLL_RATE
:
631 return __glutCurrentWindow
->joyPollInterval
;
633 case GLUT_HAS_JOYSTICK
:
634 return __glutHasJoystick
;
635 case GLUT_JOYSTICK_BUTTONS
:
636 return __glutNumJoystickButtons
;
637 case GLUT_JOYSTICK_AXES
:
638 return __glutNumJoystickAxes
;
640 __glutWarning("invalid glutDeviceGet parameter: %d", param
);