]> git.mxchange.org Git - flightgear.git/blob - src/Main/FGManipulator.cxx
remove redundant --airport-id option (OK'ed by Curt, no longer used by fgrun)
[flightgear.git] / src / Main / FGManipulator.cxx
1 #ifdef HAVE_CONFIG_H
2 #  include <config.h>
3 #endif
4 #include <osg/Math>
5 #include <osgViewer/Viewer>
6 #include <plib/pu.h>
7 #include "FGManipulator.hxx"
8
9 #if !defined(X_DISPLAY_MISSING)
10 #define X_DOUBLE_SCROLL_BUG 1
11 #endif
12
13 // The manipulator is responsible for updating a Viewer's camera. It's
14 // event handling method is also a convenient place to run the the FG
15 // idle and draw handlers.
16
17 FGManipulator::FGManipulator() :
18     idleHandler(0), drawHandler(0), windowResizeHandler(0), keyHandler(0),
19     mouseClickHandler(0), mouseMotionHandler(0), currentModifiers(0),
20     osgModifiers(0), resizable(true), mouseWarped(false),
21     scrollButtonPressed(false), useEventModifiers(false)
22 {
23     using namespace osgGA;
24     
25     keyMaskMap[GUIEventAdapter::KEY_Shift_L]
26         = GUIEventAdapter::MODKEY_LEFT_SHIFT;
27     keyMaskMap[GUIEventAdapter::KEY_Shift_R]
28         = GUIEventAdapter::MODKEY_RIGHT_SHIFT;
29     keyMaskMap[GUIEventAdapter::KEY_Control_L]
30         = GUIEventAdapter::MODKEY_LEFT_CTRL;
31     keyMaskMap[GUIEventAdapter::KEY_Control_R]
32         = GUIEventAdapter::MODKEY_RIGHT_CTRL;
33     keyMaskMap[GUIEventAdapter::KEY_Alt_L] = GUIEventAdapter::MODKEY_LEFT_ALT;
34     keyMaskMap[GUIEventAdapter::KEY_Alt_R] = GUIEventAdapter::MODKEY_RIGHT_ALT;
35     keyMaskMap[GUIEventAdapter::KEY_Meta_L] = GUIEventAdapter::MODKEY_LEFT_META;
36     keyMaskMap[GUIEventAdapter::KEY_Meta_R] = GUIEventAdapter::MODKEY_RIGHT_META;
37     keyMaskMap[GUIEventAdapter::KEY_Super_L] = GUIEventAdapter::MODKEY_LEFT_META;
38     keyMaskMap[GUIEventAdapter::KEY_Super_R] = GUIEventAdapter::MODKEY_RIGHT_META;
39     // We have to implement numlock too.
40     numlockKeyMap[GUIEventAdapter::KEY_KP_Insert]  = '0';
41     numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1';
42     numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2';
43     numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = '3';
44     numlockKeyMap[GUIEventAdapter::KEY_KP_Left] = '4';
45     numlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
46     numlockKeyMap[GUIEventAdapter::KEY_KP_Right] = '6';
47     numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7';
48     numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8';
49     numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9';
50
51     for (int i = 0; i < 128; i++)
52         release_keys[i] = i;
53 }
54
55 void FGManipulator::setByMatrix(const osg::Matrixd& matrix)
56 {
57     // Yuck
58     position = matrix.getTrans();
59     attitude = matrix.getRotate();
60 }
61
62 osg::Matrixd FGManipulator::getMatrix() const
63 {
64     return osg::Matrixd::rotate(attitude) * osg::Matrixd::translate(position);
65 }
66
67 osg::Matrixd FGManipulator::getInverseMatrix() const
68 {
69     return (osg::Matrixd::translate(-position)
70             * osg::Matrixd::rotate(attitude.inverse())) ;
71 }
72
73 // Not used, but part of the interface.
74 void FGManipulator::setNode(osg::Node* node)
75 {
76     _node = node;
77 }
78     
79 const osg::Node* FGManipulator::getNode() const
80 {
81     return _node.get();
82 }
83
84 osg::Node* FGManipulator::getNode()
85 {
86     return _node.get();
87 }
88
89 // All the usual translation from window system to FG / plib
90 static int osgToFGModifiers(int modifiers)
91 {
92     int result = 0;
93     if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT |
94                      osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT))
95         result |= KEYMOD_SHIFT;
96     if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL |
97                      osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL))
98         result |= KEYMOD_CTRL;
99     if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_ALT |
100                      osgGA::GUIEventAdapter::MODKEY_RIGHT_ALT))
101         result |= KEYMOD_ALT;
102     if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_META |
103                      osgGA::GUIEventAdapter::MODKEY_RIGHT_META))
104         result |= KEYMOD_META;
105     return result;
106 }
107
108 void FGManipulator::init(const osgGA::GUIEventAdapter& ea,
109                          osgGA::GUIActionAdapter& us)
110 {
111     currentModifiers = osgToFGModifiers(ea.getModKeyMask());
112     (void)handle(ea, us);
113 }
114
115 static bool
116 eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
117                 int& x, int& y)
118 {
119   x = -1;
120   y = -1;
121
122   const osgViewer::Viewer* viewer;
123   viewer = dynamic_cast<const osgViewer::Viewer*>(&us);
124   if (!viewer)
125       return false;
126
127   float lx, ly;
128   const osg::Camera* camera;
129   camera = viewer->getCameraContainingPosition(ea.getX(), ea.getY(), lx, ly);
130
131   if (!(camera && fgOSIsMainCamera(camera)))
132       return false;
133
134   x = int(lx);
135   y = int(camera->getViewport()->height() - ly);
136
137   return true;
138 }
139
140 bool FGManipulator::handle(const osgGA::GUIEventAdapter& ea,
141                            osgGA::GUIActionAdapter& us)
142 {
143     int x = 0;
144     int y = 0;
145     switch (ea.getEventType()) {
146     case osgGA::GUIEventAdapter::FRAME:
147         if (idleHandler)
148             (*idleHandler)();
149         if (drawHandler)
150             (*drawHandler)();
151         mouseWarped = false;
152         return true;
153     case osgGA::GUIEventAdapter::KEYDOWN:
154     case osgGA::GUIEventAdapter::KEYUP:
155     {
156         int key, modmask;
157         handleKey(ea, key, modmask);
158         eventToViewport(ea, us, x, y);
159         if (keyHandler)
160             (*keyHandler)(key, modmask, x, y);
161         return true;
162     }
163     case osgGA::GUIEventAdapter::PUSH:
164     case osgGA::GUIEventAdapter::RELEASE:
165     {
166         bool mainWindow = eventToViewport(ea, us, x, y);
167         int button = 0;
168         switch (ea.getButton()) {
169         case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
170             button = 0;
171             break;
172         case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
173             button = 1;
174             break;
175         case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
176             button = 2;
177             break;
178         }
179         if (mouseClickHandler)
180             (*mouseClickHandler)(button,
181                                  (ea.getEventType()
182                                   == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea);
183         return true;
184     }
185     case osgGA::GUIEventAdapter::SCROLL:
186     {
187         bool mainWindow = eventToViewport(ea, us, x, y);
188 #ifdef X_DOUBLE_SCROLL_BUG
189         scrollButtonPressed = !scrollButtonPressed;
190         if (!scrollButtonPressed) // Drop the button release event
191             return true;
192 #endif
193         int button;
194         if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP)
195             button = 3;
196         else
197             button = 4;
198         if (mouseClickHandler) {
199             (*mouseClickHandler)(button, 0, x, y, mainWindow, &ea);
200             (*mouseClickHandler)(button, 1, x, y, mainWindow, &ea);
201         }
202         return true;
203     }
204     case osgGA::GUIEventAdapter::MOVE:
205     case osgGA::GUIEventAdapter::DRAG:
206         // If we warped the mouse, then disregard all pointer motion
207         // events for this frame. We really want to flush the event
208         // queue of mouse events, but don't have the ability to do
209         // that with osgViewer.
210         if (mouseWarped)
211             return true;
212         if (eventToViewport(ea, us, x, y) && mouseMotionHandler)
213             (*mouseMotionHandler)(x, y);
214         return true;
215     case osgGA::GUIEventAdapter::RESIZE:
216         if (resizable && windowResizeHandler)
217             (*windowResizeHandler)(ea.getWindowWidth(), ea.getWindowHeight());
218         return true;
219      case osgGA::GUIEventAdapter::CLOSE_WINDOW:
220     case osgGA::GUIEventAdapter::QUIT_APPLICATION:
221         fgOSExit(0);
222         return true;
223     default:
224         return false;
225     }
226 }
227
228 void FGManipulator::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
229                               int& modifiers)
230 {
231     key = ea.getKey();
232     // XXX Probably other translations are needed too.
233     switch (key) {
234     case osgGA::GUIEventAdapter::KEY_Escape: key = 0x1b; break;
235     case osgGA::GUIEventAdapter::KEY_Return: key = '\n'; break;
236     case osgGA::GUIEventAdapter::KEY_BackSpace: key = '\b'; break;
237     case osgGA::GUIEventAdapter::KEY_Delete:   key = 0x7f; break;
238     case osgGA::GUIEventAdapter::KEY_Tab:      key = '\t'; break;
239     case osgGA::GUIEventAdapter::KEY_Left:     key = PU_KEY_LEFT;      break;
240     case osgGA::GUIEventAdapter::KEY_Up:       key = PU_KEY_UP;        break;
241     case osgGA::GUIEventAdapter::KEY_Right:    key = PU_KEY_RIGHT;     break;
242     case osgGA::GUIEventAdapter::KEY_Down:     key = PU_KEY_DOWN;      break;
243     case osgGA::GUIEventAdapter::KEY_Page_Up:   key = PU_KEY_PAGE_UP;   break;
244     case osgGA::GUIEventAdapter::KEY_Page_Down: key = PU_KEY_PAGE_DOWN; break;
245     case osgGA::GUIEventAdapter::KEY_Home:     key = PU_KEY_HOME;      break;
246     case osgGA::GUIEventAdapter::KEY_End:      key = PU_KEY_END;       break;
247     case osgGA::GUIEventAdapter::KEY_Insert:   key = PU_KEY_INSERT;    break;
248     case osgGA::GUIEventAdapter::KEY_F1:       key = PU_KEY_F1;        break;
249     case osgGA::GUIEventAdapter::KEY_F2:       key = PU_KEY_F2;        break;
250     case osgGA::GUIEventAdapter::KEY_F3:       key = PU_KEY_F3;        break;
251     case osgGA::GUIEventAdapter::KEY_F4:       key = PU_KEY_F4;        break;
252     case osgGA::GUIEventAdapter::KEY_F5:       key = PU_KEY_F5;        break;
253     case osgGA::GUIEventAdapter::KEY_F6:       key = PU_KEY_F6;        break;
254     case osgGA::GUIEventAdapter::KEY_F7:       key = PU_KEY_F7;        break;
255     case osgGA::GUIEventAdapter::KEY_F8:       key = PU_KEY_F8;        break;
256     case osgGA::GUIEventAdapter::KEY_F9:       key = PU_KEY_F9;        break;
257     case osgGA::GUIEventAdapter::KEY_F10:      key = PU_KEY_F10;       break;
258     case osgGA::GUIEventAdapter::KEY_F11:      key = PU_KEY_F11;       break;
259     case osgGA::GUIEventAdapter::KEY_F12:      key = PU_KEY_F12;       break;
260     case osgGA::GUIEventAdapter::KEY_KP_Delete: key = '.'; break;
261     case osgGA::GUIEventAdapter::KEY_KP_Enter: key = '\r'; break;
262     case osgGA::GUIEventAdapter::KEY_KP_Add:   key = '+'; break;
263     case osgGA::GUIEventAdapter::KEY_KP_Divide: key = '/'; break;
264     case osgGA::GUIEventAdapter::KEY_KP_Multiply: key = '*'; break;
265     case osgGA::GUIEventAdapter::KEY_KP_Subtract: key = '-'; break;
266     }
267     osgGA::GUIEventAdapter::EventType eventType = ea.getEventType();
268     std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
269
270     if (numPadIter != numlockKeyMap.end()) {
271         if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK) {
272             key = numPadIter->second;
273         }
274     } else if (useEventModifiers) {
275         
276     }else {
277         // Track the modifiers because OSG is currently (2.0) broken
278         KeyMaskMap::iterator iter = keyMaskMap.find(key);
279         if (iter != keyMaskMap.end()) {
280             int mask = iter->second;
281             if (eventType == osgGA::GUIEventAdapter::KEYUP)
282                 osgModifiers &= ~mask;
283             else
284                 osgModifiers |= mask;
285         }
286     }
287     modifiers = osgToFGModifiers(osgModifiers);
288     currentModifiers = modifiers;
289     if (eventType == osgGA::GUIEventAdapter::KEYUP)
290         modifiers |= KEYMOD_RELEASED;
291
292     // Release the letter key, for which the keypress was reported
293     if (key >= 0 && key < 128) {
294         if (modifiers & KEYMOD_RELEASED) {
295             key = release_keys[key];
296         } else {
297             release_keys[key] = key;
298             if (key >= 1 && key <= 26) {
299                 release_keys[key + '@'] = key;
300                 release_keys[key + '`'] = key;
301             } else if (key >= 'A' && key <= 'Z') {
302                 release_keys[key - '@'] = key;
303                 release_keys[tolower(key)] = key;
304             } else if (key >= 'a' && key <= 'z') {
305                 release_keys[key - '`'] = key;
306                 release_keys[toupper(key)] = key;
307             }
308         }
309     }
310 }
311