From 8668d8b2fe9c4e2f7c7c4f057b3ea4c25b58fddd Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Wed, 6 Oct 2021 09:09:05 -0700 Subject: [PATCH] [XCB] Avoid emitting text events when a key press does not generate text Many keys will generate key press events but return an empty string from `xkb_state_key_get_utf8`, like modifier keys, arrow keys, function keys, etc. This checks if the string retrieved from such a key press is empty before emitting an associated text event for it, to avoid notifying a potentially large number of listeners about an empty string. Signed-off-by: Chris Burel --- .../AzFramework/XcbInputDeviceKeyboard.cpp | 9 +++- .../Xcb/XcbInputDeviceKeyboardTests.cpp | 54 ++++++++++++++++--- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp index 454313ec5b..de326df200 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp @@ -148,8 +148,13 @@ namespace AzFramework if (responseType == XCB_KEY_PRESS) { const auto* keyPress = reinterpret_cast(event); - - QueueRawTextEvent(TextFromKeycode(m_xkbState.get(), keyPress->detail)); + { + auto text = TextFromKeycode(m_xkbState.get(), keyPress->detail); + if (!text.empty()) + { + QueueRawTextEvent(AZStd::move(text)); + } + } if (const InputChannelId* key = InputChannelFromKeyEvent(keyPress->detail)) { diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp index c01cf1e7cd..3abbcdc564 100644 --- a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp @@ -91,6 +91,9 @@ namespace AzFramework SetArgPointee<2>('A'), Return(1) )); + + ON_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForShiftLKey, nullptr, 0)) + .WillByDefault(Return(0)); } private: @@ -261,6 +264,24 @@ namespace AzFramework /*.same_screen = */ 0, /*.pad0 = */ 0 }), + // Pressing a modifier key will generate a key press event followed + // by a state notify event + MakeEvent(xcb_key_press_event_t{ + /*.response_type = */ XCB_KEY_PRESS, + /*.detail = */ s_keycodeForShiftLKey, + /*.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, @@ -319,6 +340,22 @@ namespace AzFramework /*.same_screen = */ 0, /*.pad0 = */ 0 }), + MakeEvent(xcb_key_release_event_t{ + /*.response_type = */ XCB_KEY_RELEASE, + /*.detail = */ s_keycodeForShiftLKey, + /*.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, @@ -353,15 +390,17 @@ namespace AzFramework // 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(events[0])) + .WillOnce(ReturnMalloc(events[0])) // press a .WillOnce(Return(nullptr)) - .WillOnce(ReturnMalloc(events[1])) + .WillOnce(ReturnMalloc(events[1])) // release a .WillOnce(Return(nullptr)) - .WillOnce(ReturnMalloc(events[2])) - .WillOnce(ReturnMalloc(events[3])) + .WillOnce(ReturnMalloc(events[2])) // press shift + .WillOnce(ReturnMalloc(events[3])) // state notify shift is down + .WillOnce(ReturnMalloc(events[4])) // press a .WillOnce(Return(nullptr)) - .WillOnce(ReturnMalloc(events[4])) - .WillOnce(ReturnMalloc(events[5])) + .WillOnce(ReturnMalloc(events[5])) // release a + .WillOnce(ReturnMalloc(events[6])) // release shift + .WillOnce(ReturnMalloc(events[7])) // state notify shift is up .WillRepeatedly(Return(nullptr)) ; @@ -372,6 +411,9 @@ namespace AzFramework EXPECT_CALL(m_interface, xkb_state_key_get_utf8(m_matchesStateWithShift, s_keycodeForAKey, _, 2)) .Times(1); + EXPECT_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForShiftLKey, nullptr, 0)) + .Times(1); + InputTextNotificationListener textListener; EXPECT_CALL(textListener, OnInputTextEvent(StrEq("a"), _)).Times(1); EXPECT_CALL(textListener, OnInputTextEvent(StrEq("A"), _)).Times(1);