X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FInput%2Finput.cxx;h=d281c3593985dd1f0cf895863ae2ad8120533cb8;hb=b588a92b7f31cc7030077c1906c9014d7e7bb437;hp=59f27bd89c0d13dd4339a017f2db3b1f88d64c42;hpb=94aca555e9f8443c2273acef1dec03953f6726d1;p=flightgear.git diff --git a/src/Input/input.cxx b/src/Input/input.cxx index 59f27bd89..d281c3593 100644 --- a/src/Input/input.cxx +++ b/src/Input/input.cxx @@ -16,7 +16,7 @@ // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // $Id$ @@ -24,24 +24,23 @@ # include #endif -#ifdef HAVE_WINDOWS_H -# include -#endif - #include #include #include +#include -#include STL_FSTREAM -#include STL_STRING +#include +#include #include #include #include #include +#include #include +#include #include #include @@ -59,14 +58,13 @@ #include #include
-#include -#include -SG_USING_STD(ifstream); -SG_USING_STD(string); -SG_USING_STD(vector); +using std::ifstream; +using std::ostringstream; +using std::string; +using std::vector; -void mouseClickHandler(int button, int updown, int x, int y); +void mouseClickHandler(int button, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter*); void mouseMotionHandler(int x, int y); void keyHandler(int key, int keymod, int mousex, int mousey); @@ -77,95 +75,61 @@ void keyHandler(int key, int keymod, int mousex, int mousey); static FGInput * default_input = 0; - //////////////////////////////////////////////////////////////////////// -// Implementation of FGBinding. +// Local functions. //////////////////////////////////////////////////////////////////////// -FGBinding::FGBinding () - : _command(0), - _arg(new SGPropertyNode), - _setting(0) +static int +getModifiers () { + return fgGetKeyModifiers() >> 1; } -FGBinding::FGBinding (const SGPropertyNode * node) - : _command(0), - _arg(0), - _setting(0) +static bool +getModShift () { - read(node); + return bool(fgGetKeyModifiers() & KEYMOD_SHIFT); } -FGBinding::~FGBinding () +static bool +getModCtrl () { - _arg->getParent()->removeChild(_arg->getName(), _arg->getIndex(), false); + return bool(fgGetKeyModifiers() & KEYMOD_CTRL); } -void -FGBinding::read (const SGPropertyNode * node) +static bool +getModAlt () { - const SGPropertyNode * conditionNode = node->getChild("condition"); - if (conditionNode != 0) - setCondition(sgReadCondition(globals->get_props(), conditionNode)); - - _command_name = node->getStringValue("command", ""); - if (_command_name.empty()) { - SG_LOG(SG_INPUT, SG_WARN, "No command supplied for binding."); - _command = 0; - return; - } - - _arg = (SGPropertyNode *)node; - _setting = 0; + return bool(fgGetKeyModifiers() & KEYMOD_ALT); } -void -FGBinding::fire () const +static bool +getModMeta () { - if (test()) { - if (_command == 0) - _command = globals->get_commands()->getCommand(_command_name); - if (_command == 0) { - SG_LOG(SG_INPUT, SG_WARN, "No command attached to binding"); - } else if (!(*_command)(_arg)) { - SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command " - << _command_name); - } - } + return bool(fgGetKeyModifiers() & KEYMOD_META); } -void -FGBinding::fire (double offset, double max) const +static bool +getModSuper () { - if (test()) { - _arg->setDoubleValue("offset", offset/max); - fire(); - } + return bool(fgGetKeyModifiers() & KEYMOD_SUPER); } -void -FGBinding::fire (double setting) const +static bool +getModHyper () { - if (test()) { - // A value is automatically added to - // the args - if (_setting == 0) // save the setting node for efficiency - _setting = _arg->getChild("setting", 0, true); - _setting->setDoubleValue(setting); - fire(); - } + return bool(fgGetKeyModifiers() & KEYMOD_HYPER); } - //////////////////////////////////////////////////////////////////////// // Implementation of FGInput. //////////////////////////////////////////////////////////////////////// -FGInput::FGInput () +FGInput::FGInput () : + _key_event(fgGetNode("/devices/status/keyboard/event", true)) { if (default_input == 0) default_input = this; @@ -180,7 +144,6 @@ FGInput::~FGInput () void FGInput::init () { - _init_keyboard(); _init_joystick(); _init_mouse(); @@ -199,6 +162,51 @@ void FGInput::postinit () { _postinit_joystick(); + _postinit_keyboard(); +} + +void +FGInput::bind () +{ + fgTie("/devices/status/keyboard", getModifiers); + fgTie("/devices/status/keyboard/shift", getModShift); + fgTie("/devices/status/keyboard/ctrl", getModCtrl); + fgTie("/devices/status/keyboard/alt", getModAlt); + fgTie("/devices/status/keyboard/meta", getModMeta); + fgTie("/devices/status/keyboard/super", getModSuper); + fgTie("/devices/status/keyboard/hyper", getModHyper); + + _key_event->tie("key", SGRawValuePointer(&_key_code)); + _key_event->tie("pressed", SGRawValuePointer(&_key_pressed)); + _key_event->tie("modifier", SGRawValuePointer(&_key_modifiers)); + _key_event->tie("modifier/shift", SGRawValuePointer(&_key_shift)); + _key_event->tie("modifier/ctrl", SGRawValuePointer(&_key_ctrl)); + _key_event->tie("modifier/alt", SGRawValuePointer(&_key_alt)); + _key_event->tie("modifier/meta", SGRawValuePointer(&_key_meta)); + _key_event->tie("modifier/super", SGRawValuePointer(&_key_super)); + _key_event->tie("modifier/hyper", SGRawValuePointer(&_key_hyper)); +} + +void +FGInput::unbind () +{ + fgUntie("/devices/status/keyboard"); + fgUntie("/devices/status/keyboard/shift"); + fgUntie("/devices/status/keyboard/ctrl"); + fgUntie("/devices/status/keyboard/alt"); + fgUntie("/devices/status/keyboard/meta"); + fgUntie("/devices/status/keyboard/super"); + fgUntie("/devices/status/keyboard/hyper"); + + _key_event->untie("key"); + _key_event->untie("pressed"); + _key_event->untie("modifier"); + _key_event->untie("modifier/shift"); + _key_event->untie("modifier/ctrl"); + _key_event->untie("modifier/alt"); + _key_event->untie("modifier/meta"); + _key_event->untie("modifier/super"); + _key_event->untie("modifier/hyper"); } void @@ -245,6 +253,23 @@ FGInput::doKey (int k, int modifiers, int x, int y) return; } + _key_code = k; + _key_modifiers = modifiers >> 1; + _key_pressed = !bool(modifiers & KEYMOD_RELEASED); + _key_shift = bool(modifiers & KEYMOD_SHIFT); + _key_ctrl = bool(modifiers & KEYMOD_CTRL); + _key_alt = bool(modifiers & KEYMOD_ALT); + _key_meta = bool(modifiers & KEYMOD_META); + _key_super = bool(modifiers & KEYMOD_SUPER); + _key_hyper = bool(modifiers & KEYMOD_HYPER); + _key_event->fireValueChanged(); + if (_key_code < 0) + return; + + k = _key_code; + modifiers = _key_modifiers << 1; + if (!_key_pressed) + modifiers |= KEYMOD_RELEASED; button &b = _key_bindings[k]; // Key pressed. @@ -268,29 +293,12 @@ FGInput::doKey (int k, int modifiers, int x, int y) 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) +FGInput::doMouseClick (int b, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter* ea) { int modifiers = fgGetKeyModifiers(); @@ -304,36 +312,50 @@ FGInput::doMouseClick (int b, int updown, int x, int y) // 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) { - if (puMouse(b, updown, x, y)) + if (0 <= x && 0 <= y && puMouse(b, updown, x, y)) return; - else if ((globals->get_current_panel() != 0) && + 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 (fgHandle3DPanelMouseEvent(b, updown, x, y)) + else if (0 <= x && 0 <= y && fgHandle3DPanelMouseEvent(b, updown, x, y)) return; else { - // pui and the panel didn't want the click event so compute a - // terrain intersection point corresponding to the mouse click - // and be happy. - FGScenery* scenery = globals->get_scenery(); - sgdVec3 start, dir, hit; - if (updown == MOUSE_BUTTON_DOWN && FGRenderer::getPickInfo(start, dir, x, y) - && scenery->get_cart_ground_intersection(start, dir, hit)) { - - Point3D geod = sgCartToGeod(Point3D(hit[0], hit[1], hit[2])); - - SGPropertyNode *c = fgGetNode("/sim/input/click", true); - c->setDoubleValue("longitude-deg", geod.lon() * SGD_RADIANS_TO_DEGREES); - c->setDoubleValue("latitude-deg", geod.lat() * SGD_RADIANS_TO_DEGREES); - c->setDoubleValue("elevation-m", geod.elev()); - c->setDoubleValue("elevation-ft", geod.elev() * SG_METER_TO_FEET); + // 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 pickList; + if (FGRenderer::pick(pickList, ea)) { + std::vector::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 + // 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"); @@ -387,50 +409,25 @@ FGInput::doMouseMotion (int x, int y) // Constrain the mouse if requested if (mode.constrained) { bool need_warp = false; - if (x <= 0) { - x = xsize - 2; - need_warp = true; - } else if (x >= (xsize-1)) { - x = 1; + if (x <= (xsize * .25) || x >= (xsize * .75)) { + x = int(xsize * .5); need_warp = true; } - if (y <= 0) { - y = ysize - 2; - need_warp = true; - } else if (y >= (ysize-1)) { - y = 1; + if (y <= (ysize * .25) || y >= (ysize * .75)) { + y = int(ysize * .5); need_warp = true; } if (need_warp) fgWarpMouse(x, y); } - m.x = x; - m.y = y; -} -void -FGInput::_init_keyboard () -{ - SG_LOG(SG_INPUT, SG_DEBUG, "Initializing key bindings"); - _module[0] = 0; - 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); - } - - vector 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); + if (m.x != x) + fgSetInt("/devices/status/mice/mouse/x", m.x = x); - _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); - } + if (m.y != y) + fgSetInt("/devices/status/mice/mouse/y", m.y = y); } @@ -515,8 +512,8 @@ FGInput::_init_joystick () << "\"\nUsing default: \"" << source << '"'); } else { - throw sg_throwable(string("No joystick configuration file with " - "default entry found!")); + throw sg_exception(string("No joystick configuration file with ") + + name + " entry found!"); } js_node = js_nodes->getChild("js", i, true); @@ -530,6 +527,37 @@ FGInput::_init_joystick () } +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 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 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() { @@ -575,15 +603,15 @@ FGInput::_postinit_joystick() // // Initialize nasal groups. // - string init; - init = "this=\"" + string(js_node->getPath()) + "\""; - sprintf(_module, "__js%d", i); - nasalsys->createModule(_module, _module, init.c_str(), init.size()); + ostringstream str; + str << "__js" << i; + _module = str.str(); + nasalsys->createModule(_module.c_str(), _module.c_str(), "", 0); vector nasal = js_node->getChildren("nasal"); unsigned int j; for (j = 0; j < nasal.size(); j++) { - nasal[j]->setStringValue("module", _module); + nasal[j]->setStringValue("module", _module.c_str()); nasalsys->handleCommand(nasal[j]); } @@ -694,7 +722,7 @@ void FGInput::_init_mouse () { SG_LOG(SG_INPUT, SG_DEBUG, "Initializing mouse bindings"); - _module[0] = 0; + _module = ""; SGPropertyNode * mouse_nodes = fgGetNode("/input/mice"); if (mouse_nodes == 0) { @@ -793,15 +821,11 @@ FGInput::_update_keyboard () void FGInput::_update_joystick (double dt) { - int modifiers = KEYMOD_NONE; // FIXME: any way to get the real ones? - int buttons; - // float js_val, diff; float axis_values[MAX_JOYSTICK_AXES]; + int modifiers = fgGetKeyModifiers(); + int buttons; - int i; - int j; - - for ( i = 0; i < MAX_JOYSTICKS; i++) { + for (int i = 0; i < MAX_JOYSTICKS; i++) { jsJoystick * js = _joystick_bindings[i].js; if (js == 0 || js->notWorking()) @@ -810,21 +834,18 @@ FGInput::_update_joystick (double dt) js->read(&buttons, axis_values); // Fire bindings for the axes. - for ( j = 0; j < _joystick_bindings[i].naxes; j++) { + for (int 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_DEBUG, "Axis " << j << " has moved"); a.last_value = axis_values[j]; -// SG_LOG(SG_INPUT, SG_DEBUG, "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]); + for (unsigned int k = 0; k < a.bindings[KEYMOD_NONE].size(); k++) + a.bindings[KEYMOD_NONE][k]->fire(axis_values[j]); } - + // do we have to emulate axis buttons? a.last_dt += dt; if(a.last_dt >= a.interval_sec) { @@ -833,7 +854,7 @@ FGInput::_update_joystick (double dt) modifiers, axis_values[j] < a.low_threshold, -1, -1); - + if (a.high.bindings[modifiers].size()) _update_button(_joystick_bindings[i].axes[j].high, modifiers, @@ -844,7 +865,7 @@ FGInput::_update_joystick (double dt) } // Fire bindings for the buttons. - for (j = 0; j < _joystick_bindings[i].nbuttons; j++) { + for (int j = 0; j < _joystick_bindings[i].nbuttons; j++) { button &b = _joystick_bindings[i].buttons[j]; b.last_dt += dt; if(b.last_dt >= b.interval_sec) { @@ -880,7 +901,8 @@ FGInput::_update_mouse ( double dt ) if ( fgGetBool( "/sim/mouse/hide-cursor", true ) ) { if ( m.x != m.save_x || m.y != m.save_y ) { m.timeout = fgGetDouble( "/sim/mouse/cursor-timeout-sec", 10.0 ); - fgSetMouseCursor(m.modes[mode].cursor); + if (fgGetMouseCursor() == MOUSE_CURSOR_NONE) + fgSetMouseCursor(m.modes[mode].cursor); } else { m.timeout -= dt; if ( m.timeout <= 0.0 ) { @@ -891,6 +913,16 @@ FGInput::_update_mouse ( double dt ) m.save_x = m.x; m.save_y = m.y; } + + // handle repeatable mouse press events + std::map > >::iterator mi; + for (mi = _activePickCallbacks.begin(); + mi != _activePickCallbacks.end(); ++mi) { + std::list >::iterator li; + for (li = mi->second.begin(); li != mi->second.end(); ++li) { + (*li)->update(dt); + } + } } void @@ -901,8 +933,9 @@ FGInput::_update_button (button &b, int modifiers, bool pressed, // The press event may be repeated. if (!b.last_state || b.is_repeatable) { SG_LOG( SG_INPUT, SG_DEBUG, "Button has been pressed" ); - for (unsigned int k = 0; k < b.bindings[modifiers].size(); k++) + for (unsigned int k = 0; k < b.bindings[modifiers].size(); k++) { b.bindings[modifiers][k]->fire(x, y); + } } } else { // The release event is never repeated. @@ -928,9 +961,9 @@ FGInput::_read_bindings (const SGPropertyNode * node, const char *cmd = bindings[i]->getStringValue("command"); SG_LOG(SG_INPUT, SG_DEBUG, "Reading binding " << cmd); - if (!strcmp(cmd, "nasal") && _module[0]) - bindings[i]->setStringValue("module", _module); - binding_list[modifiers].push_back(new FGBinding(bindings[i])); + if (!strcmp(cmd, "nasal") && !_module.empty()) + bindings[i]->setStringValue("module", _module.c_str()); + binding_list[modifiers].push_back(new SGBinding(bindings[i], globals->get_props())); } // Read nested bindings for modifiers @@ -949,10 +982,22 @@ FGInput::_read_bindings (const SGPropertyNode * node, if (node->getChild("mod-alt") != 0) _read_bindings(node->getChild("mod-alt"), binding_list, modifiers|KEYMOD_ALT); + + if (node->getChild("mod-meta") != 0) + _read_bindings(node->getChild("mod-meta"), binding_list, + modifiers|KEYMOD_META); + + if (node->getChild("mod-super") != 0) + _read_bindings(node->getChild("mod-super"), binding_list, + modifiers|KEYMOD_SUPER); + + if (node->getChild("mod-hyper") != 0) + _read_bindings(node->getChild("mod-hyper"), binding_list, + modifiers|KEYMOD_HYPER); } -const vector & +const FGInput::binding_list_t& FGInput::_find_key_bindings (unsigned int k, int modifiers) { unsigned char kc = (unsigned char)k; @@ -1092,6 +1137,8 @@ FGInput::mouse_mode::~mouse_mode () FGInput::mouse::mouse () : x(-1), y(-1), + save_x(-1), + save_y(-1), nModes(1), current_mode(0), modes(0) @@ -1117,10 +1164,10 @@ void keyHandler(int key, int keymod, int mousex, int mousey) default_input->doKey(key, keymod, mousex, mousey); } -void mouseClickHandler(int button, int updown, int x, int y) +void mouseClickHandler(int button, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter* ea) { if(default_input) - default_input->doMouseClick(button, updown, x, y); + default_input->doMouseClick(button, updown, x, y, mainWindow, ea); } void mouseMotionHandler(int x, int y)