- if (default_input == 0)
- default_input = this;
-}
-
-FGInput::~FGInput ()
-{
- if (default_input == this)
- default_input = 0;
-}
-
-void
-FGInput::init ()
-{
- _init_joystick();
- _init_mouse();
-
- fgRegisterKeyHandler(keyHandler);
- fgRegisterMouseClickHandler(mouseClickHandler);
- fgRegisterMouseMotionHandler(mouseMotionHandler);
-}
-
-void
-FGInput::reinit ()
-{
- init();
-}
-
-void
-FGInput::postinit ()
-{
- _postinit_joystick();
- _postinit_keyboard();
-}
-
-void
-FGInput::bind ()
-{
- fgTie("/devices/status/keyboard/shift", getModShift);
- fgTie("/devices/status/keyboard/ctrl", getModCtrl);
- fgTie("/devices/status/keyboard/alt", getModAlt);
-}
-
-void
-FGInput::unbind ()
-{
- fgUntie("/devices/status/keyboard/shift");
- fgUntie("/devices/status/keyboard/ctrl");
- fgUntie("/devices/status/keyboard/alt");
-}
-
-void
-FGInput::update (double dt)
-{
- _update_keyboard();
- _update_joystick(dt);
- _update_mouse(dt);
-}
-
-void
-FGInput::suspend ()
-{
- // NO-OP
-}
-
-void
-FGInput::resume ()
-{
- // NO-OP
-}
-
-bool
-FGInput::is_suspended () const
-{
- return false;
-}
-
-void
-FGInput::makeDefault (bool status)
-{
- if (status)
- default_input = this;
- else if (default_input == this)
- default_input = 0;
-}
-
-void
-FGInput::doKey (int k, int modifiers, int x, int y)
-{
- // Sanity check.
- if (k < 0 || k >= MAX_KEYS) {
- SG_LOG(SG_INPUT, SG_WARN, "Key value " << k << " out of range");
- return;
- }
-
- button &b = _key_bindings[k];
-
- // Key pressed.
- if (!(modifiers & KEYMOD_RELEASED)) {
- SG_LOG( SG_INPUT, SG_DEBUG, "User pressed key " << k
- << " with modifiers " << modifiers );
- if (!b.last_state || b.is_repeatable) {
- const binding_list_t &bindings = _find_key_bindings(k, modifiers);
-
- for (unsigned int i = 0; i < bindings.size(); i++)
- bindings[i]->fire();
- b.last_state = 1;
- }
- }
- // Key released.
- else {
- SG_LOG(SG_INPUT, SG_DEBUG, "User released key " << k
- << " with modifiers " << modifiers);
- if (b.last_state) {
- const binding_list_t &bindings = _find_key_bindings(k, modifiers);
- for (unsigned int i = 0; i < bindings.size(); i++)
- bindings[i]->fire();
- b.last_state = 0;
- } else {
- if (k >= 1 && k <= 26) {
- if (_key_bindings[k + '@'].last_state)
- doKey(k + '@', KEYMOD_RELEASED, x, y);
- if (_key_bindings[k + '`'].last_state)
- doKey(k + '`', KEYMOD_RELEASED, x, y);
- } else if (k >= 'A' && k <= 'Z') {
- if (_key_bindings[k - '@'].last_state)
- doKey(k - '@', KEYMOD_RELEASED, x, y);
- if (_key_bindings[tolower(k)].last_state)
- doKey(tolower(k), KEYMOD_RELEASED, x, y);
- } else if (k >= 'a' && k <= 'z') {
- if (_key_bindings[k - '`'].last_state)
- doKey(k - '`', KEYMOD_RELEASED, x, y);
- if (_key_bindings[toupper(k)].last_state)
- doKey(toupper(k), KEYMOD_RELEASED, x, y);
- }
- }
- }
-}
-
-void
-FGInput::doMouseClick (int b, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter* ea)
-{
- int modifiers = fgGetKeyModifiers();
-
- mouse &m = _mouse_bindings[0];
- mouse_mode &mode = m.modes[m.current_mode];
-
- // Let the property manager know.
- if (b >= 0 && b < MAX_MOUSE_BUTTONS)
- m.mouse_button_nodes[b]->setBoolValue(updown == MOUSE_BUTTON_DOWN);
-
- // Pass on to PUI and the panel if
- // requested, and return if one of
- // them consumes the event.
-
- if (updown != MOUSE_BUTTON_DOWN) {
- // Execute the mouse up event in any case, may be we should
- // stop processing here?
- while (!_activePickCallbacks[b].empty()) {
- _activePickCallbacks[b].front()->buttonReleased();
- _activePickCallbacks[b].pop_front();
- }
- }
-
- if (mode.pass_through) {
- // The pu stuff seems to need that. May be it does opengl picking ...
- fgMakeCurrent();
- if (0 <= x && 0 <= y && puMouse(b, updown, x, y))
- return;
- else if (0 <= x && 0 <= y && (globals->get_current_panel() != 0) &&
- globals->get_current_panel()->getVisibility() &&
- globals->get_current_panel()->doMouseAction(b, updown, x, y))
- return;
- else if (0 <= x && 0 <= y && fgHandle3DPanelMouseEvent(b, updown, x, y))
- return;
- else {
- // pui didn't want the click event so compute a
- // scenegraph intersection point corresponding to the mouse click
- if (updown == MOUSE_BUTTON_DOWN) {
-
- // Get the list of hit callbacks. Take the first callback that
- // accepts the mouse button press and ignore the rest of them
- // That is they get sorted by distance and by scenegraph depth.
- // The nearest one is the first one and the deepest
- // (the most specialized one in the scenegraph) is the first.
- std::vector<SGSceneryPick> pickList;
- if (FGRenderer::pick(x, y, pickList, ea)) {
- std::vector<SGSceneryPick>::const_iterator i;
- for (i = pickList.begin(); i != pickList.end(); ++i) {
- if (i->callback->buttonPressed(b, i->info)) {
- _activePickCallbacks[b].push_back(i->callback);
- return;
- }
- }
- }
- }
- }
- }
-
- // OK, PUI and the panel didn't want the click
- if (b >= MAX_MOUSE_BUTTONS) {
- SG_LOG(SG_INPUT, SG_ALERT, "Mouse button " << b
- << " where only " << MAX_MOUSE_BUTTONS << " expected");
- return;
- }
-
- _update_button(m.modes[m.current_mode].buttons[b], modifiers, 0 != updown, x, y);
-}
-
-void
-FGInput::doMouseMotion (int x, int y)
-{
- // Don't call fgGetKeyModifiers() here, until we are using a
- // toolkit that supports getting the mods from outside a key
- // callback. Glut doesn't.
- int modifiers = KEYMOD_NONE;
-
- int xsize = fgGetInt("/sim/startup/xsize", 800);
- int ysize = fgGetInt("/sim/startup/ysize", 600);
-
- mouse &m = _mouse_bindings[0];
-
- if (m.current_mode < 0 || m.current_mode >= m.nModes) {
- m.x = x;
- m.y = y;
- return;
- }
- mouse_mode &mode = m.modes[m.current_mode];
-
- // Pass on to PUI if requested, and return
- // if PUI consumed the event.
- if (mode.pass_through && puMouse(x, y)) {
- m.x = x;
- m.y = y;
- return;
- }
-
- // OK, PUI didn't want the event,
- // so we can play with it.
- if (x != m.x) {
- int delta = x - m.x;
- for (unsigned int i = 0; i < mode.x_bindings[modifiers].size(); i++)
- mode.x_bindings[modifiers][i]->fire(double(delta), double(xsize));
- }
- if (y != m.y) {
- int delta = y - m.y;
- for (unsigned int i = 0; i < mode.y_bindings[modifiers].size(); i++)
- mode.y_bindings[modifiers][i]->fire(double(delta), double(ysize));
- }
-
- // Constrain the mouse if requested
- if (mode.constrained) {
- bool need_warp = false;
- if (x <= (xsize * .25) || x >= (xsize * .75)) {
- x = int(xsize * .5);
- need_warp = true;
- }
-
- if (y <= (ysize * .25) || y >= (ysize * .75)) {
- y = int(ysize * .5);
- need_warp = true;
- }
-
- if (need_warp)
- fgWarpMouse(x, y);
- }
-
- if (m.x != x)
- fgSetInt("/devices/status/mice/mouse/x", m.x = x);
-
- if (m.y != y)
- fgSetInt("/devices/status/mice/mouse/y", m.y = y);
-}
-
-
-void
-FGInput::_scan_joystick_dir(SGPath *path, SGPropertyNode* node, int *index)
-{
- ulDir *dir = ulOpenDir(path->c_str());
- if (dir) {
- ulDirEnt* dent;
- while ((dent = ulReadDir(dir)) != 0) {
- if (dent->d_name[0] == '.')
- continue;
-
- SGPath p(path->str());
- p.append(dent->d_name);
- _scan_joystick_dir(&p, node, index);
- }
- ulCloseDir(dir);
-
- } else if (path->extension() == "xml") {
- SG_LOG(SG_INPUT, SG_DEBUG, "Reading joystick file " << path->str());
- SGPropertyNode *n = node->getChild("js-named", (*index)++, true);
- readProperties(path->str(), n);
- n->setStringValue("source", path->c_str());
- }
-}
-
-
-void
-FGInput::_init_joystick ()
-{
- jsInit();
- // TODO: zero the old bindings first.
- SG_LOG(SG_INPUT, SG_DEBUG, "Initializing joystick bindings");
- SGPropertyNode * js_nodes = fgGetNode("/input/joysticks", true);
-
- // read all joystick xml files into /input/joysticks/js_named[1000++]
- SGPath path(globals->get_fg_root());
- path.append("Input/Joysticks");
- int js_named_index = 1000;
- _scan_joystick_dir(&path, js_nodes, &js_named_index);
-
- // build name->node map with each <name> (reverse order)
- map<string, SGPropertyNode_ptr> jsmap;
- vector<SGPropertyNode_ptr> js_named = js_nodes->getChildren("js-named");
-
- for (int k = (int)js_named.size() - 1; k >= 0; k--) {
- SGPropertyNode *n = js_named[k];
- vector<SGPropertyNode_ptr> names = n->getChildren("name");
- if (names.size() && (n->getChildren("axis").size() || n->getChildren("button").size()))
- for (unsigned int j = 0; j < names.size(); j++)
- jsmap[names[j]->getStringValue()] = n;
- }
-
- // set up js[] nodes
- for (int i = 0; i < MAX_JOYSTICKS; i++) {
- jsJoystick * js = new jsJoystick(i);
- _joystick_bindings[i].js = js;
-
- if (js->notWorking()) {
- SG_LOG(SG_INPUT, SG_DEBUG, "Joystick " << i << " not found");
- continue;
- }
-
- const char * name = js->getName();
- SGPropertyNode_ptr js_node = js_nodes->getChild("js", i);
-
- if (js_node) {
- SG_LOG(SG_INPUT, SG_INFO, "Using existing bindings for joystick " << i);
-
- } else {
- SG_LOG(SG_INPUT, SG_INFO, "Looking for bindings for joystick \"" << name << '"');
- SGPropertyNode_ptr named;
-
- if ((named = jsmap[name])) {
- string source = named->getStringValue("source", "user defined");
- SG_LOG(SG_INPUT, SG_INFO, "... found joystick: " << source);
-
- } else if ((named = jsmap["default"])) {
- string source = named->getStringValue("source", "user defined");
- SG_LOG(SG_INPUT, SG_INFO, "No config found for joystick \"" << name
- << "\"\nUsing default: \"" << source << '"');
-
- } else {
- throw sg_throwable(string("No joystick configuration file with "
- "<name>default</name> entry found!"));
- }
-
- js_node = js_nodes->getChild("js", i, true);
- copyProperties(named, js_node);
- js_node->setStringValue("id", name);
- }
- }
-
- // get rid of unused config nodes
- js_nodes->removeChildren("js-named", false);
-}
-
-
-void
-FGInput::_postinit_keyboard()
-{
- SG_LOG(SG_INPUT, SG_DEBUG, "Initializing key bindings");
- _module = "__kbd";
- SGPropertyNode * key_nodes = fgGetNode("/input/keyboard");
- if (key_nodes == 0) {
- SG_LOG(SG_INPUT, SG_WARN, "No key bindings (/input/keyboard)!!");
- key_nodes = fgGetNode("/input/keyboard", true);
- }
-
- FGNasalSys *nasalsys = (FGNasalSys *)globals->get_subsystem("nasal");
- vector<SGPropertyNode_ptr> nasal = key_nodes->getChildren("nasal");
- for (unsigned int j = 0; j < nasal.size(); j++) {
- nasal[j]->setStringValue("module", _module.c_str());
- nasalsys->handleCommand(nasal[j]);
- }
-
- vector<SGPropertyNode_ptr> keys = key_nodes->getChildren("key");
- for (unsigned int i = 0; i < keys.size(); i++) {
- int index = keys[i]->getIndex();
- SG_LOG(SG_INPUT, SG_DEBUG, "Binding key " << index);
-
- _key_bindings[index].bindings->clear();
- _key_bindings[index].is_repeatable = keys[i]->getBoolValue("repeatable");
- _key_bindings[index].last_state = 0;
- _read_bindings(keys[i], _key_bindings[index].bindings, KEYMOD_NONE);
- }
-}
-
-
-void
-FGInput::_postinit_joystick()
-{
- FGNasalSys *nasalsys = (FGNasalSys *)globals->get_subsystem("nasal");
- SGPropertyNode *js_nodes = fgGetNode("/input/joysticks");
-
- for (int i = 0; i < MAX_JOYSTICKS; i++) {
- SGPropertyNode_ptr js_node = js_nodes->getChild("js", i);
- jsJoystick *js = _joystick_bindings[i].js;
- if (!js_node || js->notWorking())
- continue;
-
-#ifdef WIN32
- JOYCAPS jsCaps ;
- joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) );
- unsigned int nbuttons = jsCaps.wNumButtons;
- if (nbuttons > MAX_JOYSTICK_BUTTONS) nbuttons = MAX_JOYSTICK_BUTTONS;
-#else
- unsigned int nbuttons = MAX_JOYSTICK_BUTTONS;