Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emit key events from Scene3D #224

Merged
merged 8 commits into from
Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
mjcarroll marked this conversation as resolved.
Show resolved Hide resolved

/// \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