]> git.mxchange.org Git - simgear.git/commitdiff
Canvas: basic Keyboard event support (with input focus).
authorThomas Geymayer <tomgey@gmail.com>
Tue, 29 Jul 2014 20:20:24 +0000 (22:20 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Tue, 29 Jul 2014 20:22:20 +0000 (22:22 +0200)
15 files changed:
simgear/canvas/Canvas.cxx
simgear/canvas/Canvas.hxx
simgear/canvas/CanvasEventTypes.hxx
simgear/canvas/CanvasWindow.cxx
simgear/canvas/canvas_fwd.hxx
simgear/canvas/elements/CanvasElement.cxx
simgear/canvas/elements/CanvasElement.hxx
simgear/canvas/elements/CanvasImage.cxx
simgear/canvas/events/CMakeLists.txt
simgear/canvas/events/DeviceEvent.cxx [new file with mode: 0644]
simgear/canvas/events/DeviceEvent.hxx [new file with mode: 0644]
simgear/canvas/events/KeyboardEvent.cxx [new file with mode: 0644]
simgear/canvas/events/KeyboardEvent.hxx [new file with mode: 0644]
simgear/canvas/events/MouseEvent.cxx
simgear/canvas/events/MouseEvent.hxx

index 5ca1eb95e605929929361a378a0274d87c7b2d83..0a6b2b4834f4c52551fd63485cdb1d8390c390c4 100644 (file)
@@ -20,6 +20,7 @@
 #include "CanvasEventManager.hxx"
 #include "CanvasEventVisitor.hxx"
 #include "CanvasPlacement.hxx"
+#include <simgear/canvas/events/KeyboardEvent.hxx>
 #include <simgear/canvas/events/MouseEvent.hxx>
 #include <simgear/scene/util/parse_color.hxx>
 #include <simgear/scene/util/RenderConstants.hxx>
@@ -198,6 +199,19 @@ namespace canvas
     _layout->setCanvas(this);
   }
 
+  //----------------------------------------------------------------------------
+  void Canvas::setFocusElement(const ElementPtr& el)
+  {
+    if( el && el->getCanvas().lock() != this )
+    {
+      SG_LOG(SG_GUI, SG_WARN, "setFocusElement: element not from this canvas");
+      return;
+    }
+
+    // TODO focus out/in events
+    _focus_element = el;
+  }
+
   //----------------------------------------------------------------------------
   void Canvas::enableRendering(bool force)
   {
@@ -448,6 +462,18 @@ namespace canvas
     return _event_manager->handleEvent(event, visitor.getPropagationPath());
   }
 
+  //----------------------------------------------------------------------------
+  bool Canvas::handleKeyboardEvent(const KeyboardEventPtr& event)
+  {
+    ElementPtr target = _focus_element.lock();
+    if( !target )
+      target = _root_group;
+    if( !target )
+      return false;
+
+    return target->dispatchEvent(event);
+  }
+
   //----------------------------------------------------------------------------
   bool Canvas::propagateEvent( EventPtr const& event,
                                EventPropagationPath const& path )
index cf9ae2a527401d91643f12b7e32a20d864e92766..8501b50418ae7b1ac9f82592ca4206c01dbb1a44 100644 (file)
@@ -132,6 +132,15 @@ namespace canvas
        */
       void setLayout(const LayoutRef& layout);
 
