]> git.mxchange.org Git - flightgear.git/blobdiff - src/Main/FGManipulator.cxx
make isatty() available for stdout/stderr (hope it works on MS Windows)
[flightgear.git] / src / Main / FGManipulator.cxx
index 226f3685e898bf3f6cb32c2bc8bdc061e7776180..b6d761f48070ffc1a902ebad59a2ac91fc5ae4b7 100644 (file)
@@ -1,23 +1,31 @@
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
 #endif
+#include <osg/Camera>
+#include <osg/GraphicsContext>
 #include <osg/Math>
+#include <osg/Viewport>
 #include <osgViewer/Viewer>
+
 #include <plib/pu.h>
 #include <Main/fg_props.hxx>
+#include "CameraGroup.hxx"
 #include "FGManipulator.hxx"
+#include "WindowSystemAdapter.hxx"
 
 #if !defined(X_DISPLAY_MISSING)
 #define X_DOUBLE_SCROLL_BUG 1
 #endif
 
+namespace flightgear
+{
 const int displayStatsKey = 1;
 const int printStatsKey = 2;
 
 
-// The manipulator is responsible for updating a Viewer's camera. It's
-// event handling method is also a convenient place to run the the FG
-// idle and draw handlers.
+// The manipulator is responsible for updating a Viewer's camera. Its
+// event handling method is also a convenient place to run the FG idle
+// and draw handlers.
 
 FGManipulator::FGManipulator() :
     idleHandler(0),
@@ -30,32 +38,18 @@ FGManipulator::FGManipulator() :
     statsEvent(new osgGA::GUIEventAdapter),
     statsType(osgViewer::StatsHandler::NO_STATS),
     currentModifiers(0),
-    osgModifiers(0),
     resizable(true),
     mouseWarped(false),
-    scrollButtonPressed(false),
-    useEventModifiers(false)
+    scrollButtonPressed(false)
 {
     using namespace osgGA;
     statsHandler->setKeyEventTogglesOnScreenStats(displayStatsKey);
     statsHandler->setKeyEventPrintsOutStats(printStatsKey);
     statsEvent->setEventType(GUIEventAdapter::KEYDOWN);
 
-    keyMaskMap[GUIEventAdapter::KEY_Shift_L]
-       = GUIEventAdapter::MODKEY_LEFT_SHIFT;
-    keyMaskMap[GUIEventAdapter::KEY_Shift_R]
-       = GUIEventAdapter::MODKEY_RIGHT_SHIFT;
-    keyMaskMap[GUIEventAdapter::KEY_Control_L]
-       = GUIEventAdapter::MODKEY_LEFT_CTRL;
-    keyMaskMap[GUIEventAdapter::KEY_Control_R]
-       = GUIEventAdapter::MODKEY_RIGHT_CTRL;
-    keyMaskMap[GUIEventAdapter::KEY_Alt_L] = GUIEventAdapter::MODKEY_LEFT_ALT;
-    keyMaskMap[GUIEventAdapter::KEY_Alt_R] = GUIEventAdapter::MODKEY_RIGHT_ALT;
-    keyMaskMap[GUIEventAdapter::KEY_Meta_L] = GUIEventAdapter::MODKEY_LEFT_META;
-    keyMaskMap[GUIEventAdapter::KEY_Meta_R] = GUIEventAdapter::MODKEY_RIGHT_META;
-    keyMaskMap[GUIEventAdapter::KEY_Super_L] = GUIEventAdapter::MODKEY_LEFT_META;
-    keyMaskMap[GUIEventAdapter::KEY_Super_R] = GUIEventAdapter::MODKEY_RIGHT_META;
-    // We have to implement numlock too.
+    // OSG reports NumPad keycodes independent of the NumLock modifier.
+    // Both KP-4 and KP-Left are reported as KEY_KP_Left (0xff96), so we
+    // have to generate the locked keys ourselves.
     numlockKeyMap[GUIEventAdapter::KEY_KP_Insert]  = '0';
     numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1';
     numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2';
@@ -86,7 +80,7 @@ osg::Matrixd FGManipulator::getMatrix() const
 osg::Matrixd FGManipulator::getInverseMatrix() const
 {
     return (osg::Matrixd::translate(-position)
-           * osg::Matrixd::rotate(attitude.inverse())) ;
+            * osg::Matrixd::rotate(attitude.inverse())) ;
 }
 
 // Not used, but part of the interface.
@@ -94,7 +88,7 @@ void FGManipulator::setNode(osg::Node* node)
 {
     _node = node;
 }
-    
+
 const osg::Node* FGManipulator::getNode() const
 {
     return _node.get();
@@ -105,103 +99,124 @@ osg::Node* FGManipulator::getNode()
     return _node.get();
 }
 
-// All the usual translation from window system to FG / plib
-static int osgToFGModifiers(int modifiers)
+namespace
+{
+// Translate OSG modifier mask to FG modifier mask.
+int osgToFGModifiers(int modifiers)
 {
     int result = 0;
-    if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT |
-                    osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT))
-       result |= KEYMOD_SHIFT;
-    if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL |
-                    osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL))
-       result |= KEYMOD_CTRL;
-    if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_ALT |
-                    osgGA::GUIEventAdapter::MODKEY_RIGHT_ALT))
-       result |= KEYMOD_ALT;
-    if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_META |
-                    osgGA::GUIEventAdapter::MODKEY_RIGHT_META))
-       result |= KEYMOD_META;
+    if (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT)
+        result |= KEYMOD_SHIFT;
+
+    if (modifiers & osgGA::GUIEventAdapter::MODKEY_CTRL)
+        result |= KEYMOD_CTRL;
+
+    if (modifiers & osgGA::GUIEventAdapter::MODKEY_ALT)
+        result |= KEYMOD_ALT;
+
+    if (modifiers & osgGA::GUIEventAdapter::MODKEY_META)
+        result |= KEYMOD_META;
+
+    if (modifiers & osgGA::GUIEventAdapter::MODKEY_SUPER)
+        result |= KEYMOD_SUPER;
+
+    if (modifiers & osgGA::GUIEventAdapter::MODKEY_HYPER)
+        result |= KEYMOD_HYPER;
     return result;
 }
