]> git.mxchange.org Git - flightgear.git/blob - src/Input/input.cxx
c66023575fdba1346085d8ccd21a88512713d8e4
[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 <GL/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/misc/props.hxx>
49
50 #include <Aircraft/aircraft.hxx>
51 #include <Autopilot/auto_gui.hxx>
52 #include <Autopilot/newauto.hxx>
53 #include <Cockpit/hud.hxx>
54 #include <Cockpit/panel.hxx>
55 #include <Cockpit/panel_io.hxx>
56 #include <GUI/gui.h>
57
58 #ifndef FG_OLD_WEATHER
59 #  include <WeatherCM/FGLocalWeatherDatabase.h>
60 #else
61 #  include <Weather/weather.hxx>
62 #endif
63
64 #include <Main/globals.hxx>
65 #include <Main/fg_props.hxx>
66 #include <Main/options.hxx>
67
68 #include "input.hxx"
69
70 #if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
71 SG_USING_STD(ifstream);
72 #endif
73 SG_USING_STD(string);
74 SG_USING_STD(vector);
75
76
77 \f
78 ////////////////////////////////////////////////////////////////////////
79 // Local data structures.
80 ////////////////////////////////////////////////////////////////////////
81
82 \f
83 ////////////////////////////////////////////////////////////////////////
84 // Implementation of FGBinding.
85 ////////////////////////////////////////////////////////////////////////
86
87 FGBinding::FGBinding ()
88   : _command(0), _arg(0)
89 {
90 }
91
92 FGBinding::FGBinding (const SGPropertyNode * node)
93   : _command(0), _arg(0)
94 {
95   read(node);
96 }
97
98 FGBinding::~FGBinding ()
99 {
100   // no op
101 }
102
103 void
104 FGBinding::read (const SGPropertyNode * node)
105 {
106   _command_name = node->getStringValue("command", "");
107   if (_command_name == "") {
108     SG_LOG(SG_INPUT, SG_ALERT, "No command supplied for binding.");
109     _command = 0;
110     return;
111   }
112
113   _command = globals->get_commands()->getCommand(_command_name);
114   if (_command == 0) {
115     SG_LOG(SG_INPUT, SG_ALERT, "Command " << _command_name << " is undefined");
116     _arg = 0;
117     return;
118   }
119   _arg = node;                  // FIXME: don't use whole node!!!
120 }
121
122 void
123 FGBinding::fire () const
124 {
125   _fire(_arg);
126 }
127
128 void
129 FGBinding::fire (double setting) const
130 {
131   SGPropertyNode arg;
132   if (_arg != 0)
133     copyProperties(_arg, &arg);
134   arg.setDoubleValue("setting", setting);
135   _fire(&arg);
136 }
137
138 void
139 FGBinding::_fire(const SGPropertyNode * arg) const
140 {
141   if (_command == 0) {
142     SG_LOG(SG_INPUT, SG_ALERT, "No command attached to binding");
143   } else if (!(*_command)(arg)) {
144     SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command " << _command_name);
145   }
146 }
147
148
149 \f
150 ////////////////////////////////////////////////////////////////////////
151 // Implementation of FGInput.
152 ////////////////////////////////////////////////////////////////////////
153
154                                 // From main.cxx
155 extern void fgReshape( int width, int height );
156
157 FGInput current_input;
158
159
160 FGInput::FGInput ()
161 {
162   // no op
163 }
164
165 FGInput::~FGInput ()
166 {
167   // no op
168 }
169
170 void
171 FGInput::init ()
172 {
173   _init_keyboard();
174   _init_joystick();
175 }
176
177 void
178 FGInput::bind ()
179 {
180   // no op
181 }
182
183 void
184 FGInput::unbind ()
185 {
186   // no op
187 }
188
189 void 
190 FGInput::update ()
191 {
192   _update_keyboard();
193   _update_joystick();
194 }
195
196 void
197 FGInput::doKey (int k, int modifiers, int x, int y)
198 {
199   SG_LOG(SG_INPUT, SG_INFO, "User pressed key " << k
200          << " with modifiers " << modifiers);
201
202                                 // Sanity check.
203   if (k < 0 || k >= MAX_KEYS) {
204     SG_LOG(SG_INPUT, SG_ALERT, "Key value " << k << " out of range");
205     return;
206   }
207
208   button &b = _key_bindings[k];
209
210                                 // Key pressed.
211   if (modifiers&FG_MOD_UP == 0) {
212     // SG_LOG( SG_INPUT, SG_INFO, "User pressed key " << k
213     //         << " with modifiers " << modifiers );
214     if (!b.last_state || b.is_repeatable) {
215       const binding_list_t &bindings =
216         _find_key_bindings(k, modifiers);
217       int max = bindings.size();
218       if (max > 0) {
219         for (int i = 0; i < max; i++)
220           bindings[i].fire();
221         return;
222       }
223     }
224   }
225
226                                 // Key released.
227   else {
228     // SG_LOG(SG_INPUT, SG_INFO, "User released key " << k
229     //        << " with modifiers " << modifiers);
230     if (b.last_state) {
231       const binding_list_t &bindings =
232         _find_key_bindings(k, modifiers);
233       int max = bindings.size();
234       if (max > 0) {
235         for (int i = 0; i < max; i++)
236           bindings[i].fire();
237         return;
238       }
239     }
240   }
241
242
243                                 // Use the old, default actions.
244   SG_LOG(SG_INPUT, SG_INFO, "(No user binding.)");
245   if (modifiers&FG_MOD_UP)
246     return;
247
248   // float fov, tmp;
249   static bool winding_ccw = true;
250   // int speed;
251   // FGInterface *f = current_aircraft.fdm_state;
252   // FGViewer *v = globals->get_current_view();
253   
254   // everything after here will be removed sooner or later...
255
256   if (modifiers & FG_MOD_SHIFT) {
257
258         switch (k) {
259         case 18: // Ctrl-R key
260             // temporary
261             winding_ccw = !winding_ccw;
262             if ( winding_ccw ) {
263                 glFrontFace ( GL_CCW );
264             } else {
265                 glFrontFace ( GL_CW );
266             }
267             return;
268         case 72: // H key
269             HUD_brightkey( true );
270             return;
271         case 73: // I key
272             // Minimal Hud
273             fgHUDInit2(&current_aircraft);
274             return;
275         case 87: // W key
276 #if defined(FX) && !defined(WIN32)
277             global_fullscreen = ( !global_fullscreen );
278 #  if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
279             XMesaSetFXmode( global_fullscreen ? 
280                             XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW );
281 #  endif
282 #endif
283             return;
284
285 // START SPECIALS
286
287         case 256+GLUT_KEY_F10: {
288             fgToggleFDMdataLogging();
289             return;
290         }
291
292 // END SPECIALS
293
294         }
295
296
297     } else {
298         SG_LOG( SG_INPUT, SG_DEBUG, "" );
299         switch (k) {
300         case 104: // h key
301             HUD_masterswitch( true );
302             return;
303         case 105: // i key
304             fgHUDInit(&current_aircraft);  // normal HUD
305             return;
306
307 // START SPECIALS
308
309         case 256+GLUT_KEY_F6: // F6 toggles Autopilot target location
310             if ( current_autopilot->get_HeadingMode() !=
311                  FGAutopilot::FG_HEADING_WAYPOINT ) {
312                 current_autopilot->set_HeadingMode(
313                     FGAutopilot::FG_HEADING_WAYPOINT );
314                 current_autopilot->set_HeadingEnabled( true );
315             } else {
316                 current_autopilot->set_HeadingMode(
317                     FGAutopilot::FG_TC_HEADING_LOCK );
318             }
319             return;
320         case 256+GLUT_KEY_F8: {// F8 toggles fog ... off fastest nicest...
321             const string &fog = fgGetString("/sim/rendering/fog");
322             if (fog == "disabled") {
323               fgSetString("/sim/rendering/fog", "fastest");
324               SG_LOG(SG_INPUT, SG_INFO, "Fog enabled, hint=fastest");
325             } else if (fog == "fastest") {
326               fgSetString("/sim/rendering/fog", "nicest");
327               SG_LOG(SG_INPUT, SG_INFO, "Fog enabled, hint=nicest");
328             } else if (fog == "nicest") {
329               fgSetString("/sim/rendering/fog", "disabled");
330               SG_LOG(SG_INPUT, SG_INFO, "Fog disabled");
331             } else {
332               fgSetString("/sim/rendering/fog", "disabled");
333               SG_LOG(SG_INPUT, SG_ALERT, "Unrecognized fog type "
334                      << fog << ", changed to 'disabled'");
335             }
336             return;
337         }
338         case 256+GLUT_KEY_F10: // F10 toggles menu on and off...
339             SG_LOG(SG_INPUT, SG_INFO, "Invoking call back function");
340             guiToggleMenu();
341             return;
342         case 256+GLUT_KEY_F11: // F11 Altitude Dialog.
343             SG_LOG(SG_INPUT, SG_INFO, "Invoking Altitude call back function");
344             NewAltitude( NULL );
345             return;
346         case 256+GLUT_KEY_F12: // F12 Heading Dialog...
347             SG_LOG(SG_INPUT, SG_INFO, "Invoking Heading call back function");
348             NewHeading( NULL );
349             return;
350         }
351
352 // END SPECIALS
353
354     }
355 }
356
357
358 void
359 FGInput::_init_keyboard ()
360 {
361                                 // TODO: zero the old bindings first.
362   SG_LOG(SG_INPUT, SG_INFO, "Initializing key bindings");
363   SGPropertyNode * key_nodes = fgGetNode("/input/keyboard");
364   if (key_nodes == 0) {
365     SG_LOG(SG_INPUT, SG_ALERT, "No key bindings (/input/keyboard)!!");
366     return;
367   }
368   
369   vector<SGPropertyNode *> keys = key_nodes->getChildren("key");
370   for (unsigned int i = 0; i < keys.size(); i++) {
371     int index = keys[i]->getIndex();
372     SG_LOG(SG_INPUT, SG_INFO, "Binding key " << index);
373     _key_bindings[index].is_repeatable = keys[i]->getBoolValue("repeatable");
374     _read_bindings(keys[i], _key_bindings[index].bindings, FG_MOD_NONE);
375   }
376 }
377
378
379 void
380 FGInput::_init_joystick ()
381 {
382                                 // TODO: zero the old bindings first.
383   SG_LOG(SG_INPUT, SG_INFO, "Initializing joystick bindings");
384   SGPropertyNode * js_nodes = fgGetNode("/input/joysticks");
385   if (js_nodes == 0) {
386     SG_LOG(SG_INPUT, SG_ALERT, "No joystick bindings (/input/joysticks)!!");
387     return;
388   }
389
390   for (int i = 0; i < MAX_JOYSTICKS; i++) {
391     const SGPropertyNode * js_node = js_nodes->getChild("js", i);
392     if (js_node == 0) {
393       SG_LOG(SG_INPUT, SG_ALERT, "No bindings for joystick " << i);
394       continue;
395     }
396     jsJoystick * js = new jsJoystick(i);
397     _joystick_bindings[i].js = js;
398     if (js->notWorking()) {
399       SG_LOG(SG_INPUT, SG_INFO, "Joystick " << i << " not found");
400       continue;
401     }
402 #ifdef WIN32
403     JOYCAPS jsCaps ;
404     joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) );
405     int nbuttons = jsCaps.wNumButtons;
406     if (nbuttons > MAX_BUTTONS) nbuttons = MAX_BUTTONS;
407 #else
408     int nbuttons = MAX_BUTTONS;
409 #endif
410         
411     int naxes = js->getNumAxes();
412     if (naxes > MAX_AXES) naxes = MAX_AXES;
413     _joystick_bindings[i].naxes = naxes;
414     _joystick_bindings[i].nbuttons = nbuttons;
415
416     SG_LOG(SG_INPUT, SG_INFO, "Initializing joystick " << i);
417
418                                 // Set up range arrays
419     float minRange[MAX_AXES];
420     float maxRange[MAX_AXES];
421     float center[MAX_AXES];
422
423                                 // Initialize with default values
424     js->getMinRange(minRange);
425     js->getMaxRange(maxRange);
426     js->getCenter(center);
427
428                                 // Allocate axes and buttons
429     _joystick_bindings[i].axes = new axis[naxes];
430     _joystick_bindings[i].buttons = new button[nbuttons];
431
432
433     //
434     // Initialize the axes.
435     //
436     int j;
437     for (j = 0; j < naxes; j++) {
438       const SGPropertyNode * axis_node = js_node->getChild("axis", j);
439       if (axis_node == 0) {
440         SG_LOG(SG_INPUT, SG_INFO, "No bindings for axis " << j);
441         continue;
442       }
443       
444       axis &a = _joystick_bindings[i].axes[j];
445
446       js->setDeadBand(j, axis_node->getDoubleValue("dead-band", 0.0));
447
448       a.tolerance = axis_node->getDoubleValue("tolerance", 0.002);
449       minRange[j] = axis_node->getDoubleValue("min-range", minRange[j]);
450       maxRange[j] = axis_node->getDoubleValue("max-range", maxRange[j]);
451       center[j] = axis_node->getDoubleValue("center", center[j]);
452
453       _read_bindings(axis_node, a.bindings, FG_MOD_NONE);
454
455       // Initialize the virtual axis buttons.
456       _init_button(axis_node->getChild("low"), a.low, "low");
457       a.low_threshold = axis_node->getDoubleValue("low-threshold", -0.9);
458       
459       _init_button(axis_node->getChild("high"), a.high, "high");
460       a.high_threshold = axis_node->getDoubleValue("high-threshold", 0.9);
461     }
462
463     //
464     // Initialize the buttons.
465     //
466     char buf[8];
467     for (j = 0; j < nbuttons; j++) {
468       sprintf(buf, "%d", j);
469       _init_button(js_node->getChild("button", j),
470                    _joystick_bindings[i].buttons[j],
471                    buf);
472                    
473     }
474
475     js->setMinRange(minRange);
476     js->setMaxRange(maxRange);
477     js->setCenter(center);
478   }
479 }
480
481
482 inline void
483 FGInput::_init_button (const SGPropertyNode * node,
484                        button &b,
485                        const string name)
486 {       
487   if (node == 0)
488     SG_LOG(SG_INPUT, SG_INFO, "No bindings for button " << name);
489   else {
490     _read_bindings(node, b.bindings, FG_MOD_NONE);
491     b.is_repeatable = node->getBoolValue("repeatable", b.is_repeatable);
492     
493                 // Get the bindings for the button
494     _read_bindings(node, b.bindings, FG_MOD_NONE);
495   }
496 }
497
498
499 void
500 FGInput::_update_keyboard ()
501 {
502   // no-op
503 }
504
505
506 void
507 FGInput::_update_joystick ()
508 {
509   int modifiers = FG_MOD_NONE;  // FIXME: any way to get the real ones?
510   int buttons;
511   // float js_val, diff;
512   float axis_values[MAX_AXES];
513
514   int i;
515   int j;
516
517   for ( i = 0; i < MAX_JOYSTICKS; i++) {
518
519     jsJoystick * js = _joystick_bindings[i].js;
520     if (js == 0 || js->notWorking())
521       continue;
522
523     js->read(&buttons, axis_values);
524
525
526                                 // Fire bindings for the axes.
527     for ( j = 0; j < _joystick_bindings[i].naxes; j++) {
528       axis &a = _joystick_bindings[i].axes[j];
529       
530                                 // Do nothing if the axis position
531                                 // is unchanged; only a change in
532                                 // position fires the bindings.
533       if (fabs(axis_values[j] - a.last_value) > a.tolerance) {
534 //      SG_LOG(SG_INPUT, SG_INFO, "Axis " << j << " has moved");
535         SGPropertyNode node;
536         a.last_value = axis_values[j];
537 //      SG_LOG(SG_INPUT, SG_INFO, "There are "
538 //             << a.bindings[modifiers].size() << " bindings");
539         for (unsigned int k = 0; k < a.bindings[modifiers].size(); k++)
540           a.bindings[modifiers][k].fire(axis_values[j]);
541       }
542      
543                                 // do we have to emulate axis buttons?
544       if (a.low.bindings[modifiers].size())
545         _update_button(_joystick_bindings[i].axes[j].low,
546                        modifiers,
547                        axis_values[j] < a.low_threshold);
548       
549       if (a.high.bindings[modifiers].size())
550         _update_button(_joystick_bindings[i].axes[j].high,
551                        modifiers,
552                        axis_values[j] > a.high_threshold);
553     }
554
555                                 // Fire bindings for the buttons.
556     for (j = 0; j < _joystick_bindings[i].nbuttons; j++)
557       _update_button(_joystick_bindings[i].buttons[j],
558                      modifiers,
559                      (buttons & (1 << j)) > 0);
560   }
561 }
562
563
564 inline void
565 FGInput::_update_button (button &b, int modifiers, bool pressed)
566 {
567   if (pressed) {
568                                 // The press event may be repeated.
569     if (!b.last_state || b.is_repeatable) {
570 //    SG_LOG(SG_INPUT, SG_INFO, "Button " << j << " has been pressed");
571       for (unsigned int k = 0; k < b.bindings[modifiers].size(); k++)
572         b.bindings[modifiers][k].fire();
573     }
574   } else {
575                                 // The release event is never repeated.
576     if (b.last_state)
577 //    SG_LOG(SG_INPUT, SG_INFO, "Button " << j << " has been released");
578       for (unsigned int k = 0; k < b.bindings[modifiers|FG_MOD_UP].size(); k++)
579         b.bindings[modifiers|FG_MOD_UP][k].fire();
580   }
581           
582   b.last_state = pressed;
583 }  
584
585
586 void
587 FGInput::_read_bindings (const SGPropertyNode * node, 
588                          binding_list_t * binding_list,
589                          int modifiers)
590 {
591   vector<const SGPropertyNode *> bindings = node->getChildren("binding");
592   for (unsigned int i = 0; i < bindings.size(); i++) {
593     SG_LOG(SG_INPUT, SG_INFO, "Reading binding "
594            << bindings[i]->getStringValue("command"));
595     binding_list[modifiers].push_back(FGBinding(bindings[i]));
596   }
597
598                                 // Read nested bindings for modifiers
599   if (node->getChild("mod-up") != 0)
600     _read_bindings(node->getChild("mod-up"), binding_list,
601                    modifiers|FG_MOD_UP);
602
603   if (node->getChild("mod-shift") != 0)
604     _read_bindings(node->getChild("mod-shift"), binding_list,
605                    modifiers|FG_MOD_SHIFT);
606
607   if (node->getChild("mod-ctrl") != 0)
608     _read_bindings(node->getChild("mod-ctrl"), binding_list,
609                    modifiers|FG_MOD_CTRL);
610
611   if (node->getChild("mod-alt") != 0)
612     _read_bindings(node->getChild("mod-alt"), binding_list,
613                    modifiers|FG_MOD_ALT);
614 }
615
616
617 const vector<FGBinding> &
618 FGInput::_find_key_bindings (unsigned int k, int modifiers)
619 {
620   button &b = _key_bindings[k];
621
622                                 // Try it straight, first.
623   if (b.bindings[modifiers].size() > 0)
624     return b.bindings[modifiers];
625
626                                 // Try removing the control modifier
627                                 // for control keys.
628   else if ((modifiers&FG_MOD_CTRL) && iscntrl(k))
629     return _find_key_bindings(k, modifiers&~FG_MOD_CTRL);
630
631                                 // Try removing shift modifier 
632                                 // for upper case or any punctuation
633                                 // (since different keyboards will
634                                 // shift different punctuation types)
635   else if ((modifiers&FG_MOD_SHIFT) && (isupper(k) || ispunct(k)))
636     return _find_key_bindings(k, modifiers&~FG_MOD_SHIFT);
637
638                                 // Try removing alt modifier for
639                                 // high-bit characters.
640   else if ((modifiers&FG_MOD_ALT) && k >= 128 && k < 256)
641     return _find_key_bindings(k, modifiers&~FG_MOD_ALT);
642
643                                 // Give up and return the empty vector.
644   else
645     return b.bindings[modifiers];
646 }
647
648
649 /**
650  * Construct the modifiers.
651  */
652 static inline int get_mods ()
653 {
654   int glut_modifiers = glutGetModifiers();
655   int modifiers = 0;
656
657   if (glut_modifiers & GLUT_ACTIVE_SHIFT)
658     modifiers |= FGInput::FG_MOD_SHIFT;
659   if (glut_modifiers & GLUT_ACTIVE_CTRL)
660     modifiers |= FGInput::FG_MOD_CTRL;
661   if (glut_modifiers & GLUT_ACTIVE_ALT)
662     modifiers |= FGInput::FG_MOD_ALT;
663
664   return modifiers;
665 }
666
667
668 /**
669  * Key-down event handler for Glut.
670  *
671  * <p>Pass the value on to the FGInput module unless PUI wants it.</p>
672  *
673  * @param k The integer value for the key pressed.
674  * @param x (unused)
675  * @param y (unused)
676  */
677 void GLUTkey(unsigned char k, int x, int y)
678 {
679                                 // Give PUI a chance to grab it first.
680   if (!puKeyboard(k, PU_DOWN))
681     current_input.doKey(k, get_mods(), x, y);
682 }
683
684
685 /**
686  * Key-up event handler for GLUT.
687  *
688  * <p>PUI doesn't use this, so always pass it to the input manager.</p>
689  *
690  * @param k The integer value for the key pressed.
691  * @param x (unused)
692  * @param y (unused)
693  */
694 void GLUTkeyup(unsigned char k, int x, int y)
695 {
696   current_input.doKey(k, get_mods()|FGInput::FG_MOD_UP, x, y);
697 }
698
699
700 /**
701  * Special key-down handler for Glut.
702  *
703  * <p>Pass the value on to the FGInput module unless PUI wants it.
704  * The key value will have 256 added to it.</p>
705  *
706  * @param k The integer value for the key pressed (will have 256 added
707  * to it).
708  * @param x (unused)
709  * @param y (unused)
710  */
711 void GLUTspecialkey(int k, int x, int y)
712 {
713                                 // Give PUI a chance to grab it first.
714   if (!puKeyboard(k + PU_KEY_GLUT_SPECIAL_OFFSET, PU_DOWN))
715     current_input.doKey(k + 256, get_mods(), x, y);
716 }
717
718
719 /**
720  * Special key-up handler for Glut.
721  *
722  * @param k The integer value for the key pressed (will have 256 added
723  * to it).
724  * @param x (unused)
725  * @param y (unused)
726  */
727 void GLUTspecialkeyup(int k, int x, int y)
728 {
729   current_input.doKey(k + 256, get_mods()|FGInput::FG_MOD_UP, x, y);
730 }
731
732 // end of input.cxx