+      /**
+       * Set the focus to the given element.
+       *
+       * The focus element will receive all keyboard events propagated to this
+       * canvas. If there is no valid focus element the root group will receive
+       * the events instead.
+       */
+      void setFocusElement(const ElementPtr& el);
+
       /**
        * Enable rendering for the next frame
        *
@@ -159,6 +168,8 @@ namespace canvas
       SGRect<int> getViewport() const;
 
       bool handleMouseEvent(const MouseEventPtr& event);
+      bool handleKeyboardEvent(const KeyboardEventPtr& event);
+
       bool propagateEvent( EventPtr const& event,
                            EventPropagationPath const& path );
 
@@ -210,6 +221,8 @@ namespace canvas
       GroupPtr  _root_group;
       LayoutRef _layout;
 
+      ElementWeakPtr _focus_element;
+
       CullCallbackPtr _cull_callback;
       bool _render_always; //<! Used to disable automatic lazy rendering (culling)
 
index 78c772a7d2ec68320698a9298cdfc0dc8584da69..5f36ba1c94b70ba3c60a0fcd9dc9a4ce0e326c50 100644 (file)
@@ -31,3 +31,5 @@ ENUM_MAPPING(MOUSE_OVER,  "mouseover")
 ENUM_MAPPING(MOUSE_OUT,   "mouseout")
 ENUM_MAPPING(MOUSE_ENTER, "mouseenter")
 ENUM_MAPPING(MOUSE_LEAVE, "mouseleave")
+ENUM_MAPPING(KEY_DOWN, "keydown")
+ENUM_MAPPING(KEY_UP, "keyup")
index ac3e16a2bdfd975b5304cff8b8905f7cfec668ed..29ef354aaae482992424289c4a26282fea84599e 100644 (file)
@@ -280,6 +280,9 @@ namespace canvas
                                          ->createChild<Image>("content");
       _image_content->setSrcCanvas(content);
 
+      // Forward keyboard events to content
+      _image_content->setFocus();
+
       // Draw content on top of decoration
       _image_content->set<int>("z-index", 1);
     }
index b14d2886cd01845fd538ee4f4c6925e5b82390e3..3b1b464690dcd8c1783d71de27c4853f2394b5fe 100644 (file)
@@ -53,6 +53,8 @@ namespace canvas
 
   SG_FWD_DECL(Event)
   SG_FWD_DECL(CustomEvent)
+  SG_FWD_DECL(DeviceEvent)
+  SG_FWD_DECL(KeyboardEvent)
   SG_FWD_DECL(MouseEvent)
 
 #undef SG_FWD_DECL
index 5621973491aa66630b2bb0545cf4307a4310b235..478cfb8b7f5ebcfbb77b671f71ef2d37856c1188 100644 (file)
@@ -303,6 +303,14 @@ namespace canvas
     _listener.clear();
   }
 
+  //----------------------------------------------------------------------------
+  void Element::setFocus()
+  {
+    CanvasPtr canvas = _canvas.lock();
+    if( canvas )
+      canvas->setFocusElement(this);
+  }
+
   //----------------------------------------------------------------------------
   bool Element::accept(EventVisitor& visitor)
   {
@@ -326,6 +334,15 @@ namespace canvas
     return true;
   }
 
+  //----------------------------------------------------------------------------
+  size_t Element::numEventHandler(int type) const
+  {
+    ListenerMap::const_iterator listeners = _listener.find(type);
+    if( listeners != _listener.end() )
+      return listeners->second.size();
+    return 0;
+  }
+
   //----------------------------------------------------------------------------
   bool Element::handleEvent(const EventPtr& event)
   {
index 70f676f001d14fdbd915a6c221f0325d2633f244..242c22021b2b2b8adf129abef1311173a8c53272 100644 (file)
@@ -108,10 +108,16 @@ namespace canvas
       bool addEventListener(const std::string& type, const EventListener& cb);
       virtual void clearEventListener();
 
+      /// Get (keyboard) input focus.
+      void setFocus();
+
       virtual bool accept(EventVisitor& visitor);
       virtual bool ascend(EventVisitor& visitor);
       virtual bool traverse(EventVisitor& visitor);
 
+      /// Get the number of event handlers for the given type
+      size_t numEventHandler(int type) const;
+
       virtual bool handleEvent(const EventPtr& event);
       bool dispatchEvent(const EventPtr& event);
 
index c7ca43d0f4090bbc37bcc95e40f2cbda3cb4c608..4f4ffc7b14eccf7860985f729aac8ad52c05ff91 100644 (file)
@@ -21,6 +21,7 @@
 #include <simgear/canvas/Canvas.hxx>
 #include <simgear/canvas/CanvasMgr.hxx>
 #include <simgear/canvas/CanvasSystemAdapter.hxx>
+#include <simgear/canvas/events/KeyboardEvent.hxx>
 #include <simgear/canvas/events/MouseEvent.hxx>
 #include <simgear/scene/util/OsgMath.hxx>
 #include <simgear/scene/util/parse_color.hxx>
@@ -525,8 +526,7 @@ namespace canvas
     if( !src_canvas )
       return handled;
 
-    MouseEventPtr mouse_event = dynamic_cast<MouseEvent*>(event.get());
-    if( mouse_event )
+    if( MouseEventPtr mouse_event = dynamic_cast<MouseEvent*>(event.get()) )
     {
       mouse_event.reset( new MouseEvent(*mouse_event) );
 
@@ -551,6 +551,11 @@ namespace canvas
 
       handled |= src_canvas->handleMouseEvent(mouse_event);
     }
+    else if( KeyboardEventPtr keyboard_event =
+               dynamic_cast<KeyboardEvent*>(event.get()) )
+    {
+      handled |= src_canvas->handleKeyboardEvent(keyboard_event);
+    }
 
     return handled;
   }
index cfac3f69d90bc76494bb5678f3d05843a319b129..8168ea5c97bbf1602258caa8907db4997d663ad5 100644 (file)
@@ -2,11 +2,15 @@ include (SimGearComponent)
 
 set(HEADERS
   CustomEvent.hxx
+  DeviceEvent.hxx
+  KeyboardEvent.hxx
   MouseEvent.hxx
 )
 
 set(SOURCES
   CustomEvent.cxx
+  DeviceEvent.cxx
+  KeyboardEvent.cxx
   MouseEvent.cxx
 )
 
diff --git a/simgear/canvas/events/DeviceEvent.cxx b/simgear/canvas/events/DeviceEvent.cxx
new file mode 100644 (file)
index 0000000..1475172
--- /dev/null
@@ -0,0 +1,66 @@
+// Input device event
+//
+// Copyright (C) 2014  Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
+
+#include "DeviceEvent.hxx"
+#include <osgGA/GUIEventAdapter>
+
+namespace simgear
+{
+namespace canvas
+{
+
+  //----------------------------------------------------------------------------
+  DeviceEvent::DeviceEvent():
+    modifiers(0)
+  {
+
+  }
+
+  //----------------------------------------------------------------------------
+  DeviceEvent::DeviceEvent(const osgGA::GUIEventAdapter& ea):
+    modifiers(ea.getModKeyMask())
+  {
+    time = ea.getTime();
+  }
+
+  //----------------------------------------------------------------------------
+  bool DeviceEvent::ctrlKey() const
+  {
+    return (modifiers & osgGA::GUIEventAdapter::MODKEY_CTRL) != 0;
+  }
+
+  //----------------------------------------------------------------------------
+  bool DeviceEvent::shiftKey() const
+  {
+    return (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT) != 0;
+  }
+
+  //----------------------------------------------------------------------------
+  bool DeviceEvent::altKey() const
+  {
+    return (modifiers & osgGA::GUIEventAdapter::MODKEY_ALT) != 0;
+  }
+
+  //----------------------------------------------------------------------------
+  bool DeviceEvent::metaKey() const
+  {
+    return (modifiers & osgGA::GUIEventAdapter::MODKEY_META) != 0;
+  }
+
+} // namespace canvas
+} // namespace simgear
diff --git a/simgear/canvas/events/DeviceEvent.hxx b/simgear/canvas/events/DeviceEvent.hxx
new file mode 100644 (file)
index 0000000..8fc366a
--- /dev/null
@@ -0,0 +1,55 @@
+///@file Input device event (keyboard/mouse)
+//
+// Copyright (C) 2014  Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
+
+#ifndef CANVAS_DEVICE_EVENT_HXX_
+#define CANVAS_DEVICE_EVENT_HXX_
+
+#include <simgear/canvas/CanvasEvent.hxx>
+
+namespace osgGA { class GUIEventAdapter; }
+
+namespace simgear
+{
+namespace canvas
+{
+
+  /**
+   * Common interface for input device events.
+   */
+  class DeviceEvent:
+    public Event
+  {
+    public:
+      DeviceEvent();
+      DeviceEvent(const osgGA::GUIEventAdapter& ea);
+
+      int getModifiers() const { return modifiers; }
+
+      bool ctrlKey() const;
+      bool shiftKey() const;
+      bool altKey() const;
+      bool metaKey() const;
+
+    protected:
+      int modifiers;  //!< Keyboard modifier state
+  };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_DEVICE_EVENT_HXX_ */
diff --git a/simgear/canvas/events/KeyboardEvent.cxx b/simgear/canvas/events/KeyboardEvent.cxx
new file mode 100644 (file)
index 0000000..978894a
--- /dev/null
@@ -0,0 +1,282 @@
+// Keyboard event
+//
+// Copyright (C) 2014  Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
+
+#include "KeyboardEvent.hxx"
+
+#include <osgGA/GUIEventAdapter>
+
+#include <boost/container/flat_map.hpp>
+#include <boost/container/flat_set.hpp>
+#include <boost/locale/encoding_utf.hpp>
+
+namespace simgear
+{
+namespace canvas
+{
+  typedef osgGA::GUIEventAdapter EA;
+
+  // TODO check Win/Mac keycode for altgr/ISO Level3 Shift
+  const uint32_t KEY_AltGraph = 0xfe03;
+
+  //----------------------------------------------------------------------------
+  KeyboardEvent::KeyboardEvent():
+    _key(0),
+    _unmodified_key(0),
+    _repeat(false),
+    _location(DOM_KEY_LOCATION_STANDARD)
+  {
+
+  }
+
+  //----------------------------------------------------------------------------
+  KeyboardEvent::KeyboardEvent(const osgGA::GUIEventAdapter& ea):
+    DeviceEvent(ea),
+    _key(ea.getKey()),
+    _unmodified_key(ea.getUnmodifiedKey()),
+    _repeat(false),
+    _location(DOM_KEY_LOCATION_STANDARD)
+  {
+    if( ea.getEventType() == EA::KEYDOWN )
+      type = KEY_DOWN;
+    else if( ea.getEventType() == EA::KEYUP )
+      type = KEY_UP;
+//    else
+//      // TODO what to do with wrong event type?
+  }
+
+  //----------------------------------------------------------------------------
+  void KeyboardEvent::setKey(uint32_t key)
+  {
+    _name.clear();
+    _key = key;
+  }
+
+  //----------------------------------------------------------------------------
+  void KeyboardEvent::setUnmodifiedKey(uint32_t key)
+  {
+    _name.clear();
+    _unmodified_key = key;
+  }
+
+  //----------------------------------------------------------------------------
+  void KeyboardEvent::setRepeat(bool repeat)
+  {
+    _repeat = repeat;
+  }
+
+  //----------------------------------------------------------------------------
+  std::string KeyboardEvent::key() const
+  {
+    if( !_name.empty() )
+      return _name;
+
+    // We need to make sure only valid const char* pointers are passed. The best
+    // way is just to use string constants.
+    // Use an empty string ("") to just use the value reported by the operating
+    // system.
+    typedef std::pair<const char*, uint8_t> InternalKeyInfo;
+    typedef boost::container::flat_map<int, InternalKeyInfo> InternalKeyMap;
+    typedef boost::container::flat_set<int> KeyList;
+
+    static InternalKeyMap key_map;
+    static KeyList num_pad_keys;
+
+    if( key_map.empty() )
+    {
+      const uint8_t S = DOM_KEY_LOCATION_STANDARD,
+                    L = DOM_KEY_LOCATION_LEFT,
+                    R = DOM_KEY_LOCATION_RIGHT,
+                    N = DOM_KEY_LOCATION_NUMPAD;
+
+      key_map[ EA::KEY_BackSpace    ] = std::make_pair("Backspace", S);
+      key_map[ EA::KEY_Tab          ] = std::make_pair("Tab", S);
+      key_map[ EA::KEY_Linefeed     ] = std::make_pair("Linefeed", S);
+      key_map[ EA::KEY_Clear        ] = std::make_pair("Clear", S);
+      key_map[ EA::KEY_Return       ] = std::make_pair("Enter", S);
+      key_map[ EA::KEY_Pause        ] = std::make_pair("Pause", S);
+      key_map[ EA::KEY_Scroll_Lock  ] = std::make_pair("ScrollLock", S);
+      key_map[ EA::KEY_Sys_Req      ] = std::make_pair("SystemRequest", S);
+      key_map[ EA::KEY_Escape       ] = std::make_pair("Escape", S);
+      key_map[ EA::KEY_Delete       ] = std::make_pair("Delete", S);
+
+      key_map[ EA::KEY_Home         ] = std::make_pair("Home", S);
+      key_map[ EA::KEY_Left         ] = std::make_pair("Left", S);
+      key_map[ EA::KEY_Up           ] = std::make_pair("Up", S);
+      key_map[ EA::KEY_Right        ] = std::make_pair("Right", S);
+      key_map[ EA::KEY_Down         ] = std::make_pair("Down", S);
+      key_map[ EA::KEY_Page_Up      ] = std::make_pair("PageUp", S);
+      key_map[ EA::KEY_Page_Down    ] = std::make_pair("PageDown", S);
+      key_map[ EA::KEY_End          ] = std::make_pair("End", S);
+      key_map[ EA::KEY_Begin        ] = std::make_pair("Begin", S);
+
+      key_map[ EA::KEY_Select       ] = std::make_pair("Select", S);
+      key_map[ EA::KEY_Print        ] = std::make_pair("PrintScreen", S);
+      key_map[ EA::KEY_Execute      ] = std::make_pair("Execute", S);
+      key_map[ EA::KEY_Insert       ] = std::make_pair("Insert", S);
+      key_map[ EA::KEY_Undo         ] = std::make_pair("Undo", S);
+      key_map[ EA::KEY_Redo         ] = std::make_pair("Redo", S);
+      key_map[ EA::KEY_Menu         ] = std::make_pair("ContextMenu", S);
+      key_map[ EA::KEY_Find         ] = std::make_pair("Find", S);
+      key_map[ EA::KEY_Cancel       ] = std::make_pair("Cancel", S);
+      key_map[ EA::KEY_Help         ] = std::make_pair("Help", S);
+      key_map[ EA::KEY_Break        ] = std::make_pair("Break", S);
+      key_map[ EA::KEY_Mode_switch  ] = std::make_pair("ModeChange", S);
+      key_map[ EA::KEY_Num_Lock     ] = std::make_pair("NumLock", S);
+
+      key_map[ EA::KEY_KP_Space     ] = std::make_pair(" ", N);
+      key_map[ EA::KEY_KP_Tab       ] = std::make_pair("Tab", N);
+      key_map[ EA::KEY_KP_Enter     ] = std::make_pair("Enter", N);
+      key_map[ EA::KEY_KP_F1        ] = std::make_pair("F1", N);
+      key_map[ EA::KEY_KP_F2        ] = std::make_pair("F2", N);
+      key_map[ EA::KEY_KP_F3        ] = std::make_pair("F3", N);
+      key_map[ EA::KEY_KP_F4        ] = std::make_pair("F4", N);
+      key_map[ EA::KEY_KP_Home      ] = std::make_pair("Home", N);
+      key_map[ EA::KEY_KP_Left      ] = std::make_pair("Left", N);
+      key_map[ EA::KEY_KP_Up        ] = std::make_pair("Up", N);
+      key_map[ EA::KEY_KP_Right     ] = std::make_pair("Right", N);
+      key_map[ EA::KEY_KP_Down      ] = std::make_pair("Down", N);
+      key_map[ EA::KEY_KP_Page_Up   ] = std::make_pair("PageUp", N);
+      key_map[ EA::KEY_KP_Page_Down ] = std::make_pair("PageDown", N);
+      key_map[ EA::KEY_KP_End       ] = std::make_pair("End", N);
+      key_map[ EA::KEY_KP_Begin     ] = std::make_pair("Begin", N);
+      key_map[ EA::KEY_KP_Insert    ] = std::make_pair("Insert", N);
+      key_map[ EA::KEY_KP_Delete    ] = std::make_pair("Delete", N);
+      key_map[ EA::KEY_KP_Equal     ] = std::make_pair("=", N);
+      key_map[ EA::KEY_KP_Multiply  ] = std::make_pair("*", N);
+      key_map[ EA::KEY_KP_Add       ] = std::make_pair("+", N);
+      key_map[ EA::KEY_KP_Separator ] = std::make_pair("", N);
+      key_map[ EA::KEY_KP_Subtract  ] = std::make_pair("-", N);
+      key_map[ EA::KEY_KP_Decimal   ] = std::make_pair("", N);
+      key_map[ EA::KEY_KP_Divide    ] = std::make_pair("/", N);
+
+      key_map[ EA::KEY_KP_0 ] = std::make_pair("0", N);
+      key_map[ EA::KEY_KP_1 ] = std::make_pair("1", N);
+      key_map[ EA::KEY_KP_2 ] = std::make_pair("2", N);
+      key_map[ EA::KEY_KP_3 ] = std::make_pair("3", N);
+      key_map[ EA::KEY_KP_4 ] = std::make_pair("4", N);
+      key_map[ EA::KEY_KP_5 ] = std::make_pair("5", N);
+      key_map[ EA::KEY_KP_6 ] = std::make_pair("6", N);
+      key_map[ EA::KEY_KP_7 ] = std::make_pair("7", N);
+      key_map[ EA::KEY_KP_8 ] = std::make_pair("8", N);
+      key_map[ EA::KEY_KP_9 ] = std::make_pair("9", N);
+
+      key_map[ EA::KEY_F1   ] = std::make_pair("F1", S);
+      key_map[ EA::KEY_F2   ] = std::make_pair("F2", S);
+      key_map[ EA::KEY_F3   ] = std::make_pair("F3", S);
+      key_map[ EA::KEY_F4   ] = std::make_pair("F4", S);
+      key_map[ EA::KEY_F5   ] = std::make_pair("F5", S);
+      key_map[ EA::KEY_F6   ] = std::make_pair("F6", S);
+      key_map[ EA::KEY_F7   ] = std::make_pair("F7", S);
+      key_map[ EA::KEY_F8   ] = std::make_pair("F8", S);
+      key_map[ EA::KEY_F9   ] = std::make_pair("F9", S);
+      key_map[ EA::KEY_F10  ] = std::make_pair("F10", S);
+      key_map[ EA::KEY_F11  ] = std::make_pair("F11", S);
+      key_map[ EA::KEY_F12  ] = std::make_pair("F12", S);
+      key_map[ EA::KEY_F13  ] = std::make_pair("F13", S);
+      key_map[ EA::KEY_F14  ] = std::make_pair("F14", S);
+      key_map[ EA::KEY_F15  ] = std::make_pair("F15", S);
+      key_map[ EA::KEY_F16  ] = std::make_pair("F16", S);
+      key_map[ EA::KEY_F17  ] = std::make_pair("F17", S);
+      key_map[ EA::KEY_F18  ] = std::make_pair("F18", S);
+      key_map[ EA::KEY_F19  ] = std::make_pair("F19", S);
+      key_map[ EA::KEY_F20  ] = std::make_pair("F20", S);
+      key_map[ EA::KEY_F21  ] = std::make_pair("F21", S);
+      key_map[ EA::KEY_F22  ] = std::make_pair("F22", S);
+      key_map[ EA::KEY_F23  ] = std::make_pair("F23", S);
+      key_map[ EA::KEY_F24  ] = std::make_pair("F24", S);
+      key_map[ EA::KEY_F25  ] = std::make_pair("F25", S);
+      key_map[ EA::KEY_F26  ] = std::make_pair("F26", S);
+      key_map[ EA::KEY_F27  ] = std::make_pair("F27", S);
+      key_map[ EA::KEY_F28  ] = std::make_pair("F28", S);
+      key_map[ EA::KEY_F29  ] = std::make_pair("F29", S);
+      key_map[ EA::KEY_F30  ] = std::make_pair("F30", S);
+      key_map[ EA::KEY_F31  ] = std::make_pair("F31", S);
+      key_map[ EA::KEY_F32  ] = std::make_pair("F32", S);
+      key_map[ EA::KEY_F33  ] = std::make_pair("F33", S);
+      key_map[ EA::KEY_F34  ] = std::make_pair("F34", S);
+      key_map[ EA::KEY_F35  ] = std::make_pair("F35", S);
+
+      key_map[ KEY_AltGraph       ] = std::make_pair("AltGraph", S);
+      key_map[ EA::KEY_Shift_L    ] = std::make_pair("Shift", L);
+      key_map[ EA::KEY_Shift_R    ] = std::make_pair("Shift", R);
+      key_map[ EA::KEY_Control_L  ] = std::make_pair("Control", L);
+      key_map[ EA::KEY_Control_R  ] = std::make_pair("Control", R);
+      key_map[ EA::KEY_Caps_Lock  ] = std::make_pair("CapsLock", S);
+      key_map[ EA::KEY_Shift_Lock ] = std::make_pair("ShiftLock", S);
+      key_map[ EA::KEY_Meta_L     ] = std::make_pair("Meta", L);
+      key_map[ EA::KEY_Meta_R     ] = std::make_pair("Meta", R);
+      key_map[ EA::KEY_Alt_L      ] = std::make_pair("Alt", L);
+      key_map[ EA::KEY_Alt_R      ] = std::make_pair("Alt", R);
+      key_map[ EA::KEY_Super_L    ] = std::make_pair("Super", L);
+      key_map[ EA::KEY_Super_R    ] = std::make_pair("Super", R);
+      key_map[ EA::KEY_Hyper_L    ] = std::make_pair("Hyper", L);
+      key_map[ EA::KEY_Hyper_R    ] = std::make_pair("Hyper", R);
+
+      num_pad_keys.insert(EA::KEY_KP_Home     );
+      num_pad_keys.insert(EA::KEY_KP_Left     );
+      num_pad_keys.insert(EA::KEY_KP_Up       );
+      num_pad_keys.insert(EA::KEY_KP_Right    );
+      num_pad_keys.insert(EA::KEY_KP_Down     );
+      num_pad_keys.insert(EA::KEY_KP_Page_Up  );
+      num_pad_keys.insert(EA::KEY_KP_Page_Down);
+      num_pad_keys.insert(EA::KEY_KP_End      );
+      num_pad_keys.insert(EA::KEY_KP_Begin    );
+      num_pad_keys.insert(EA::KEY_KP_Insert   );
+      num_pad_keys.insert(EA::KEY_KP_Delete   );
+    }
+
+    _location = DOM_KEY_LOCATION_STANDARD;
+
+    InternalKeyMap::const_iterator it = key_map.find(_key);
+    if( it != key_map.end())
+    {
+      _name = it->second.first;
+      _location = it->second.second;
+    }
+
+    // Empty or no mapping -> convert UTF-32 key value to UTF-8
+    if( _name.empty() )
+      _name = boost::locale::conv::utf_to_utf<char>(&_key, &_key + 1);
+
+    // Keys on the numpad with NumLock enabled are reported just like their
+    // equivalent keys in the standard key block. Using the unmodified key value
+    // we can detect such keys and set the location accordingly.
+    if( num_pad_keys.find(_unmodified_key) != num_pad_keys.end() )
+      _location = DOM_KEY_LOCATION_NUMPAD;
+
+    return _name;
+  }
+
+  //----------------------------------------------------------------------------
+  KeyboardEvent::DOMKeyLocation KeyboardEvent::location() const
+  {
+    key(); // ensure location is up-to-date
+    return static_cast<DOMKeyLocation>(_location);
+  }
+
+  //----------------------------------------------------------------------------
+  bool KeyboardEvent::isModifier() const
+  {
+    return (  _key >= EA::KEY_Shift_L
+           && _key <= EA::KEY_Hyper_R
+           )
+        || _key == KEY_AltGraph;
+  }
+
+} // namespace canvas
+} // namespace simgear
diff --git a/simgear/canvas/events/KeyboardEvent.hxx b/simgear/canvas/events/KeyboardEvent.hxx
new file mode 100644 (file)
index 0000000..d90a924
--- /dev/null
@@ -0,0 +1,74 @@
+///@file Keyboard event
+//
+// Copyright (C) 2014  Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
+
+#ifndef CANVAS_KEYBOARD_EVENT_HXX_
+#define CANVAS_KEYBOARD_EVENT_HXX_
+
+#include "DeviceEvent.hxx"
+
+namespace simgear
+{
+namespace canvas
+{
+
+  class KeyboardEvent:
+    public DeviceEvent
+  {
+    public:
+
+      enum DOMKeyLocation
+      {
+        DOM_KEY_LOCATION_STANDARD = 0,
+        DOM_KEY_LOCATION_LEFT,
+        DOM_KEY_LOCATION_RIGHT,
+        DOM_KEY_LOCATION_NUMPAD
+      };
+
+      KeyboardEvent();
+      KeyboardEvent(const osgGA::GUIEventAdapter& ea);
+
+      void setKey(uint32_t key);
+      void setUnmodifiedKey(uint32_t key);
+      void setRepeat(bool repeat);
+
+      std::string key() const;
+      DOMKeyLocation location() const;
+      bool repeat() const { return _repeat; }
+
+      uint32_t charCode() const { return _key; }
+      uint32_t keyCode() const { return _unmodified_key; }
+
+      /// Whether the key which has triggered this event is a modifier
+      bool isModifier() const;
+
+    protected:
+      uint32_t _key,            //<! Key identifier for this event
+               _unmodified_key; //<! Virtual key identifier without any
+                                //   modifiers applied
+      bool     _repeat;         //<! If key has been depressed long enough to
+                                //   generate key repetition
+
+      mutable std::string _name;        //<! Printable representation/name
+      mutable uint8_t _location; //<! Location of the key on the keyboard
+
+  };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_KEYBOARD_EVENT_HXX_ */
index 86c18bd22c8aeddccd88dcab9405d5149fbe5ce3..b1d3a8bec29d900016cfa3b625dc2be7f5309523 100644 (file)
@@ -17,6 +17,7 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
 
 #include "MouseEvent.hxx"
+#include <osgGA/GUIEventAdapter>
 
 namespace simgear
 {
@@ -27,7 +28,6 @@ namespace canvas
   MouseEvent::MouseEvent():
     button(0),
     buttons(0),
-    modifiers(0),
     click_count(0)
   {
 
@@ -35,13 +35,11 @@ namespace canvas
 
   //----------------------------------------------------------------------------
   MouseEvent::MouseEvent(const osgGA::GUIEventAdapter& ea):
+    DeviceEvent(ea),
     button(0),
     buttons(ea.getButtonMask()),
-    modifiers(ea.getModKeyMask()),
     click_count(0)
   {
-    time = ea.getTime();
-
     // Convert button mask to index
     int button_mask = ea.getButton();
     while( (button_mask >>= 1) > 0 )
index d50b52383176252e1e63246bc5e1f046400b203e..d3223f59dc9e99a3b1db2146c4319ba61e33bf53 100644 (file)
@@ -19,8 +19,7 @@
 #ifndef CANVAS_MOUSE_EVENT_HXX_
 #define CANVAS_MOUSE_EVENT_HXX_
 
-#include <simgear/canvas/CanvasEvent.hxx>
-#include <osgGA/GUIEventAdapter>
+#include "DeviceEvent.hxx"
 
 namespace simgear
 {
@@ -28,7 +27,7 @@ namespace canvas
 {
 
   class MouseEvent:
-    public Event
+    public DeviceEvent
   {
     public:
       MouseEvent();
@@ -55,7 +54,6 @@ namespace canvas
 
       int getButton() const { return button; }
       int getButtonMask() const { return buttons; }
-      int getModifiers() const { return modifiers; }
 
       int getCurrentClickCount() const { return click_count; }
 
@@ -65,7 +63,6 @@ namespace canvas
                   delta;
       int         button,       //<! Button for this event
                   buttons,      //<! Current button state
-                  modifiers,    //<! Keyboard modifier state
                   click_count;  //<! Current click count
   };