3 Event systems have various pros and cons. iMSTK has one that it minimally uses internally. With iMSTK events, an object that has base class type EventObject may send and receive events.
5 The "connect" function is used to add a receiver/observer to a sender. There are two ways to observe a sender. Queued or direct.
7 - Direct: When the event is emitted, all direct observers are called immediately.
8 - It happens in sync. Sequentially. Does not return from the event emit until receivers are all called.
9 - It happens on the same thread it was emitted from.
10 - Queued: When the event is emitted, all queued observers receive the event in a message queue.
11 - It happens async. Handled sometime later. The observer must implement the pop and handle of the event.
12 - It can switch threads or even machines.
14 Consider a KeyboardDeviceClient. It may emit a KeyEvent.
17 std::shared_ptr<KeyboardDeviceClient> myKeyboardDevice = viewer->getKeyboardDevice();
18 connect<KeyEvent>(myKeyboardDevice, &KeyboardDeviceClient::keyPress,
21 printf("action %d occured on key %d\n", e->m_keyPressType, e->m_key);
25 This function is called immediately and on the same thread when the event happens.
27 Additionally you may direct connect to the function of an object instead of using a C++ lambda.
30 std::shared_ptr<KeyboardDeviceClient> myKeyboardDevice = viewer->getKeyboardDevice();
31 connect<KeyEvent>(myKeyboardDevice,
32 &KeyboardDeviceClient::keyPress,
34 &MyCustomObject::myCustomFunction);
37 Alternatively queue it to another object like so:
40 std::shared_ptr<KeyboardDeviceClient> myKeyboardDevice = viewer->getKeyboardDevice();
41 queueConnect<KeyEvent>(myKeyboardDevice, &KeyboardDeviceClient::keyPress, sceneManager,
44 printf("action %d occured on key %d\n", e->m_keyPressType, e->m_key);
48 In this case, the function is not run until sceneManager processes its event queue. SceneManager can process its event queue when it wants too.
50 ## Queued Event Example 1
52 Here a device is setup that will emit a button event and stapler is made to listen to it.
55 class StaplerObject : public SceneObject
58 void staple(ButtonEvent* e)
63 void update() override
73 // Setup default haptics manager
74 std::shared_ptr<DeviceManager> hapticManager = DeviceManagerFactory::makeDeviceManager();
75 std::shared_ptr<DeviceClient> deviceClient = hapticManager->makeDeviceClient();
78 auto stapler = std::make_shared<StaplerObject>();
79 scene->addSceneObject(stapler);
81 // Connect hapticClient buttonStateChanged event to stapler's staple slot
82 queueConnect<ButtonEvent>(hapticClient, &HapticDeviceClient::buttonStateChanged,
83 stapler, &StaplerObject::staple);
85 ... Setup SimulationManager and start ...
90 ## Queued Event Example 2
92 Here a custom event is emitted for a tool when the object is touching. Either directly handle the event, or queue it. Queuing is generally safer but not as fast.
95 class ToolObject : public SceneObject
98 SIGNAL(ToolObject, isTouching);
101 void update() override
103 if (geometry is touching)
104 this->postEvent(vent(ToolObject::isTouching()));
112 auto myToolObject = std::make_shared<ToolObject>();
113 scene->addSceneObject(myToolObject);
115 // We could queue it to anything, even another SceneObject, here we queue it
116 // directly to the sceneManager as we know it will handle its events every update
117 queueConnect<Event>(myToolObject, &ToolObject::isTouching, sceneManager,
120 // Do stuff for when it touches
123 ... Setup SimulationManager and start ...