# include <config.h>
#endif
+#ifdef HAVE_WINDOWS_H
+# include <windows.h>
+#endif
+
#include <simgear/compiler.h>
+#include <math.h>
#include <ctype.h>
#include STL_FSTREAM
#include STL_STRING
+#include <vector>
+
+#include <GL/glut.h>
+
+#include <plib/pu.h>
+
+#include <simgear/compiler.h>
#include <simgear/constants.h>
#include <simgear/debug/logstream.hxx>
# include <Weather/weather.hxx>
#endif
-#include <Main/bfi.hxx>
#include <Main/globals.hxx>
-#include <Main/keyboard.hxx>
#include <Main/fg_props.hxx>
#include <Main/options.hxx>
#include "input.hxx"
+#if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
SG_USING_STD(ifstream);
+#endif
SG_USING_STD(string);
+SG_USING_STD(vector);
+\f
+////////////////////////////////////////////////////////////////////////
+// Local data structures.
+////////////////////////////////////////////////////////////////////////
+
\f
////////////////////////////////////////////////////////////////////////
// Implementation of FGBinding.
////////////////////////////////////////////////////////////////////////
FGBinding::FGBinding ()
- : _action(ACTION_NONE), _node(0), _adjust_step(0), _assign_value(0)
+ : _command(0), _arg(0)
{
}
FGBinding::FGBinding (const SGPropertyNode * node)
- : _action(ACTION_NONE), _node(0), _adjust_step(0), _assign_value(0)
+ : _command(0), _arg(0)
{
- read(node);
+ read(node);
}
FGBinding::~FGBinding ()
{
- // no op
-}
-
-void
-FGBinding::setAction (Action action)
-{
- _action = action;
-}
-
-void
-FGBinding::setProperty (SGPropertyNode * node)
-{
- _node = node;
+ // no op
}
void
-FGBinding::setAdjustStep (const SGValue * step)
+FGBinding::read (const SGPropertyNode * node)
{
- _adjust_step = step;
+ _command_name = node->getStringValue("command", "");
+ if (_command_name == "") {
+ SG_LOG(SG_INPUT, SG_ALERT, "No command supplied for binding.");
+ _command = 0;
+ return;
+ }
+
+ _command = globals->get_commands()->getCommand(_command_name);
+ if (_command == 0) {
+ SG_LOG(SG_INPUT, SG_ALERT, "Command " << _command_name << " is undefined");
+ _arg = 0;
+ return;
+ }
+ _arg = node; // FIXME: don't use whole node!!!
}
void
-FGBinding::setAssignValue (const SGValue * value)
+FGBinding::fire () const
{
- _assign_value = value;
+ _fire(_arg);
}
void
-FGBinding::read (const SGPropertyNode * node)
+FGBinding::fire (double setting) const
{
- if (node->hasValue("action")) {
- string action = node->getStringValue("action");
- if (action == "none")
- _action = ACTION_NONE;
- else if (action == "switch")
- _action = ACTION_SWITCH;
- else if (action == "adjust")
- _action = ACTION_ADJUST;
- else if (action == "assign")
- _action = ACTION_ASSIGN;
- else
- SG_LOG(SG_INPUT, SG_ALERT, "Ignoring unrecognized action type "
- << action);
- }
-
- if (node->hasValue("control"))
- _node = fgGetNode(node->getStringValue("control"), true);
-
- if (node->hasValue("step"))
- _adjust_step = node->getChild("step")->getValue();
-
- if (node->hasValue("value"))
- _assign_value = node->getChild("value")->getValue();
+ SGPropertyNode arg;
+ if (_arg != 0)
+ copyProperties(_arg, &arg);
+ arg.setDoubleValue("setting", setting);
+ _fire(&arg);
}
void
-FGBinding::fire () const
+FGBinding::_fire(const SGPropertyNode * arg) const
{
- if (_node == 0) {
- SG_LOG(SG_INPUT, SG_ALERT, "No control property attached to binding");
- return;
- }
-
- switch (_action) {
-
- case ACTION_NONE:
- break;
-
- case ACTION_SWITCH:
- _node->setBoolValue(!_node->getBoolValue());
- break;
-
- case ACTION_ADJUST:
- if (_adjust_step == 0) {
- SG_LOG(SG_INPUT, SG_ALERT, "No step provided for adjust binding");
- break;
- }
- switch (_node->getType()) {
- case SGValue::BOOL:
- if (_adjust_step->getBoolValue())
- _node->setBoolValue(!_node->getBoolValue());
- break;
- case SGValue::INT:
- _node->setIntValue(_node->getIntValue() + _adjust_step->getIntValue());
- break;
- case SGValue::LONG:
- _node->setLongValue(_node->getLongValue() + _adjust_step->getLongValue());
- break;
- case SGValue::FLOAT:
- _node->setFloatValue(_node->getFloatValue()
- + _adjust_step->getFloatValue());
- break;
- case SGValue::DOUBLE:
- case SGValue::UNKNOWN: // force to double
- _node->setDoubleValue(_node->getDoubleValue()
- + _adjust_step->getDoubleValue());
- break;
- case SGValue::STRING:
- SG_LOG(SG_INPUT, SG_ALERT, "Cannot increment or decrement string value"
- << _node->getStringValue());
- break;
- }
- break;
-
- case ACTION_ASSIGN:
- if (_assign_value == 0) {
- SG_LOG(SG_INPUT, SG_ALERT, "No value provided for assign binding");
- break;
- }
- switch (_node->getType()) {
- case SGValue::BOOL:
- _node->setBoolValue(_assign_value->getBoolValue());
- break;
- case SGValue::INT:
- _node->setIntValue(_assign_value->getIntValue());
- break;
- case SGValue::LONG:
- _node->setLongValue(_assign_value->getLongValue());
- break;
- case SGValue::FLOAT:
- _node->setFloatValue(_assign_value->getFloatValue());
- break;
- case SGValue::DOUBLE:
- _node->setDoubleValue(_assign_value->getDoubleValue());
- break;
- case SGValue::STRING:
- _node->setStringValue(_assign_value->getStringValue());
- break;
- case SGValue::UNKNOWN:
- _node->setUnknownValue(_assign_value->getStringValue());
- break;
- }
- break;
- }
+ if (_command == 0) {
+ SG_LOG(SG_INPUT, SG_ALERT, "No command attached to binding");
+ } else if (!(*_command)(arg)) {
+ SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command " << _command_name);
+ }
}
// Implementation of FGInput.
////////////////////////////////////////////////////////////////////////
-// From main.cxx
+ // From main.cxx
extern void fgReshape( int width, int height );
FGInput current_input;
FGInput::FGInput ()
{
- // no op
+ // no op
}
FGInput::~FGInput ()
{
- // no op
+ // no op
}
void
FGInput::init ()
{
- // Read the keyboard bindings.
- // TODO: zero the old bindings first.
- const SGPropertyNode * keyboard =
- globals->get_props()->getNode("/input/keyboard", true);
- vector<const SGPropertyNode *> keys = keyboard->getChildren("key");
-
- for (unsigned int i = 0; i < keys.size(); i++) {
- int code = keys[i]->getIndex();
- int modifiers = FG_MOD_NONE;
- if (keys[i]->getBoolValue("mod-shift"))
- modifiers |= FG_MOD_SHIFT;
- if (keys[i]->getBoolValue("mod-ctrl"))
- modifiers |= FG_MOD_CTRL;
- if (keys[i]->getBoolValue("mod-alt"))
- modifiers |= FG_MOD_ALT;
-
- if (code < 0) {
- SG_LOG(SG_INPUT, SG_ALERT, "Key stroke not bound = "
- << keys[i]->getStringValue("name", "[unnamed]"));
- } else {
- SG_LOG(SG_INPUT, SG_INFO, "Binding key " << code
- << " with modifiers " << modifiers);
- vector<const SGPropertyNode *> bindings =
- keys[i]->getChildren("binding");
- for (unsigned int j = 0; j < bindings.size(); j++) {
- SG_LOG(SG_INPUT, SG_INFO, " Adding binding " << j);
- _key_bindings[modifiers][code].push_back(FGBinding(bindings[j]));
- }
- }
- }
+ _init_keyboard();
+ _init_joystick();
}
void
FGInput::bind ()
{
- // no op
+ // no op
}
void
FGInput::unbind ()
{
- // no op
+ // no op
}
void
FGInput::update ()
{
- // we'll do something here with the joystick
+ _update_keyboard();
+ _update_joystick();
}
void
FGInput::doKey (int k, int modifiers, int x, int y)
{
- float fov, tmp;
- static bool winding_ccw = true;
- int speed;
-
- SG_LOG(SG_INPUT, SG_INFO, "User pressed key " << k
- << " with modifiers " << modifiers);
-
- if (_key_bindings[modifiers].find(k) != _key_bindings[modifiers].end()) {
- const vector<FGBinding> &bindings = _key_bindings[modifiers][k];
- for (unsigned int i = 0; i < bindings.size(); i++) {
- bindings[i].fire();
- }
- return;
+ SG_LOG(SG_INPUT, SG_INFO, "User pressed key " << k
+ << " with modifiers " << modifiers);
+
+ // Sanity check.
+ if (k < 0 || k >= MAX_KEYS) {
+ SG_LOG(SG_INPUT, SG_ALERT, "Key value " << k << " out of range");
+ return;
+ }
+
+ button &b = _key_bindings[k];
+
+ // Key pressed.
+ if (modifiers&FG_MOD_UP == 0) {
+ // SG_LOG( SG_INPUT, SG_INFO, "User pressed key " << k
+ // << " with modifiers " << modifiers );
+ if (!b.last_state || b.is_repeatable) {
+ const binding_list_t &bindings =
+ _find_key_bindings(k, modifiers);
+ int max = bindings.size();
+ if (max > 0) {
+ for (int i = 0; i < max; i++)
+ bindings[i].fire();
+ return;
+ }
}
+ }
+
+ // Key released.
+ else {
+ // SG_LOG(SG_INPUT, SG_INFO, "User released key " << k
+ // << " with modifiers " << modifiers);
+ if (b.last_state) {
+ const binding_list_t &bindings =
+ _find_key_bindings(k, modifiers);
+ int max = bindings.size();
+ if (max > 0) {
+ for (int i = 0; i < max; i++)
+ bindings[i].fire();
+ return;
+ }
+ }
+ }
+
- SG_LOG(SG_INPUT, SG_INFO, "(No user binding.)");
+ // Use the old, default actions.
+ SG_LOG(SG_INPUT, SG_INFO, "(No user binding.)");
+ if (modifiers&FG_MOD_UP)
+ return;
- // Use the old, default actions.
- FGInterface *f = current_aircraft.fdm_state;
- FGViewer *v = globals->get_current_view();
+ float fov, tmp;
+ static bool winding_ccw = true;
+ // int speed;
+ FGInterface *f = current_aircraft.fdm_state;
+ // FGViewer *v = globals->get_current_view();
- // everything after here will be removed sooner or later...
+ // everything after here will be removed sooner or later...
- if (modifiers & FG_MOD_SHIFT) {
+ if (modifiers & FG_MOD_SHIFT) {
switch (k) {
case 7: // Ctrl-G key
current_autopilot->set_AltitudeMode(
- FGAutopilot::FG_ALTITUDE_GS1 );
+ FGAutopilot::FG_ALTITUDE_GS1 );
current_autopilot->set_AltitudeEnabled(
- ! current_autopilot->get_AltitudeEnabled()
- );
+ ! current_autopilot->get_AltitudeEnabled()
+ );
return;
case 18: // Ctrl-R key
// temporary
glFrontFace ( GL_CW );
}
return;
- case 19: // Ctrl-S key
- current_autopilot->set_AutoThrottleEnabled(
- ! current_autopilot->get_AutoThrottleEnabled()
- );
- return;
case 20: // Ctrl-T key
current_autopilot->set_AltitudeMode(
- FGAutopilot::FG_ALTITUDE_TERRAIN );
+ FGAutopilot::FG_ALTITUDE_TERRAIN );
current_autopilot->set_AltitudeEnabled(
- ! current_autopilot->get_AltitudeEnabled()
- );
- return;
- case 49: // numeric keypad 1
- v->set_goal_view_offset( SGD_PI * 0.75 );
- return;
- case 50: // numeric keypad 2
- v->set_goal_view_offset( SGD_PI );
- return;
- case 51: // numeric keypad 3
- v->set_goal_view_offset( SGD_PI * 1.25 );
- return;
- case 52: // numeric keypad 4
- v->set_goal_view_offset( SGD_PI * 0.50 );
- return;
- case 54: // numeric keypad 6
- v->set_goal_view_offset( SGD_PI * 1.50 );
- return;
- case 55: // numeric keypad 7
- v->set_goal_view_offset( SGD_PI * 0.25 );
- return;
- case 56: // numeric keypad 8
- v->set_goal_view_offset( 0.00 );
- return;
- case 57: // numeric keypad 9
- v->set_goal_view_offset( SGD_PI * 1.75 );
+ ! current_autopilot->get_AltitudeEnabled()
+ );
return;
case 72: // H key
HUD_brightkey( true );
#endif
return;
- // START SPECIALS
+// START SPECIALS
- case 256+GLUT_KEY_F1: {
- ifstream input("fgfs.sav");
- if (input.good() && fgLoadFlight(input)) {
- input.close();
- SG_LOG(SG_INPUT, SG_INFO, "Restored flight from fgfs.sav");
- } else {
- SG_LOG(SG_INPUT, SG_ALERT, "Cannot load flight from fgfs.sav");
- }
- return;
- }
- case 256+GLUT_KEY_F2: {
- SG_LOG(SG_INPUT, SG_INFO, "Saving flight");
- ofstream output("fgfs.sav");
- if (output.good() && fgSaveFlight(output)) {
- output.close();
- SG_LOG(SG_INPUT, SG_INFO, "Saved flight to fgfs.sav");
- } else {
- SG_LOG(SG_INPUT, SG_ALERT, "Cannot save flight to fgfs.sav");
- }
- return;
- }
- case 256+GLUT_KEY_F3: {
- string panel_path =
- fgGetString("/sim/panel/path", "Panels/Default/default.xml");
- FGPanel * new_panel = fgReadPanel(panel_path);
- if (new_panel == 0) {
- SG_LOG(SG_INPUT, SG_ALERT,
- "Error reading new panel from " << panel_path);
- return;
- }
- SG_LOG(SG_INPUT, SG_INFO, "Loaded new panel from " << panel_path);
- current_panel->unbind();
- delete current_panel;
- current_panel = new_panel;
- return;
- }
- case 256+GLUT_KEY_F4: {
- SGPath props_path(globals->get_fg_root());
- props_path.append("preferences.xml");
- SG_LOG(SG_INPUT, SG_INFO, "Rereading global preferences");
- if (!readProperties(props_path.str(), globals->get_props())) {
- SG_LOG(SG_INPUT, SG_ALERT,
- "Failed to reread global preferences from "
- << props_path.str());
- } else {
- SG_LOG(SG_INPUT, SG_INFO, "Finished Reading global preferences");
- }
- return;
- }
- case 256+GLUT_KEY_F5: {
- current_panel->setYOffset(current_panel->getYOffset() - 5);
- fgReshape(fgGetInt("/sim/startup/xsize"),
- fgGetInt("/sim/startup/ysize"));
- return;
- }
- case 256+GLUT_KEY_F6: {
- current_panel->setYOffset(current_panel->getYOffset() + 5);
- fgReshape(fgGetInt("/sim/startup/xsize"),
- fgGetInt("/sim/startup/ysize"));
- return;
- }
- case 256+GLUT_KEY_F7: {
- current_panel->setXOffset(current_panel->getXOffset() - 5);
- return;
- }
- case 256+GLUT_KEY_F8: {
- current_panel->setXOffset(current_panel->getXOffset() + 5);
- return;
- }
- // case 256+GLUT_KEY_F9: {
- // return;
- // }
case 256+GLUT_KEY_F10: {
fgToggleFDMdataLogging();
return;
}
- // case 256+GLUT_KEY_F11: {
- // return;
- // }
- // case 256+GLUT_KEY_F12: {
- // return;
- // }
- case 256+GLUT_KEY_END: // numeric keypad 1
- v->set_goal_view_offset( SGD_PI * 0.75 );
- return;
- case 256+GLUT_KEY_DOWN: // numeric keypad 2
- v->set_goal_view_offset( SGD_PI );
- return;
- case 256+GLUT_KEY_PAGE_DOWN: // numeric keypad 3
- v->set_goal_view_offset( SGD_PI * 1.25 );
- return;
- case 256+GLUT_KEY_LEFT: // numeric keypad 4
- v->set_goal_view_offset( SGD_PI * 0.50 );
- return;
- case 256+GLUT_KEY_RIGHT: // numeric keypad 6
- v->set_goal_view_offset( SGD_PI * 1.50 );
- return;
- case 256+GLUT_KEY_HOME: // numeric keypad 7
- v->set_goal_view_offset( SGD_PI * 0.25 );
- return;
- case 256+GLUT_KEY_UP: // numeric keypad 8
- v->set_goal_view_offset( 0.00 );
- return;
- case 256+GLUT_KEY_PAGE_UP: // numeric keypad 9
- v->set_goal_view_offset( SGD_PI * 1.75 );
- return;
- // END SPECIALS
+// END SPECIALS
}
} else {
SG_LOG( SG_INPUT, SG_DEBUG, "" );
switch (k) {
- case 98: // b key
- int b_ret;
- double b_set;
- b_ret = int( controls.get_brake( 0 ) );
- b_set = double(!b_ret);
- controls.set_brake( FGControls::ALL_WHEELS, b_set);
- return;
- case 44: // , key
- if (controls.get_brake(0) > 0.0) {
- controls.set_brake(0, 0.0);
- } else {
- controls.set_brake(0, 1.0);
- }
- return;
- case 46: // . key
- if (controls.get_brake(1) > 0.0) {
- controls.set_brake(1, 0.0);
- } else {
- controls.set_brake(1, 1.0);
- }
- return;
case 104: // h key
HUD_masterswitch( true );
return;
globals->inc_warp_delta( 30 );
fgUpdateSkyAndLightingParams();
return;
- case 118: // v key
- // handles GUI state as well as Viewer LookAt Direction
- CenterView();
- globals->set_current_view( globals->get_viewmgr()->next_view() );
- fgReshape( fgGetInt("/sim/startup/xsize"),
- fgGetInt("/sim/startup/ysize") );
- return;
case 120: // x key
fov = globals->get_current_view()->get_fov();
fov /= 1.05;
ConfirmExitDialog();
return;
- // START SPECIALS
+// START SPECIALS
case 256+GLUT_KEY_F2: // F2 Reload Tile Cache...
{
if ( global_tile_mgr.init() ) {
// Load the local scenery data
global_tile_mgr.update(
- cur_fdm_state->get_Longitude() * SGD_RADIANS_TO_DEGREES,
- cur_fdm_state->get_Latitude() * SGD_RADIANS_TO_DEGREES );
+ cur_fdm_state->get_Longitude() * SGD_RADIANS_TO_DEGREES,
+ cur_fdm_state->get_Latitude() * SGD_RADIANS_TO_DEGREES );
} else {
SG_LOG( SG_GENERAL, SG_ALERT,
"Error in Tile Manager initialization!" );
}
BusyCursor(1);
if ( !freeze )
- globals->set_freeze( false );
+ globals->set_freeze( false );
return;
}
- case 256+GLUT_KEY_F3: // F3 Take a screen shot
- fgDumpSnapShot();
- return;
case 256+GLUT_KEY_F4: // F4 Update lighting manually
fgUpdateSkyAndLightingParams();
return;
if ( current_autopilot->get_HeadingMode() !=
FGAutopilot::FG_HEADING_WAYPOINT ) {
current_autopilot->set_HeadingMode(
- FGAutopilot::FG_HEADING_WAYPOINT );
+ FGAutopilot::FG_HEADING_WAYPOINT );
current_autopilot->set_HeadingEnabled( true );
} else {
current_autopilot->set_HeadingMode(
- FGAutopilot::FG_TC_HEADING_LOCK );
+ FGAutopilot::FG_TC_HEADING_LOCK );
}
return;
case 256+GLUT_KEY_F8: {// F8 toggles fog ... off fastest nicest...
const string &fog = fgGetString("/sim/rendering/fog");
if (fog == "disabled") {
- fgSetString("/sim/rendering/fog", "fastest");
- SG_LOG(SG_INPUT, SG_INFO, "Fog enabled, hint=fastest");
+ fgSetString("/sim/rendering/fog", "fastest");
+ SG_LOG(SG_INPUT, SG_INFO, "Fog enabled, hint=fastest");
} else if (fog == "fastest") {
- fgSetString("/sim/rendering/fog", "nicest");
- SG_LOG(SG_INPUT, SG_INFO, "Fog enabled, hint=nicest");
+ fgSetString("/sim/rendering/fog", "nicest");
+ SG_LOG(SG_INPUT, SG_INFO, "Fog enabled, hint=nicest");
} else if (fog == "nicest") {
- fgSetString("/sim/rendering/fog", "disabled");
- SG_LOG(SG_INPUT, SG_INFO, "Fog disabled");
+ fgSetString("/sim/rendering/fog", "disabled");
+ SG_LOG(SG_INPUT, SG_INFO, "Fog disabled");
} else {
- fgSetString("/sim/rendering/fog", "disabled");
- SG_LOG(SG_INPUT, SG_ALERT, "Unrecognized fog type "
- << fog << ", changed to 'disabled'");
+ fgSetString("/sim/rendering/fog", "disabled");
+ SG_LOG(SG_INPUT, SG_ALERT, "Unrecognized fog type "
+ << fog << ", changed to 'disabled'");
}
return;
}
return;
}
- // END SPECIALS
+// END SPECIALS
}
}
void
-FGInput::action (const SGPropertyNode * binding)
+FGInput::_init_keyboard ()
{
- const string &action = binding->getStringValue("action", "");
- const string &control = binding->getStringValue("control", "");
- bool repeatable = binding->getBoolValue("repeatable", false);
- int step = binding->getIntValue("step", 0.0);
-
- if (control == "") {
- SG_LOG(SG_INPUT, SG_ALERT, "No control specified for key "
- << binding->getIndex());
- return;
- }
+ // TODO: zero the old bindings first.
+ SG_LOG(SG_INPUT, SG_INFO, "Initializing key bindings");
+ SGPropertyNode * key_nodes = fgGetNode("/input/keyboard");
+ if (key_nodes == 0) {
+ SG_LOG(SG_INPUT, SG_ALERT, "No key bindings (/input/keyboard)!!");
+ return;
+ }
+
+ vector<SGPropertyNode *> keys = key_nodes->getChildren("key");
+ for (unsigned int i = 0; i < keys.size(); i++) {
+ int index = keys[i]->getIndex();
+ SG_LOG(SG_INPUT, SG_INFO, "Binding key " << index);
+ _key_bindings[index].is_repeatable = keys[i]->getBoolValue("repeatable");
+ _read_bindings(keys[i], _key_bindings[index].bindings, FG_MOD_NONE);
+ }
+}
- else if (action == "") {
- SG_LOG(SG_INPUT, SG_ALERT, "No action specified for key "
- << binding->getIndex());
- return;
- }
- else if (action == "switch") {
- fgSetBool(control, !fgGetBool(control));
+void
+FGInput::_init_joystick ()
+{
+ // TODO: zero the old bindings first.
+ SG_LOG(SG_INPUT, SG_INFO, "Initializing joystick bindings");
+ SGPropertyNode * js_nodes = fgGetNode("/input/joysticks");
+ if (js_nodes == 0) {
+ SG_LOG(SG_INPUT, SG_ALERT, "No joystick bindings (/input/joysticks)!!");
+ return;
+ }
+
+ for (int i = 0; i < MAX_JOYSTICKS; i++) {
+ const SGPropertyNode * js_node = js_nodes->getChild("js", i);
+ if (js_node == 0) {
+ SG_LOG(SG_INPUT, SG_ALERT, "No bindings for joystick " << i);
+ continue;
+ }
+ jsJoystick * js = new jsJoystick(i);
+ _joystick_bindings[i].js = js;
+ if (js->notWorking()) {
+ SG_LOG(SG_INPUT, SG_INFO, "Joystick " << i << " not found");
+ continue;
+ }
+#ifdef WIN32
+ JOYCAPS jsCaps ;
+ joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) );
+ int nbuttons = jsCaps.wNumButtons;
+ if (nbuttons > MAX_BUTTONS) nbuttons = MAX_BUTTONS;
+#else
+ int nbuttons = MAX_BUTTONS;
+#endif
+
+ int naxes = js->getNumAxes();
+ if (naxes > MAX_AXES) naxes = MAX_AXES;
+ _joystick_bindings[i].naxes = naxes;
+ _joystick_bindings[i].nbuttons = nbuttons;
+
+ SG_LOG(SG_INPUT, SG_INFO, "Initializing joystick " << i);
+
+ // Set up range arrays
+ float minRange[MAX_AXES];
+ float maxRange[MAX_AXES];
+ float center[MAX_AXES];
+
+ // Initialize with default values
+ js->getMinRange(minRange);
+ js->getMaxRange(maxRange);
+ js->getCenter(center);
+
+ // Allocate axes and buttons
+ _joystick_bindings[i].axes = new axis[naxes];
+ _joystick_bindings[i].buttons = new button[nbuttons];
+
+
+ //
+ // Initialize the axes.
+ //
+ int j;
+ for (j = 0; j < naxes; j++) {
+ const SGPropertyNode * axis_node = js_node->getChild("axis", j);
+ if (axis_node == 0) {
+ SG_LOG(SG_INPUT, SG_INFO, "No bindings for axis " << j);
+ continue;
+ }
+
+ axis &a = _joystick_bindings[i].axes[j];
+
+ js->setDeadBand(j, axis_node->getDoubleValue("dead-band", 0.0));
+
+ a.tolerance = axis_node->getDoubleValue("tolerance", 0.002);
+ minRange[j] = axis_node->getDoubleValue("min-range", minRange[j]);
+ maxRange[j] = axis_node->getDoubleValue("max-range", maxRange[j]);
+ center[j] = axis_node->getDoubleValue("center", center[j]);
+
+ _read_bindings(axis_node, a.bindings, FG_MOD_NONE);
+
+ // Initialize the virtual axis buttons.
+ _init_button(axis_node->getChild("low"), a.low, "low");
+ a.low_threshold = axis_node->getDoubleValue("low-threshold", -0.9);
+
+ _init_button(axis_node->getChild("high"), a.high, "high");
+ a.high_threshold = axis_node->getDoubleValue("high-threshold", 0.9);
}
- else if (action == "adjust") {
- const SGValue * step = binding->getValue("step");
- if (step == 0) {
- SG_LOG(SG_INPUT, SG_ALERT, "No step supplied for adjust action for key "
- << binding->getIndex());
- return;
- }
- SGValue * target = fgGetValue(control, true);
- // Use the target's type...
- switch (target->getType()) {
- case SGValue::BOOL:
- case SGValue::INT:
- target->setIntValue(target->getIntValue() + step->getIntValue());
- break;
- case SGValue::LONG:
- target->setLongValue(target->getLongValue() + step->getLongValue());
- break;
- case SGValue::FLOAT:
- target->setFloatValue(target->getFloatValue() + step->getFloatValue());
- break;
- case SGValue::DOUBLE:
- case SGValue::UNKNOWN: // treat unknown as a double
- target->setDoubleValue(target->getDoubleValue()
- + step->getDoubleValue());
- break;
- case SGValue::STRING:
- SG_LOG(SG_INPUT, SG_ALERT, "Failed attempt to adjust string property "
- << control);
- break;
- }
+ //
+ // Initialize the buttons.
+ //
+ char buf[8];
+ for (j = 0; j < nbuttons; j++) {
+ sprintf(buf, "%d", j);
+ _init_button(js_node->getChild("button", j),
+ _joystick_bindings[i].buttons[j],
+ buf);
+
}
- else if (action == "assign") {
- const SGValue * value = binding->getValue("value");
- if (value == 0) {
- SG_LOG(SG_INPUT, SG_ALERT, "No value supplied for assign action for key "
- << binding->getIndex());
- return;
- }
- SGValue * target = fgGetValue(control, true);
- // Use the target's type...
- switch (target->getType()) {
- case SGValue::BOOL:
- target->setBoolValue(value->getBoolValue());
- break;
- case SGValue::INT:
- target->setIntValue(value->getIntValue());
- break;
- case SGValue::LONG:
- target->setLongValue(value->getLongValue());
- break;
- case SGValue::FLOAT:
- target->setFloatValue(value->getFloatValue());
- break;
- case SGValue::DOUBLE:
- target->setDoubleValue(value->getDoubleValue());
- break;
- case SGValue::STRING:
- target->setStringValue(value->getStringValue());
- break;
- case SGValue::UNKNOWN:
- target->setUnknownValue(value->getStringValue());
- break;
- }
+ js->setMinRange(minRange);
+ js->setMaxRange(maxRange);
+ js->setCenter(center);
+ }
+}
+
+
+inline void
+FGInput::_init_button (const SGPropertyNode * node,
+ button &b,
+ const string name)
+{
+ if (node == 0)
+ SG_LOG(SG_INPUT, SG_INFO, "No bindings for button " << name);
+ else {
+ _read_bindings(node, b.bindings, FG_MOD_NONE);
+ b.is_repeatable = node->getBoolValue("repeatable", b.is_repeatable);
+
+ // Get the bindings for the button
+ _read_bindings(node, b.bindings, FG_MOD_NONE);
+ }
+}
+
+
+void
+FGInput::_update_keyboard ()
+{
+ // no-op
+}
+
+
+void
+FGInput::_update_joystick ()
+{
+ int modifiers = FG_MOD_NONE; // FIXME: any way to get the real ones?
+ int buttons;
+ // float js_val, diff;
+ float axis_values[MAX_AXES];
+
+ int i;
+ int j;
+
+ for ( i = 0; i < MAX_JOYSTICKS; i++) {
+
+ jsJoystick * js = _joystick_bindings[i].js;
+ if (js == 0 || js->notWorking())
+ continue;
+
+ js->read(&buttons, axis_values);
+
+
+ // Fire bindings for the axes.
+ for ( j = 0; j < _joystick_bindings[i].naxes; j++) {
+ axis &a = _joystick_bindings[i].axes[j];
+
+ // Do nothing if the axis position
+ // is unchanged; only a change in
+ // position fires the bindings.
+ if (fabs(axis_values[j] - a.last_value) > a.tolerance) {
+// SG_LOG(SG_INPUT, SG_INFO, "Axis " << j << " has moved");
+ SGPropertyNode node;
+ a.last_value = axis_values[j];
+// SG_LOG(SG_INPUT, SG_INFO, "There are "
+// << a.bindings[modifiers].size() << " bindings");
+ for (unsigned int k = 0; k < a.bindings[modifiers].size(); k++)
+ a.bindings[modifiers][k].fire(axis_values[j]);
+ }
+
+ // do we have to emulate axis buttons?
+ if (a.low.bindings[modifiers].size())
+ _update_button(_joystick_bindings[i].axes[j].low,
+ modifiers,
+ axis_values[j] < a.low_threshold);
+
+ if (a.high.bindings[modifiers].size())
+ _update_button(_joystick_bindings[i].axes[j].high,
+ modifiers,
+ axis_values[j] > a.high_threshold);
}
- else {
- SG_LOG(SG_INPUT, SG_ALERT, "Unknown action " << action
- << " for key " << binding->getIndex());
+ // Fire bindings for the buttons.
+ for (j = 0; j < _joystick_bindings[i].nbuttons; j++)
+ _update_button(_joystick_bindings[i].buttons[j],
+ modifiers,
+ (buttons & (1 << j)) > 0);
+ }
+}
+
+
+inline void
+FGInput::_update_button (button &b, int modifiers, bool pressed)
+{
+ if (pressed) {
+ // The press event may be repeated.
+ if (!b.last_state || b.is_repeatable) {
+// SG_LOG(SG_INPUT, SG_INFO, "Button " << j << " has been pressed");
+ for (unsigned int k = 0; k < b.bindings[modifiers].size(); k++)
+ b.bindings[modifiers][k].fire();
}
+ } else {
+ // The release event is never repeated.
+ if (b.last_state)
+// SG_LOG(SG_INPUT, SG_INFO, "Button " << j << " has been released");
+ for (unsigned int k = 0; k < b.bindings[modifiers|FG_MOD_UP].size(); k++)
+ b.bindings[modifiers|FG_MOD_UP][k].fire();
+ }
+
+ b.last_state = pressed;
+}
+
+
+void
+FGInput::_read_bindings (const SGPropertyNode * node,
+ binding_list_t * binding_list,
+ int modifiers)
+{
+ vector<const SGPropertyNode *> bindings = node->getChildren("binding");
+ for (unsigned int i = 0; i < bindings.size(); i++) {
+ SG_LOG(SG_INPUT, SG_INFO, "Reading binding "
+ << bindings[i]->getStringValue("command"));
+ binding_list[modifiers].push_back(FGBinding(bindings[i]));
+ }
+
+ // Read nested bindings for modifiers
+ if (node->getChild("mod-up") != 0)
+ _read_bindings(node->getChild("mod-up"), binding_list,
+ modifiers|FG_MOD_UP);
+
+ if (node->getChild("mod-shift") != 0)
+ _read_bindings(node->getChild("mod-shift"), binding_list,
+ modifiers|FG_MOD_SHIFT);
+
+ if (node->getChild("mod-ctrl") != 0)
+ _read_bindings(node->getChild("mod-ctrl"), binding_list,
+ modifiers|FG_MOD_CTRL);
+
+ if (node->getChild("mod-alt") != 0)
+ _read_bindings(node->getChild("mod-alt"), binding_list,
+ modifiers|FG_MOD_ALT);
}
-#if 0
-FGViewer *v = globals->get_current_view();
+const vector<FGBinding> &
+FGInput::_find_key_bindings (unsigned int k, int modifiers)
+{
+ button &b = _key_bindings[k];
+
+ // Try it straight, first.
+ if (b.bindings[modifiers].size() > 0)
+ return b.bindings[modifiers];
+
+ // Try removing the control modifier
+ // for control keys.
+ else if ((modifiers&FG_MOD_CTRL) && iscntrl(k))
+ return _find_key_bindings(k, modifiers&~FG_MOD_CTRL);
+
+ // Try removing shift modifier
+ // for upper case or any punctuation
+ // (since different keyboards will
+ // shift different punctuation types)
+ else if ((modifiers&FG_MOD_SHIFT) && (isupper(k) || ispunct(k)))
+ return _find_key_bindings(k, modifiers&~FG_MOD_SHIFT);
+
+ // Try removing alt modifier for
+ // high-bit characters.
+ else if ((modifiers&FG_MOD_ALT) && k >= 128 && k < 256)
+ return _find_key_bindings(k, modifiers&~FG_MOD_ALT);
+
+ // Give up and return the empty vector.
+ else
+ return b.bindings[modifiers];
+}
-SG_LOG( SG_INPUT, SG_DEBUG, "Special key hit = " << k );
-if ( GLUT_ACTIVE_SHIFT && glutGetModifiers() ) {
- SG_LOG( SG_INPUT, SG_DEBUG, " SHIFTED" );
- switch (k)
- } else
- }
+/**
+ * Construct the modifiers.
+ */
+static inline int get_mods ()
+{
+ int glut_modifiers = glutGetModifiers();
+ int modifiers = 0;
+
+ if (glut_modifiers & GLUT_ACTIVE_SHIFT)
+ modifiers |= FGInput::FG_MOD_SHIFT;
+ if (glut_modifiers & GLUT_ACTIVE_CTRL)
+ modifiers |= FGInput::FG_MOD_CTRL;
+ if (glut_modifiers & GLUT_ACTIVE_ALT)
+ modifiers |= FGInput::FG_MOD_ALT;
+
+ return modifiers;
+}
+
+
+/**
+ * Key-down event handler for Glut.
+ *
+ * <p>Pass the value on to the FGInput module unless PUI wants it.</p>
+ *
+ * @param k The integer value for the key pressed.
+ * @param x (unused)
+ * @param y (unused)
+ */
+void GLUTkey(unsigned char k, int x, int y)
+{
+ // Give PUI a chance to grab it first.
+ if (!puKeyboard(k, PU_DOWN))
+ current_input.doKey(k, get_mods(), x, y);
+}
+
+
+/**
+ * Key-up event handler for GLUT.
+ *
+ * <p>PUI doesn't use this, so always pass it to the input manager.</p>
+ *
+ * @param k The integer value for the key pressed.
+ * @param x (unused)
+ * @param y (unused)
+ */
+void GLUTkeyup(unsigned char k, int x, int y)
+{
+ current_input.doKey(k, get_mods()|FGInput::FG_MOD_UP, x, y);
+}
-#endif
+/**
+ * Special key-down handler for Glut.
+ *
+ * <p>Pass the value on to the FGInput module unless PUI wants it.
+ * The key value will have 256 added to it.</p>
+ *
+ * @param k The integer value for the key pressed (will have 256 added
+ * to it).
+ * @param x (unused)
+ * @param y (unused)
+ */
+void GLUTspecialkey(int k, int x, int y)
+{
+ // Give PUI a chance to grab it first.
+ if (!puKeyboard(k + PU_KEY_GLUT_SPECIAL_OFFSET, PU_DOWN))
+ current_input.doKey(k + 256, get_mods(), x, y);
+}
+
+
+/**
+ * Special key-up handler for Glut.
+ *
+ * @param k The integer value for the key pressed (will have 256 added
+ * to it).
+ * @param x (unused)
+ * @param y (unused)
+ */
+void GLUTspecialkeyup(int k, int x, int y)
+{
+ current_input.doKey(k + 256, get_mods()|FGInput::FG_MOD_UP, x, y);
+}
// end of input.cxx