[XCB] Add tests to cover text events from key presses
Signed-off-by: Chris Burel <burelc@amazon.com>
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
inline testing::PolymorphicMatcher<testing::internal::StrEqualityMatcher<AZStd::string>> StrEq(const AZStd::string& str)
|
||||
{
|
||||
return ::testing::MakePolymorphicMatcher(testing::internal::StrEqualityMatcher<AZStd::string>(str, true, true));
|
||||
}
|
||||
@@ -103,5 +103,17 @@ int xkb_state_key_get_utf8(xkb_state* state, xkb_keycode_t key, char* buffer, si
|
||||
{
|
||||
return MockXcbInterface::Instance()->xkb_state_key_get_utf8(state, key, buffer, size);
|
||||
}
|
||||
xkb_state_component xkb_state_update_mask(
|
||||
xkb_state* state,
|
||||
xkb_mod_mask_t depressed_mods,
|
||||
xkb_mod_mask_t latched_mods,
|
||||
xkb_mod_mask_t locked_mods,
|
||||
xkb_layout_index_t depressed_layout,
|
||||
xkb_layout_index_t latched_layout,
|
||||
xkb_layout_index_t locked_layout)
|
||||
{
|
||||
return MockXcbInterface::Instance()->xkb_state_update_mask(
|
||||
state, depressed_mods, latched_mods, locked_mods, depressed_layout, latched_layout, locked_layout);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,14 +36,7 @@ struct xkb_keymap
|
||||
|
||||
struct xkb_state
|
||||
{
|
||||
enum class Modifier
|
||||
{
|
||||
None = 0,
|
||||
Shift = 1,
|
||||
Ctrl = 1 << 1,
|
||||
Alt = 1 << 2,
|
||||
};
|
||||
Modifier m_modifiers;
|
||||
xkb_mod_mask_t m_modifiers{};
|
||||
};
|
||||
|
||||
class MockXcbInterface
|
||||
@@ -87,7 +80,8 @@ public:
|
||||
MOCK_CONST_METHOD1(xkb_keymap_unref, void(xkb_keymap* keymap));
|
||||
MOCK_CONST_METHOD1(xkb_state_unref, void(xkb_state* state));
|
||||
MOCK_CONST_METHOD2(xkb_state_key_get_one_sym, xkb_keysym_t(xkb_state* state, xkb_keycode_t key));
|
||||
MOCK_CONST_METHOD4(xkb_state_key_get_utf8, int(struct xkb_state* state, xkb_keycode_t key, char* buffer, size_t size));
|
||||
MOCK_CONST_METHOD4(xkb_state_key_get_utf8, int(xkb_state* state, xkb_keycode_t key, char* buffer, size_t size));
|
||||
MOCK_CONST_METHOD7(xkb_state_update_mask, xkb_state_component(xkb_state* state, xkb_mod_mask_t depressed_mods, xkb_mod_mask_t latched_mods, xkb_mod_mask_t locked_mods, xkb_layout_index_t depressed_layout, xkb_layout_index_t latched_layout, xkb_layout_index_t locked_layout));
|
||||
|
||||
private:
|
||||
static inline MockXcbInterface* self = nullptr;
|
||||
|
||||
+228
-9
@@ -14,7 +14,9 @@
|
||||
|
||||
#include <AzFramework/XcbApplication.h>
|
||||
#include <AzFramework/XcbInputDeviceKeyboard.h>
|
||||
#include <AzFramework/Input/Buses/Notifications/InputTextNotificationBus.h>
|
||||
#include "MockXcbInterface.h"
|
||||
#include "Matchers.h"
|
||||
#include "Actions.h"
|
||||
#include "XcbBaseTestFixture.h"
|
||||
|
||||
@@ -58,7 +60,7 @@ namespace AzFramework
|
||||
Return(1)
|
||||
));
|
||||
|
||||
constexpr unsigned int xcbXkbSelectEventsSequence = 1;
|
||||
constexpr unsigned int xcbXkbSelectEventsSequence = 342;
|
||||
ON_CALL(m_interface, xcb_xkb_select_events(&m_connection, _, _, _, _, _, _, _))
|
||||
.WillByDefault(Return(xcb_void_cookie_t{/*.sequence = */ xcbXkbSelectEventsSequence}));
|
||||
ON_CALL(m_interface, xcb_request_check(&m_connection, testing::Field(&xcb_void_cookie_t::sequence, testing::Eq(xcbXkbSelectEventsSequence))))
|
||||
@@ -70,15 +72,64 @@ namespace AzFramework
|
||||
ON_CALL(m_interface, xkb_state_key_get_one_sym(&m_xkbState, s_keycodeForAKey))
|
||||
.WillByDefault(Return(XKB_KEY_a))
|
||||
;
|
||||
ON_CALL(m_interface, xkb_state_key_get_one_sym(&m_xkbState, s_keycodeForShiftLKey))
|
||||
.WillByDefault(Return(XKB_KEY_Shift_L))
|
||||
;
|
||||
|
||||
ON_CALL(m_interface, xkb_state_update_mask(&m_xkbState, _, _, _, _, _, _))
|
||||
.WillByDefault(testing::Invoke(this, &XcbInputDeviceKeyboardTests::UpdateStateMask));
|
||||
|
||||
ON_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForAKey, nullptr, 0))
|
||||
.WillByDefault(Return(1));
|
||||
ON_CALL(m_interface, xkb_state_key_get_utf8(m_matchesStateWithoutShift, s_keycodeForAKey, _, 2))
|
||||
.WillByDefault(DoAll(
|
||||
SetArgPointee<2>('a'),
|
||||
Return(1)
|
||||
));
|
||||
ON_CALL(m_interface, xkb_state_key_get_utf8(m_matchesStateWithShift, s_keycodeForAKey, _, 2))
|
||||
.WillByDefault(DoAll(
|
||||
SetArgPointee<2>('A'),
|
||||
Return(1)
|
||||
));
|
||||
}
|
||||
|
||||
private:
|
||||
xkb_state_component UpdateStateMask(
|
||||
xkb_state* state,
|
||||
xkb_mod_mask_t depressed_mods,
|
||||
xkb_mod_mask_t latched_mods,
|
||||
xkb_mod_mask_t locked_mods,
|
||||
xkb_layout_index_t depressed_layout,
|
||||
xkb_layout_index_t latched_layout,
|
||||
xkb_layout_index_t locked_layout)
|
||||
{
|
||||
state->m_modifiers = depressed_mods | locked_mods;
|
||||
return {};
|
||||
}
|
||||
|
||||
protected:
|
||||
xkb_context m_xkbContext{};
|
||||
xkb_keymap m_xkbKeymap{};
|
||||
xkb_state m_xkbState{};
|
||||
const testing::Matcher<xkb_state*> m_matchesStateWithoutShift = testing::AllOf(&m_xkbState, testing::Field(&xkb_state::m_modifiers, 0));
|
||||
const testing::Matcher<xkb_state*> m_matchesStateWithShift = testing::AllOf(&m_xkbState, testing::Field(&xkb_state::m_modifiers, XCB_MOD_MASK_SHIFT));
|
||||
|
||||
static constexpr int32_t s_coreDeviceId{1};
|
||||
static constexpr uint8_t s_xkbEventCode{85};
|
||||
|
||||
static constexpr xcb_keycode_t s_keycodeForAKey{38};
|
||||
static constexpr xcb_keycode_t s_keycodeForShiftLKey{50};
|
||||
};
|
||||
|
||||
class InputTextNotificationListener
|
||||
: public InputTextNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
InputTextNotificationListener()
|
||||
{
|
||||
BusConnect();
|
||||
}
|
||||
MOCK_METHOD2(OnInputTextEvent, void(const AZStd::string& /*textUTF8*/, bool& /*o_hasBeenConsumed*/));
|
||||
};
|
||||
|
||||
TEST_F(XcbInputDeviceKeyboardTests, InputChannelsUpdateStateFromXcbEvents)
|
||||
@@ -140,14 +191,6 @@ namespace AzFramework
|
||||
EXPECT_CALL(m_interface, xkb_state_key_get_one_sym(&m_xkbState, s_keycodeForAKey))
|
||||
.Times(2);
|
||||
|
||||
EXPECT_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForAKey, nullptr, 0))
|
||||
.WillRepeatedly(Return(1));
|
||||
EXPECT_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForAKey, _, 2))
|
||||
.WillRepeatedly(DoAll(
|
||||
SetArgPointee<2>('a'),
|
||||
Return(1)
|
||||
));
|
||||
|
||||
Application application;
|
||||
application.Start({}, {});
|
||||
|
||||
@@ -169,4 +212,180 @@ namespace AzFramework
|
||||
|
||||
application.Stop();
|
||||
}
|
||||
|
||||
TEST_F(XcbInputDeviceKeyboardTests, TextEnteredFromXcbKeyPressEvents)
|
||||
{
|
||||
using testing::DoAll;
|
||||
using testing::Eq;
|
||||
using testing::Return;
|
||||
using testing::SetArgPointee;
|
||||
using testing::_;
|
||||
|
||||
// press a
|
||||
// release a
|
||||
// press shift
|
||||
// press a
|
||||
// release a
|
||||
// release shift
|
||||
const AZStd::array events
|
||||
{
|
||||
MakeEvent(xcb_key_press_event_t{
|
||||
/*.response_type = */ XCB_KEY_PRESS,
|
||||
/*.detail = */ s_keycodeForAKey,
|
||||
/*.sequence = */ 0,
|
||||
/*.time = */ 0,
|
||||
/*.root = */ 0,
|
||||
/*.event = */ 0,
|
||||
/*.child = */ 0,
|
||||
/*.root_x = */ 0,
|
||||
/*.root_y = */ 0,
|
||||
/*.event_x = */ 0,
|
||||
/*.event_y = */ 0,
|
||||
/*.state = */ 0,
|
||||
/*.same_screen = */ 0,
|
||||
/*.pad0 = */ 0
|
||||
}),
|
||||
MakeEvent(xcb_key_release_event_t{
|
||||
/*.response_type = */ XCB_KEY_RELEASE,
|
||||
/*.detail = */ s_keycodeForAKey,
|
||||
/*.sequence = */ 0,
|
||||
/*.time = */ 0,
|
||||
/*.root = */ 0,
|
||||
/*.event = */ 0,
|
||||
/*.child = */ 0,
|
||||
/*.root_x = */ 0,
|
||||
/*.root_y = */ 0,
|
||||
/*.event_x = */ 0,
|
||||
/*.event_y = */ 0,
|
||||
/*.state = */ 0,
|
||||
/*.same_screen = */ 0,
|
||||
/*.pad0 = */ 0
|
||||
}),
|
||||
MakeEvent(xcb_xkb_state_notify_event_t{
|
||||
/*.response_type = */ s_xkbEventCode,
|
||||
/*.xkbType = */ XCB_XKB_STATE_NOTIFY,
|
||||
/*.sequence = */ 0,
|
||||
/*.time = */ 0,
|
||||
/*.deviceID = */ s_coreDeviceId,
|
||||
/*.mods = */ XCB_MOD_MASK_SHIFT,
|
||||
/*.baseMods = */ XCB_MOD_MASK_SHIFT,
|
||||
/*.latchedMods = */ 0,
|
||||
/*.lockedMods = */ 0,
|
||||
/*.group = */ 0,
|
||||
/*.baseGroup = */ 0,
|
||||
/*.latchedGroup = */ 0,
|
||||
/*.lockedGroup = */ 0,
|
||||
/*.compatState = */ XCB_MOD_MASK_SHIFT,
|
||||
/*.grabMods = */ XCB_MOD_MASK_SHIFT,
|
||||
/*.compatGrabMods = */ XCB_MOD_MASK_SHIFT,
|
||||
/*.lookupMods = */ XCB_MOD_MASK_SHIFT,
|
||||
/*.compatLoockupMods = */ XCB_MOD_MASK_SHIFT,
|
||||
/*.ptrBtnState = */ 0,
|
||||
/*.changed = */ 0,
|
||||
/*.keycode = */ s_keycodeForShiftLKey,
|
||||
/*.eventType = */ XCB_KEY_PRESS,
|
||||
/*.requestMajor = */ 0,
|
||||
/*.requestMinor = */ 0,
|
||||
}),
|
||||
MakeEvent(xcb_key_press_event_t{
|
||||
/*.response_type = */ XCB_KEY_PRESS,
|
||||
/*.detail = */ s_keycodeForAKey,
|
||||
/*.sequence = */ 0,
|
||||
/*.time = */ 0,
|
||||
/*.root = */ 0,
|
||||
/*.event = */ 0,
|
||||
/*.child = */ 0,
|
||||
/*.root_x = */ 0,
|
||||
/*.root_y = */ 0,
|
||||
/*.event_x = */ 0,
|
||||
/*.event_y = */ 0,
|
||||
/*.state = */ 0,
|
||||
/*.same_screen = */ 0,
|
||||
/*.pad0 = */ 0
|
||||
}),
|
||||
MakeEvent(xcb_key_release_event_t{
|
||||
/*.response_type = */ XCB_KEY_RELEASE,
|
||||
/*.detail = */ s_keycodeForAKey,
|
||||
/*.sequence = */ 0,
|
||||
/*.time = */ 0,
|
||||
/*.root = */ 0,
|
||||
/*.event = */ 0,
|
||||
/*.child = */ 0,
|
||||
/*.root_x = */ 0,
|
||||
/*.root_y = */ 0,
|
||||
/*.event_x = */ 0,
|
||||
/*.event_y = */ 0,
|
||||
/*.state = */ 0,
|
||||
/*.same_screen = */ 0,
|
||||
/*.pad0 = */ 0
|
||||
}),
|
||||
MakeEvent(xcb_xkb_state_notify_event_t{
|
||||
/*.response_type = */ s_xkbEventCode,
|
||||
/*.xkbType = */ XCB_XKB_STATE_NOTIFY,
|
||||
/*.sequence = */ 0,
|
||||
/*.time = */ 0,
|
||||
/*.deviceID = */ s_coreDeviceId,
|
||||
/*.mods = */ 0,
|
||||
/*.baseMods = */ 0,
|
||||
/*.latchedMods = */ 0,
|
||||
/*.lockedMods = */ 0,
|
||||
/*.group = */ 0,
|
||||
/*.baseGroup = */ 0,
|
||||
/*.latchedGroup = */ 0,
|
||||
/*.lockedGroup = */ 0,
|
||||
/*.compatState = */ 0,
|
||||
/*.grabMods = */ 0,
|
||||
/*.compatGrabMods = */ 0,
|
||||
/*.lookupMods = */ 0,
|
||||
/*.compatLoockupMods = */ 0,
|
||||
/*.ptrBtnState = */ 0,
|
||||
/*.changed = */ 0,
|
||||
/*.keycode = */ s_keycodeForShiftLKey,
|
||||
/*.eventType = */ XCB_KEY_RELEASE,
|
||||
/*.requestMajor = */ 0,
|
||||
/*.requestMinor = */ 0,
|
||||
}),
|
||||
};
|
||||
|
||||
// Set the expectations for the events that will be generated
|
||||
// nullptr entries represent when the event queue is empty, and will cause
|
||||
// PumpSystemEventLoopUntilEmpty to return
|
||||
// event pointers are freed by the calling code, so we malloc new copies
|
||||
// here
|
||||
EXPECT_CALL(m_interface, xcb_poll_for_event(&m_connection))
|
||||
.WillOnce(ReturnMalloc<xcb_generic_event_t>(events[0]))
|
||||
.WillOnce(Return(nullptr))
|
||||
.WillOnce(ReturnMalloc<xcb_generic_event_t>(events[1]))
|
||||
.WillOnce(Return(nullptr))
|
||||
.WillOnce(ReturnMalloc<xcb_generic_event_t>(events[2]))
|
||||
.WillOnce(ReturnMalloc<xcb_generic_event_t>(events[3]))
|
||||
.WillOnce(Return(nullptr))
|
||||
.WillOnce(ReturnMalloc<xcb_generic_event_t>(events[4]))
|
||||
.WillOnce(ReturnMalloc<xcb_generic_event_t>(events[5]))
|
||||
.WillRepeatedly(Return(nullptr))
|
||||
;
|
||||
|
||||
EXPECT_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForAKey, nullptr, 0))
|
||||
.Times(2);
|
||||
EXPECT_CALL(m_interface, xkb_state_key_get_utf8(m_matchesStateWithoutShift, s_keycodeForAKey, _, 2))
|
||||
.Times(1);
|
||||
EXPECT_CALL(m_interface, xkb_state_key_get_utf8(m_matchesStateWithShift, s_keycodeForAKey, _, 2))
|
||||
.Times(1);
|
||||
|
||||
InputTextNotificationListener textListener;
|
||||
EXPECT_CALL(textListener, OnInputTextEvent(StrEq("a"), _)).Times(1);
|
||||
EXPECT_CALL(textListener, OnInputTextEvent(StrEq("A"), _)).Times(1);
|
||||
|
||||
Application application;
|
||||
application.Start({}, {});
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
application.PumpSystemEventLoopUntilEmpty();
|
||||
application.TickSystem();
|
||||
application.Tick();
|
||||
}
|
||||
|
||||
application.Stop();
|
||||
}
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
set(FILES
|
||||
Actions.h
|
||||
Main.cpp
|
||||
Matchers.h
|
||||
MockXcbInterface.cpp
|
||||
MockXcbInterface.h
|
||||
Printers.cpp
|
||||
|
||||
Reference in New Issue
Block a user