Skip to content

Commit

Permalink
Emit key events from Scene3D (#224)
Browse files Browse the repository at this point in the history
* Emit key events from Scene3D

Signed-off-by: ahcorde <[email protected]>

* Make linters happy

Signed-off-by: ahcorde <[email protected]>

* Fix windows

Signed-off-by: ahcorde <[email protected]>

* Fix windows

Signed-off-by: ahcorde <[email protected]>

* Documentation, ign-utils PIMPL, small tweaks

Signed-off-by: Louise Poubel <[email protected]>

Co-authored-by: Louise Poubel <[email protected]>
  • Loading branch information
ahcorde and chapulina authored Jun 30, 2021
1 parent 2fc2862 commit a9ddfad
Show file tree
Hide file tree
Showing 6 changed files with 234 additions and 7 deletions.
41 changes: 41 additions & 0 deletions include/ignition/gui/GuiEvents.hh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <utility>
#include <vector>

#include <ignition/common/KeyEvent.hh>
#include <ignition/common/MouseEvent.hh>
#include <ignition/math/Vector2.hh>
#include <ignition/math/Vector3.hh>
Expand Down Expand Up @@ -310,6 +311,46 @@ namespace ignition
/// \brief Private data pointer
IGN_UTILS_IMPL_PTR(dataPtr)
};

/// \brief Event which is called to broadcast the key release within
/// the scene.
class IGNITION_GUI_VISIBLE KeyReleaseOnScene : public QEvent
{
/// \brief Constructor
/// \param[in] _key The key released event within the scene
public: explicit KeyReleaseOnScene(const common::KeyEvent &_key);

/// \brief Unique type for this event.
static const QEvent::Type kType = QEvent::Type(QEvent::MaxUser - 8);

/// \brief Get the released key within the scene that the user released.
/// \return The key code.
public: common::KeyEvent Key() const;

/// \internal
/// \brief Private data pointer
IGN_UTILS_IMPL_PTR(dataPtr)
};

/// \brief Event which is called to broadcast the key press within
/// the scene.
class IGNITION_GUI_VISIBLE KeyPressOnScene : public QEvent
{
/// \brief Constructor
/// \param[in] _key The pressed key within the scene
public: explicit KeyPressOnScene(const common::KeyEvent &_key);

/// \brief Unique type for this event.
static const QEvent::Type kType = QEvent::Type(QEvent::MaxUser - 9);

/// \brief Get the key within the scene that the user pressed
/// \return The key code.
public: common::KeyEvent Key() const;

/// \internal
/// \brief Private data pointer
IGN_UTILS_IMPL_PTR(dataPtr)
};
}
}
}
Expand Down
39 changes: 39 additions & 0 deletions src/GuiEvents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ class ignition::gui::events::RightClickOnScene::Implementation
public: common::MouseEvent mouse;
};

class ignition::gui::events::KeyReleaseOnScene::Implementation
{
/// \brief Key event
public: common::KeyEvent key;
};

class ignition::gui::events::KeyPressOnScene::Implementation
{
/// \brief Key event
public: common::KeyEvent key;
};

using namespace ignition;
using namespace gui;
using namespace events;
Expand Down Expand Up @@ -59,3 +71,30 @@ const common::MouseEvent &LeftClickOnScene::Mouse() const
return this->dataPtr->mouse;
}

/////////////////////////////////////////////////
KeyReleaseOnScene::KeyReleaseOnScene(
const common::KeyEvent &_key)
: QEvent(kType), dataPtr(utils::MakeImpl<Implementation>())
{
this->dataPtr->key = _key;
}

/////////////////////////////////////////////////
common::KeyEvent KeyReleaseOnScene::Key() const
{
return this->dataPtr->key;
}

/////////////////////////////////////////////////
KeyPressOnScene::KeyPressOnScene(
const common::KeyEvent &_key)
: QEvent(kType), dataPtr(utils::MakeImpl<Implementation>())
{
this->dataPtr->key = _key;
}

/////////////////////////////////////////////////
common::KeyEvent KeyPressOnScene::Key() const
{
return this->dataPtr->key;
}
34 changes: 34 additions & 0 deletions src/GuiEvents_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,40 @@ TEST(GuiEventsTest, RightClickOnScene)
EXPECT_FALSE(event.Mouse().Shift());
}

/////////////////////////////////////////////////
TEST(GuiEventsTest, KeyPressOnScene)
{
ignition::common::KeyEvent key;
key.SetKey(49);
key.SetControl(true);
key.SetAlt(false);
key.SetShift(false);
events::KeyPressOnScene event(key);

EXPECT_LT(QEvent::User, event.type());
EXPECT_EQ(49, event.Key().Key());
EXPECT_TRUE(event.Key().Control());
EXPECT_FALSE(event.Key().Shift());
EXPECT_FALSE(event.Key().Alt());
}

