5 #include <osgViewer/Viewer>
7 #include <Main/fg_props.hxx>
8 #include "FGManipulator.hxx"
10 #if !defined(X_DISPLAY_MISSING)
11 #define X_DOUBLE_SCROLL_BUG 1
14 const int displayStatsKey = 1;
15 const int printStatsKey = 2;
18 // The manipulator is responsible for updating a Viewer's camera. Its
19 // event handling method is also a convenient place to run the FG idle
22 FGManipulator::FGManipulator() :
25 windowResizeHandler(0),
28 mouseMotionHandler(0),
29 statsHandler(new osgViewer::StatsHandler),
30 statsEvent(new osgGA::GUIEventAdapter),
31 statsType(osgViewer::StatsHandler::NO_STATS),
35 scrollButtonPressed(false)
37 using namespace osgGA;
38 statsHandler->setKeyEventTogglesOnScreenStats(displayStatsKey);
39 statsHandler->setKeyEventPrintsOutStats(printStatsKey);
40 statsEvent->setEventType(GUIEventAdapter::KEYDOWN);
42 // OSG reports NumPad keycodes independent of the NumLock modifier.
43 // Both KP-4 and KP-Left are reported as KEY_KP_Left (0xff96), so we
44 // have to generate the locked keys ourselves.
45 numlockKeyMap[GUIEventAdapter::KEY_KP_Insert] = '0';
46 numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1';
47 numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2';
48 numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = '3';
49 numlockKeyMap[GUIEventAdapter::KEY_KP_Left] = '4';
50 numlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
51 numlockKeyMap[GUIEventAdapter::KEY_KP_Right] = '6';
52 numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7';
53 numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8';
54 numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9';
56 for (int i = 0; i < 128; i++)
60 void FGManipulator::setByMatrix(const osg::Matrixd& matrix)
63 position = matrix.getTrans();
64 attitude = matrix.getRotate();
67 osg::Matrixd FGManipulator::getMatrix() const
69 return osg::Matrixd::rotate(attitude) * osg::Matrixd::translate(position);
72 osg::Matrixd FGManipulator::getInverseMatrix() const
74 return (osg::Matrixd::translate(-position)
75 * osg::Matrixd::rotate(attitude.inverse())) ;
78 // Not used, but part of the interface.
79 void FGManipulator::setNode(osg::Node* node)
84 const osg::Node* FGManipulator::getNode() const
89 osg::Node* FGManipulator::getNode()
94 // Translate OSG modifier mask to FG modifier mask.
95 static int osgToFGModifiers(int modifiers)
98 if (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT)
99 result |= KEYMOD_SHIFT;
101 if (modifiers & osgGA::GUIEventAdapter::MODKEY_CTRL)
102 result |= KEYMOD_CTRL;
104 if (modifiers & osgGA::GUIEventAdapter::MODKEY_ALT)
105 result |= KEYMOD_ALT;
107 if (modifiers & osgGA::GUIEventAdapter::MODKEY_META)
108 result |= KEYMOD_META;
110 if (modifiers & osgGA::GUIEventAdapter::MODKEY_SUPER)
111 result |= KEYMOD_SUPER;
113 if (modifiers & osgGA::GUIEventAdapter::MODKEY_HYPER)
114 result |= KEYMOD_HYPER;
118 void FGManipulator::init(const osgGA::GUIEventAdapter& ea,
119 osgGA::GUIActionAdapter& us)
121 currentModifiers = osgToFGModifiers(ea.getModKeyMask());
122 (void)handle(ea, us);
126 eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
132 const osgViewer::Viewer* viewer;
133 viewer = dynamic_cast<const osgViewer::Viewer*>(&us);
138 const osg::Camera* camera;
139 camera = viewer->getCameraContainingPosition(ea.getX(), ea.getY(), lx, ly);
141 if (!(camera && fgOSIsMainCamera(camera)))
145 y = int(camera->getViewport()->height() - ly);
150 bool FGManipulator::handle(const osgGA::GUIEventAdapter& ea,
151 osgGA::GUIActionAdapter& us)
156 switch (ea.getEventType()) {
157 case osgGA::GUIEventAdapter::FRAME:
165 case osgGA::GUIEventAdapter::KEYDOWN:
166 case osgGA::GUIEventAdapter::KEYUP:
169 handleKey(ea, key, modmask);
170 eventToViewport(ea, us, x, y);
172 (*keyHandler)(key, modmask, x, y);
175 case osgGA::GUIEventAdapter::PUSH:
176 case osgGA::GUIEventAdapter::RELEASE:
178 bool mainWindow = eventToViewport(ea, us, x, y);
180 switch (ea.getButton()) {
181 case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
184 case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
187 case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
191 if (mouseClickHandler)
192 (*mouseClickHandler)(button,
194 == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea);
197 case osgGA::GUIEventAdapter::SCROLL:
199 bool mainWindow = eventToViewport(ea, us, x, y);
200 #ifdef X_DOUBLE_SCROLL_BUG
201 scrollButtonPressed = !scrollButtonPressed;
202 if (!scrollButtonPressed) // Drop the button release event
206 if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP)
210 if (mouseClickHandler) {
211 (*mouseClickHandler)(button, 0, x, y, mainWindow, &ea);
212 (*mouseClickHandler)(button, 1, x, y, mainWindow, &ea);
216 case osgGA::GUIEventAdapter::MOVE:
217 case osgGA::GUIEventAdapter::DRAG:
218 // If we warped the mouse, then disregard all pointer motion
219 // events for this frame. We really want to flush the event
220 // queue of mouse events, but don't have the ability to do
221 // that with osgViewer.
224 if (eventToViewport(ea, us, x, y) && mouseMotionHandler)
225 (*mouseMotionHandler)(x, y);
227 case osgGA::GUIEventAdapter::RESIZE:
228 if (resizable && windowResizeHandler)
229 (*windowResizeHandler)(ea.getWindowWidth(), ea.getWindowHeight());
231 case osgGA::GUIEventAdapter::CLOSE_WINDOW:
232 case osgGA::GUIEventAdapter::QUIT_APPLICATION:
240 void FGManipulator::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
243 using namespace osgGA;
245 // XXX Probably other translations are needed too.
247 case GUIEventAdapter::KEY_Escape: key = 0x1b; break;
248 case GUIEventAdapter::KEY_Return: key = '\n'; break;
249 case GUIEventAdapter::KEY_BackSpace: key = '\b'; break;
250 case GUIEventAdapter::KEY_Delete: key = 0x7f; break;
251 case GUIEventAdapter::KEY_Tab: key = '\t'; break;
252 case GUIEventAdapter::KEY_Left: key = PU_KEY_LEFT; break;
253 case GUIEventAdapter::KEY_Up: key = PU_KEY_UP; break;
254 case GUIEventAdapter::KEY_Right: key = PU_KEY_RIGHT; break;
255 case GUIEventAdapter::KEY_Down: key = PU_KEY_DOWN; break;
256 case GUIEventAdapter::KEY_Page_Up: key = PU_KEY_PAGE_UP; break;
257 case GUIEventAdapter::KEY_Page_Down: key = PU_KEY_PAGE_DOWN; break;
258 case GUIEventAdapter::KEY_Home: key = PU_KEY_HOME; break;
259 case GUIEventAdapter::KEY_End: key = PU_KEY_END; break;
260 case GUIEventAdapter::KEY_Insert: key = PU_KEY_INSERT; break;
261 case GUIEventAdapter::KEY_F1: key = PU_KEY_F1; break;
262 case GUIEventAdapter::KEY_F2: key = PU_KEY_F2; break;
263 case GUIEventAdapter::KEY_F3: key = PU_KEY_F3; break;
264 case GUIEventAdapter::KEY_F4: key = PU_KEY_F4; break;
265 case GUIEventAdapter::KEY_F5: key = PU_KEY_F5; break;
266 case GUIEventAdapter::KEY_F6: key = PU_KEY_F6; break;
267 case GUIEventAdapter::KEY_F7: key = PU_KEY_F7; break;
268 case GUIEventAdapter::KEY_F8: key = PU_KEY_F8; break;
269 case GUIEventAdapter::KEY_F9: key = PU_KEY_F9; break;
270 case GUIEventAdapter::KEY_F10: key = PU_KEY_F10; break;
271 case GUIEventAdapter::KEY_F11: key = PU_KEY_F11; break;
272 case GUIEventAdapter::KEY_F12: key = PU_KEY_F12; break;
273 case GUIEventAdapter::KEY_KP_Delete: key = '.'; break;
274 case GUIEventAdapter::KEY_KP_Enter: key = '\r'; break;
275 case GUIEventAdapter::KEY_KP_Add: key = '+'; break;
276 case GUIEventAdapter::KEY_KP_Divide: key = '/'; break;
277 case GUIEventAdapter::KEY_KP_Multiply: key = '*'; break;
278 case GUIEventAdapter::KEY_KP_Subtract: key = '-'; break;
280 osgGA::GUIEventAdapter::EventType eventType = ea.getEventType();
282 std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
284 if (numPadIter != numlockKeyMap.end()) {
285 if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK) {
286 key = numPadIter->second;
290 modifiers = osgToFGModifiers(ea.getModKeyMask());
291 currentModifiers = modifiers;
292 if (eventType == osgGA::GUIEventAdapter::KEYUP)
293 modifiers |= KEYMOD_RELEASED;
295 // Release the letter key, for which the key press was reported. This
296 // is to deal with Ctrl-press -> a-press -> Ctrl-release -> a-release
298 if (key >= 0 && key < 128) {
299 if (modifiers & KEYMOD_RELEASED) {
300 key = release_keys[key];
302 release_keys[key] = key;
303 if (key >= 1 && key <= 26) {
304 release_keys[key + '@'] = key;
305 release_keys[key + '`'] = key;
306 } else if (key >= 'A' && key <= 'Z') {
307 release_keys[key - '@'] = key;
308 release_keys[tolower(key)] = key;
309 } else if (key >= 'a' && key <= 'z') {
310 release_keys[key - '`'] = key;
311 release_keys[toupper(key)] = key;
317 void FGManipulator::handleStats(osgGA::GUIActionAdapter& us)
319 static SGPropertyNode_ptr display = fgGetNode("/sim/rendering/on-screen-statistics", true);
320 static SGPropertyNode_ptr print = fgGetNode("/sim/rendering/print-statistics", true);
322 int type = display->getIntValue() % osgViewer::StatsHandler::LAST;
323 if (type != statsType) {
324 statsEvent->setKey(displayStatsKey);
326 statsType = (statsType + 1) % osgViewer::StatsHandler::LAST;
327 statsHandler->handle(*statsEvent, us);
328 } while (statsType != type);
330 display->setIntValue(statsType);
333 if (print->getBoolValue()) {
334 statsEvent->setKey(printStatsKey);
335 statsHandler->handle(*statsEvent, us);
336 print->setBoolValue(false);