]> git.mxchange.org Git - flightgear.git/blob - src/Input/input.cxx
f2635973a31f33d7640f44913d5ccc1f244dd60b
[flightgear.git] / src / Input / input.cxx
1 // input.cxx -- handle user input from various sources.
2 //
3 // Written by David Megginson, started May 2001.
4 //
5 // Copyright (C) 2001 David Megginson, david@megginson.com
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23 #ifdef HAVE_CONFIG_H
24 #  include <config.h>
25 #endif
26
27 #ifdef HAVE_WINDOWS_H
28 #  include <windows.h>                     
29 #endif
30
31 #include <simgear/compiler.h>
32
33 #include <math.h>
34 #include <ctype.h>
35
36 #include STL_FSTREAM
37 #include STL_STRING
38 #include <vector>
39
40 #include FG_GLUT_H
41
42 #include <plib/pu.h>
43
44 #include <simgear/compiler.h>
45
46 #include <simgear/constants.h>
47 #include <simgear/debug/logstream.hxx>
48 #include <simgear/props/props.hxx>
49
50 #include <Aircraft/aircraft.hxx>
51 #include <Autopilot/xmlauto.hxx>
52 #include <Cockpit/hud.hxx>
53 #include <Cockpit/panel.hxx>
54 #include <Cockpit/panel_io.hxx>
55 #include <GUI/gui.h>
56 #include <Model/panelnode.hxx>
57
58 #include <Main/globals.hxx>
59 #include <Main/fg_props.hxx>
60
61 #include "input.hxx"
62
63 SG_USING_STD(ifstream);
64 SG_USING_STD(string);
65 SG_USING_STD(vector);
66
67
68 \f
69 ////////////////////////////////////////////////////////////////////////
70 // Local variables.
71 ////////////////////////////////////////////////////////////////////////
72
73 static FGInput * default_input = 0;
74
75
76 \f
77 ////////////////////////////////////////////////////////////////////////
78 // Implementation of FGBinding.
79 ////////////////////////////////////////////////////////////////////////
80
81 FGBinding::FGBinding ()
82   : _command(0),
83     _arg(new SGPropertyNode),
84     _setting(0)
85 {
86 }
87
88 FGBinding::FGBinding (const SGPropertyNode * node)
89   : _command(0),
90     _arg(0),
91     _setting(0)
92 {
93   read(node);
94 }
95
96 void
97 FGBinding::read (const SGPropertyNode * node)
98 {
99   const SGPropertyNode * conditionNode = node->getChild("condition");
100   if (conditionNode != 0)
101     setCondition(sgReadCondition(globals->get_props(), conditionNode));
102
103   _command_name = node->getStringValue("command", "");
104   if (_command_name.empty()) {
105     SG_LOG(SG_INPUT, SG_WARN, "No command supplied for binding.");
106     _command = 0;
107     return;
108   }
109
110   _arg = new SGPropertyNode;
111   _setting = 0;
112   copyProperties(node, _arg);  // FIXME: don't use whole node!!!
113 }
114
115 void
116 FGBinding::fire () const
117 {
118   if (test()) {
119     if (_command == 0)
120       _command = globals->get_commands()->getCommand(_command_name);
121     if (_command == 0) {
122       SG_LOG(SG_INPUT, SG_WARN, "No command attached to binding");
123     } else if (!(*_command)(_arg)) {
124       SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command "
125              << _command_name);
126     }
127   }
128 }
129
130 void
131 FGBinding::fire (double offset, double max) const
132 {
133   if (test()) {
134     _arg->setDoubleValue("offset", offset/max);
135     fire();
136   }
137 }
138
139 void
140 FGBinding::fire (double setting) const
141 {
142   if (test()) {
143                                 // A value is automatically added to
144                                 // the args
145     if (_setting == 0)          // save the setting node for efficiency
146       _setting = _arg->getChild("setting", 0, true);
147     _setting->setDoubleValue(setting);
148     fire();
149   }
150 }
151
152
153 \f
154 ////////////////////////////////////////////////////////////////////////
155 // Implementation of FGInput.
156 ////////////////////////////////////////////////////////////////////////
157
158
159 FGInput::FGInput ()
160 {
161     if (default_input == 0)
162         default_input = this;
163 }
164
165 FGInput::~FGInput ()
166 {
167     if (default_input == this)
168         default_input = 0;
169 }
170
171 void
172 FGInput::init ()
173 {
174   _init_keyboard();
175   _init_joystick();
176   _init_mouse();
177
178   glutKeyboardFunc(GLUTkey);
179   glutKeyboardUpFunc(GLUTkeyup);
180   glutSpecialFunc(GLUTspecialkey);
181   glutSpecialUpFunc(GLUTspecialkeyup);
182   glutMouseFunc (GLUTmouse);
183   glutMotionFunc (GLUTmotion);
184   glutPassiveMotionFunc (GLUTmotion);
185 }
186
187 void 
188 FGInput::update (double dt)
189 {
190   _update_keyboard();
191   _update_joystick(dt);
192   _update_mouse();
193 }
194
195 void
196 FGInput::suspend ()
197 {
198     // NO-OP
199 }
200
201 void
202 FGInput::resume ()
203 {
204     // NO-OP
205 }
206
207 bool
208 FGInput::is_suspended () const
209 {
210     return false;
211 }
212
213 void
214 FGInput::makeDefault (bool status)
215 {
216     if (status)
217         default_input = this;
218     else if (default_input == this)
219         default_input = 0;
220 }
221
222 void
223 FGInput::doKey (int k, int modifiers, int x, int y)
224 {
225     static SGPropertyNode *heading_enabled
226         = fgGetNode("/autopilot/locks/heading", true);
227
228                                 // Sanity check.
229   if (k < 0 || k >= MAX_KEYS) {
230     SG_LOG(SG_INPUT, SG_WARN, "Key value " << k << " out of range");
231     return;
232   }
233
234   button &b = _key_bindings[k];
235
236                                 // Key pressed.
237   if (modifiers&FG_MOD_UP == 0) {
238     SG_LOG( SG_INPUT, SG_DEBUG, "User pressed key " << k
239             << " with modifiers " << modifiers );
240     if (!b.last_state || b.is_repeatable) {
241       const binding_list_t &bindings =
242         _find_key_bindings(k, modifiers);
243       int max = bindings.size();
244       if (max > 0) {
245         for (int i = 0; i < max; i++)
246           bindings[i]->fire();
247         return;
248       }
249     }
250   }
251
252                                 // Key released.
253   else {
254     SG_LOG(SG_INPUT, SG_DEBUG, "User released key " << k
255            << " with modifiers " << modifiers);
256     if (b.last_state) {
257       const binding_list_t &bindings =
258         _find_key_bindings(k, modifiers);
259       int max = bindings.size();
260       if (max > 0) {
261         for (int i = 0; i < max; i++)
262           bindings[i]->fire();
263         return;
264       }
265     }
266   }
267
268
269                                 // Use the old, default actions.
270   SG_LOG( SG_INPUT, SG_DEBUG, "(No user binding.)" );
271   if (modifiers&FG_MOD_UP)
272     return;
273
274   // everything after here will be removed sooner or later...
275
276   if (modifiers & FG_MOD_SHIFT) {
277
278         switch (k) {
279         case 72: // H key
280             HUD_brightkey( true );
281             return;
282         case 73: // I key
283             // Minimal Hud
284             fgHUDInit2(&current_aircraft);
285             return;
286         }
287
288
289     } else {
290         SG_LOG( SG_INPUT, SG_DEBUG, "" );
291         switch (k) {
292         case 104: // h key
293             HUD_masterswitch( true );
294             return;
295         case 105: // i key
296             fgHUDInit(&current_aircraft);  // normal HUD
297             return;
298
299 // START SPECIALS
300
301         case 256+GLUT_KEY_F6: // F6 toggles Autopilot target location
302             if ( strcmp( heading_enabled->getStringValue(),
303                          "true-heading-hold" ) != 0 ) {
304                 heading_enabled->setStringValue( "true-heading-hold" );
305             } else {
306                 heading_enabled->setStringValue( "" );
307             }
308             return;
309         }
310
311 // END SPECIALS
312
313     }
314 }
315
316 void
317 FGInput::doMouseClick (int b, int updown, int x, int y)
318 {
319   int modifiers = FG_MOD_NONE;  // FIXME: any way to get the real ones?
320
321   mouse &m = _mouse_bindings[0];
322   mouse_mode &mode = m.modes[m.current_mode];
323
324                                 // Let the property manager know.
325   if (b >= 0 && b < MAX_MOUSE_BUTTONS)
326     m.mouse_button_nodes[b]->setBoolValue(updown == GLUT_DOWN);
327
328                                 // Pass on to PUI and the panel if
329                                 // requested, and return if one of
330                                 // them consumes the event.
331   if (mode.pass_through) {
332     if (puMouse(b, updown, x, y))
333       return;
334     else if ((globals->get_current_panel() != 0) &&
335              globals->get_current_panel()->getVisibility() &&
336              globals->get_current_panel()->doMouseAction(b, updown, x, y))
337       return;
338     else if (fgHandle3DPanelMouseEvent(b, updown, x, y))
339       return;
340   }
341
342                                 // OK, PUI and the panel didn't want the click
343   if (b >= MAX_MOUSE_BUTTONS) {
344     SG_LOG(SG_INPUT, SG_ALERT, "Mouse button " << b
345            << " where only " << MAX_MOUSE_BUTTONS << " expected");
346     return;
347   }
348
349   _update_button(m.modes[m.current_mode].buttons[b], modifiers, 0 != updown, x, y);
350 }
351
352 void
353 FGInput::doMouseMotion (int x, int y)
354 {
355   int modifiers = FG_MOD_NONE;  // FIXME: any way to get the real ones?
356
357   int xsize = fgGetInt("/sim/startup/xsize", 800);
358   int ysize = fgGetInt("/sim/startup/ysize", 600);
359   mouse &m = _mouse_bindings[0];
360   if (m.current_mode < 0 || m.current_mode >= m.nModes)
361     return;
362   mouse_mode &mode = m.modes[m.current_mode];
363
364                                 // Pass on to PUI if requested, and return
365                                 // if PUI consumed the event.
366   if (mode.pass_through && puMouse(x, y))
367     return;
368
369                                 // OK, PUI didn't want the event,
370                                 // so we can play with it.
371   if (x != m.x) {
372     int delta = x - m.x;
373     for (unsigned int i = 0; i < mode.x_bindings[modifiers].size(); i++)
374       mode.x_bindings[modifiers][i]->fire(double(delta), double(xsize));
375   }
376   if (y != m.y) {
377     int delta = y - m.y;
378     for (unsigned int i = 0; i < mode.y_bindings[modifiers].size(); i++)
379       mode.y_bindings[modifiers][i]->fire(double(delta), double(ysize));
380   }
381
382                                 // Constrain the mouse if requested
383   if (mode.constrained) {
384     bool need_warp = false;
385     if (x <= 0) {
386       x = xsize - 2;
387       need_warp = true;
388     } else if (x >= (xsize-1)) {
389       x = 1;
390       need_warp = true;
391     }
392
393     if (y <= 0) {
394       y = ysize - 2;
395       need_warp = true;
396     } else if (y >= (ysize-1)) {
397       y = 1;
398       need_warp = true;
399     }
400
401     if (need_warp)
402       glutWarpPointer(x, y);
403   }
404   m.x = x;
405   m.y = y;
406 }
407
408 void
409 FGInput::_init_keyboard ()
410 {
411   SG_LOG(SG_INPUT, SG_DEBUG, "Initializing key bindings");
412   SGPropertyNode * key_nodes = fgGetNode("/input/keyboard");
413   if (key_nodes == 0) {
414     SG_LOG(SG_INPUT, SG_WARN, "No key bindings (/input/keyboard)!!");
415     key_nodes = fgGetNode("/input/keyboard", true);
416   }
417   
418   vector<SGPropertyNode_ptr> keys = key_nodes->getChildren("key");
419   for (unsigned int i = 0; i < keys.size(); i++) {
420     int index = keys[i]->getIndex();
421     SG_LOG(SG_INPUT, SG_DEBUG, "Binding key " << index);
422
423     _key_bindings[index].bindings->clear();
424     _key_bindings[index].is_repeatable = keys[i]->getBoolValue("repeatable");
425     _read_bindings(keys[i], _key_bindings[index].bindings, FG_MOD_NONE);
426   }
427 }
428
429
430 void
431 FGInput::_init_joystick ()
432 {
433                                 // TODO: zero the old bindings first.
434   SG_LOG(SG_INPUT, SG_DEBUG, "Initializing joystick bindings");
435   SGPropertyNode * js_nodes = fgGetNode("/input/joysticks");
436   if (js_nodes == 0) {
437     SG_LOG(SG_INPUT, SG_WARN, "No joystick bindings (/input/joysticks)!!");
438     js_nodes = fgGetNode("/input/joysticks", true);
439   }
440
441   for (int i = 0; i < MAX_JOYSTICKS; i++) {
442     SGPropertyNode_ptr js_node = js_nodes->getChild("js", i);
443     if (js_node == 0) {
444       SG_LOG(SG_INPUT, SG_DEBUG, "No bindings for joystick " << i);
445       js_node = js_nodes->getChild("js", i, true);
446     }
447     jsJoystick * js = new jsJoystick(i);
448     _joystick_bindings[i].js = js;
449     if (js->notWorking()) {
450       SG_LOG(SG_INPUT, SG_DEBUG, "Joystick " << i << " not found");
451       continue;
452     } else {
453       bool found_js = false;
454       const char * name = js->getName();
455       SG_LOG(SG_INPUT, SG_INFO, "Looking for bindings for joystick \""
456              << name << '"');
457       vector<SGPropertyNode_ptr> nodes = js_nodes->getChildren("js-named");
458       for (unsigned int i = 0; i < nodes.size(); i++) {
459         SGPropertyNode_ptr node = nodes[i];
460         vector<SGPropertyNode_ptr> name_nodes = node->getChildren("name");
461         for (unsigned int j = 0; j < name_nodes.size(); j++) {
462             const char * js_name = name_nodes[j]->getStringValue();
463             SG_LOG(SG_INPUT, SG_INFO, "  Trying \"" << js_name << '"');
464             if (!strcmp(js_name, name)) {
465                 SG_LOG(SG_INPUT, SG_INFO, "  Found bindings");
466                 js_node = node;
467                 found_js = true;
468                 break;
469             }
470         }
471         if (found_js)
472             break;
473       }
474     }
475 #ifdef WIN32
476     JOYCAPS jsCaps ;
477     joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) );
478     int nbuttons = jsCaps.wNumButtons;
479     if (nbuttons > MAX_JOYSTICK_BUTTONS) nbuttons = MAX_JOYSTICK_BUTTONS;
480 #else
481     int nbuttons = MAX_JOYSTICK_BUTTONS;
482 #endif
483         
484     int naxes = js->getNumAxes();
485     if (naxes > MAX_JOYSTICK_AXES) naxes = MAX_JOYSTICK_AXES;
486     _joystick_bindings[i].naxes = naxes;
487     _joystick_bindings[i].nbuttons = nbuttons;
488
489     SG_LOG(SG_INPUT, SG_DEBUG, "Initializing joystick " << i);
490
491                                 // Set up range arrays
492     float minRange[MAX_JOYSTICK_AXES];
493     float maxRange[MAX_JOYSTICK_AXES];
494     float center[MAX_JOYSTICK_AXES];
495
496                                 // Initialize with default values
497     js->getMinRange(minRange);
498     js->getMaxRange(maxRange);
499     js->getCenter(center);
500
501                                 // Allocate axes and buttons
502     _joystick_bindings[i].axes = new axis[naxes];
503     _joystick_bindings[i].buttons = new button[nbuttons];
504
505
506     //
507     // Initialize the axes.
508     //
509     int j;
510     for (j = 0; j < naxes; j++) {
511       const SGPropertyNode * axis_node = js_node->getChild("axis", j);
512       if (axis_node == 0) {
513         SG_LOG(SG_INPUT, SG_DEBUG, "No bindings for axis " << j);
514         axis_node = js_node->getChild("axis", j, true);
515       }
516       
517       axis &a = _joystick_bindings[i].axes[j];
518
519       js->setDeadBand(j, axis_node->getDoubleValue("dead-band", 0.0));
520
521       a.tolerance = axis_node->getDoubleValue("tolerance", 0.002);
522       minRange[j] = axis_node->getDoubleValue("min-range", minRange[j]);
523       maxRange[j] = axis_node->getDoubleValue("max-range", maxRange[j]);
524       center[j] = axis_node->getDoubleValue("center", center[j]);
525
526       _read_bindings(axis_node, a.bindings, FG_MOD_NONE);
527
528       // Initialize the virtual axis buttons.
529       _init_button(axis_node->getChild("low"), a.low, "low");
530       a.low_threshold = axis_node->getDoubleValue("low-threshold", -0.9);
531       
532       _init_button(axis_node->getChild("high"), a.high, "high");
533       a.high_threshold = axis_node->getDoubleValue("high-threshold", 0.9);
534       a.interval_sec = axis_node->getDoubleValue("interval-sec",0.0);
535       a.last_dt = 0.0;
536     }
537
538     //
539     // Initialize the buttons.
540     //
541     char buf[32];
542     for (j = 0; j < nbuttons; j++) {
543       sprintf(buf, "%d", j);
544       SG_LOG(SG_INPUT, SG_DEBUG, "Initializing button " << j);
545       _init_button(js_node->getChild("button", j),
546                    _joystick_bindings[i].buttons[j],
547                    buf);
548       
549       // get interval-sec property             
550       button &b = _joystick_bindings[i].buttons[j];
551       const SGPropertyNode * button_node = js_node->getChild("button", j);
552       if (button_node != 0) {
553         b.interval_sec = button_node->getDoubleValue("interval-sec",0.0);
554         b.last_dt = 0.0;
555       }
556     }
557
558     js->setMinRange(minRange);
559     js->setMaxRange(maxRange);
560     js->setCenter(center);
561   }
562 }
563
564 // 
565 // Map of all known GLUT cursor names
566 //
567 struct {
568   const char * name;
569   int cursor;
570 } mouse_cursor_map[] = {
571   { "right-arrow", GLUT_CURSOR_RIGHT_ARROW },
572   { "left-arrow", GLUT_CURSOR_LEFT_ARROW },
573   { "info", GLUT_CURSOR_INFO },
574   { "destroy", GLUT_CURSOR_DESTROY },
575   { "help", GLUT_CURSOR_HELP },
576   { "cycle", GLUT_CURSOR_CYCLE },
577   { "spray", GLUT_CURSOR_SPRAY },
578   { "wait", GLUT_CURSOR_WAIT },
579   { "text", GLUT_CURSOR_TEXT },
580   { "crosshair", GLUT_CURSOR_CROSSHAIR },
581   { "up-down", GLUT_CURSOR_UP_DOWN },
582   { "left-right", GLUT_CURSOR_LEFT_RIGHT },
583   { "top-side", GLUT_CURSOR_TOP_SIDE },
584   { "bottom-side", GLUT_CURSOR_BOTTOM_SIDE },
585   { "left-side", GLUT_CURSOR_LEFT_SIDE },
586   { "right-side", GLUT_CURSOR_RIGHT_SIDE },
587   { "top-left-corner", GLUT_CURSOR_TOP_LEFT_CORNER },
588   { "top-right-corner", GLUT_CURSOR_TOP_RIGHT_CORNER },
589   { "bottom-right-corner", GLUT_CURSOR_BOTTOM_RIGHT_CORNER },
590   { "bottom-left-corner", GLUT_CURSOR_BOTTOM_LEFT_CORNER },
591   { "inherit", GLUT_CURSOR_INHERIT },
592   { "none", GLUT_CURSOR_NONE },
593   { "full-crosshair", GLUT_CURSOR_FULL_CROSSHAIR },
594   { 0, 0 }
595 };
596
597
598
599 void
600 FGInput::_init_mouse ()
601 {
602   SG_LOG(SG_INPUT, SG_DEBUG, "Initializing mouse bindings");
603
604   SGPropertyNode * mouse_nodes = fgGetNode("/input/mice");
605   if (mouse_nodes == 0) {
606     SG_LOG(SG_INPUT, SG_WARN, "No mouse bindings (/input/mice)!!");
607     mouse_nodes = fgGetNode("/input/mice", true);
608   }
609
610   int j;
611   for (int i = 0; i < MAX_MICE; i++) {
612     SGPropertyNode * mouse_node = mouse_nodes->getChild("mouse", i, true);
613     mouse &m = _mouse_bindings[i];
614
615                                 // Grab node pointers
616     char buf[64];
617     sprintf(buf, "/devices/status/mice/mouse[%d]/mode", i);
618     m.mode_node = fgGetNode(buf);
619     if (m.mode_node == NULL) {
620       m.mode_node = fgGetNode(buf, true);
621       m.mode_node->setIntValue(0);
622     }
623     for (j = 0; j < MAX_MOUSE_BUTTONS; j++) {
624       sprintf(buf, "/devices/status/mice/mouse[%d]/button[%d]", i, j);
625       m.mouse_button_nodes[j] = fgGetNode(buf, true);
626       m.mouse_button_nodes[j]->setBoolValue(false);
627     }
628
629                                 // Read all the modes
630     m.nModes = mouse_node->getIntValue("mode-count", 1);
631     m.modes = new mouse_mode[m.nModes];
632
633     for (int j = 0; j < m.nModes; j++) {
634       int k;
635
636                                 // Read the mouse cursor for this mode
637       SGPropertyNode * mode_node = mouse_node->getChild("mode", j, true);
638       const char * cursor_name =
639         mode_node->getStringValue("cursor", "inherit");
640       m.modes[j].cursor = GLUT_CURSOR_INHERIT;
641       for (k = 0; mouse_cursor_map[k].name != 0; k++) {
642         if (!strcmp(mouse_cursor_map[k].name, cursor_name)) {
643           m.modes[j].cursor = mouse_cursor_map[k].cursor;
644           break;
645         }
646       }
647
648                                 // Read other properties for this mode
649       m.modes[j].constrained = mode_node->getBoolValue("constrained", false);
650       m.modes[j].pass_through = mode_node->getBoolValue("pass-through", false);
651
652                                 // Read the button bindings for this mode
653       m.modes[j].buttons = new button[MAX_MOUSE_BUTTONS];
654       char buf[32];
655       for (k = 0; k < MAX_MOUSE_BUTTONS; k++) {
656         sprintf(buf, "mouse button %d", k);
657         SG_LOG(SG_INPUT, SG_DEBUG, "Initializing mouse button " << k);
658         _init_button(mode_node->getChild("button", k),
659                      m.modes[j].buttons[k],
660                      buf);
661       }
662
663                                 // Read the axis bindings for this mode
664       _read_bindings(mode_node->getChild("x-axis", 0, true),
665                      m.modes[j].x_bindings,
666                      FG_MOD_NONE);
667       _read_bindings(mode_node->getChild("y-axis", 0, true),
668                      m.modes[j].y_bindings,
669                      FG_MOD_NONE);
670     }
671   }
672 }
673
674
675 void
676 FGInput::_init_button (const SGPropertyNode * node,
677                        button &b,
678                        const string name)
679 {       
680   if (node == 0) {
681     SG_LOG(SG_INPUT, SG_DEBUG, "No bindings for button " << name);
682   } else {
683     b.is_repeatable = node->getBoolValue("repeatable", b.is_repeatable);
684     
685                 // Get the bindings for the button
686     _read_bindings(node, b.bindings, FG_MOD_NONE);
687   }
688 }
689
690
691 void
692 FGInput::_update_keyboard ()
693 {
694   // no-op
695 }
696
697
698 void
699 FGInput::_update_joystick (double dt)
700 {
701   int modifiers = FG_MOD_NONE;  // FIXME: any way to get the real ones?
702   int buttons;
703   // float js_val, diff;
704   float axis_values[MAX_JOYSTICK_AXES];
705
706   int i;
707   int j;
708
709   for ( i = 0; i < MAX_JOYSTICKS; i++) {
710
711     jsJoystick * js = _joystick_bindings[i].js;
712     if (js == 0 || js->notWorking())
713       continue;
714
715     js->read(&buttons, axis_values);
716
717
718                                 // Fire bindings for the axes.
719     for ( j = 0; j < _joystick_bindings[i].naxes; j++) {
720       axis &a = _joystick_bindings[i].axes[j];
721       
722                                 // Do nothing if the axis position
723                                 // is unchanged; only a change in
724                                 // position fires the bindings.
725       if (fabs(axis_values[j] - a.last_value) > a.tolerance) {
726 //      SG_LOG(SG_INPUT, SG_DEBUG, "Axis " << j << " has moved");
727         SGPropertyNode node;
728         a.last_value = axis_values[j];
729 //      SG_LOG(SG_INPUT, SG_DEBUG, "There are "
730 //             << a.bindings[modifiers].size() << " bindings");
731         for (unsigned int k = 0; k < a.bindings[modifiers].size(); k++)
732           a.bindings[modifiers][k]->fire(axis_values[j]);
733       }
734      
735                                 // do we have to emulate axis buttons?
736       a.last_dt += dt;
737       if(a.last_dt >= a.interval_sec) {
738         if (a.low.bindings[modifiers].size())
739           _update_button(_joystick_bindings[i].axes[j].low,
740                          modifiers,
741                          axis_values[j] < a.low_threshold,
742                          -1, -1);
743       
744         if (a.high.bindings[modifiers].size())
745           _update_button(_joystick_bindings[i].axes[j].high,
746                          modifiers,
747                          axis_values[j] > a.high_threshold,
748                          -1, -1);
749          a.last_dt -= a.interval_sec;
750       }
751     }
752
753                                 // Fire bindings for the buttons.
754     for (j = 0; j < _joystick_bindings[i].nbuttons; j++) {
755       button &b = _joystick_bindings[i].buttons[j];
756       b.last_dt += dt;
757       if(b.last_dt >= b.interval_sec) {
758         _update_button(_joystick_bindings[i].buttons[j],
759                        modifiers,
760                        (buttons & (1 << j)) > 0,
761                        -1, -1);
762         b.last_dt -= b.interval_sec;
763       }
764     }
765   }
766 }
767
768 void
769 FGInput::_update_mouse ()
770 {
771   mouse &m = _mouse_bindings[0];
772   int mode =  m.mode_node->getIntValue();
773   if (mode != m.current_mode) {
774     m.current_mode = mode;
775     if (mode >= 0 && mode < m.nModes) {
776       glutSetCursor(m.modes[mode].cursor);
777       m.x = fgGetInt("/sim/startup/xsize", 800) / 2;
778       m.y = fgGetInt("/sim/startup/ysize", 600) / 2;
779       glutWarpPointer(m.x, m.y);
780     } else {
781       SG_LOG(SG_INPUT, SG_DEBUG, "Mouse mode " << mode << " out of range");
782       glutSetCursor(GLUT_CURSOR_INHERIT);
783     }
784   }
785 }
786
787 void
788 FGInput::_update_button (button &b, int modifiers, bool pressed,
789                          int x, int y)
790 {
791   if (pressed) {
792                                 // The press event may be repeated.
793     if (!b.last_state || b.is_repeatable) {
794       SG_LOG( SG_INPUT, SG_DEBUG, "Button has been pressed" );
795       for (unsigned int k = 0; k < b.bindings[modifiers].size(); k++)
796         b.bindings[modifiers][k]->fire(x, y);
797     }
798   } else {
799                                 // The release event is never repeated.
800     if (b.last_state) {
801       SG_LOG( SG_INPUT, SG_DEBUG, "Button has been released" );
802       for (unsigned int k = 0; k < b.bindings[modifiers|FG_MOD_UP].size(); k++)
803         b.bindings[modifiers|FG_MOD_UP][k]->fire(x, y);
804     }
805   }
806           
807   b.last_state = pressed;
808 }  
809
810
811 void
812 FGInput::_read_bindings (const SGPropertyNode * node, 
813                          binding_list_t * binding_list,
814                          int modifiers)
815 {
816   SG_LOG(SG_INPUT, SG_DEBUG, "Reading all bindings");
817   vector<SGPropertyNode_ptr> bindings = node->getChildren("binding");
818   for (unsigned int i = 0; i < bindings.size(); i++) {
819     SG_LOG(SG_INPUT, SG_DEBUG, "Reading binding "
820            << bindings[i]->getStringValue("command"));
821     binding_list[modifiers].push_back(new FGBinding(bindings[i]));
822   }
823
824                                 // Read nested bindings for modifiers
825   if (node->getChild("mod-up") != 0)
826     _read_bindings(node->getChild("mod-up"), binding_list,
827                    modifiers|FG_MOD_UP);
828
829   if (node->getChild("mod-shift") != 0)
830     _read_bindings(node->getChild("mod-shift"), binding_list,
831                    modifiers|FG_MOD_SHIFT);
832
833   if (node->getChild("mod-ctrl") != 0)
834     _read_bindings(node->getChild("mod-ctrl"), binding_list,
835                    modifiers|FG_MOD_CTRL);
836
837   if (node->getChild("mod-alt") != 0)
838     _read_bindings(node->getChild("mod-alt"), binding_list,
839                    modifiers|FG_MOD_ALT);
840 }
841
842
843 const vector<FGBinding *> &
844 FGInput::_find_key_bindings (unsigned int k, int modifiers)
845 {
846   unsigned char kc = (unsigned char)k;
847   button &b = _key_bindings[k];
848
849                                 // Try it straight, first.
850   if (b.bindings[modifiers].size() > 0)
851     return b.bindings[modifiers];
852
853                                 // Alt-Gr is CTRL+ALT
854   else if (modifiers&(FG_MOD_CTRL|FG_MOD_ALT))
855     return _find_key_bindings(k, modifiers&~(FG_MOD_CTRL|FG_MOD_ALT));
856
857                                 // Try removing the control modifier
858                                 // for control keys.
859   else if ((modifiers&FG_MOD_CTRL) && iscntrl(kc))
860     return _find_key_bindings(k, modifiers&~FG_MOD_CTRL);
861
862                                 // Try removing shift modifier 
863                                 // for upper case or any punctuation
864                                 // (since different keyboards will
865                                 // shift different punctuation types)
866   else if ((modifiers&FG_MOD_SHIFT) && (isupper(kc) || ispunct(kc)))
867     return _find_key_bindings(k, modifiers&~FG_MOD_SHIFT);
868
869                                 // Try removing alt modifier for
870                                 // high-bit characters.
871   else if ((modifiers&FG_MOD_ALT) && k >= 128 && k < 256)
872     return _find_key_bindings(k, modifiers&~FG_MOD_ALT);
873
874                                 // Give up and return the empty vector.
875   else
876     return b.bindings[modifiers];
877 }
878
879
880 \f
881 ////////////////////////////////////////////////////////////////////////
882 // Implementation of FGInput::button.
883 ////////////////////////////////////////////////////////////////////////
884
885 FGInput::button::button ()
886   : is_repeatable(false),
887     last_state(-1)
888 {
889 }
890
891 FGInput::button::~button ()
892 {
893                                 // FIXME: memory leak
894 //   for (int i = 0; i < FG_MOD_MAX; i++)
895 //     for (int j = 0; i < bindings[i].size(); j++)
896 //       delete bindings[i][j];
897 }
898
899
900 \f
901 ////////////////////////////////////////////////////////////////////////
902 // Implementation of FGInput::axis.
903 ////////////////////////////////////////////////////////////////////////
904
905 FGInput::axis::axis ()
906   : last_value(9999999),
907     tolerance(0.002),
908     low_threshold(-0.9),
909     high_threshold(0.9)
910 {
911 }
912
913 FGInput::axis::~axis ()
914 {
915 //   for (int i = 0; i < FG_MOD_MAX; i++)
916 //     for (int j = 0; i < bindings[i].size(); j++)
917 //       delete bindings[i][j];
918 }
919
920
921 \f
922 ////////////////////////////////////////////////////////////////////////
923 // Implementation of FGInput::joystick.
924 ////////////////////////////////////////////////////////////////////////
925
926 FGInput::joystick::joystick ()
927 {
928 }
929
930 FGInput::joystick::~joystick ()
931 {
932 //   delete js;
933   delete[] axes;
934   delete[] buttons;
935 }
936
937
938 \f
939 ////////////////////////////////////////////////////////////////////////
940 // Implementation of FGInput::mouse_mode
941 ////////////////////////////////////////////////////////////////////////
942
943 FGInput::mouse_mode::mouse_mode ()
944   : cursor(GLUT_CURSOR_INHERIT),
945     constrained(false),
946     pass_through(false),
947     buttons(0)
948 {
949 }
950
951 FGInput::mouse_mode::~mouse_mode ()
952 {
953                                 // FIXME: memory leak
954 //   for (int i = 0; i < FG_MOD_MAX; i++) {
955 //     int j;
956 //     for (j = 0; i < x_bindings[i].size(); j++)
957 //       delete bindings[i][j];
958 //     for (j = 0; j < y_bindings[i].size(); j++)
959 //       delete bindings[i][j];
960 //   }
961   delete [] buttons;
962 }
963
964
965 \f
966 ////////////////////////////////////////////////////////////////////////
967 // Implementation of FGInput::mouse
968 ////////////////////////////////////////////////////////////////////////
969
970 FGInput::mouse::mouse ()
971   : x(-1),
972     y(-1),
973     nModes(1),
974     current_mode(0),
975     modes(0)
976 {
977 }
978
979 FGInput::mouse::~mouse ()
980 {
981   delete [] modes;
982 }
983
984
985 \f
986 ////////////////////////////////////////////////////////////////////////
987 // Implementation of GLUT callbacks.
988 ////////////////////////////////////////////////////////////////////////
989
990
991 /**
992  * Construct the modifiers.
993  */
994 static inline int get_mods ()
995 {
996   int glut_modifiers = glutGetModifiers();
997   int modifiers = 0;
998
999   if (glut_modifiers & GLUT_ACTIVE_SHIFT)
1000     modifiers |= FGInput::FG_MOD_SHIFT;
1001   if (glut_modifiers & GLUT_ACTIVE_CTRL)
1002     modifiers |= FGInput::FG_MOD_CTRL;
1003   if (glut_modifiers & GLUT_ACTIVE_ALT)
1004     modifiers |= FGInput::FG_MOD_ALT;
1005
1006   return modifiers;
1007 }
1008
1009
1010 \f
1011 ////////////////////////////////////////////////////////////////////////
1012 // GLUT C callbacks.
1013 ////////////////////////////////////////////////////////////////////////
1014
1015 void
1016 GLUTkey(unsigned char k, int x, int y)
1017 {
1018                                 // Give PUI a chance to grab it first.
1019     if (!puKeyboard(k, PU_DOWN)) {
1020       if (default_input != 0)
1021           default_input->doKey(k, get_mods(), x, y);
1022     }
1023 }
1024
1025 void
1026 GLUTkeyup(unsigned char k, int x, int y)
1027 {
1028     if (default_input != 0)
1029         default_input->doKey(k, get_mods()|FGInput::FG_MOD_UP, x, y);
1030 }
1031
1032 void
1033 GLUTspecialkey(int k, int x, int y)
1034 {
1035                                 // Give PUI a chance to grab it first.
1036     if (!puKeyboard(k + PU_KEY_GLUT_SPECIAL_OFFSET, PU_DOWN)) {
1037         if (default_input != 0)
1038             default_input->doKey(k + 256, get_mods(), x, y);
1039     }
1040 }
1041
1042 void
1043 GLUTspecialkeyup(int k, int x, int y)
1044 {
1045     if (default_input != 0)
1046         default_input->doKey(k + 256, get_mods()|FGInput::FG_MOD_UP, x, y);
1047 }
1048
1049 void
1050 GLUTmouse (int button, int updown, int x, int y)
1051 {
1052     if (default_input != 0)
1053         default_input->doMouseClick(button, updown, x, y);
1054 }
1055
1056 void
1057 GLUTmotion (int x, int y)
1058 {
1059     if (default_input != 0)
1060         default_input->doMouseMotion(x, y);
1061 }
1062
1063 // end of input.cxx