/////////////////////////////////////////////////
TEST(GuiEventsTest, KeyReleaseOnScene)
{
ignition::common::KeyEvent key;
key.SetKey(49);
key.SetControl(true);
key.SetAlt(true);
key.SetShift(true);
events::KeyReleaseOnScene event(key);

EXPECT_LT(QEvent::User, event.type());
EXPECT_EQ(49, event.Key().Key());
EXPECT_TRUE(event.Key().Control());
EXPECT_TRUE(event.Key().Shift());
EXPECT_TRUE(event.Key().Alt());
}

/////////////////////////////////////////////////
TEST(GuiEventsTest, DropdownMenuEnabled)
{
Expand Down
38 changes: 37 additions & 1 deletion src/plugins/scene3d/Scene3D.cc
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,8 @@ void IgnRenderer::HandleMouseEvent()
this->BroadcastHoverPos();
this->BroadcastLeftClick();
this->BroadcastRightClick();
this->BroadcastKeyPress();
this->BroadcastKeyRelease();
this->HandleMouseViewControl();
}

Expand Down Expand Up @@ -1010,7 +1012,7 @@ void IgnRenderer::HandleKeyRelease(QKeyEvent *_e)

std::lock_guard<std::mutex> lock(this->dataPtr->mutex);

this->dataPtr->keyEvent.SetKey(0);
this->dataPtr->keyEvent.SetKey(_e->key());

this->dataPtr->keyEvent.SetControl(
(_e->modifiers() & Qt::ControlModifier)
Expand Down Expand Up @@ -1084,6 +1086,28 @@ void IgnRenderer::BroadcastRightClick()
App()->sendEvent(App()->findChild<MainWindow *>(), &rightClickOnSceneEvent);
}

/////////////////////////////////////////////////
void IgnRenderer::BroadcastKeyRelease()
{
if (this->dataPtr->keyEvent.Type() == common::KeyEvent::RELEASE)
{
events::KeyReleaseOnScene keyRelease(this->dataPtr->keyEvent);
App()->sendEvent(App()->findChild<MainWindow *>(), &keyRelease);
this->dataPtr->keyEvent.SetType(common::KeyEvent::NO_EVENT);
}
}

/////////////////////////////////////////////////
void IgnRenderer::BroadcastKeyPress()
{
if (this->dataPtr->keyEvent.Type() == common::KeyEvent::PRESS)
{
events::KeyPressOnScene keyPress(this->dataPtr->keyEvent);
App()->sendEvent(App()->findChild<MainWindow *>(), &keyPress);
this->dataPtr->keyEvent.SetType(common::KeyEvent::NO_EVENT);
}
}

/////////////////////////////////////////////////
void IgnRenderer::Initialize()
{
Expand Down Expand Up @@ -1665,6 +1689,18 @@ void RenderWindowItem::wheelEvent(QWheelEvent *_e)
this->dataPtr->mouseEvent, math::Vector2d(scroll, scroll));
}

////////////////////////////////////////////////
void RenderWindowItem::keyPressEvent(QKeyEvent *_event)
{
this->HandleKeyPress(_event);
}

////////////////////////////////////////////////
void RenderWindowItem::keyReleaseEvent(QKeyEvent *_event)
{
this->HandleKeyRelease(_event);
}

