Convert crlf->lf line endings.
[mesa.git] / src / glut / os2 / glut_input.cpp
1
2 /* Copyright (c) Mark J. Kilgard, 1994, 1997, 1998. */
3
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. */
7
8 #include <assert.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include "glutint.h"
14 #define POFIG 0
15 #if POFIG
16
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;
25
26 int __glutHasJoystick = 0;
27 int __glutNumJoystickButtons = 0;
28 int __glutNumJoystickAxes = 0;
29
30 #if !defined(_WIN32)
31 typedef struct _Range {
32 int min;
33 int range;
34 } Range;
35
36 #define NUM_SPACEBALL_AXIS 6
37 #define NUM_TABLET_AXIS 2
38 #define NUM_DIALS_AXIS 8
39
40 Range __glutSpaceballRange[NUM_SPACEBALL_AXIS];
41 Range __glutTabletRange[NUM_TABLET_AXIS];
42 int *__glutDialsResolution;
43
44 /* Safely assumes 0 is an illegal event type for X Input
45 extension events. */
46 int __glutDeviceMotionNotify = 0;
47 int __glutDeviceButtonPress = 0;
48 int __glutDeviceButtonPressGrab = 0;
49 int __glutDeviceButtonRelease = 0;
50 int __glutDeviceStateNotify = 0;
51
52 static int
53 normalizeTabletPos(int axis, int rawValue)
54 {
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;
61 }
62
63 static int
64 normalizeDialAngle(int axis, int rawValue)
65 {
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];
70 }
71
72 static int
73 normalizeSpaceballAngle(int axis, int rawValue)
74 {
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;
81 }
82
83 static int
84 normalizeSpaceballDelta(int axis, int rawValue)
85 {
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;
92 }
93
94 static void
95 queryTabletPos(GLUTwindow * window)
96 {
97 XDeviceState *state;
98 XInputClass *any;
99 XValuatorState *v;
100 int i;
101
102 state = XQueryDeviceState(__glutDisplay, __glutTablet);
103 any = state->data;
104 for (i = 0; i < state->num_classes; i++) {
105 #if defined(__cplusplus) || defined(c_plusplus)
106 switch (any->c_class) {
107 #else
108 switch (any->class) {
109 #endif
110 case ValuatorClass:
111 v = (XValuatorState *) any;
112 if (v->num_valuators < 2)
113 goto end;
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]);
118 }
119 any = (XInputClass *) ((char *) any + any->length);
120 }
121 end:
122 XFreeDeviceState(state);
123 }
124
125 static void
126 tabletPosChange(GLUTwindow * window, int first, int count, int *data)
127 {
128 int i, value, genEvent = 0;
129
130 for (i = first; i < first + count; i++) {
131 switch (i) {
132 case 0: /* X axis */
133 case 1: /* Y axis */
134 value = normalizeTabletPos(i, data[i - first]);
135 if (value != window->tabletPos[i]) {
136 window->tabletPos[i] = value;
137 genEvent = 1;
138 }
139 break;
140 }
141 }
142 if (window->tabletPos[0] == -1 || window->tabletPos[1] == -1)
143 queryTabletPos(window);
144 if (genEvent)
145 window->tabletMotion(window->tabletPos[0], window->tabletPos[1]);
146 }
147 #endif /* !_WIN32 */
148
149 static int
150 __glutProcessDeviceEvents(XEvent * event)
151 {
152 #if !defined(_WIN32)
153 GLUTwindow *window;
154
155 /* XXX Ugly code fan out. */
156
157 /* Can't use switch/case since X Input event types are
158 dynamic. */
159
160 if (__glutDeviceMotionNotify && event->type == __glutDeviceMotionNotify) {
161 XDeviceMotionEvent *devmot = (XDeviceMotionEvent *) event;
162
163 window = __glutGetWindow(devmot->window);
164 if (window) {
165 if (__glutTablet
166 && devmot->deviceid == __glutTablet->device_id
167 && window->tabletMotion) {
168 tabletPosChange(window, devmot->first_axis, devmot->axes_count,
169 devmot->axis_data);
170 } else if (__glutDials
171 && devmot->deviceid == __glutDials->device_id
172 && window->dials) {
173 int i, first = devmot->first_axis, count = devmot->axes_count;
174
175 for (i = first; i < first + count; i++)
176 window->dials(i + 1,
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)
185 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)
190 window->spaceRotate(
191 normalizeSpaceballAngle(3, devmot->axis_data[3]),
192 normalizeSpaceballAngle(4, devmot->axis_data[4]),
193 normalizeSpaceballAngle(5, devmot->axis_data[5]));
194 }
195 }
196 return 1;
197 }
198 } else if (__glutDeviceButtonPress
199 && event->type == __glutDeviceButtonPress) {
200 XDeviceButtonEvent *devbtn = (XDeviceButtonEvent *) event;
201
202 window = __glutGetWindow(devbtn->window);
203 if (window) {
204 if (__glutTablet
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,
210 devbtn->axis_data);
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);
221 }
222 return 1;
223 }
224 } else if (__glutDeviceButtonRelease
225 && event->type == __glutDeviceButtonRelease) {
226 XDeviceButtonEvent *devbtn = (XDeviceButtonEvent *) event;
227
228 window = __glutGetWindow(devbtn->window);
229 if (window) {
230 if (__glutTablet
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,
236 devbtn->axis_data);
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);
247 }
248 return 1;
249 }
250 }
251 #else
252 {
253 JOYINFOEX info;
254 JOYCAPS joyCaps;
255
256 memset(&info, 0, sizeof(JOYINFOEX));
257 info.dwSize = sizeof(JOYINFOEX);
258 info.dwFlags = JOY_RETURNALL;
259
260 if (joyGetPosEx(JOYSTICKID1,&info) != JOYERR_NOERROR) {
261 __glutHasJoystick = 1;
262 joyGetDevCaps(JOYSTICKID1, &joyCaps, sizeof(joyCaps));
263 __glutNumJoystickButtons = joyCaps.wNumButtons;
264 __glutNumJoystickAxes = joyCaps.wNumAxes;
265 } else {
266 __glutHasJoystick = 0;
267 __glutNumJoystickButtons = 0;
268 __glutNumJoystickAxes = 0;
269 }
270 }
271 #endif /* !_WIN32 */
272 return 0;
273 }
274
275 static GLUTeventParser eventParser =
276 {__glutProcessDeviceEvents, NULL};
277
278 static void
279 addDeviceEventParser(void)
280 {
281 static Bool been_here = False;
282
283 if (been_here)
284 return;
285 been_here = True;
286 __glutRegisterEventParser(&eventParser);
287 }
288
289 static int
290 probeDevices(void)
291 {
292 static Bool been_here = False;
293 static int support;
294 #if !defined(_WIN32)
295 XExtensionVersion *version;
296 XDeviceInfoPtr device_info, device;
297 XAnyClassPtr any;
298 XButtonInfoPtr b;
299 XValuatorInfoPtr v;
300 XAxisInfoPtr a;
301 int num_dev = 0, btns = 0, dials = 0;
302 int i, j, k;
303 #endif /* !_WIN32 */
304
305 if (been_here) {
306 return support;
307 }
308 been_here = True;
309
310 #if !defined(_WIN32)
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) {
316 support = 0;
317 return support;
318 }
319 XFree(version);
320 device_info = XListInputDevices(__glutDisplay, &num_dev);
321 if (device_info) {
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. */
326
327 device = &device_info[i];
328 any = (XAnyClassPtr) device->inputclassinfo;
329
330 if (!__glutSpaceball && !strcmp(device->name, "spaceball")) {
331 v = NULL;
332 b = NULL;
333 for (j = 0; j < device->num_classes; j++) {
334 #if defined(__cplusplus) || defined(c_plusplus)
335 switch (any->c_class) {
336 #else
337 switch (any->class) {
338 #endif
339 case ButtonClass:
340 b = (XButtonInfoPtr) any;
341 btns = b->num_buttons;
342 break;
343 case ValuatorClass:
344 v = (XValuatorInfoPtr) any;
345 /* Sanity check: at least 6 valuators? */
346 if (v->num_axes < NUM_SPACEBALL_AXIS)
347 goto skip_device;
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;
352 }
353 break;
354 }
355 any = (XAnyClassPtr) ((char *) any + any->length);
356 }
357 if (v) {
358 __glutSpaceball = XOpenDevice(__glutDisplay, device->id);
359 if (__glutSpaceball) {
360 __glutNumSpaceballButtons = btns;
361 addDeviceEventParser();
362 }
363 }
364 } else if (!__glutDials && !strcmp(device->name, "dial+buttons")) {
365 v = NULL;
366 b = NULL;
367 for (j = 0; j < device->num_classes; j++) {
368 #if defined(__cplusplus) || defined(c_plusplus)
369 switch (any->c_class) {
370 #else
371 switch (any->class) {
372 #endif
373 case ButtonClass:
374 b = (XButtonInfoPtr) any;
375 btns = b->num_buttons;
376 break;
377 case ValuatorClass:
378 v = (XValuatorInfoPtr) any;
379 /* Sanity check: at least 8 valuators? */
380 if (v->num_axes < NUM_DIALS_AXIS)
381 goto skip_device;
382 dials = v->num_axes;
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;
387 }
388 break;
389 }
390 any = (XAnyClassPtr) ((char *) any + any->length);
391 }
392 if (v) {
393 __glutDials = XOpenDevice(__glutDisplay, device->id);
394 if (__glutDials) {
395 __glutNumButtonBoxButtons = btns;
396 __glutNumDials = dials;
397 addDeviceEventParser();
398 }
399 }
400 } else if (!__glutTablet && !strcmp(device->name, "tablet")) {
401 v = NULL;
402 b = NULL;
403 for (j = 0; j < device->num_classes; j++) {
404 #if defined(__cplusplus) || defined(c_plusplus)
405 switch (any->c_class) {
406 #else
407 switch (any->class) {
408 #endif
409 case ButtonClass:
410 b = (XButtonInfoPtr) any;
411 btns = b->num_buttons;
412 break;
413 case ValuatorClass:
414 v = (XValuatorInfoPtr) any;
415 /* Sanity check: exactly 2 valuators? */
416 if (v->num_axes != NUM_TABLET_AXIS)
417 goto skip_device;
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;
422 }
423 break;
424 }
425 any = (XAnyClassPtr) ((char *) any + any->length);
426 }
427 if (v) {
428 __glutTablet = XOpenDevice(__glutDisplay, device->id);
429 if (__glutTablet) {
430 __glutNumTabletButtons = btns;
431 addDeviceEventParser();
432 }
433 }
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) {
438 #else
439 if (any->class == ButtonClass) {
440 #endif
441 b = (XButtonInfoPtr) any;
442 __glutNumMouseButtons = b->num_buttons;
443 }
444 any = (XAnyClassPtr) ((char *) any + any->length);
445 }
446 }
447 skip_device:;
448 }
449 XFreeDeviceList(device_info);
450 }
451 #else /* _WIN32 */
452 __glutNumMouseButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);
453 #endif /* !_WIN32 */
454 /* X Input extension might be supported, but only if there is
455 a tablet, dials, or spaceball do we claim devices are
456 supported. */
457 support = __glutTablet || __glutDials || __glutSpaceball;
458 return support;
459 }
460
461 void
462 __glutUpdateInputDeviceMask(GLUTwindow * window)
463 {
464 #if !defined(_WIN32)
465 /* 5 (dial and buttons) + 5 (tablet locator and buttons) + 5
466 (Spaceball buttons and axis) = 15 */
467 XEventClass eventList[15];
468 int rc, numEvents;
469
470 rc = probeDevices();
471 if (rc) {
472 numEvents = 0;
473 if (__glutTablet) {
474 if (window->tabletMotion) {
475 DeviceMotionNotify(__glutTablet, __glutDeviceMotionNotify,
476 eventList[numEvents]);
477 numEvents++;
478 }
479 if (window->tabletButton) {
480 DeviceButtonPress(__glutTablet, __glutDeviceButtonPress,
481 eventList[numEvents]);
482 numEvents++;
483 DeviceButtonPressGrab(__glutTablet, __glutDeviceButtonPressGrab,
484 eventList[numEvents]);
485 numEvents++;
486 DeviceButtonRelease(__glutTablet, __glutDeviceButtonRelease,
487 eventList[numEvents]);
488 numEvents++;
489 }
490 if (window->tabletMotion || window->tabletButton) {
491 DeviceStateNotify(__glutTablet, __glutDeviceStateNotify,
492 eventList[numEvents]);
493 numEvents++;
494 }
495 }
496 if (__glutDials) {
497 if (window->dials) {
498 DeviceMotionNotify(__glutDials, __glutDeviceMotionNotify,
499 eventList[numEvents]);
500 numEvents++;
501 }
502 if (window->buttonBox) {
503 DeviceButtonPress(__glutDials, __glutDeviceButtonPress,
504 eventList[numEvents]);
505 numEvents++;
506 DeviceButtonPressGrab(__glutDials, __glutDeviceButtonPressGrab,
507 eventList[numEvents]);
508 numEvents++;
509 DeviceButtonRelease(__glutDials, __glutDeviceButtonRelease,
510 eventList[numEvents]);
511 numEvents++;
512 }
513 if (window->dials || window->buttonBox) {
514 DeviceStateNotify(__glutDials, __glutDeviceStateNotify,
515 eventList[numEvents]);
516 numEvents++;
517 }
518 }
519 if (__glutSpaceball) {
520 if (window->spaceMotion || window->spaceRotate) {
521 DeviceMotionNotify(__glutSpaceball, __glutDeviceMotionNotify,
522 eventList[numEvents]);
523 numEvents++;
524 }
525 if (window->spaceButton) {
526 DeviceButtonPress(__glutSpaceball, __glutDeviceButtonPress,
527 eventList[numEvents]);
528 numEvents++;
529 DeviceButtonPressGrab(__glutSpaceball, __glutDeviceButtonPressGrab,
530 eventList[numEvents]);
531 numEvents++;
532 DeviceButtonRelease(__glutSpaceball, __glutDeviceButtonRelease,
533 eventList[numEvents]);
534 numEvents++;
535 }
536 if (window->spaceMotion || window->spaceRotate || window->spaceButton) {
537 DeviceStateNotify(__glutSpaceball, __glutDeviceStateNotify,
538 eventList[numEvents]);
539 numEvents++;
540 }
541 }
542 #if 0
543 if (window->children) {
544 GLUTwindow *child = window->children;
545
546 do {
547 XChangeDeviceDontPropagateList(__glutDisplay, child->win,
548 numEvents, eventList, AddToList);
549 child = child->siblings;
550 } while (child);
551 }
552 #endif
553 XSelectExtensionEvent(__glutDisplay, window->win,
554 eventList, numEvents);
555 if (window->overlay) {
556 XSelectExtensionEvent(__glutDisplay, window->overlay->win,
557 eventList, numEvents);
558 }
559 } else {
560 /* X Input extension not supported; no chance for exotic
561 input devices. */
562 }
563 #endif /* !_WIN32 */
564 }
565
566 #endif //POFIG
567
568 /* CENTRY */
569 int GLUTAPIENTRY
570 glutDeviceGet(GLenum param)
571 {
572 #if POFIG
573 probeDevices();
574 #endif
575 switch (param) {
576 case GLUT_HAS_KEYBOARD:
577 case GLUT_HAS_MOUSE:
578 /* Assume window system always has mouse and keyboard. */
579 return 1;
580 #if POFIG
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;
593 case GLUT_NUM_DIALS:
594 return __glutNumDials;
595 case GLUT_NUM_TABLET_BUTTONS:
596 return __glutNumTabletButtons;
597 case GLUT_DEVICE_IGNORE_KEY_REPEAT:
598 return __glutCurrentWindow->ignoreKeyRepeat;
599 #ifndef _WIN32
600 case GLUT_DEVICE_KEY_REPEAT:
601 {
602 XKeyboardState state;
603
604 XGetKeyboardControl(__glutDisplay, &state);
605 return state.global_auto_repeat;
606 }
607 case GLUT_JOYSTICK_POLL_RATE:
608 return 0;
609 #else
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;
615 #endif
616 case GLUT_HAS_JOYSTICK:
617 return __glutHasJoystick;
618 case GLUT_JOYSTICK_BUTTONS:
619 return __glutNumJoystickButtons;
620 case GLUT_JOYSTICK_AXES:
621 return __glutNumJoystickAxes;
622 #endif //POFIG
623 default:
624 __glutWarning("invalid glutDeviceGet parameter: %d", param);
625 return -1;
626 }
627 }
628 /* ENDCENTRY */