]> git.mxchange.org Git - flightgear.git/blob - src/Input/input.cxx
c23b03e5f862fb9e16c01bbc4f719b5169e68b2b
[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 #include <simgear/compiler.h>
28
29 #include <ctype.h>
30
31 #include STL_FSTREAM
32 #include STL_STRING
33
34 #include <simgear/constants.h>
35 #include <simgear/debug/logstream.hxx>
36 #include <simgear/misc/props.hxx>
37
38 #include <Aircraft/aircraft.hxx>
39 #include <Autopilot/auto_gui.hxx>
40 #include <Autopilot/newauto.hxx>
41 #include <Cockpit/hud.hxx>
42 #include <Cockpit/panel.hxx>
43 #include <Cockpit/panel_io.hxx>
44 #include <GUI/gui.h>
45 #include <Scenery/tilemgr.hxx>
46 #include <Objects/matlib.hxx>
47 #include <Time/light.hxx>
48 #include <Time/tmp.hxx>
49
50 #ifndef FG_OLD_WEATHER
51 #  include <WeatherCM/FGLocalWeatherDatabase.h>
52 #else
53 #  include <Weather/weather.hxx>
54 #endif
55
56 #include <Main/bfi.hxx>
57 #include <Main/globals.hxx>
58 #include <Main/keyboard.hxx>
59 #include <Main/fg_props.hxx>
60 #include <Main/options.hxx>
61
62 #include "input.hxx"
63
64 SG_USING_STD(ifstream);
65 SG_USING_STD(string);
66
67
68 \f
69 ////////////////////////////////////////////////////////////////////////
70 // Implementation of FGBinding.
71 ////////////////////////////////////////////////////////////////////////
72
73 FGBinding::FGBinding ()
74   : _command(0), _arg(0)
75 {
76 }
77
78 FGBinding::FGBinding (const SGPropertyNode * node)
79   : _command(0), _arg(0)
80 {
81   read(node);
82 }
83
84 FGBinding::~FGBinding ()
85 {
86   // no op
87 }
88
89 void
90 FGBinding::read (const SGPropertyNode * node)
91 {
92   _command_name = node->getStringValue("command", "");
93   if (_command_name == "") {
94     SG_LOG(SG_INPUT, SG_ALERT, "No command supplied for binding.");
95     _command = 0;
96     return;
97   }
98
99   _command = globals->get_commands()->getCommand(_command_name);
100   if (_command == 0) {
101     SG_LOG(SG_INPUT, SG_ALERT, "Command " << _command_name << " is undefined");
102     _arg = 0;
103     return;
104   }
105   _arg = node;                  // FIXME: don't use whole node!!!
106 }
107
108 void
109 FGBinding::fire () const
110 {
111   if (_command == 0) {
112     SG_LOG(SG_INPUT, SG_ALERT, "No command attached to binding");
113   } else if (!(*_command)(_arg)) {
114     SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command " << _command_name);
115   }
116 }
117
118
119 \f
120 ////////////////////////////////////////////////////////////////////////
121 // Implementation of FGInput.
122 ////////////////////////////////////////////////////////////////////////
123
124                                 // From main.cxx
125 extern void fgReshape( int width, int height );
126
127 FGInput current_input;
128
129
130 FGInput::FGInput ()
131 {
132   // no op
133 }
134
135 FGInput::~FGInput ()
136 {
137   // no op
138 }
139
140 void
141 FGInput::init ()
142 {
143                                 // Read the keyboard bindings.
144                                 // TODO: zero the old bindings first.
145   const SGPropertyNode * keyboard =
146     globals->get_props()->getNode("/input/keyboard", true);
147   vector<const SGPropertyNode *> keys = keyboard->getChildren("key");
148
149   for (unsigned int i = 0; i < keys.size(); i++) {
150     int code = keys[i]->getIntValue("code", -1);
151     int modifiers = FG_MOD_NONE;
152     if (keys[i]->getBoolValue("mod-shift"))
153       modifiers |= FG_MOD_SHIFT;
154     if (keys[i]->getBoolValue("mod-ctrl"))
155       modifiers |= FG_MOD_CTRL;
156     if (keys[i]->getBoolValue("mod-alt"))
157       modifiers |= FG_MOD_ALT;
158
159     if (code < 0) {
160       SG_LOG(SG_INPUT, SG_ALERT, "No code provided for key "
161              << keys[i]->getStringValue("name", "[unnamed]"));
162     } else {
163       SG_LOG(SG_INPUT, SG_INFO, "Binding key " << code
164              << " with modifiers " << modifiers);
165       vector<const SGPropertyNode *> bindings =
166         keys[i]->getChildren("binding");
167       for (unsigned int j = 0; j < bindings.size(); j++) {
168         SG_LOG(SG_INPUT, SG_INFO, "  Adding binding " << j);
169         _key_bindings[modifiers][code].push_back(FGBinding(bindings[j]));
170       }
171     }
172   }
173 }
174
175 void
176 FGInput::bind ()
177 {
178   // no op
179 }
180
181 void
182 FGInput::unbind ()
183 {
184   // no op
185 }
186
187 void 
188 FGInput::update ()
189 {
190   // we'll do something here with the joystick
191 }
192
193 void
194 FGInput::doKey (int k, int modifiers, int x, int y)
195 {
196   float fov, tmp;
197   static bool winding_ccw = true;
198   int speed;
199
200   SG_LOG(SG_INPUT, SG_INFO, "User pressed key " << k
201          << " with modifiers " << modifiers);
202
203   const vector<FGBinding> * bindings = _find_bindings(k, modifiers);
204   if (bindings != 0) {
205     for (unsigned int i = 0; i < bindings->size(); i++)
206       (*bindings)[i].fire();
207     return;
208   }
209
210   SG_LOG(SG_INPUT, SG_INFO, "(No user binding.)");
211
212                                 // Use the old, default actions.
213   FGInterface *f = current_aircraft.fdm_state;
214   FGViewer *v = globals->get_current_view();
215   
216   // everything after here will be removed sooner or later...
217
218   if (modifiers & FG_MOD_SHIFT) {
219
220         switch (k) {
221         case 7: // Ctrl-G key
222             current_autopilot->set_AltitudeMode( 
223                   FGAutopilot::FG_ALTITUDE_GS1 );
224             current_autopilot->set_AltitudeEnabled(
225                   ! current_autopilot->get_AltitudeEnabled()
226                 );
227             return;
228         case 18: // Ctrl-R key
229             // temporary
230             winding_ccw = !winding_ccw;
231             if ( winding_ccw ) {
232                 glFrontFace ( GL_CCW );
233             } else {
234                 glFrontFace ( GL_CW );
235             }
236             return;
237         case 20: // Ctrl-T key
238             current_autopilot->set_AltitudeMode( 
239                   FGAutopilot::FG_ALTITUDE_TERRAIN );
240             current_autopilot->set_AltitudeEnabled(
241                   ! current_autopilot->get_AltitudeEnabled()
242                 );
243             return;
244         case 72: // H key
245             HUD_brightkey( true );
246             return;
247         case 73: // I key
248             // Minimal Hud
249             fgHUDInit2(&current_aircraft);
250             return;
251         case 77: // M key
252             globals->inc_warp( -60 );
253             fgUpdateSkyAndLightingParams();
254             return;
255         case 84: // T key
256             globals->inc_warp_delta( -30 );
257             fgUpdateSkyAndLightingParams();
258             return;
259         case 87: // W key
260 #if defined(FX) && !defined(WIN32)
261             global_fullscreen = ( !global_fullscreen );
262 #  if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
263             XMesaSetFXmode( global_fullscreen ? 
264                             XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW );
265 #  endif
266 #endif
267             return;
268         case 88: // X key
269             fov = globals->get_current_view()->get_fov();
270             fov *= 1.05;
271             if ( fov > FG_FOV_MAX ) {
272                 fov = FG_FOV_MAX;
273             }
274             globals->get_current_view()->set_fov(fov);
275             // v->force_update_fov_math();
276             return;
277         case 90: // Z key
278 #ifndef FG_OLD_WEATHER
279             tmp = WeatherDatabase->getWeatherVisibility();
280             tmp /= 1.10;
281             WeatherDatabase->setWeatherVisibility( tmp );
282 #else
283             tmp = current_weather.get_visibility();   // in meters
284             tmp /= 1.10;
285             current_weather.set_visibility( tmp );
286 #endif
287             return;
288
289 // START SPECIALS
290
291         case 256+GLUT_KEY_F1: {
292             ifstream input("fgfs.sav");
293             if (input.good() && fgLoadFlight(input)) {
294                 input.close();
295                 SG_LOG(SG_INPUT, SG_INFO, "Restored flight from fgfs.sav");
296             } else {
297                 SG_LOG(SG_INPUT, SG_ALERT, "Cannot load flight from fgfs.sav");
298             }
299             return;
300         }
301         case 256+GLUT_KEY_F2: {
302             SG_LOG(SG_INPUT, SG_INFO, "Saving flight");
303             ofstream output("fgfs.sav");
304             if (output.good() && fgSaveFlight(output)) {
305                 output.close();
306                 SG_LOG(SG_INPUT, SG_INFO, "Saved flight to fgfs.sav");
307             } else {
308                 SG_LOG(SG_INPUT, SG_ALERT, "Cannot save flight to fgfs.sav");
309             }
310             return;
311         }
312         case 256+GLUT_KEY_F3: {
313             string panel_path =
314                 fgGetString("/sim/panel/path", "Panels/Default/default.xml");
315             FGPanel * new_panel = fgReadPanel(panel_path);
316             if (new_panel == 0) {
317                 SG_LOG(SG_INPUT, SG_ALERT,
318                        "Error reading new panel from " << panel_path);
319                 return;
320             }
321             SG_LOG(SG_INPUT, SG_INFO, "Loaded new panel from " << panel_path);
322             current_panel->unbind();
323             delete current_panel;
324             current_panel = new_panel;
325             current_panel->bind();
326             return;
327         }
328         case 256+GLUT_KEY_F4: {
329             SGPath props_path(globals->get_fg_root());
330             props_path.append("preferences.xml");
331             SG_LOG(SG_INPUT, SG_INFO, "Rereading global preferences");
332             if (!readProperties(props_path.str(), globals->get_props())) {
333                 SG_LOG(SG_INPUT, SG_ALERT,
334                        "Failed to reread global preferences from "
335                        << props_path.str());
336             } else {
337                 SG_LOG(SG_INPUT, SG_INFO, "Finished Reading global preferences");
338             }
339             return;
340         }
341         case 256+GLUT_KEY_F5: {
342             current_panel->setYOffset(current_panel->getYOffset() - 5);
343             fgReshape(fgGetInt("/sim/startup/xsize"),
344                       fgGetInt("/sim/startup/ysize"));
345             return;
346         }
347         case 256+GLUT_KEY_F6: {
348             current_panel->setYOffset(current_panel->getYOffset() + 5);
349             fgReshape(fgGetInt("/sim/startup/xsize"),
350                       fgGetInt("/sim/startup/ysize"));
351             return;
352         }
353         case 256+GLUT_KEY_F7: {
354             current_panel->setXOffset(current_panel->getXOffset() - 5);
355             return;
356         }
357         case 256+GLUT_KEY_F8: {
358             current_panel->setXOffset(current_panel->getXOffset() + 5);
359             return;
360         }
361         case 256+GLUT_KEY_F10: {
362             fgToggleFDMdataLogging();
363             return;
364         }
365
366 // END SPECIALS
367
368         }
369
370
371     } else {
372         SG_LOG( SG_INPUT, SG_DEBUG, "" );
373         switch (k) {
374         case 98: // b key
375             int b_ret;
376             double b_set;
377             b_ret = int( controls.get_brake( 0 ) );
378             b_set = double(!b_ret);
379             controls.set_brake( FGControls::ALL_WHEELS, b_set);
380             return;
381         case 44: // , key
382             if (controls.get_brake(0) > 0.0) {
383                 controls.set_brake(0, 0.0);
384             } else {
385                 controls.set_brake(0, 1.0);
386             }
387             return;
388         case 46: // . key
389             if (controls.get_brake(1) > 0.0) {
390                 controls.set_brake(1, 0.0);
391             } else {
392                 controls.set_brake(1, 1.0);
393             }
394             return;
395         case 104: // h key
396             HUD_masterswitch( true );
397             return;
398         case 105: // i key
399             fgHUDInit(&current_aircraft);  // normal HUD
400             return;
401         case 109: // m key
402             globals->inc_warp( 60 );
403             fgUpdateSkyAndLightingParams();
404             return;
405         case 112: // p key
406             globals->set_freeze( ! globals->get_freeze() );
407
408             {
409                 SGBucket p( f->get_Longitude() * SGD_RADIANS_TO_DEGREES,
410                             f->get_Latitude() * SGD_RADIANS_TO_DEGREES );
411                 SGPath tile_path( globals->get_fg_root() );
412                 tile_path.append( "Scenery" );
413                 tile_path.append( p.gen_base_path() );
414                 tile_path.append( p.gen_index_str() );
415
416                 // printf position and attitude information
417                 SG_LOG( SG_INPUT, SG_INFO,
418                         "Lon = " << f->get_Longitude() * SGD_RADIANS_TO_DEGREES
419                         << "  Lat = " << f->get_Latitude() * SGD_RADIANS_TO_DEGREES
420                         << "  Altitude = " << f->get_Altitude() * SG_FEET_TO_METER
421                         );
422                 SG_LOG( SG_INPUT, SG_INFO,
423                         "Heading = " << f->get_Psi() * SGD_RADIANS_TO_DEGREES 
424                         << "  Roll = " << f->get_Phi() * SGD_RADIANS_TO_DEGREES
425                         << "  Pitch = " << f->get_Theta() * SGD_RADIANS_TO_DEGREES );
426                 SG_LOG( SG_INPUT, SG_INFO, tile_path.c_str());
427             }
428             return;
429         case 116: // t key
430             globals->inc_warp_delta( 30 );
431             fgUpdateSkyAndLightingParams();
432             return;
433         case 120: // x key
434             fov = globals->get_current_view()->get_fov();
435             fov /= 1.05;
436             if ( fov < FG_FOV_MIN ) {
437                 fov = FG_FOV_MIN;
438             }
439             globals->get_current_view()->set_fov(fov);
440             // v->force_update_fov_math();
441             return;
442         case 122: // z key
443 #ifndef FG_OLD_WEATHER
444             tmp = WeatherDatabase->getWeatherVisibility();
445             tmp *= 1.10;
446             WeatherDatabase->setWeatherVisibility( tmp );
447 #else
448             tmp = current_weather.get_visibility();   // in meters
449             tmp *= 1.10;
450             current_weather.set_visibility( tmp );
451 #endif
452             return;
453         case 27: // ESC
454             // if( fg_DebugOutput ) {
455             //   fclose( fg_DebugOutput );
456             // }
457             SG_LOG( SG_INPUT, SG_ALERT, 
458                     "Program exit requested." );
459             ConfirmExitDialog();
460             return;
461
462 // START SPECIALS
463
464         case 256+GLUT_KEY_F2: // F2 Reload Tile Cache...
465             {
466                 bool freeze = globals->get_freeze();
467                 SG_LOG(SG_INPUT, SG_INFO, "ReIniting TileCache");
468                 if ( !freeze ) 
469                     globals->set_freeze( true );
470                 BusyCursor(0);
471                 if ( global_tile_mgr.init() ) {
472                     // Load the local scenery data
473                     global_tile_mgr.update( 
474                         cur_fdm_state->get_Longitude() * SGD_RADIANS_TO_DEGREES,
475                         cur_fdm_state->get_Latitude() * SGD_RADIANS_TO_DEGREES );
476                 } else {
477                     SG_LOG( SG_GENERAL, SG_ALERT, 
478                             "Error in Tile Manager initialization!" );
479                     exit(-1);
480                 }
481                 BusyCursor(1);
482                 if ( !freeze )
483                    globals->set_freeze( false );
484                 return;
485             }
486         case 256+GLUT_KEY_F4: // F4 Update lighting manually
487             fgUpdateSkyAndLightingParams();
488             return;
489         case 256+GLUT_KEY_F6: // F6 toggles Autopilot target location
490             if ( current_autopilot->get_HeadingMode() !=
491                  FGAutopilot::FG_HEADING_WAYPOINT ) {
492                 current_autopilot->set_HeadingMode(
493                     FGAutopilot::FG_HEADING_WAYPOINT );
494                 current_autopilot->set_HeadingEnabled( true );
495             } else {
496                 current_autopilot->set_HeadingMode(
497                     FGAutopilot::FG_TC_HEADING_LOCK );
498             }
499             return;
500         case 256+GLUT_KEY_F8: {// F8 toggles fog ... off fastest nicest...
501             const string &fog = fgGetString("/sim/rendering/fog");
502             if (fog == "disabled") {
503               fgSetString("/sim/rendering/fog", "fastest");
504               SG_LOG(SG_INPUT, SG_INFO, "Fog enabled, hint=fastest");
505             } else if (fog == "fastest") {
506               fgSetString("/sim/rendering/fog", "nicest");
507               SG_LOG(SG_INPUT, SG_INFO, "Fog enabled, hint=nicest");
508             } else if (fog == "nicest") {
509               fgSetString("/sim/rendering/fog", "disabled");
510               SG_LOG(SG_INPUT, SG_INFO, "Fog disabled");
511             } else {
512               fgSetString("/sim/rendering/fog", "disabled");
513               SG_LOG(SG_INPUT, SG_ALERT, "Unrecognized fog type "
514                      << fog << ", changed to 'disabled'");
515             }
516             return;
517         }
518         case 256+GLUT_KEY_F9: // F9 toggles textures on and off...
519             SG_LOG( SG_INPUT, SG_INFO, "Toggling texture" );
520             if ( fgGetBool("/sim/rendering/textures")) {
521                 fgSetBool("/sim/rendering/textures", false);
522                 material_lib.set_step( 1 );
523             } else {
524                 fgSetBool("/sim/rendering/textures", true);
525                 material_lib.set_step( 0 );
526             }
527             return;
528         case 256+GLUT_KEY_F10: // F10 toggles menu on and off...
529             SG_LOG(SG_INPUT, SG_INFO, "Invoking call back function");
530             guiToggleMenu();
531             return;
532         case 256+GLUT_KEY_F11: // F11 Altitude Dialog.
533             SG_LOG(SG_INPUT, SG_INFO, "Invoking Altitude call back function");
534             NewAltitude( NULL );
535             return;
536         case 256+GLUT_KEY_F12: // F12 Heading Dialog...
537             SG_LOG(SG_INPUT, SG_INFO, "Invoking Heading call back function");
538             NewHeading( NULL );
539             return;
540         }
541
542 // END SPECIALS
543
544     }
545 }
546
547
548 const vector<FGBinding> *
549 FGInput::_find_bindings (int k, int modifiers)
550 {
551   keyboard_map::const_iterator it = _key_bindings[modifiers].find(k);
552
553                                 // Try it straight, first.
554   if (it != _key_bindings[modifiers].end())
555     return &(_key_bindings[modifiers][k]);
556
557                                 // Try removing the control modifier
558                                 // for control keys.
559   else if ((modifiers&FG_MOD_CTRL) && iscntrl(k))
560     return _find_bindings(k, modifiers&~FG_MOD_CTRL);
561
562                                 // Try removing shift modifier 
563                                 // for upper case or any punctuation
564                                 // (since different keyboards will
565                                 // shift different punctuation types)
566   else if ((modifiers&FG_MOD_SHIFT) && (isupper(k) || ispunct(k)))
567     return _find_bindings(k, modifiers&~FG_MOD_SHIFT);
568
569                                 // Try removing alt modifier for
570                                 // high-bit characters.
571   else if ((modifiers&FG_MOD_ALT) && k >= 128 && k < 256)
572     return _find_bindings(k, modifiers&~FG_MOD_ALT);
573
574   else
575     return 0;
576 }
577
578 // end of input.cxx