5 #include <osgViewer/Viewer>
7 #include "FGManipulator.hxx"
9 #if !defined(X_DISPLAY_MISSING)
10 #define X_DOUBLE_SCROLL_BUG 1
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.
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)
23 using namespace osgGA;
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 // We have to implement numlock too.
36 numlockKeyMap[GUIEventAdapter::KEY_KP_Insert] = '0';
37 numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1';
38 numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2';
39 numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = '3';
40 numlockKeyMap[GUIEventAdapter::KEY_KP_Left] = '4';
41 numlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
42 numlockKeyMap[GUIEventAdapter::KEY_KP_Right] = '6';
43 numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7';
44 numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8';
45 numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9';
48 void FGManipulator::setByMatrix(const osg::Matrixd& matrix)
51 position = matrix.getTrans();
52 attitude = matrix.getRotate();
55 osg::Matrixd FGManipulator::getMatrix() const
57 return osg::Matrixd::rotate(attitude) * osg::Matrixd::translate(position);
60 osg::Matrixd FGManipulator::getInverseMatrix() const
62 return (osg::Matrixd::translate(-position)
63 * osg::Matrixd::rotate(attitude.inverse())) ;
66 // Not used, but part of the interface.
67 void FGManipulator::setNode(osg::Node* node)
72 const osg::Node* FGManipulator::getNode() const
77 osg::Node* FGManipulator::getNode()
82 // All the usual translation from window system to FG / plib
83 static int osgToFGModifiers(int modifiers)
86 if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT |
87 osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT))
88 result |= KEYMOD_SHIFT;
89 if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL |
90 osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL))
91 result |= KEYMOD_CTRL;
92 if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_ALT |
93 osgGA::GUIEventAdapter::MODKEY_RIGHT_ALT))
98 void FGManipulator::init(const osgGA::GUIEventAdapter& ea,
99 osgGA::GUIActionAdapter& us)
101 currentModifiers = osgToFGModifiers(ea.getModKeyMask());
102 (void)handle(ea, us);
106 eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
112 const osgViewer::Viewer* viewer;
113 viewer = dynamic_cast<const osgViewer::Viewer*>(&us);
118 const osg::Camera* camera;
119 camera = viewer->getCameraContainingPosition(ea.getX(), ea.getY(), lx, ly);
121 if (!fgOSIsMainCamera(camera))
125 y = int(camera->getViewport()->height() - ly);
130 bool FGManipulator::handle(const osgGA::GUIEventAdapter& ea,
131 osgGA::GUIActionAdapter& us)
134 switch (ea.getEventType()) {
135 case osgGA::GUIEventAdapter::FRAME:
142 case osgGA::GUIEventAdapter::KEYDOWN:
143 case osgGA::GUIEventAdapter::KEYUP:
146 handleKey(ea, key, modmask);
147 eventToViewport(ea, us, x, y);
149 (*keyHandler)(key, modmask, x, y);
152 case osgGA::GUIEventAdapter::PUSH:
153 case osgGA::GUIEventAdapter::RELEASE:
155 bool mainWindow = eventToViewport(ea, us, x, y);
157 switch (ea.getButton()) {
158 case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
161 case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
164 case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
168 if (mouseClickHandler)
169 (*mouseClickHandler)(button,
171 == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea);
174 case osgGA::GUIEventAdapter::SCROLL:
176 bool mainWindow = eventToViewport(ea, us, x, y);
177 #ifdef X_DOUBLE_SCROLL_BUG
178 scrollButtonPressed = !scrollButtonPressed;
179 if (!scrollButtonPressed) // Drop the button release event
183 if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP)
187 if (mouseClickHandler) {
188 (*mouseClickHandler)(button, 0, x, y, mainWindow, &ea);
189 (*mouseClickHandler)(button, 1, x, y, mainWindow, &ea);
193 case osgGA::GUIEventAdapter::MOVE:
194 case osgGA::GUIEventAdapter::DRAG:
195 // If we warped the mouse, then disregard all pointer motion
196 // events for this frame. We really want to flush the event
197 // queue of mouse events, but don't have the ability to do
198 // that with osgViewer.
201 eventToViewport(ea, us, x, y);
202 if (mouseMotionHandler)
203 (*mouseMotionHandler)(x, y);
205 case osgGA::GUIEventAdapter::RESIZE:
206 if (resizable && windowResizeHandler)
207 (*windowResizeHandler)(ea.getWindowWidth(), ea.getWindowHeight());
209 case osgGA::GUIEventAdapter::CLOSE_WINDOW:
210 case osgGA::GUIEventAdapter::QUIT_APPLICATION:
218 void FGManipulator::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
222 // XXX Probably other translations are needed too.
224 case osgGA::GUIEventAdapter::KEY_Escape: key = 0x1b; break;
225 case osgGA::GUIEventAdapter::KEY_Return: key = '\n'; break;
226 case osgGA::GUIEventAdapter::KEY_BackSpace: key = '\b'; break;
227 case osgGA::GUIEventAdapter::KEY_Delete: key = 0x7f; break;
228 case osgGA::GUIEventAdapter::KEY_Tab: key = '\t'; break;
229 case osgGA::GUIEventAdapter::KEY_Left: key = PU_KEY_LEFT; break;
230 case osgGA::GUIEventAdapter::KEY_Up: key = PU_KEY_UP; break;
231 case osgGA::GUIEventAdapter::KEY_Right: key = PU_KEY_RIGHT; break;
232 case osgGA::GUIEventAdapter::KEY_Down: key = PU_KEY_DOWN; break;
233 case osgGA::GUIEventAdapter::KEY_Page_Up: key = PU_KEY_PAGE_UP; break;
234 case osgGA::GUIEventAdapter::KEY_Page_Down: key = PU_KEY_PAGE_DOWN; break;
235 case osgGA::GUIEventAdapter::KEY_Home: key = PU_KEY_HOME; break;
236 case osgGA::GUIEventAdapter::KEY_End: key = PU_KEY_END; break;
237 case osgGA::GUIEventAdapter::KEY_Insert: key = PU_KEY_INSERT; break;
238 case osgGA::GUIEventAdapter::KEY_F1: key = PU_KEY_F1; break;
239 case osgGA::GUIEventAdapter::KEY_F2: key = PU_KEY_F2; break;
240 case osgGA::GUIEventAdapter::KEY_F3: key = PU_KEY_F3; break;
241 case osgGA::GUIEventAdapter::KEY_F4: key = PU_KEY_F4; break;
242 case osgGA::GUIEventAdapter::KEY_F5: key = PU_KEY_F5; break;
243 case osgGA::GUIEventAdapter::KEY_F6: key = PU_KEY_F6; break;
244 case osgGA::GUIEventAdapter::KEY_F7: key = PU_KEY_F7; break;
245 case osgGA::GUIEventAdapter::KEY_F8: key = PU_KEY_F8; break;
246 case osgGA::GUIEventAdapter::KEY_F9: key = PU_KEY_F9; break;
247 case osgGA::GUIEventAdapter::KEY_F10: key = PU_KEY_F10; break;
248 case osgGA::GUIEventAdapter::KEY_F11: key = PU_KEY_F11; break;
249 case osgGA::GUIEventAdapter::KEY_F12: key = PU_KEY_F12; break;
250 case osgGA::GUIEventAdapter::KEY_KP_Delete: key = '.'; break;
251 case osgGA::GUIEventAdapter::KEY_KP_Enter: key = '\r'; break;
252 case osgGA::GUIEventAdapter::KEY_KP_Add: key = '+'; break;
253 case osgGA::GUIEventAdapter::KEY_KP_Divide: key = '/'; break;
254 case osgGA::GUIEventAdapter::KEY_KP_Multiply: key = '*'; break;
255 case osgGA::GUIEventAdapter::KEY_KP_Subtract: key = '-'; break;
257 osgGA::GUIEventAdapter::EventType eventType = ea.getEventType();
258 std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
260 if (numPadIter != numlockKeyMap.end()) {
261 if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK) {
262 key = numPadIter->second;
265 // Track the modifiers because OSG is currently (2.0) broken
266 KeyMaskMap::iterator iter = keyMaskMap.find(key);
267 if (iter != keyMaskMap.end()) {
268 int mask = iter->second;
269 if (eventType == osgGA::GUIEventAdapter::KEYUP)
270 osgModifiers &= ~mask;
272 osgModifiers |= mask;
275 modifiers = osgToFGModifiers(osgModifiers);
276 currentModifiers = modifiers;
277 if (eventType == osgGA::GUIEventAdapter::KEYUP)
278 modifiers |= KEYMOD_RELEASED;
280 // Release the letter key, for which the keypress was reported
281 if (key >= 0 && key < int(sizeof(release_keys))) {
282 if (modifiers & KEYMOD_RELEASED) {
283 key = release_keys[key];
285 release_keys[key] = key;
286 if (key >= 1 && key <= 26) {
287 release_keys[key + '@'] = key;
288 release_keys[key + '`'] = key;
289 } else if (key >= 'A' && key <= 'Z') {
290 release_keys[key - '@'] = key;
291 release_keys[tolower(key)] = key;
292 } else if (key >= 'a' && key <= 'z') {
293 release_keys[key - '`'] = key;
294 release_keys[toupper(key)] = key;