- 事件响应流程
事件由操作系统捕捉,压入到osg事件中,如在windows中,由标准接口事件循环中的获取事件
static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
osgViewer::GraphicsWindowWin32* window = Win32WindowingSystem::getInterface()->getGraphicsWindowFor(hwnd);
return window ? window->handleNativeWindowingEvent(hwnd, uMsg, wParam, lParam) :
::DefWindowProc(hwnd, uMsg, wParam, lParam);
}
window->handleNativeWindowingEvent(hwnd, uMsg, wParam, lParam) :
LRESULT GraphicsWindowWin32::handleNativeWindowingEvent( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
//!@todo adapt windows event time to osgGA event queue time for better resolution
double eventTime = getEventQueue()->getTime();
_timeOfLastCheckEvents = eventTime;
if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH)
{
switch(uMsg)
{
/
case WM_SYSCOMMAND:
/
{
UINT cmd = LOWORD(wParam);
if (cmd == SC_CLOSE)
getEventQueue()->closeWindow(eventTime);//压入事件
break;
}
/
case WM_NCLBUTTONUP:
/
{
UINT cmd = LOWORD(wParam);
if (cmd == HTCLOSE)
getEventQueue()->closeWindow(eventTime);//压入事件
break;
}
default: break;
}
return TRUE;
}
再由最好的osg事件获取eventTraversal(),如下:
void ViewerBase::frame(double simulationTime)
{
if (_done) return;
// OSG_NOTICE<<std::endl<<"CompositeViewer::frame()"<<std::endl<<std::endl;
if (_firstFrame)
{
viewerInit();
if (!isRealized())
{
realize();
}
_firstFrame = false;
}
advance(simulationTime);
eventTraversal();//事件获取
updateTraversal();
renderingTraversals();
}
由于窗口可能不是全屏,所以需要先处理,把全局鼠标坐标变为窗口的局部坐标。
void Viewer::eventTraversal()
{
if (_done) return;
double cutOffTime = _frameStamp->getReferenceTime();
double beginEventTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
// OSG_NOTICE<<"Viewer::frameEventTraversal()."<<std::endl;
// need to copy events from the GraphicsWindow's into local EventQueue;
osgGA::EventQueue::Events events;
Contexts contexts;
getContexts(contexts);
// set done if there are no windows
checkWindowStatus(contexts);
if (_done) return;
osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState();
// get events from user Devices attached to Viewer.
for(Devices::iterator eitr = _eventSources.begin();
eitr != _eventSources.end();
++eitr)
{
osgGA::Device* es = eitr->get();
if (es->getCapabilities() & osgGA::Device::RECEIVE_EVENTS)
es->checkEvents();
// open question, will we need to reproject mouse coordinates into current view's coordinate frame as is down for GraphicsWindow provided events?
// for now assume now and just get the events directly without any reprojection.
es->getEventQueue()->takeEvents(events, cutOffTime);
}
// get events from all windows attached to Viewer.
for(Contexts::iterator citr = contexts.begin();
citr != contexts.end();
++citr)
{
osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(*citr);
if (gw)
{
gw->checkEvents();
osgGA::EventQueue::Events gw_events;
gw->getEventQueue()->takeEvents(gw_events, cutOffTime);
osgGA::EventQueue::Events::iterator itr;
for(itr = gw_events.begin();
itr != gw_events.end();
++itr)
{
osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter();
if (!event) continue;
event->setGraphicsContext(gw);
switch(event->getEventType())
{
case(osgGA::GUIEventAdapter::PUSH):
case(osgGA::GUIEventAdapter::RELEASE):
case(osgGA::GUIEventAdapter::DOUBLECLICK):
case(osgGA::GUIEventAdapter::MOVE):
case(osgGA::GUIEventAdapter::DRAG):
{
if (event->getEventType()!=osgGA::GUIEventAdapter::DRAG ||
eventState->getGraphicsContext()!=event->getGraphicsContext() ||
eventState->getNumPointerData()<2)
{
generatePointerData(*event);
}
else
{
reprojectPointerData(*eventState, *event);
}
eventState->copyPointerDataFrom(*event);
break;
}
default:
event->copyPointerDataFrom(*eventState);
break;
}
events.push_back(event);
}
for(itr = gw_events.begin();
itr != gw_events.end();
++itr)
{
osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter();
if (!event) continue;
switch(event->getEventType())
{
case(osgGA::GUIEventAdapter::CLOSE_WINDOW):
{
bool wasThreading = areThreadsRunning();
if (wasThreading) stopThreading();
gw->close();
_currentContext = NULL;
if (wasThreading) startThreading();
break;
}
default:
break;
}
}
}
}
// create a frame event for the new frame.
{
osg::ref_ptr<osgGA::GUIEventAdapter> event = _eventQueue->frame( getFrameStamp()->getReferenceTime() );
if (!eventState || eventState->getNumPointerData()<2)
{
generatePointerData(*event);
}
else
{
reprojectPointerData(*eventState, *event);
}
}
// OSG_NOTICE<<"mouseEventState Xmin = "<<eventState->getXmin()<<" Ymin="<<eventState->getYmin()<<" xMax="<<eventState->getXmax()<<" Ymax="<<eventState->getYmax()<<std::endl;
_eventQueue->takeEvents(events, cutOffTime);
// OSG_NOTICE<<"Events "<<events.size()<<std::endl;
if ((_keyEventSetsDone!=0) || _quitEventSetsDone)
{
for(osgGA::EventQueue::Events::iterator itr = events.begin();
itr != events.end();
++itr)
{
osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter();
if (!event) continue;
// ignore event if it's already been handled.
if (event->getHandled()) continue;
switch(event->getEventType())
{
case(osgGA::GUIEventAdapter::KEYUP):
if (_keyEventSetsDone && event->getKey()==_keyEventSetsDone) _done = true;
break;
case(osgGA::GUIEventAdapter::QUIT_APPLICATION):
if (_quitEventSetsDone) _done = true;
break;
default:
break;
}
}
}
if (_done) return;
if (_eventVisitor.valid() && getSceneData())
{
_eventVisitor->setFrameStamp(getFrameStamp());
_eventVisitor->setTraversalNumber(getFrameStamp()->getFrameNumber());
for(osgGA::EventQueue::Events::iterator itr = events.begin();
itr != events.end();
++itr)
{
osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter();
if (!event) continue;
_eventVisitor->reset();
_eventVisitor->addEvent( event );
getSceneData()->accept(*_eventVisitor);
// Do EventTraversal for slaves with their own subgraph
for(unsigned int i=0; i<getNumSlaves(); ++i)
{
osg::View::Slave& slave = getSlave(i);
osg::Camera* camera = slave._camera.get();
if(camera && !slave._useMastersSceneData)
{
camera->accept(*_eventVisitor);
}
}
// call any camera event callbacks, but only traverse that callback, don't traverse its subgraph
// leave that to the scene update traversal.
osg::NodeVisitor::TraversalMode tm = _eventVisitor->getTraversalMode();
_eventVisitor->setTraversalMode(osg::NodeVisitor::TRAVERSE_NONE);
if (_camera.valid()) _camera->accept(*_eventVisitor);
for(unsigned int i=0; i<getNumSlaves(); ++i)
{
osg::View::Slave& slave = getSlave(i);
osg::Camera* camera = slave._camera.get();
if (camera && slave._useMastersSceneData)
{
camera->accept(*_eventVisitor);
}
}
_eventVisitor->setTraversalMode(tm);
}
}
for(osgGA::EventQueue::Events::iterator itr = events.begin();
itr != events.end();
++itr)
{
osgGA::Event* event = itr->get();
for(EventHandlers::iterator hitr = _eventHandlers.begin();
hitr != _eventHandlers.end();
++hitr)
{
(*hitr)->handle( event, 0, _eventVisitor.get());
}
}
遍历所有我们自定义的事件接收器,并把事件给到handle函数中。我们就可以使用了。