/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include "OscReceivingDevice.hpp" #include #include #include #include #include #include #include "osc/OscPrintReceivedElements.h" #include "osc/OscHostEndianness.h" namespace OscDevice { template struct NativeTypeTraits { typedef T type; static T create(const std::vector& t) { return type(t); } }; template<> struct NativeTypeTraits { typedef osg::Vec2f type; static type create(const std::vector& t) { return type(t[0], t[1]); } }; template<> struct NativeTypeTraits { typedef osg::Vec3f type; static type create(const std::vector& t) { return type(t[0], t[1], t[2]); } }; template<> struct NativeTypeTraits { typedef osg::Vec4f type; static type create(const std::vector& t) { return type(t[0], t[1], t[2], t[3]); } }; template<> struct NativeTypeTraits { typedef osg::Matrixf type; static type create(const std::vector& t) { return type(&t.front()); } }; template<> struct NativeTypeTraits { typedef osg::Vec2d type; static type create(const std::vector& t) { return type(t[0], t[1]); } }; template<> struct NativeTypeTraits { typedef osg::Vec3d type; static type create(const std::vector& t) { return type(t[0], t[1], t[2]); } }; template<> struct NativeTypeTraits { typedef osg::Vec4d type; static type create(const std::vector& t) { return type(t[0], t[1], t[2], t[3]); } }; template<> struct NativeTypeTraits { typedef osg::Matrixd type; static type create(const std::vector& t) { return type(&t.front()); } }; class StandardRequestHandler : public OscReceivingDevice::RequestHandler { public: StandardRequestHandler(const std::string& request_handler, bool treat_first_argument_as_value_name) : OscReceivingDevice::RequestHandler(request_handler) , _treatFirstArgumentAsValueName(treat_first_argument_as_value_name) { } virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint); virtual void describeTo(std::ostream& out) const { out << getRequestPath() << ": add all transmitted arguments as ValueObjects to an event"; if (_treatFirstArgumentAsValueName) out << ", the first argument is used as the name of the value, if it's a string"; } private: void addArgumentToUdc(osg::UserDataContainer* udc, const std::string& key, const osc::ReceivedMessageArgumentIterator& itr); template bool addNativeTypeFromVector(osg::UserDataContainer* udc, const std::string& key, const std::vector& arr) { switch (arr.size()) { case 2: udc->setUserValue(key, NativeTypeTraits::create(arr)); return true; break; case 3: udc->setUserValue(key, NativeTypeTraits::create(arr)); return true; break; case 4: udc->setUserValue(key, NativeTypeTraits::create(arr)); return true; break; case 16: udc->setUserValue(key, NativeTypeTraits::create(arr)); return true; break; default: return false; } return false; } bool _treatFirstArgumentAsValueName; }; bool StandardRequestHandler::operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint) { try { std::string path = osgDB::getFilePath(full_request_path); std::string last_elem = osgDB::getSimpleFileName(full_request_path); osg::ref_ptr ea = getDevice()->getOrCreateUserDataEvent(); osg::UserDataContainer* udc = ea->getOrCreateUserDataContainer(); ea->setName(_treatFirstArgumentAsValueName ? full_request_path : path); udc->setName(ea->getName()); if (m.ArgumentCount() == 0) { return true; } // if we have only one argument, get it and save it to the udc else if (m.ArgumentCount() == 1) { addArgumentToUdc(udc, last_elem, m.ArgumentsBegin()); return true; } else { unsigned int i(0); osc::ReceivedMessageArgumentIterator start = m.ArgumentsBegin(); if ((_treatFirstArgumentAsValueName) && (start->TypeTag() == osc::STRING_TYPE_TAG)) { last_elem = start->AsString(); ++start; // if we hav only 2 arguments, then save the value and return if (m.ArgumentCount() == 2) { addArgumentToUdc(udc, last_elem, start); return true; } } std::vector float_vec; std::vector double_vec; bool mixed_arguments(false); for(osc::ReceivedMessageArgumentIterator itr = start; itr != m.ArgumentsEnd(); ++itr, ++i) { if(itr->TypeTag() == osc::FLOAT_TYPE_TAG) { float_vec.push_back(itr->AsFloat()); } else if(itr->TypeTag() == osc::DOUBLE_TYPE_TAG) { double_vec.push_back(itr->AsDouble()); } else if(itr->TypeTag() == osc::INT32_TYPE_TAG) { float_vec.push_back(itr->AsInt32()); } else { mixed_arguments = true; break; } } if (!mixed_arguments) { unsigned int sum = float_vec.size() + double_vec.size(); if (sum == float_vec.size()) { if (addNativeTypeFromVector(udc, last_elem, float_vec)) return true; } else if (sum == double_vec.size()) { if (addNativeTypeFromVector(udc, last_elem, double_vec)) return true; } } for(osc::ReceivedMessageArgumentIterator itr = start; itr != m.ArgumentsEnd(); ++itr, ++i) { std::ostringstream ss; ss << last_elem << "_" << i; addArgumentToUdc(udc, ss.str(), itr); } } return true; } catch(osc::Exception& e) { handleException(e); return false; } return false; } void StandardRequestHandler::addArgumentToUdc(osg::UserDataContainer* udc, const std::string& key, const osc::ReceivedMessageArgumentIterator& itr) { switch((*itr).TypeTag()) { case osc::TRUE_TYPE_TAG: udc->setUserValue(key, true); break; case osc::FALSE_TYPE_TAG: udc->setUserValue(key, false); break; case osc::INT32_TYPE_TAG: udc->setUserValue(key, (int)((*itr).AsInt32Unchecked())); break; case osc::FLOAT_TYPE_TAG: udc->setUserValue(key, (*itr).AsFloatUnchecked()); break; case osc::CHAR_TYPE_TAG: udc->setUserValue(key, (*itr).AsCharUnchecked()); break; case osc::RGBA_COLOR_TYPE_TAG: // TODO: should we convert the color to an osg::Vec4? udc->setUserValue(key, static_cast((*itr).AsRgbaColorUnchecked())); break; case osc::INT64_TYPE_TAG: // TODO 64bit ints not supported by ValueObject udc->setUserValue(key, static_cast((*itr).AsInt64Unchecked())); break; case osc::TIME_TAG_TYPE_TAG: // TODO 64bit ints not supported by ValueObject udc->setUserValue(key, static_cast((*itr).AsTimeTagUnchecked())); break; case osc::DOUBLE_TYPE_TAG: udc->setUserValue(key, (*itr).AsDoubleUnchecked()); break; case osc::STRING_TYPE_TAG: udc->setUserValue(key, std::string((*itr).AsStringUnchecked())); break; case osc::SYMBOL_TYPE_TAG: udc->setUserValue(key, std::string((*itr).AsSymbol())); break; default: break; } } class SetMouseInputRangeRequestHandler : public OscReceivingDevice::RequestHandler { public: SetMouseInputRangeRequestHandler() : OscReceivingDevice::RequestHandler("/osgga/mouse/set_input_range") { } virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint) { try { float x_min(-1.0f), y_min(-1.0f), x_max(1.0f), y_max(1.0f); osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); args >> x_min >> y_min >> x_max >> y_max >> osc::EndMessage; getDevice()->getEventQueue()->setMouseInputRange(x_min, y_min, x_max, y_max); return true; } catch(osc::Exception e) { handleException(e); } return false; } virtual void describeTo(std::ostream& out) const { out << getRequestPath() << "(float x_min, float y_min, float x_max, float y_max): sets the mouse-input-range" << std::dec; } }; class SetMouseOrientationRequestHandler : public OscReceivingDevice::RequestHandler { public: SetMouseOrientationRequestHandler() : OscReceivingDevice::RequestHandler("/osgga/mouse/y_orientation_increasing_upwards") { } virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint) { try { bool increasing_upwards(false); osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); args >>increasing_upwards >> osc::EndMessage; getDevice()->getEventQueue()->getCurrentEventState()->setMouseYOrientation( increasing_upwards ? osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS : osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS); return true; } catch(osc::Exception e) { handleException(e); } return false; } virtual void describeTo(std::ostream& out) const { out << getRequestPath() << "(float x_min, float y_min, float x_max, float y_max): sets the mouse-input-range" << std::dec; } }; class KeyCodeRequestHandler : public OscReceivingDevice::RequestHandler { public: KeyCodeRequestHandler(bool handle_key_press) : OscReceivingDevice::RequestHandler(std::string("/osgga/key/") + ((handle_key_press) ? "press" : "release")) , _handleKeyPress(handle_key_press) { } virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint) { try { osc::int32 keycode(0); osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); args >> keycode >> osc::EndMessage; if (_handleKeyPress) getDevice()->getEventQueue()->keyPress(keycode, getLocalTime()); else getDevice()->getEventQueue()->keyRelease(keycode, getLocalTime()); return true; } catch(osc::Exception e) { handleException(e); } return false; } virtual void describeTo(std::ostream& out) const { out << getRequestPath() << "(int keycode): send KEY_" << (_handleKeyPress ? "DOWN" : "UP"); } private: bool _handleKeyPress; }; class KeyPressAndReleaseRequestHandler : public OscReceivingDevice::RequestHandler { public: KeyPressAndReleaseRequestHandler() : OscReceivingDevice::RequestHandler("/osgga/key/press_and_release") { } virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint) { try { osc::int32 keycode(0); osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); args >> keycode >> osc::EndMessage; getDevice()->getEventQueue()->keyPress(keycode, getLocalTime()); getDevice()->getEventQueue()->keyRelease(keycode, getLocalTime()); return true; } catch(osc::Exception e) { handleException(e); } return false; } virtual void describeTo(std::ostream& out) const { out << getRequestPath() << "(int keycode): send KEY_DOWN and KEY_UP"; } private: bool _handleKeyPress; }; class MouseMotionRequestHandler : public OscReceivingDevice::RequestHandler { public: MouseMotionRequestHandler() : OscReceivingDevice::RequestHandler("/osgga/mouse/motion") , _lastX(0.0f) , _lastY(0.0f) { } virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint) { try { osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); args >> _lastX >> _lastY >> osc::EndMessage; getDevice()->getEventQueue()->mouseMotion(_lastX, _lastY, getLocalTime()); return true; } catch (osc::Exception e) { handleException(e); } return false; } virtual void describeTo(std::ostream& out) const { out << getRequestPath() << "(float x, float y): send mouse motion"; } float getLastX() const { return _lastX; } float getLastY() const { return _lastY; } private: float _lastX, _lastY; }; class MouseScrollRequestHandler : public OscReceivingDevice::RequestHandler { public: MouseScrollRequestHandler() : OscReceivingDevice::RequestHandler("/osgga/mouse/scroll") { } virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint) { try { osc::int32 sm(osgGA::GUIEventAdapter::SCROLL_NONE); float delta_x(0.0f), delta_y(0.0f); osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); args >> sm >> delta_x >> delta_y >> osc::EndMessage; if (sm != osgGA::GUIEventAdapter::SCROLL_NONE) getDevice()->getEventQueue()->mouseScroll((osgGA::GUIEventAdapter::ScrollingMotion)sm, getLocalTime()); if ((delta_x != 0.0f) || (delta_y != 0.0f)) getDevice()->getEventQueue()->mouseScroll2D(delta_x, delta_y, getLocalTime()); return true; } catch (osc::Exception e) { handleException(e); } return false; } virtual void describeTo(std::ostream& out) const { out << getRequestPath() << "(int scroll_motion, float x, float y): send mouse scroll-motion"; } }; class MouseButtonToggleRequestHandler : public OscReceivingDevice::RequestHandler { public: MouseButtonToggleRequestHandler(const std::string& btn_name, MouseMotionRequestHandler* mm_handler) : OscReceivingDevice::RequestHandler("/osgga/mouse/toggle/"+btn_name) , _mmHandler(mm_handler) , _btnNum(atoi(btn_name.c_str())) { } virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint) { float down(0.0f); try { osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); args >> down >> osc::EndMessage; if (down > 0) getDevice()->getEventQueue()->mouseButtonPress(_mmHandler->getLastX(), _mmHandler->getLastY(), _btnNum, getLocalTime()); else getDevice()->getEventQueue()->mouseButtonRelease(_mmHandler->getLastX(), _mmHandler->getLastY(), _btnNum, getLocalTime()); return true; } catch (osc::Exception e) { handleException(e); } return false; } virtual void describeTo(std::ostream& out) const { out << getRequestPath() << "(float down): toggle mouse button"; } private: osg::observer_ptr _mmHandler; int _btnNum; }; class MouseButtonRequestHandler : public OscReceivingDevice::RequestHandler { public: enum Mode { PRESS, RELEASE, DOUBLE_PRESS}; MouseButtonRequestHandler(Mode mode) : OscReceivingDevice::RequestHandler("") , _mode(mode) { switch(mode) { case PRESS: setRequestPath("/osgga/mouse/press"); break; case RELEASE: setRequestPath("/osgga/mouse/release"); break; case DOUBLE_PRESS: setRequestPath("/osgga/mouse/doublepress"); break; } } virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint) { float x(0.0f), y(0.0f); osc::int32 btn(0); try { osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); args >> x >> y >> btn >> osc::EndMessage; switch (_mode) { case PRESS: getDevice()->getEventQueue()->mouseButtonPress(x,y, btn, getLocalTime()); break; case RELEASE: getDevice()->getEventQueue()->mouseButtonRelease(x,y, btn, getLocalTime()); break; case DOUBLE_PRESS: getDevice()->getEventQueue()->mouseDoubleButtonPress(x,y, btn, getLocalTime()); break; } return true; } catch (osc::Exception e) { handleException(e); } return false; } virtual void describeTo(std::ostream& out) const { out << getRequestPath() << "(float x, float y, int btn): send mouse "; switch (_mode) { case PRESS: out << "press"; break; case RELEASE: out << "release"; break; case DOUBLE_PRESS: out << "double press"; break; } } private: Mode _mode; }; class PenPressureRequestHandler : public OscReceivingDevice::RequestHandler { public: PenPressureRequestHandler() : OscReceivingDevice::RequestHandler("/osgga/pen/pressure") { } virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint) { try { float pressure(0.0f); osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); args >> pressure >> osc::EndMessage; getDevice()->getEventQueue()->penPressure(pressure, getLocalTime()); return true; } catch (osc::Exception e) { handleException(e); } return false; } virtual void describeTo(std::ostream& out) const { out << getRequestPath() << "(float pressure): send pen pressure"; } }; class PenProximityRequestHandler : public OscReceivingDevice::RequestHandler { public: PenProximityRequestHandler(bool handle_enter) : OscReceivingDevice::RequestHandler(std::string("/osgga/pen/proximity/") + ((handle_enter) ? std::string("enter") : std::string("leave"))) , _handleEnter(handle_enter) { } virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint) { try { osc::int32 pt(osgGA::GUIEventAdapter::UNKNOWN); osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); args >> pt >> osc::EndMessage; getDevice()->getEventQueue()->penProximity((osgGA::GUIEventAdapter::TabletPointerType)pt, _handleEnter, getLocalTime()); return true; } catch (osc::Exception e) { handleException(e); } return false; } virtual void describeTo(std::ostream& out) const { out << getRequestPath() << "(int table_pointer_type): send pen proximity " << (_handleEnter ? "enter":"leave"); } private: bool _handleEnter; }; class PenOrientationRequestHandler : public OscReceivingDevice::RequestHandler { public: PenOrientationRequestHandler() : OscReceivingDevice::RequestHandler("/osgga/pen/orientation") { } virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint) { try { float rotation(0.0f), tilt_x(0.0f), tilt_y(0.0f); osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); args >> rotation >> tilt_x >> tilt_y >> osc::EndMessage; getDevice()->getEventQueue()->penOrientation(tilt_x, tilt_y, rotation, getLocalTime()); return true; } catch (osc::Exception e) { handleException(e); } return false; } virtual void describeTo(std::ostream& out) const { out << getRequestPath() << "(float rotation, float tilt_x, float tilt_y): send pen orientation"; } }; class TUIO2DCursorRequestHandler : public OscReceivingDevice::RequestHandler { public: struct Cursor { std::string end_point; unsigned int id, frameId; osg::Vec2f pos, vel; float accel; osgGA::GUIEventAdapter::TouchPhase phase; Cursor() : end_point(), id(0), frameId(0), pos(), vel(), accel(), phase(osgGA::GUIEventAdapter::TOUCH_UNKNOWN) {} }; struct EndpointData { std::string source; osc::int32 frameId; bool mayClearUnhandledPointer; std::set unhandled; }; typedef std::map EndpointDataMap; typedef std::map CursorMap; typedef std::map ApplicationCursorMap; typedef std::map SourceIdMap; TUIO2DCursorRequestHandler() : OscReceivingDevice::RequestHandler("/tuio/2Dcur") { } virtual void setDevice(OscReceivingDevice* device) { OscReceivingDevice::RequestHandler::setDevice(device); device->addHandleOnCheckEvents(this); } virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint) { // std::cout << m << std::endl; OpenThreads::ScopedLock lock(_mutex); std::string end_point(' ', IpEndpointName::ADDRESS_AND_PORT_STRING_LENGTH); remoteEndPoint.AddressAndPortAsString(&end_point[0]); osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); const char* str; args >> str; std::string what(str); if (what == "source") { args >> str; _endpointData[end_point].source = std::string(str); updateSourceIdMap(_endpointData[end_point].source); _endpointData[end_point].unhandled.clear(); _endpointData[end_point].mayClearUnhandledPointer = true; return true; } else if (what == "fseq") { args >> _endpointData[end_point].frameId; return true; } else { std::string source = _endpointData[end_point].source; unsigned int frame_id = _endpointData[end_point].frameId; if (what == "alive") { while (!args.Eos()) { osc::int32 id; args >> id; _endpointData[end_point].unhandled.insert(id); } return true; } else if (what == "set") { osc::int32 id; args >> id; if (_alive[source].find(id) == _alive[source].end()) { _alive[source][id] = Cursor(); } Cursor& c(_alive[source][id]); args >> c.pos.x() >> c.pos.y() >> c.vel.x() >> c.vel.y() >> c.accel >> osc::EndMessage; c.frameId = frame_id; c.end_point = end_point; _endpointData[end_point].unhandled.insert(id); return true; } } return false; } virtual void operator()(osgGA::EventQueue* queue) { // dispatch all touchpoints in one GUIEventAdapter OpenThreads::ScopedLock lock(_mutex); osg::ref_ptr event = NULL; for(ApplicationCursorMap::iterator i = _alive.begin(); i != _alive.end(); ++i) { const std::string& source(i->first); /* std::cout << source << ": "; for(std::set::iterator k = _endpointData[source].unhandled.begin(); k != _endpointData[source].unhandled.end(); ++k) { std::cout << *k << " "; } std::cout << std::endl; */ // remove all touchpoints which are not transmitted via alive-message, dispatching TOUCH_ENDED unsigned int source_id = getSourceId(source); std::vector to_delete; for(CursorMap::iterator k = i->second.begin(); k != i->second.end(); ++k) { EndpointData& endpoint_data(_endpointData[k->second.end_point]); /*if (!endpoint_data.mayClearUnhandledPointer) { continue; }*/ //create a unique touchpoint-id unsigned int touch_id = (source_id << 16) + k->first; std::set& unhandled(endpoint_data.unhandled); if ((unhandled.find(k->first) == unhandled.end())) { // std::cout << "deleting: " << k->first << " from " << k->second.end_point << std::endl; to_delete.push_back(k->first); float win_x = k->second.pos.x(); float win_y = k->second.pos.y(); if (!event) event = queue->touchEnded(touch_id, osgGA::GUIEventAdapter::TOUCH_ENDED, win_x, win_y, 1); else event->addTouchPoint(touch_id, osgGA::GUIEventAdapter::TOUCH_ENDED, win_x, win_y, 1); } } // remove "dead" cursors for(std::vector::iterator k = to_delete.begin(); k != to_delete.end(); ++k) { _alive[source].erase(i->second.find(*k)); } if (i->second.size() == 0) { // std::cout << "removing endpoint" << source << std::endl; // _alive.erase(_alive.find(source)); } } // send all alive touchpoints for(ApplicationCursorMap::iterator i = _alive.begin(); i != _alive.end(); ++i) { const std::string& source(i->first); unsigned int source_id = getSourceId(source); for(CursorMap::iterator k = i->second.begin(); k != i->second.end(); ++k) { unsigned int id = k->first; unsigned int touch_id = (source_id << 16) + id; Cursor& c(k->second); float win_x = c.pos.x(); float win_y = c.pos.y(); bool down = c.phase != osgGA::GUIEventAdapter::TOUCH_MOVED && c.phase != osgGA::GUIEventAdapter::TOUCH_STATIONERY; if(!event) { if(down) event = queue->touchBegan(touch_id, osgGA::GUIEventAdapter::TOUCH_BEGAN, win_x, win_y); else event = queue->touchMoved(touch_id, osgGA::GUIEventAdapter::TOUCH_MOVED, win_x, win_y); } else { event->addTouchPoint(touch_id, down ? osgGA::GUIEventAdapter::TOUCH_BEGAN : osgGA::GUIEventAdapter::TOUCH_MOVED, win_x, win_y); } c.phase = osgGA::GUIEventAdapter::TOUCH_MOVED; } } // adjust time + input range if (event) { event->setInputRange(0, 0, 1.0, 1.0); event->setTime(queue->getTime()); event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS); } } inline void updateSourceIdMap(const std::string& source) { if (_sourceIdMap.find(source) == _sourceIdMap.end()) _sourceIdMap[source] = _sourceIdMap.size(); } inline unsigned int getSourceId(const std::string& source) { return _sourceIdMap[source]; } private: EndpointDataMap _endpointData; ApplicationCursorMap _alive; OpenThreads::Mutex _mutex; SourceIdMap _sourceIdMap; }; } // end of namespace OscReceivingDevice::OscReceivingDevice(const std::string& server_address, int listening_port) : osgGA::Device() , OpenThreads::Thread() , osc::OscPacketListener() , _listeningAddress(server_address) , _listeningPort(listening_port) , _socket(NULL) , _map() , _lastMsgId(0) { setCapabilities(RECEIVE_EVENTS); OSG_NOTICE << "OscDevice :: listening on " << server_address << ":" << listening_port << " "; #ifdef OSC_HOST_LITTLE_ENDIAN OSG_NOTICE << "(little endian)"; #elif OSC_HOST_BIG_ENDIAN OSG_NOTICE << "(big endian)"; #endif OSG_NOTICE << std::endl; _socket = new UdpListeningReceiveSocket(IpEndpointName( server_address.c_str(), listening_port ), this); addRequestHandler(new OscDevice::KeyCodeRequestHandler(false)); addRequestHandler(new OscDevice::KeyCodeRequestHandler(true)); addRequestHandler(new OscDevice::KeyPressAndReleaseRequestHandler()); addRequestHandler(new OscDevice::SetMouseInputRangeRequestHandler()); addRequestHandler(new OscDevice::SetMouseOrientationRequestHandler()); OscDevice::MouseMotionRequestHandler* mm_handler = new OscDevice::MouseMotionRequestHandler(); addRequestHandler(mm_handler); addRequestHandler(new OscDevice::MouseButtonRequestHandler(OscDevice::MouseButtonRequestHandler::PRESS)); addRequestHandler(new OscDevice::MouseButtonRequestHandler(OscDevice::MouseButtonRequestHandler::RELEASE)); addRequestHandler(new OscDevice::MouseButtonRequestHandler(OscDevice::MouseButtonRequestHandler::DOUBLE_PRESS)); addRequestHandler(new OscDevice::MouseScrollRequestHandler()); addRequestHandler(new OscDevice::MouseButtonToggleRequestHandler("1", mm_handler)); addRequestHandler(new OscDevice::MouseButtonToggleRequestHandler("2", mm_handler)); addRequestHandler(new OscDevice::MouseButtonToggleRequestHandler("3", mm_handler)); addRequestHandler(new OscDevice::PenPressureRequestHandler()); addRequestHandler(new OscDevice::PenOrientationRequestHandler()); addRequestHandler(new OscDevice::PenProximityRequestHandler(true)); addRequestHandler(new OscDevice::PenProximityRequestHandler(false)); addRequestHandler(new OscDevice::TUIO2DCursorRequestHandler()); addRequestHandler(new OscDevice::StandardRequestHandler("/osg/set_user_value", true)); addRequestHandler(new OscDevice::StandardRequestHandler("", false)); // getEventQueue()->setFirstTouchEmulatesMouse(false); setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_LOW); start(); } OscReceivingDevice::~OscReceivingDevice() { _socket->AsynchronousBreak(); join(); delete _socket; } void OscReceivingDevice::run() { _socket->Run(); } void OscReceivingDevice::ProcessMessage( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint ) { std::string in_request_path(m.AddressPattern()); if (in_request_path == "/osc/msg_id") return; std::string request_path = in_request_path + "/"; std::size_t pos(std::string::npos); bool handled(false); do { pos = request_path.find_last_of('/', pos-1); if (pos != std::string::npos) { std::string mangled_path = request_path.substr(0, pos); std::pair range = _map.equal_range(mangled_path); for(RequestHandlerMap::iterator i = range.first; i != range.second; ++i) { // OSG_INFO << "OscDevice :: handling " << mangled_path << " with " << i->second << std::endl; if (i->second->operator()(mangled_path, in_request_path, m, remoteEndpoint) && !handled) handled = true; } } } while ((pos != std::string::npos) && (pos > 0) && !handled); } void OscReceivingDevice::ProcessBundle( const osc::ReceivedBundle& b, const IpEndpointName& remoteEndpoint ) { // find msg-id MsgIdType msg_id(0); for( osc::ReceivedBundle::const_iterator i = b.ElementsBegin(); i != b.ElementsEnd(); ++i ){ const osc::ReceivedMessage& m = osc::ReceivedMessage(*i); std::string address_pattern(m.AddressPattern()); if(address_pattern == "/osc/msg_id") { osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); args >> msg_id; break; } } if (msg_id) { osg::Timer_t now(osg::Timer::instance()->tick()); if (osg::Timer::instance()->delta_s(_lastMsgTimeStamp, now) > 0.5) { OSG_INFO << "OscReceiver :: resetting msg_id to 0 " << std::endl; _lastMsgId = 0; } _lastMsgTimeStamp = now; if (msg_id <= _lastMsgId) { // already handled // OSG_WARN << "OscReceiver :: message with lower id received: " << msg_id << std::endl; return; } else { if ((msg_id > _lastMsgId+1) && (_lastMsgId > 0)) { OSG_WARN << "OscReceiver :: missed " << (msg_id - _lastMsgId) << " messages, (" << msg_id << "/" << _lastMsgId << ")" << std::endl; } _lastMsgId = msg_id; } } for( osc::ReceivedBundle::const_iterator i = b.ElementsBegin(); i != b.ElementsEnd(); ++i ){ if( i->IsBundle() ) ProcessBundle( osc::ReceivedBundle(*i), remoteEndpoint ); else { ProcessMessage( osc::ReceivedMessage(*i), remoteEndpoint ); } } } void OscReceivingDevice::ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint ) { try { osc::OscPacketListener::ProcessPacket(data, size, remoteEndpoint); } catch(const osc::Exception& e) { OSG_WARN << "OscDevice :: could not process UDP-packet: " << e.what() << std::endl; } catch(...) { OSG_WARN << "OscDevice :: could not process UDP-packet because of an exception!" << std::endl; } if (_userDataEvent.valid()) { char address[IpEndpointName::ADDRESS_AND_PORT_STRING_LENGTH]; remoteEndpoint.AddressAndPortAsString(address); _userDataEvent->setUserValue("osc/remote_end_point", std::string(address)); _userDataEvent->setTime(getEventQueue()->getTime()); getEventQueue()->addEvent(_userDataEvent.get()); _userDataEvent = NULL; } } void OscReceivingDevice::addRequestHandler(RequestHandler* handler) { if (handler) { _map.insert(std::make_pair(handler->getRequestPath(), handler)); handler->setDevice(this); } } void OscReceivingDevice::describeTo(std::ostream& out) const { out << "OscDevice :: listening on " << _listeningAddress << ":" << _listeningPort << std::endl; out << std::endl; for(RequestHandlerMap::const_iterator i = _map.begin(); i != _map.end(); ++i) { const RequestHandler* handler(i->second.get()); out << "OscDevice :: "; handler->describeTo(out); out << std::endl; } }