////////////////////////////////////////////////
void RenderWindowItem::HandleKeyPress(QKeyEvent *_e)
{
Expand Down
12 changes: 12 additions & 0 deletions src/plugins/scene3d/Scene3D.hh
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ namespace plugins
/// \brief Broadcasts a right click within the scene
private: void BroadcastRightClick();

/// \brief Broadcasts the current key release
private: void BroadcastKeyRelease();

/// \brief Broadcasts the current key press
private: void BroadcastKeyPress();

/// \brief Retrieve the first point on a surface in the 3D scene hit by a
/// ray cast from the given 2D screen coordinates.
/// \param[in] _screenPos 2D coordinates on the screen, in pixels.
Expand Down Expand Up @@ -318,6 +324,12 @@ namespace plugins
// Documentation inherited
protected: virtual void wheelEvent(QWheelEvent *_e) override;

// Documentation inherited
protected: virtual void keyPressEvent(QKeyEvent *_event) override;

// Documentation inherited
protected: virtual void keyReleaseEvent(QKeyEvent *_event) override;

/// \brief Overrides the paint event to render the render engine
/// camera view
/// \param[in] _oldNode The node passed in previous updatePaintNode
Expand Down
77 changes: 71 additions & 6 deletions test/integration/scene3d.cc
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,19 @@ TEST(Scene3DTest, IGN_UTILS_TEST_ENABLED_ONLY_ON_LINUX(Events))
bool receivedLeftControlEvent{false};
bool receivedLeftShiftEvent{false};
bool receivedHoverEvent{false};
bool receivedKeyPressEvent{false};
bool receivedKeyPressEventAlt{false};
bool receivedKeyPressEventControl{false};
bool receivedKeyPressEventShift{false};
bool receivedKeyReleaseEvent{false};
bool receivedKeyReleaseEventAlt{false};
bool receivedKeyReleaseEventControl{false};
bool receivedKeyReleaseEventShift{false};

// Position vectors reported by click events
math::Vector3d leftClickPoint, rightClickPoint;
// key pressed or released
int keyPressedValue, keyReleasedValue;

// Helper to filter events
auto testHelper = std::make_unique<TestHelper>();
Expand Down Expand Up @@ -221,28 +231,72 @@ TEST(Scene3DTest, IGN_UTILS_TEST_ENABLED_ONLY_ON_LINUX(Events))
{
receivedHoverEvent = true;
}
else if (_event->type() == events::KeyReleaseOnScene::kType)
{
receivedKeyReleaseEvent = true;
auto keyReleased = static_cast<events::KeyReleaseOnScene*>(_event);
keyReleasedValue = keyReleased->Key().Key();
receivedKeyReleaseEventAlt = keyReleased->Key().Alt();
receivedKeyReleaseEventControl = keyReleased->Key().Control();
receivedKeyReleaseEventShift = keyReleased->Key().Shift();
}
else if (_event->type() == events::KeyPressOnScene::kType)
{
receivedKeyPressEvent = true;
auto keyPress = static_cast<events::KeyPressOnScene*>(_event);
keyPressedValue = keyPress->Key().Key();
receivedKeyPressEventAlt = keyPress->Key().Alt();
receivedKeyPressEventControl = keyPress->Key().Control();
receivedKeyPressEventShift = keyPress->Key().Shift();
}
};

int sleep = 0;
int maxSleep = 30;
while ((!receivedRenderEvent || !receivedRightEvent ||
!receivedLeftEvent || !receivedHoverEvent) && sleep < maxSleep)
while (!receivedRenderEvent && sleep < maxSleep)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
QCoreApplication::processEvents();

sleep++;
}
sleep = 0;
while (!receivedHoverEvent && sleep < maxSleep)
{
QTest::mouseMove(win->QuickWindow(), QPoint(70, 100), -1);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
QCoreApplication::processEvents();

sleep++;
}
sleep = 0;
while (!receivedRightEvent && sleep < maxSleep)
{
QTest::mouseClick(win->QuickWindow(), Qt::RightButton, Qt::ShiftModifier);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
QCoreApplication::processEvents();

sleep++;
}
sleep = 0;
while (!receivedLeftEvent && sleep < maxSleep)
{
QTest::mouseClick(win->QuickWindow(), Qt::LeftButton, Qt::AltModifier);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
QCoreApplication::processEvents();

sleep++;
}
sleep = 0;
while (!receivedKeyPressEvent && sleep < maxSleep)
{
QTest::keyPress(win->QuickWindow(), Qt::Key_A, Qt::AltModifier);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
QCoreApplication::processEvents();
sleep++;
}
sleep = 0;
while (!receivedKeyReleaseEvent && sleep < maxSleep)
{
QTest::keyRelease(win->QuickWindow(), Qt::Key_Escape, Qt::NoModifier);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
QCoreApplication::processEvents();
sleep++;
}

Expand All @@ -262,6 +316,17 @@ TEST(Scene3DTest, IGN_UTILS_TEST_ENABLED_ONLY_ON_LINUX(Events))
EXPECT_NEAR(11.942695, leftClickPoint.Y(), 1e-4);
EXPECT_NEAR(4.159424, leftClickPoint.Z(), 1e-4);

EXPECT_TRUE(receivedKeyReleaseEvent);
EXPECT_FALSE(receivedKeyReleaseEventAlt);
EXPECT_FALSE(receivedKeyReleaseEventControl);
EXPECT_FALSE(receivedKeyReleaseEventShift);
EXPECT_EQ(Qt::Key_Escape, keyReleasedValue);
EXPECT_TRUE(receivedKeyPressEvent);
EXPECT_TRUE(receivedKeyPressEventAlt);
EXPECT_FALSE(receivedKeyPressEventControl);
EXPECT_FALSE(receivedKeyPressEventShift);
EXPECT_EQ(Qt::Key_A, keyPressedValue);

// Cleanups
auto plugins = win->findChildren<Plugin *>();
for (auto & p : plugins)
Expand Down

0 comments on commit a9ddfad

Please sign in to comment.