]> git.mxchange.org Git - flightgear.git/commitdiff
Canvas: Keyboard events and input focus.
authorThomas Geymayer <tomgey@gmail.com>
Tue, 29 Jul 2014 22:00:03 +0000 (00:00 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Tue, 29 Jul 2014 22:00:03 +0000 (00:00 +0200)
Also allow events on desktop group if no window is receiving
events. Currently it is not possible to prevent events handled
by the desktop group to further propagate (eg. to normal
control input).

src/Canvas/gui_mgr.cxx
src/Canvas/gui_mgr.hxx
src/Scripting/NasalCanvas.cxx

index 1750f5a5ba518ffdf90d4c3a561a60c9ce4299dc..a4a47ffa7396a07342deb42b0e591cc5f3640aa8 100644 (file)
@@ -27,6 +27,7 @@
 #include <simgear/canvas/Canvas.hxx>
 #include <simgear/canvas/CanvasPlacement.hxx>
 #include <simgear/canvas/CanvasWindow.hxx>
+#include <simgear/canvas/events/KeyboardEvent.hxx>
 #include <simgear/scene/util/OsgMath.hxx>
 
 #include <osg/BlendFunc>
@@ -100,6 +101,8 @@ class DesktopGroup:
 {
   public:
     DesktopGroup();
+
+    void setFocusWindow(const sc::WindowPtr& window);
     bool handleEvent(const osgGA::GUIEventAdapter& ea);
 
   protected:
@@ -114,7 +117,9 @@ class DesktopGroup:
 
     sc::WindowWeakPtr _last_push,
                       _last_mouse_over,
-                      _resize_window;
+                      _resize_window,
+                      _focus_window;
+
     uint8_t _resize;
     int     _last_cursor;
 
@@ -123,7 +128,10 @@ class DesktopGroup:
           _last_y;
     double _last_scroll_time;
 
+    uint32_t _last_key_down_no_mod; // Key repeat for non modifier keys
+
     bool handleMouse(const osgGA::GUIEventAdapter& ea);
+    bool handleKeyboard(const osgGA::GUIEventAdapter& ea);
     void handleResize(int x, int y, int width, int height);
     void handleMouseMode(SGPropertyNode* node);
 
@@ -173,7 +181,8 @@ DesktopGroup::DesktopGroup():
   _last_cursor(MOUSE_CURSOR_NONE),
   _last_x(-1),
   _last_y(-1),
-  _last_scroll_time(0)
+  _last_scroll_time(0),
+  _last_key_down_no_mod(-1)
 {
   osg::Camera* camera =
     flightgear::getGUICamera( flightgear::CameraGroup::getDefault() );
@@ -211,6 +220,9 @@ bool DesktopGroup::handleEvent(const osgGA::GUIEventAdapter& ea)
     case osgGA::GUIEventAdapter::MOVE:
     case osgGA::GUIEventAdapter::SCROLL:
       return handleMouse(ea);
+    case osgGA::GUIEventAdapter::KEYDOWN:
+    case osgGA::GUIEventAdapter::KEYUP:
+      return handleKeyboard(ea);
     case osgGA::GUIEventAdapter::RESIZE:
       handleResize( ea.getWindowX(),
                     ea.getWindowY(),
@@ -222,6 +234,12 @@ bool DesktopGroup::handleEvent(const osgGA::GUIEventAdapter& ea)
   }
 }
 
+//------------------------------------------------------------------------------
+void DesktopGroup::setFocusWindow(const sc::WindowPtr& window)
+{
+  _focus_window = window;
+}
+
 /*
 RESIZE AREAS
 ============
@@ -247,7 +265,6 @@ bool DesktopGroup::handleMouse(const osgGA::GUIEventAdapter& ea)
   if( !_transform->getNumChildren() || !_handle_events )
     return false;
 
-  namespace sc = simgear::canvas;
   sc::MouseEventPtr event(new sc::MouseEvent(ea));
 
   event->screen_pos.x() = 0.5 * (ea.getXnormalized() + 1) * _width + 0.5;
@@ -450,7 +467,54 @@ bool DesktopGroup::handleMouse(const osgGA::GUIEventAdapter& ea)
     return target_window->handleEvent(event);
   }
   else
+  {
+    // TODO somehow return if event has been consumed
+    sc::Element::handleEvent(event);
     return false;
+  }
+}
+
+//------------------------------------------------------------------------------
+bool DesktopGroup::handleKeyboard(const osgGA::GUIEventAdapter& ea)
+{
+  if( !_transform->getNumChildren() || !_handle_events )
+    return false;
+
+  sc::WindowPtr active_window = _focus_window.lock();
+  if( !active_window )
+  {
+    int type = (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN)
+             ? sc::Event::KEY_DOWN
+             : sc::Event::KEY_UP;
+
+    if( !numEventHandler(type) )
+      // TODO handle global shortcuts/grabs/etc.
+      return false;
+  }
+
+  sc::KeyboardEventPtr event(new sc::KeyboardEvent(ea));
+
+  // Detect key repeat (of non modifier keys)
+  if( !event->isModifier() )
+  {
+    if( event->type == sc::Event::KEY_DOWN )
+    {
+      if( event->keyCode() == _last_key_down_no_mod )
+        event->setRepeat(true);
+      _last_key_down_no_mod = event->keyCode();
+    }
+    else
+    {
+      if( event->keyCode() == _last_key_down_no_mod )
+      _last_key_down_no_mod = -1;
+    }
+  }
+
+  if( active_window )
+    return active_window->handleEvent(event);
+
+  sc::Element::handleEvent(event);
+  return false;
 }
 
 //------------------------------------------------------------------------------
@@ -571,6 +635,12 @@ sc::GroupPtr GUIMgr::getDesktop()
   return _desktop;
 }
 
+//------------------------------------------------------------------------------
+void GUIMgr::setInputFocus(const simgear::canvas::WindowPtr& window)
+{
+  static_cast<DesktopGroup*>(_desktop.get())->setFocusWindow(window);
+}
+
 //------------------------------------------------------------------------------
 sc::Placements
 GUIMgr::addWindowPlacement( SGPropertyNode* placement,
index c6764692c635629067278c8486bfa8e34648c863..c2cd341cd0cb67408987992b94cf09971a2b509e 100644 (file)
@@ -52,6 +52,11 @@ class GUIMgr:
      */
     simgear::canvas::GroupPtr getDesktop();
 
+    /**
+     * Set the input (keyboard) focus to the given window.
+     */
+    void setInputFocus(const simgear::canvas::WindowPtr& window);
+
   protected:
 
     simgear::canvas::GroupPtr           _desktop;
index deee79324ae0f87bb4adc1d63e240d8e4a3cca64..637734c1c993b1d575634f147357d8180ff81e8a 100644 (file)
@@ -39,6 +39,7 @@
 #include <simgear/canvas/layout/BoxLayout.hxx>
 #include <simgear/canvas/layout/NasalWidget.hxx>
 #include <simgear/canvas/events/CustomEvent.hxx>
+#include <simgear/canvas/events/KeyboardEvent.hxx>
 #include <simgear/canvas/events/MouseEvent.hxx>
 
 #include <simgear/nasal/cppbind/from_nasal.hxx>
@@ -58,6 +59,8 @@ naRef elementGetNode(Element& element, naContext c)
 
 typedef nasal::Ghost<sc::EventPtr> NasalEvent;
 typedef nasal::Ghost<sc::CustomEventPtr> NasalCustomEvent;
+typedef nasal::Ghost<sc::DeviceEventPtr> NasalDeviceEvent;
+typedef nasal::Ghost<sc::KeyboardEventPtr> NasalKeyboardEvent;
 typedef nasal::Ghost<sc::MouseEventPtr> NasalMouseEvent;
 
 struct CustomEventDetailWrapper;
@@ -177,6 +180,12 @@ naRef f_getDesktop(naContext c, naRef me, int argc, naRef* args)
   return nasal::to_nasal(c, requireGUIMgr(c).getDesktop());
 }
 
+naRef f_setInputFocus(const nasal::CallContext& ctx)
+{
+  requireGUIMgr(ctx.c).setInputFocus(ctx.requireArg<sc::WindowPtr>(0));
+  return naNil();
+}
+
 static naRef f_groupCreateChild(sc::Group& group, const nasal::CallContext& ctx)
 {
   return ctx.to_nasal( group.createChild( ctx.requireArg<std::string>(0),
@@ -272,12 +281,6 @@ static naRef f_propElementData( simgear::PropertyBasedElement& el,
   return naNil();
 }
 
-template<int Mask>
-naRef f_eventGetModifier(sc::MouseEvent& event, naContext)
-{
-  return naNum((event.getModifiers() & Mask) != 0);
-}
-
 static naRef f_createCustomEvent(const nasal::CallContext& ctx)
 {
   std::string const& type = ctx.requireArg<std::string>(0);
@@ -408,8 +411,24 @@ naRef initNasalCanvas(naRef globals, naContext c)
   canvas_module.createHash("CustomEvent")
                .set("new", &f_createCustomEvent);
 
-  NasalMouseEvent::init("canvas.MouseEvent")
+  NasalDeviceEvent::init("canvas.DeviceEvent")
     .bases<NasalEvent>()
+    .member("modifiers", &sc::DeviceEvent::getModifiers)
+    .member("ctrlKey", &sc::DeviceEvent::ctrlKey)
+    .member("shiftKey", &sc::DeviceEvent::shiftKey)
+    .member("altKey",  &sc::DeviceEvent::altKey)
+    .member("metaKey",  &sc::DeviceEvent::metaKey);
+
+  NasalKeyboardEvent::init("canvas.KeyboardEvent")
+    .bases<NasalDeviceEvent>()
+    .member("key", &sc::KeyboardEvent::key)
+    .member("location", &sc::KeyboardEvent::location)
+    .member("repeat", &sc::KeyboardEvent::repeat)
+    .member("charCode", &sc::KeyboardEvent::charCode)
+    .member("keyCode", &sc::KeyboardEvent::keyCode);
+
+  NasalMouseEvent::init("canvas.MouseEvent")
+    .bases<NasalDeviceEvent>()
     .member("screenX", &sc::MouseEvent::getScreenX)
     .member("screenY", &sc::MouseEvent::getScreenY)
     .member("clientX", &sc::MouseEvent::getClientX)
@@ -420,11 +439,6 @@ naRef initNasalCanvas(naRef globals, naContext c)
     .member("deltaY", &sc::MouseEvent::getDeltaY)
     .member("button", &sc::MouseEvent::getButton)
     .member("buttons", &sc::MouseEvent::getButtonMask)
-    .member("modifiers", &sc::MouseEvent::getModifiers)
-    .member("ctrlKey", &f_eventGetModifier<GUIEventAdapter::MODKEY_CTRL>)
-    .member("shiftKey", &f_eventGetModifier<GUIEventAdapter::MODKEY_SHIFT>)
-    .member("altKey", &f_eventGetModifier<GUIEventAdapter::MODKEY_ALT>)
-    .member("metaKey", &f_eventGetModifier<GUIEventAdapter::MODKEY_META>)
     .member("click_count", &sc::MouseEvent::getCurrentClickCount);
 
   //----------------------------------------------------------------------------
@@ -534,6 +548,7 @@ naRef initNasalCanvas(naRef globals, naContext c)
 
   canvas_module.set("_newWindowGhost", f_createWindow);
   canvas_module.set("_getDesktopGhost", f_getDesktop);
+  canvas_module.set("setInputFocus", f_setInputFocus);
 
   return naNil();
 }