+}
 
 void FGManipulator::init(const osgGA::GUIEventAdapter& ea,
-                        osgGA::GUIActionAdapter& us)
+                         osgGA::GUIActionAdapter& us)
 {
     currentModifiers = osgToFGModifiers(ea.getModKeyMask());
     (void)handle(ea, us);
 }
 
-static bool
+// Calculate event coordinates in the viewport of the GUI camera, if
+// possible. Otherwise return false and (-1, -1).
+namespace
+{
+bool
 eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
                 int& x, int& y)
 {
-  x = -1;
-  y = -1;
-
-  const osgViewer::Viewer* viewer;
-  viewer = dynamic_cast<const osgViewer::Viewer*>(&us);
-  if (!viewer)
-      return false;
-
-  float lx, ly;
-  const osg::Camera* camera;
-  camera = viewer->getCameraContainingPosition(ea.getX(), ea.getY(), lx, ly);
+    x = -1;
+    y = -1;
 
-  if (!(camera && fgOSIsMainCamera(camera)))
-      return false;
-
-  x = int(lx);
-  y = int(camera->getViewport()->height() - ly);
-
-  return true;
+    const osg::GraphicsContext* eventGC = ea.getGraphicsContext();
+    const osg::GraphicsContext::Traits* traits = eventGC->getTraits();
+    osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
+    if (!guiCamera)
+        return false;
+    osg::Viewport* vport = guiCamera->getViewport();
+    if (!vport)
+        return false;
+    
+    // Scale x, y to the dimensions of the window
+    double wx = (((ea.getX() - ea.getXmin()) / (ea.getXmax() - ea.getXmin()))
+                 * (float)traits->width);
+    double wy = (((ea.getY() - ea.getYmin()) / (ea.getYmax() - ea.getYmin()))
+                 * (float)traits->height);
+    if (vport->x() <= wx && wx <= vport->x() + vport->width()
+        && vport->y() <= wy && wy <= vport->y() + vport->height()) {
+        // Finally, into viewport coordinates. Change y to "increasing
+        // downwards".
+        x = wx - vport->x();
+        y = vport->height() - (wy - vport->y());
+        return true;
+    } else {
+        return false;
+    }
+}
 }
 
 bool FGManipulator::handle(const osgGA::GUIEventAdapter& ea,
-                          osgGA::GUIActionAdapter& us)
+                           osgGA::GUIActionAdapter& us)
 {
     int x = 0;
     int y = 0;
-    handleStats(us);
 
     switch (ea.getEventType()) {
     case osgGA::GUIEventAdapter::FRAME:
-       if (idleHandler)
-           (*idleHandler)();
-       if (drawHandler)
-           (*drawHandler)();
-       mouseWarped = false;
-       return true;
+        if (idleHandler)
+            (*idleHandler)();
+        if (drawHandler)
+            (*drawHandler)();
+        mouseWarped = false;
+        handleStats(us);
+        return true;
     case osgGA::GUIEventAdapter::KEYDOWN:
     case osgGA::GUIEventAdapter::KEYUP:
     {
-       int key, modmask;
-       handleKey(ea, key, modmask);
-       eventToViewport(ea, us, x, y);
-       if (keyHandler)
-           (*keyHandler)(key, modmask, x, y);
+        int key, modmask;
+        handleKey(ea, key, modmask);
+        eventToViewport(ea, us, x, y);
+        if (keyHandler)
+            (*keyHandler)(key, modmask, x, y);
         return true;
     }
     case osgGA::GUIEventAdapter::PUSH:
     case osgGA::GUIEventAdapter::RELEASE:
     {
         bool mainWindow = eventToViewport(ea, us, x, y);
-       int button = 0;
-       switch (ea.getButton()) {
-       case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
-           button = 0;
-           break;
-       case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
-           button = 1;
-           break;
-       case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
-           button = 2;
-           break;
-       }
-       if (mouseClickHandler)
-           (*mouseClickHandler)(button,
-                                (ea.getEventType()
-                                 == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea);
-       return true;
+        int button = 0;
+        switch (ea.getButton()) {
+        case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
+            button = 0;
+            break;
+        case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
+            button = 1;
+            break;
+        case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
+            button = 2;
+            break;
+        }
+        if (mouseClickHandler)
+            (*mouseClickHandler)(button,
+                                 (ea.getEventType()
+                                  == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea);
+        return true;
     }
     case osgGA::GUIEventAdapter::SCROLL:
     {
@@ -228,89 +243,82 @@ bool FGManipulator::handle(const osgGA::GUIEventAdapter& ea,
         // events for this frame. We really want to flush the event
         // queue of mouse events, but don't have the ability to do
         // that with osgViewer.
-       if (mouseWarped)
-           return true;
-       if (eventToViewport(ea, us, x, y) && mouseMotionHandler)
-           (*mouseMotionHandler)(x, y);
-       return true;
+        if (mouseWarped)
+            return true;
+        if (eventToViewport(ea, us, x, y) && mouseMotionHandler)
+            (*mouseMotionHandler)(x, y);
+        return true;
     case osgGA::GUIEventAdapter::RESIZE:
-       if (resizable && windowResizeHandler)
-           (*windowResizeHandler)(ea.getWindowWidth(), ea.getWindowHeight());
-       return true;
+        if (resizable && windowResizeHandler)
+            (*windowResizeHandler)(ea.getWindowWidth(), ea.getWindowHeight());
+        return true;
      case osgGA::GUIEventAdapter::CLOSE_WINDOW:
     case osgGA::GUIEventAdapter::QUIT_APPLICATION:
         fgOSExit(0);
         return true;
     default:
-       return false;
+        return false;
     }
 }
 
 void FGManipulator::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
-                             int& modifiers)
+                              int& modifiers)
 {
+    using namespace osgGA;
     key = ea.getKey();
     // XXX Probably other translations are needed too.
     switch (key) {
-    case osgGA::GUIEventAdapter::KEY_Escape: key = 0x1b; break;
-    case osgGA::GUIEventAdapter::KEY_Return: key = '\n'; break;
-    case osgGA::GUIEventAdapter::KEY_BackSpace: key = '\b'; break;
-    case osgGA::GUIEventAdapter::KEY_Delete:   key = 0x7f; break;
-    case osgGA::GUIEventAdapter::KEY_Tab:      key = '\t'; break;
-    case osgGA::GUIEventAdapter::KEY_Left:     key = PU_KEY_LEFT;      break;
-    case osgGA::GUIEventAdapter::KEY_Up:       key = PU_KEY_UP;        break;
-    case osgGA::GUIEventAdapter::KEY_Right:    key = PU_KEY_RIGHT;     break;
-    case osgGA::GUIEventAdapter::KEY_Down:     key = PU_KEY_DOWN;      break;
-    case osgGA::GUIEventAdapter::KEY_Page_Up:   key = PU_KEY_PAGE_UP;   break;
-    case osgGA::GUIEventAdapter::KEY_Page_Down: key = PU_KEY_PAGE_DOWN; break;
-    case osgGA::GUIEventAdapter::KEY_Home:     key = PU_KEY_HOME;      break;
-    case osgGA::GUIEventAdapter::KEY_End:      key = PU_KEY_END;       break;
-    case osgGA::GUIEventAdapter::KEY_Insert:   key = PU_KEY_INSERT;    break;
-    case osgGA::GUIEventAdapter::KEY_F1:       key = PU_KEY_F1;        break;
-    case osgGA::GUIEventAdapter::KEY_F2:       key = PU_KEY_F2;        break;
-    case osgGA::GUIEventAdapter::KEY_F3:       key = PU_KEY_F3;        break;
-    case osgGA::GUIEventAdapter::KEY_F4:       key = PU_KEY_F4;        break;
-    case osgGA::GUIEventAdapter::KEY_F5:       key = PU_KEY_F5;        break;
-    case osgGA::GUIEventAdapter::KEY_F6:       key = PU_KEY_F6;        break;
-    case osgGA::GUIEventAdapter::KEY_F7:       key = PU_KEY_F7;        break;
-    case osgGA::GUIEventAdapter::KEY_F8:       key = PU_KEY_F8;        break;
-    case osgGA::GUIEventAdapter::KEY_F9:       key = PU_KEY_F9;        break;
-    case osgGA::GUIEventAdapter::KEY_F10:      key = PU_KEY_F10;       break;
-    case osgGA::GUIEventAdapter::KEY_F11:      key = PU_KEY_F11;       break;
-    case osgGA::GUIEventAdapter::KEY_F12:      key = PU_KEY_F12;       break;
-    case osgGA::GUIEventAdapter::KEY_KP_Delete: key = '.'; break;
-    case osgGA::GUIEventAdapter::KEY_KP_Enter: key = '\r'; break;
-    case osgGA::GUIEventAdapter::KEY_KP_Add:   key = '+'; break;
-    case osgGA::GUIEventAdapter::KEY_KP_Divide: key = '/'; break;
-    case osgGA::GUIEventAdapter::KEY_KP_Multiply: key = '*'; break;
-    case osgGA::GUIEventAdapter::KEY_KP_Subtract: key = '-'; break;
+    case GUIEventAdapter::KEY_Escape:      key = 0x1b; break;
+    case GUIEventAdapter::KEY_Return:      key = '\n'; break;
+    case GUIEventAdapter::KEY_BackSpace:   key = '\b'; break;
+    case GUIEventAdapter::KEY_Delete:      key = 0x7f; break;
+    case GUIEventAdapter::KEY_Tab:         key = '\t'; break;
+    case GUIEventAdapter::KEY_Left:        key = PU_KEY_LEFT;      break;
+    case GUIEventAdapter::KEY_Up:          key = PU_KEY_UP;        break;
+    case GUIEventAdapter::KEY_Right:       key = PU_KEY_RIGHT;     break;
+    case GUIEventAdapter::KEY_Down:        key = PU_KEY_DOWN;      break;
+    case GUIEventAdapter::KEY_Page_Up:     key = PU_KEY_PAGE_UP;   break;
+    case GUIEventAdapter::KEY_Page_Down:   key = PU_KEY_PAGE_DOWN; break;
+    case GUIEventAdapter::KEY_Home:        key = PU_KEY_HOME;      break;
+    case GUIEventAdapter::KEY_End:         key = PU_KEY_END;       break;
+    case GUIEventAdapter::KEY_Insert:      key = PU_KEY_INSERT;    break;
+    case GUIEventAdapter::KEY_F1:          key = PU_KEY_F1;        break;
+    case GUIEventAdapter::KEY_F2:          key = PU_KEY_F2;        break;
+    case GUIEventAdapter::KEY_F3:          key = PU_KEY_F3;        break;
+    case GUIEventAdapter::KEY_F4:          key = PU_KEY_F4;        break;
+    case GUIEventAdapter::KEY_F5:          key = PU_KEY_F5;        break;
+    case GUIEventAdapter::KEY_F6:          key = PU_KEY_F6;        break;
+    case GUIEventAdapter::KEY_F7:          key = PU_KEY_F7;        break;
+    case GUIEventAdapter::KEY_F8:          key = PU_KEY_F8;        break;
+    case GUIEventAdapter::KEY_F9:          key = PU_KEY_F9;        break;
+    case GUIEventAdapter::KEY_F10:         key = PU_KEY_F10;       break;
+    case GUIEventAdapter::KEY_F11:         key = PU_KEY_F11;       break;
+    case GUIEventAdapter::KEY_F12:         key = PU_KEY_F12;       break;
+    case GUIEventAdapter::KEY_KP_Delete:   key = '.';  break;
+    case GUIEventAdapter::KEY_KP_Enter:    key = '\r'; break;
+    case GUIEventAdapter::KEY_KP_Add:      key = '+';  break;
+    case GUIEventAdapter::KEY_KP_Divide:   key = '/';  break;
+    case GUIEventAdapter::KEY_KP_Multiply: key = '*';  break;
+    case GUIEventAdapter::KEY_KP_Subtract: key = '-';  break;
     }
     osgGA::GUIEventAdapter::EventType eventType = ea.getEventType();
+
     std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
 
     if (numPadIter != numlockKeyMap.end()) {
-       if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK) {
-           key = numPadIter->second;
-       }
-    } else if (useEventModifiers) {
-        
-    }else {
-       // Track the modifiers because OSG is currently (2.0) broken
-       KeyMaskMap::iterator iter = keyMaskMap.find(key);
-       if (iter != keyMaskMap.end()) {
-           int mask = iter->second;
-           if (eventType == osgGA::GUIEventAdapter::KEYUP)
-               osgModifiers &= ~mask;
-           else
-               osgModifiers |= mask;
-       }
+        if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK) {
+            key = numPadIter->second;
+        }
     }
-    modifiers = osgToFGModifiers(osgModifiers);
+
+    modifiers = osgToFGModifiers(ea.getModKeyMask());
     currentModifiers = modifiers;
     if (eventType == osgGA::GUIEventAdapter::KEYUP)
-       modifiers |= KEYMOD_RELEASED;
+        modifiers |= KEYMOD_RELEASED;
 
-    // Release the letter key, for which the keypress was reported
+    // Release the letter key, for which the key press was reported. This
+    // is to deal with Ctrl-press -> a-press -> Ctrl-release -> a-release
+    // correctly.
     if (key >= 0 && key < 128) {
         if (modifiers & KEYMOD_RELEASED) {
             key = release_keys[key];
@@ -339,7 +347,7 @@ void FGManipulator::handleStats(osgGA::GUIActionAdapter& us)
     if (type != statsType) {
         statsEvent->setKey(displayStatsKey);
         do {
-            statsType = ++statsType % osgViewer::StatsHandler::LAST;
+            statsType = (statsType + 1) % osgViewer::StatsHandler::LAST;
             statsHandler->handle(*statsEvent, us);
         } while (statsType != type);
 
@@ -353,3 +361,33 @@ void FGManipulator::handleStats(osgGA::GUIActionAdapter& us)
     }
 }
 
+void eventToWindowCoords(const osgGA::GUIEventAdapter* ea,
+                         double& x, double& y)
+{
+    using namespace osg;
+    const GraphicsContext* gc = ea->getGraphicsContext();
+    const GraphicsContext::Traits* traits = gc->getTraits() ;
+    // Scale x, y to the dimensions of the window
+    x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin()))
+         * (double)traits->width);
+    y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin()))
+         * (double)traits->height);
+    if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS)
+        y = (double)traits->height - y;
+}
+
+void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea,
+                              double& x, double& y)
+{
+    using namespace osg;
+    const GraphicsContext* gc = ea->getGraphicsContext();
+    const GraphicsContext::Traits* traits = gc->getTraits() ;
+    // Scale x, y to the dimensions of the window
+    x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin()))
+         * (double)traits->width);
+    y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin()))
+         * (double)traits->height);
+    if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS)
+        y = (double)traits->height - y;
+}
+}