From c0b642682a57e828a111255f230184503d69cf60 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 20 Feb 2026 12:12:24 +0100 Subject: [PATCH] fix(core): fix keydown/up handling for LDML keyboards For LDML keyboards this change fixes the `emit_key` flag so that it has the same value for the KeyDown and the KeyUp event. This fixes some problems with stuck keys. Previously we would set `emit_key=TRUE` on KeyDown but `emit_key=FALSE` on KeyUp for frame keys. This caused Linux to never see the KeyUp event, resulting in a stuck key. Also add unit tests that verifies that the actions that we get after calling `km_core_process_event` are what we expect. Fixes: #15569 Fixes: #15550 --- core/src/km_core_processevent_api.cpp | 7 + core/src/ldml/ldml_processor.cpp | 59 ++- core/src/ldml/ldml_processor.hpp | 15 +- core/src/state.cpp | 3 +- core/src/state.hpp | 7 + .../tests/unit/km_core_keyboard_api.tests.cpp | 2 +- .../unit/km_core_process_event.tests.cpp | 355 ++++++++++++++++++ core/tests/unit/kmx/meson.build | 4 +- core/tests/unit/meson.build | 12 + 9 files changed, 434 insertions(+), 30 deletions(-) create mode 100644 core/tests/unit/km_core_process_event.tests.cpp diff --git a/core/src/km_core_processevent_api.cpp b/core/src/km_core_processevent_api.cpp index a2bca95ea8b..ade26653535 100644 --- a/core/src/km_core_processevent_api.cpp +++ b/core/src/km_core_processevent_api.cpp @@ -50,6 +50,9 @@ km_core_process_event(km_core_state *state, if(state == nullptr) { return KM_CORE_STATUS_INVALID_ARGUMENT; } + if (vk == KM_CORE_VKEY_BKSP && is_key_down) { + state->set_backspace_handled_internally(false); + } km_core_status status = state->processor().process_event(state, vk, modifier_state, is_key_down, event_flags); if (state_should_invalidate_context(state, vk, modifier_state, is_key_down, event_flags)) { @@ -78,6 +81,10 @@ km_core_process_event(km_core_state *state, state->apply_actions_and_merge_app_context(); + if (vk == KM_CORE_VKEY_BKSP) { + state->set_backspace_handled_internally(!state->action_struct().emit_keystroke); + } + return status; } diff --git a/core/src/ldml/ldml_processor.cpp b/core/src/ldml/ldml_processor.cpp index 17e4d634eba..031669fbe51 100644 --- a/core/src/ldml/ldml_processor.cpp +++ b/core/src/ldml/ldml_processor.cpp @@ -179,21 +179,20 @@ ldml_processor::process_event( ldml_state.clear(); try { - if (!is_key_down) { - process_key_up(ldml_state); - } else { - switch (vk) { - // Currently, only one VK gets spoecial treatment. - // Special handling for backspace VK - case KM_CORE_VKEY_BKSP: - process_backspace(ldml_state); - break; - default: - // all other VKs + switch (vk) { + // Currently, only one VK gets special treatment. + // Special handling for backspace VK + case KM_CORE_VKEY_BKSP: + process_backspace(ldml_state); + break; + default: + // all other VKs + if (is_key_down) { process_key_down(ldml_state); - } // end of switch - } // end of normal processing - + } else { + process_key_up(ldml_state); + } + } // end of switch // all key-up and key-down events end up here. // commit the ldml state into the core state ldml_state.commit(); @@ -210,11 +209,31 @@ void ldml_processor::process_key_up(ldml_event_state &ldml_state) const { // TODO-LDML: Implement caps lock handling - ldml_state.clear(); + + // Look up the key + bool found = false; + const std::u16string key_str = keys.lookup(ldml_state.get_vk(), ldml_state.get_modifier_state(), found); + + if (!found) { + ldml_state.emit_passthrough_keystroke(); + } } void ldml_processor::process_backspace(ldml_event_state &ldml_state) const { + if (ldml_state.get_modifier_state() & K_MODIFIERFLAG) { + // we never process modifier+bksp + ldml_state.emit_passthrough_keystroke(); + return; + } + + if (!ldml_state.is_key_down()) { + if (!ldml_state.get_state()->backspace_handled_internally()) { + ldml_state.emit_passthrough_keystroke(); + } + return; + } + if (!!bksp_transforms) { // process with an empty string via the bksp transforms auto matchedContext = process_output(ldml_state, std::u32string(), bksp_transforms.get()); @@ -243,7 +262,7 @@ void ldml_event_state::emit_backspace() { // else loop again assert(end.type != KM_CORE_CT_END); // inappropriate here. state->context().pop_back(); - } + } /* We couldn't find a character at end of context (context is empty), so we'll pass the backspace keystroke on to the app to process; the @@ -532,10 +551,10 @@ ldml_event_state::ldml_event_state( uint8_t i, uint16_t e) { this->state = s; - this->vk = v; - this->modifier_state = m; - this->is_key_down = i; - this->event_flags = e; + this->_vk = v; + this->_modifier_state = m; + this->_is_key_down = i; + this->_event_flags = e; actions.persist_options = new km_core_option_item[1]; actions.persist_options[0] = NULL_OPTIONS[0]; diff --git a/core/src/ldml/ldml_processor.hpp b/core/src/ldml/ldml_processor.hpp index 6bf8a8fa318..a10294cc329 100644 --- a/core/src/ldml/ldml_processor.hpp +++ b/core/src/ldml/ldml_processor.hpp @@ -176,12 +176,15 @@ class ldml_event_state { * @return the number of context items consumed */ size_t context_to_string(std::u32string &str, bool include_markers = true); + km_core_state* get_state() const { return state; } + + uint8_t is_key_down() const { return _is_key_down; } private: - km_core_virtual_key vk; - uint16_t modifier_state; - uint8_t is_key_down; - uint16_t event_flags; + km_core_virtual_key _vk; + uint16_t _modifier_state; + uint8_t _is_key_down; + uint16_t _event_flags; km_core_state *state; // our in-flight action struct. @@ -194,12 +197,12 @@ class ldml_event_state { // implementation km_core_virtual_key ldml_event_state::get_vk() const { - return vk; + return _vk; } uint16_t ldml_event_state::get_modifier_state() const { - return modifier_state; + return _modifier_state; } } // namespace core diff --git a/core/src/state.cpp b/core/src/state.cpp index c6142b34561..47f29d0a67f 100644 --- a/core/src/state.cpp +++ b/core/src/state.cpp @@ -52,6 +52,7 @@ state::state(km::core::abstract_processor & ap, km_core_option_item const *env) env->key, env->value); } + _backspace_handled_internally = false; _imx_callback = nullptr; _imx_object = nullptr; memset(const_cast(&_action_struct), 0, sizeof(km_core_actions)); @@ -117,4 +118,4 @@ void state::apply_actions_and_merge_app_context() { } this->_action_struct.deleted_context = km::core::get_deleted_context(app_context_for_deletion, this->_action_struct.code_points_to_delete); -} \ No newline at end of file +} diff --git a/core/src/state.hpp b/core/src/state.hpp index 49eea8ffd2f..fafe78edfa1 100644 --- a/core/src/state.hpp +++ b/core/src/state.hpp @@ -130,6 +130,7 @@ class state core::debug_items _debug_items; km_core_keyboard_imx_platform _imx_callback; void *_imx_object; + bool _backspace_handled_internally; public: state(core::abstract_processor & kb, km_core_option_item const *env); @@ -174,6 +175,12 @@ class state km_core_actions const &actions ); void apply_actions_and_merge_app_context(); + + // This is used to track whether the backspace key was handled internally + // during the keydown event. This is needed so that we can return the same + // value from the keyup event. Only used when processing KM_CORE_VKEY_BKSP. + void set_backspace_handled_internally(bool handled) { _backspace_handled_internally = handled; } + bool backspace_handled_internally() const { return _backspace_handled_internally; } }; } // namespace core } // namespace km diff --git a/core/tests/unit/km_core_keyboard_api.tests.cpp b/core/tests/unit/km_core_keyboard_api.tests.cpp index 06e604c023a..262390d7c69 100644 --- a/core/tests/unit/km_core_keyboard_api.tests.cpp +++ b/core/tests/unit/km_core_keyboard_api.tests.cpp @@ -18,7 +18,7 @@ class KmCoreKeyboardApiTests : public testing::Test { km_core_keyboard_dispose(this->keyboard); this->keyboard = nullptr; } - } + } }; TEST_F(KmCoreKeyboardApiTests, LoadFromBlob) { diff --git a/core/tests/unit/km_core_process_event.tests.cpp b/core/tests/unit/km_core_process_event.tests.cpp new file mode 100644 index 00000000000..67b84760b31 --- /dev/null +++ b/core/tests/unit/km_core_process_event.tests.cpp @@ -0,0 +1,355 @@ +/* + * Keyman is copyright (C) SIL Global. MIT License. + */ +#include +#include "path.hpp" +#include "state.hpp" +#include "kmx/kmx_processevent.h" + +#include "emscripten_filesystem.h" +#include "kmnkbd/action_items.hpp" +#include "load_kmx_file.hpp" + +using namespace km::core::kmx; +km::core::path test_dir; + +km_core_option_item test_env_opts[] = {KM_CORE_OPTIONS_END}; + +#define KEY_DOWN TRUE +#define KEY_UP FALSE + +struct TestData { + const char* test_name; + + const char* keyboard_name; + km_core_virtual_key vkey; + uint16_t modifier_state; + + // Initial context + km_core_cu const* context; + + // Whether keydown handled the event. Only relevant for keyup tests. + bool keydown_handled; + + // Expected actions for keydown and keyup + std::initializer_list keydown_actions; + std::initializer_list keyup_actions; +}; + +std::string GenerateTestName(const testing::TestParamInfo& info) { + return info.param.test_name; +} + +class ProcessEventTests : public testing::TestWithParam { +protected: + km_core_keyboard* keyboard = nullptr; + km_core_state* state = nullptr; + KMX_ProcessEvent process_event; + + void Initialize(TestData const& data) { + km::core::path kmxfile = km::core::path(test_dir / data.keyboard_name); + auto blob = km::tests::load_kmx_file(kmxfile.native().c_str()); + + EXPECT_EQ(km_core_keyboard_load_from_blob(kmxfile.stem().c_str(), blob.data(), blob.size(), &this->keyboard), KM_CORE_STATUS_OK); + EXPECT_EQ(km_core_state_create(this->keyboard, test_env_opts, &this->state), KM_CORE_STATUS_OK); + EXPECT_TRUE(this->process_event.Load(blob.data(), blob.size())); + if (data.context) { + EXPECT_EQ(km_core_state_context_set_if_needed(this->state, data.context), KM_CORE_CONTEXT_STATUS_UPDATED); + } + ((km::core::state*)this->state)->set_backspace_handled_internally(data.keydown_handled); + } + + void TearDown() override { + if (this->state) { + km_core_state_dispose(this->state); + this->state = nullptr; + } + if (this->keyboard) { + km_core_keyboard_dispose(this->keyboard); + this->keyboard = nullptr; + } + } +}; + +void print_all_action_items(km_core_state const* state) { + size_t n = 0; + auto act = km_core_state_action_items(state, &n); + std::cout << "Action items:" << std::endl; + for (size_t i = 0; i < n; i++) { + print_action_item("", *act++); + } + std::cout << "---------------" << std::endl; +} + +TEST_P(ProcessEventTests, ReturnsExpectedActionsForKeyDown) { + auto data = GetParam(); + Initialize(data); + EXPECT_EQ(km_core_process_event(this->state, data.vkey, data.modifier_state, + KEY_DOWN, KM_CORE_EVENT_FLAG_DEFAULT), KM_CORE_STATUS_OK); + // print_all_action_items(this->state); + EXPECT_TRUE(action_items(this->state, data.keydown_actions)); +} + +TEST_P(ProcessEventTests, ReturnsExpectedActionsForKeyUp) { + auto data = GetParam(); + Initialize(data); + EXPECT_EQ(km_core_process_event(this->state, data.vkey, data.modifier_state, KEY_UP, KM_CORE_EVENT_FLAG_DEFAULT), KM_CORE_STATUS_OK); + // print_all_action_items(this->state); + EXPECT_TRUE(action_items(this->state, data.keyup_actions)); +} + +union backspace_union { + km_core_backspace_item backspace; + uint32_t value; +}; +// const backspace_union backspace_with_context = {{KM_CORE_BT_CHAR, 'x'}}; +const backspace_union backspace_no_context = {{KM_CORE_BT_CHAR, 0}}; + +const TestData values[] = { + //-------------------------------------------------------------------- + // KMN + // Key with rule + {"KMN_VKey_A", "kmx/k_005___nul_with_initial_context.kmx", KM_CORE_VKEY_A, 0, u"x", true, + { // KeyDown + {KM_CORE_IT_CHAR, { 0, }, {'d'}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + {"KMN_Ctrl_VKey_A", "kmx/k_005___nul_with_initial_context.kmx", KM_CORE_VKEY_A, KM_CORE_MODIFIER_LCTRL, u"x", true, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Key without rule + {"KMN_VKey_X", "kmx/k_005___nul_with_initial_context.kmx", KM_CORE_VKEY_X, 0, u"x", true, + { // KeyDown + {KM_CORE_IT_CHAR, { 0, }, {'x'}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + {"KMN_Ctrl_VKey_X", "kmx/k_005___nul_with_initial_context.kmx", KM_CORE_VKEY_X, KM_CORE_MODIFIER_LCTRL, u"x", true, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Frame key without rule + {"KMN_VKey_Enter", "kmx/k_000___null_keyboard.kmx", KM_CORE_VKEY_ENTER, 0, u"x", false, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // // Backspace (with available context) + // // TODO: fix the implementation to make this test pass. Currently failing in KeyUp + // {"KMN_VKey_Backspace_Ctxt", "kmx/k_000___null_keyboard.kmx", KM_CORE_VKEY_BKSP, 0, u"x", true, + // { // KeyDown + // // Once we use C++ 20 we can use: + // //{KM_CORE_IT_BACK, { 0, }, {.backspace = {KM_CORE_BT_CHAR, 'x'}}}, + // {KM_CORE_IT_BACK, { 0, }, {backspace_with_context.value}}, + // {KM_CORE_IT_END} + // }, + // { // KeyUp + // {KM_CORE_IT_END} + // } + // }, + // Backspace (without context) + {"KMN_VKey_Backspace_NoCtxt", "kmx/k_000___null_keyboard.kmx", KM_CORE_VKEY_BKSP, 0, NULL, false, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Ctrl+Backspace (with context) + {"KMN_Ctrl_VKey_Backspace_Ctxt", "kmx/k_000___null_keyboard.kmx", KM_CORE_VKEY_BKSP, KM_CORE_MODIFIER_LCTRL, u"x", true, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Ctrl+Backspace (no context) + {"KMN_Ctrl_VKey_Backspace_NoCtxt", "kmx/k_000___null_keyboard.kmx", KM_CORE_VKEY_BKSP, KM_CORE_MODIFIER_LCTRL, NULL, false, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Modifier frame key + {"KMN_VKey_Shift", "kmx/k_000___null_keyboard.kmx", KM_CORE_VKEY_SHIFT, 0, u"x", false, + { // KeyDown + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_END} + } + }, + + //-------------------------------------------------------------------- + // LDML + // Key with rule + {"LDML_VKey_A", "ldml/keyboards/k_020_fr.kmx", KM_CORE_VKEY_A, 0, u"x", true, + { // KeyDown + {KM_CORE_IT_CHAR, { 0, }, {'q'}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_END} + } + }, + {"LDML_Ctrl_VKey_A", "ldml/keyboards/k_020_fr.kmx", KM_CORE_VKEY_A, KM_CORE_MODIFIER_LCTRL, u"x", true, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Key without rule + {"LDML_VKey_X", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_X, 0, u"x", true, + { // KeyDown + {KM_CORE_IT_END} // LDML: no output without rule + }, + { // KeyUp + {KM_CORE_IT_END} + } + }, + {"LDML_Ctrl_VKey_X", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_X, KM_CORE_MODIFIER_LCTRL, u"x", true, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} // LDML: no output without rule + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Frame key without rule + {"LDML_VKey_Enter", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_ENTER, 0, u"x", false, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Backspace (with available context) + {"LDML_VKey_Backspace_Ctxt", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_BKSP, 0, u"x", true, + { // KeyDown + // Once we use C++ 20 we can use: + //{KM_CORE_IT_BACK, { 0, }, {.backspace = {KM_CORE_BT_CHAR, 0}}}, + {KM_CORE_IT_BACK, { 0, }, {backspace_no_context.value}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_END} + } + }, + // Backspace (without context) + {"LDML_VKey_Backspace_NoCtxt", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_BKSP, 0, NULL, false, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Ctrl+Backspace (with context) + {"LDML_Ctrl_VKey_Backspace_Ctxt", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_BKSP, KM_CORE_MODIFIER_LCTRL, u"x", false, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Ctrl+Backspace (no context) + {"LDML_Ctrl_VKey_Backspace_NoCtxt", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_BKSP, KM_CORE_MODIFIER_LCTRL, NULL, false, + { // KeyDown + {KM_CORE_IT_INVALIDATE_CONTEXT, { 0, }, {0}}, + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, + // Modifier frame key + {"LDML_VKey_Shift", "ldml/keyboards/k_000_minimal_keyboard.kmx", KM_CORE_VKEY_SHIFT, 0, u"x", false, + { // KeyDown + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + }, + { // KeyUp + {KM_CORE_IT_EMIT_KEYSTROKE, { 0, }, {0}}, + {KM_CORE_IT_END} + } + }, +}; + +INSTANTIATE_TEST_SUITE_P(KMXProcessEvent, ProcessEventTests, testing::ValuesIn(values), GenerateTestName); + +// provide our own `main` so that we can get the path of the exe so that +// we have a well-defined location to find our test keyboards +int main(int argc, char** argv) { +#ifdef __EMSCRIPTEN__ + test_dir = get_wasm_file_path(km::core::path(argv[0]).parent()); +#else + test_dir = km::core::path(argv[0]).parent(); +#endif + std::cout << "test_dir=" << test_dir.c_str() << std::endl; + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/core/tests/unit/kmx/meson.build b/core/tests/unit/kmx/meson.build index 22158b6a834..71e2aed1b56 100644 --- a/core/tests/unit/kmx/meson.build +++ b/core/tests/unit/kmx/meson.build @@ -239,7 +239,7 @@ kbd_log = custom_target(test_kbd + '.kmx'.underscorify(), input: kbd_src, command: kmc_cmd + ['build', '--debug', '--no-compiler-version', '@INPUT@', '--out-file', kbd_obj] ) - test('imx_list', imx_e, depends: kbd_log, args: [kbd_obj] ) +test('imx_list', imx_e, depends: kbd_log, args: [kbd_obj] ) external_e = executable('ext_event_tests', ['kmx_external_event.tests.cpp', common_test_files], cpp_args: defns + warns, @@ -258,4 +258,4 @@ kbd_log = custom_target(test_kbd + '.kmx'.underscorify(), input: kbd_src, command: kmc_cmd + ['build', '--debug', '--no-compiler-version', '@INPUT@', '--out-file', kbd_obj] ) - test('ext_event', external_e, depends: kbd_log, args: [kbd_obj] ) +test('ext_event', external_e, depends: kbd_log, args: [kbd_obj] ) diff --git a/core/tests/unit/meson.build b/core/tests/unit/meson.build index 0637ace96e5..3861d459127 100644 --- a/core/tests/unit/meson.build +++ b/core/tests/unit/meson.build @@ -48,6 +48,18 @@ kmcorekeyboardapitests = executable('km_core_keyboard_api.tests', test('km-core-keyboard-api-tests', kmcorekeyboardapitests) +# tests for km_core_process_even +km_core_process_event_tests_exe = executable( + 'km_core_process_event_tests', + ['km_core_process_event.tests.cpp', common_test_files], + include_directories: [inc, libsrc], + cpp_args: defns + warns, + link_args: [ links, extra_link_args ], + dependencies: [icu_uc, icu_i18n, gtest_dep, gmock_dep], + objects: lib.extract_all_objects(recursive: false), +) +test('km_core_process_event', km_core_process_event_tests_exe) + subdir('json') subdir('utftest') subdir('kmnkbd')