From c86ab582a7694f19015d9a287e76b04e635fff8d Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Thu, 4 Apr 2024 12:14:54 -0500 Subject: [PATCH 01/20] chore(core): reinstate context reset test in ldml - reverts 04a6e164d7c65df1d9e1496646332e1d933c188d for k_102_keytest.xml --- core/tests/unit/ldml/keyboards/k_102_keytest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/tests/unit/ldml/keyboards/k_102_keytest.xml b/core/tests/unit/ldml/keyboards/k_102_keytest.xml index 5b47eb5f155..907295bac40 100644 --- a/core/tests/unit/ldml/keyboards/k_102_keytest.xml +++ b/core/tests/unit/ldml/keyboards/k_102_keytest.xml @@ -2,7 +2,7 @@ From c91095f0caeb688b99a0e14e850fde3ed8bdc4d5 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Thu, 4 Apr 2024 17:12:26 -0500 Subject: [PATCH 02/20] fix(core): core to automatically reset context if a frame key pressed - update ldml test with an exception for k_102_keytest --- core/src/km_core_processevent_api.cpp | 4 + core/src/km_core_state_api.cpp | 29 ++- core/src/km_vkey_to_contextreset.hpp | 278 ++++++++++++++++++++++++++ core/src/kmx/kmx_consts.cpp | 272 ------------------------- core/src/kmx/kmx_processevent.cpp | 2 - core/src/kmx/kmx_processevent.h | 3 - core/src/state.hpp | 13 ++ core/tests/unit/ldml/ldml.cpp | 21 +- 8 files changed, 336 insertions(+), 286 deletions(-) create mode 100644 core/src/km_vkey_to_contextreset.hpp diff --git a/core/src/km_core_processevent_api.cpp b/core/src/km_core_processevent_api.cpp index 7d48979cc4a..4b5b1fd715f 100644 --- a/core/src/km_core_processevent_api.cpp +++ b/core/src/km_core_processevent_api.cpp @@ -52,6 +52,10 @@ km_core_process_event(km_core_state *state, } km_core_status status = state->processor().process_event(state, vk, modifier_state, is_key_down, event_flags); + if (km_core_state_should_clear_context(state, vk, modifier_state, is_key_down, event_flags)) { + state->context().clear(); + } + state->apply_actions_and_merge_app_context(); return status; diff --git a/core/src/km_core_state_api.cpp b/core/src/km_core_state_api.cpp index 8b8807b1d24..7f12aa7a66a 100644 --- a/core/src/km_core_state_api.cpp +++ b/core/src/km_core_state_api.cpp @@ -24,6 +24,9 @@ using namespace km::core; +// pull in the reset table +#include "km_vkey_to_contextreset.hpp" + // Forward declarations class context; @@ -363,4 +366,28 @@ km_core_cp * km_core_state_context_debug( result[s.size()] = 0; return result; -} \ No newline at end of file +} + +bool +km_core_state_has_type(km_core_state *state, uint8_t type) { + return std::any_of( + state->actions().begin(), state->actions().end(), + [type](const km::core::action &a) { return a.type == type; }); +} + +bool +km_core_state_should_clear_context(km_core_state *state, + km_core_virtual_key vk, + uint16_t modifier_state, + uint8_t is_key_down, + uint16_t event_flags) { + // if emit_keystroke is present, check if a context reset is needed + if (km_core_state_has_type(state, KM_CORE_IT_EMIT_KEYSTROKE)) { + if (km::core::vkey_to_contextreset[vk]) { + return true; + } else if (vk == KM_CORE_VKEY_BKSP && km_core_state_has_type(state, KM_CORE_IT_BACK)) { + return true; + } + } + return false; +} diff --git a/core/src/km_vkey_to_contextreset.hpp b/core/src/km_vkey_to_contextreset.hpp new file mode 100644 index 00000000000..0f8ae7cf05c --- /dev/null +++ b/core/src/km_vkey_to_contextreset.hpp @@ -0,0 +1,278 @@ +#pragma once + +namespace km { +namespace core { + +static bool vkey_to_contextreset[256] = { + true, //L"K_?00", // &H0 + true, //L"K_LBUTTON", // &H1 + true, //L"K_RBUTTON", // &H2 + true, //L"K_CANCEL", // &H3 + true, //L"K_MBUTTON", // &H4 + true, //L"K_?05", // &H5 + true, //L"K_?06", // &H6 + true, //L"K_?07", // &H7 + true, //L"K_BKSP", // &H8 + true, //L"K_TAB", // &H9 + true, //L"K_?0A", // &HA + true, //L"K_?0B", // &HB + true, //L"K_KP5", // &HC + true, //L"K_ENTER", // &HD + true, //L"K_?0E", // &HE + true, //L"K_?0F", // &HF + false, //L"K_SHIFT", // &H10 + false, //L"K_CONTROL", // &H11 + false, //L"K_ALT", // &H12 + true, //L"K_PAUSE", // &H13 + false, //L"K_CAPS", // &H14 + true, //L"K_KANJI?15", // &H15 + true, //L"K_KANJI?16", // &H16 + true, //L"K_KANJI?17", // &H17 + true, //L"K_KANJI?18", // &H18 + true, //L"K_KANJI?19", // &H19 + true, //L"K_?1A", // &H1A + true, //L"K_ESC", // &H1B + true, //L"K_KANJI?1C", // &H1C + true, //L"K_KANJI?1D", // &H1D + true, //L"K_KANJI?1E", // &H1E + true, //L"K_KANJI?1F", // &H1F + false, //L"K_SPACE", // &H20 + true, //L"K_PGUP", // &H21 + true, //L"K_PGDN", // &H22 + true, //L"K_END", // &H23 + true, //L"K_HOME", // &H24 + true, //L"K_LEFT", // &H25 + true, //L"K_UP", // &H26 + true, //L"K_RIGHT", // &H27 + true, //L"K_DOWN", // &H28 + true, //L"K_SEL", // &H29 + true, //L"K_PRINT", // &H2A + true, //L"K_EXEC", // &H2B + true, //L"K_PRTSCN", // &H2C + false, //L"K_INS", // &H2D + true, //L"K_DEL", // &H2E + true, //L"K_HELP", // &H2F + false, //L"K_0", // &H30 + false, //L"K_1", // &H31 + false, //L"K_2", // &H32 + false, //L"K_3", // &H33 + false, //L"K_4", // &H34 + false, //L"K_5", // &H35 + false, //L"K_6", // &H36 + false, //L"K_7", // &H37 + false, //L"K_8", // &H38 + false, //L"K_9", // &H39 + false, //L"K_?3A", // &H3A + false, //L"K_?3B", // &H3B + false, //L"K_?3C", // &H3C + false, //L"K_?3D", // &H3D + false, //L"K_?3E", // &H3E + false, //L"K_?3F", // &H3F + false, //L"K_?40", // &H40 + + false, //L"K_A", // &H41 + false, //L"K_B", // &H42 + false, //L"K_C", // &H43 + false, //L"K_D", // &H44 + false, //L"K_E", // &H45 + false, //L"K_F", // &H46 + false, //L"K_G", // &H47 + false, //L"K_H", // &H48 + false, //L"K_I", // &H49 + false, //L"K_J", // &H4A + false, //L"K_K", // &H4B + false, //L"K_L", // &H4C + false, //L"K_M", // &H4D + false, //L"K_N", // &H4E + false, //L"K_O", // &H4F + false, //L"K_P", // &H50 + false, //L"K_Q", // &H51 + false, //L"K_R", // &H52 + false, //L"K_S", // &H53 + false, //L"K_T", // &H54 + false, //L"K_U", // &H55 + false, //L"K_V", // &H56 + false, //L"K_W", // &H57 + false, //L"K_X", // &H58 + false, //L"K_Y", // &H59 + false, //L"K_Z", // &H5A + false, //L"K_?5B", // &H5B + false, //L"K_?5C", // &H5C + false, //L"K_?5D", // &H5D + false, //L"K_?5E", // &H5E + false, //L"K_?5F", // &H5F + false, //L"K_NP0", // &H60 + false, //L"K_NP1", // &H61 + false, //L"K_NP2", // &H62 + false, //L"K_NP3", // &H63 + false, //L"K_NP4", // &H64 + false, //L"K_NP5", // &H65 + false, //L"K_NP6", // &H66 + false, //L"K_NP7", // &H67 + false, //L"K_NP8", // &H68 + false, //L"K_NP9", // &H69 + false, //L"K_NPSTAR", // &H6A + false, //L"K_NPPLUS", // &H6B + false, //L"K_SEPARATOR", // &H6C + false, //L"K_NPMINUS", // &H6D + false, //L"K_NPDOT", // &H6E + false, //L"K_NPSLASH", // &H6F + true, //L"K_F1", // &H70 + true, //L"K_F2", // &H71 + true, //L"K_F3", // &H72 + true, //L"K_F4", // &H73 + true, //L"K_F5", // &H74 + true, //L"K_F6", // &H75 + true, //L"K_F7", // &H76 + true, //L"K_F8", // &H77 + true, //L"K_F9", // &H78 + true, //L"K_F10", // &H79 + true, //L"K_F11", // &H7A + true, //L"K_F12", // &H7B + true, //L"K_F13", // &H7C + true, //L"K_F14", // &H7D + true, //L"K_F15", // &H7E + true, //L"K_F16", // &H7F + true, //L"K_F17", // &H80 + true, //L"K_F18", // &H81 + true, //L"K_F19", // &H82 + true, //L"K_F20", // &H83 + true, //L"K_F21", // &H84 + true, //L"K_F22", // &H85 + true, //L"K_F23", // &H86 + true, //L"K_F24", // &H87 + + false, //L"K_?88", // &H88 + false, //L"K_?89", // &H89 + false, //L"K_?8A", // &H8A + false, //L"K_?8B", // &H8B + false, //L"K_?8C", // &H8C + false, //L"K_?8D", // &H8D + false, //L"K_?8E", // &H8E + false, //L"K_?8F", // &H8F + + false, //L"K_NUMLOCK", // &H90 + false, //L"K_SCROLL", // &H91 + + false, //L"K_?92", // &H92 + false, //L"K_?93", // &H93 + false, //L"K_?94", // &H94 + false, //L"K_?95", // &H95 + false, //L"K_?96", // &H96 + false, //L"K_?97", // &H97 + false, //L"K_?98", // &H98 + false, //L"K_?99", // &H99 + false, //L"K_?9A", // &H9A + false, //L"K_?9B", // &H9B + false, //L"K_?9C", // &H9C + false, //L"K_?9D", // &H9D + false, //L"K_?9E", // &H9E + false, //L"K_?9F", // &H9F + false, //L"K_?A0", // &HA0 + false, //L"K_?A1", // &HA1 + false, //L"K_?A2", // &HA2 + false, //L"K_?A3", // &HA3 + false, //L"K_?A4", // &HA4 + false, //L"K_?A5", // &HA5 + false, //L"K_?A6", // &HA6 + false, //L"K_?A7", // &HA7 + false, //L"K_?A8", // &HA8 + false, //L"K_?A9", // &HA9 + false, //L"K_?AA", // &HAA + false, //L"K_?AB", // &HAB + false, //L"K_?AC", // &HAC + false, //L"K_?AD", // &HAD + false, //L"K_?AE", // &HAE + false, //L"K_?AF", // &HAF + false, //L"K_?B0", // &HB0 + false, //L"K_?B1", // &HB1 + false, //L"K_?B2", // &HB2 + false, //L"K_?B3", // &HB3 + false, //L"K_?B4", // &HB4 + false, //L"K_?B5", // &HB5 + false, //L"K_?B6", // &HB6 + false, //L"K_?B7", // &HB7 + false, //L"K_?B8", // &HB8 + false, //L"K_?B9", // &HB9 + + false, //L"K_COLON", // &HBA + false, //L"K_EQUAL", // &HBB + false, //L"K_COMMA", // &HBC + false, //L"K_HYPHEN", // &HBD + false, //L"K_PERIOD", // &HBE + false, //L"K_SLASH", // &HBF + false, //L"K_BKQUOTE", // &HC0 + + false, //L"K_?C1", // &HC1 + false, //L"K_?C2", // &HC2 + false, //L"K_?C3", // &HC3 + false, //L"K_?C4", // &HC4 + false, //L"K_?C5", // &HC5 + false, //L"K_?C6", // &HC6 + false, //L"K_?C7", // &HC7 + false, //L"K_?C8", // &HC8 + false, //L"K_?C9", // &HC9 + false, //L"K_?CA", // &HCA + false, //L"K_?CB", // &HCB + false, //L"K_?CC", // &HCC + false, //L"K_?CD", // &HCD + false, //L"K_?CE", // &HCE + false, //L"K_?CF", // &HCF + false, //L"K_?D0", // &HD0 + false, //L"K_?D1", // &HD1 + false, //L"K_?D2", // &HD2 + false, //L"K_?D3", // &HD3 + false, //L"K_?D4", // &HD4 + false, //L"K_?D5", // &HD5 + false, //L"K_?D6", // &HD6 + false, //L"K_?D7", // &HD7 + false, //L"K_?D8", // &HD8 + false, //L"K_?D9", // &HD9 + false, //L"K_?DA", // &HDA + + false, //L"K_LBRKT", // &HDB + false, //L"K_BKSLASH", // &HDC + false, //L"K_RBRKT", // &HDD + false, //L"K_QUOTE", // &HDE + false, //L"K_oDF", // &HDF + false, //L"K_oE0", // &HE0 + false, //L"K_oE1", // &HE1 + false, //L"K_oE2", // &HE2 + false, //L"K_oE3", // &HE3 + false, //L"K_oE4", // &HE4 + + false, //L"K_?E5", // &HE5 + + false, //L"K_oE6", // &HE6 + + false, //L"K_?E7", // &HE7 + false, //L"K_?E8", // &HE8 + + false, //L"K_oE9", // &HE9 + false, //L"K_oEA", // &HEA + false, //L"K_oEB", // &HEB + false, //L"K_oEC", // &HEC + false, //L"K_oED", // &HED + false, //L"K_oEE", // &HEE + false, //L"K_oEF", // &HEF + false, //L"K_oF0", // &HF0 + false, //L"K_oF1", // &HF1 + false, //L"K_oF2", // &HF2 + false, //L"K_oF3", // &HF3 + false, //L"K_oF4", // &HF4 + false, //L"K_oF5", // &HF5 + + false, //L"K_?F6", // &HF6 + false, //L"K_?F7", // &HF7 + false, //L"K_?F8", // &HF8 + false, //L"K_?F9", // &HF9 + false, //L"K_?FA", // &HFA + false, //L"K_?FB", // &HFB + false, //L"K_?FC", // &HFC + false, //L"K_?FD", // &HFD + false, //L"K_?FE", // &HFE + false, //L"K_?FF" // &HFF +}; + +} +} diff --git a/core/src/kmx/kmx_consts.cpp b/core/src/kmx/kmx_consts.cpp index ae9e7806896..009ef1a4433 100644 --- a/core/src/kmx/kmx_consts.cpp +++ b/core/src/kmx/kmx_consts.cpp @@ -104,278 +104,6 @@ const struct char_to_vkey s_char_to_vkey[] = { {0, 0, 0} }; -const bool vkey_to_contextreset[256] = { - true, //L"K_?00", // &H0 - true, //L"K_LBUTTON", // &H1 - true, //L"K_RBUTTON", // &H2 - true, //L"K_CANCEL", // &H3 - true, //L"K_MBUTTON", // &H4 - true, //L"K_?05", // &H5 - true, //L"K_?06", // &H6 - true, //L"K_?07", // &H7 - true, //L"K_BKSP", // &H8 - true, //L"K_TAB", // &H9 - true, //L"K_?0A", // &HA - true, //L"K_?0B", // &HB - true, //L"K_KP5", // &HC - true, //L"K_ENTER", // &HD - true, //L"K_?0E", // &HE - true, //L"K_?0F", // &HF - false, //L"K_SHIFT", // &H10 - false, //L"K_CONTROL", // &H11 - false, //L"K_ALT", // &H12 - true, //L"K_PAUSE", // &H13 - false, //L"K_CAPS", // &H14 - true, //L"K_KANJI?15", // &H15 - true, //L"K_KANJI?16", // &H16 - true, //L"K_KANJI?17", // &H17 - true, //L"K_KANJI?18", // &H18 - true, //L"K_KANJI?19", // &H19 - true, //L"K_?1A", // &H1A - true, //L"K_ESC", // &H1B - true, //L"K_KANJI?1C", // &H1C - true, //L"K_KANJI?1D", // &H1D - true, //L"K_KANJI?1E", // &H1E - true, //L"K_KANJI?1F", // &H1F - false, //L"K_SPACE", // &H20 - true, //L"K_PGUP", // &H21 - true, //L"K_PGDN", // &H22 - true, //L"K_END", // &H23 - true, //L"K_HOME", // &H24 - true, //L"K_LEFT", // &H25 - true, //L"K_UP", // &H26 - true, //L"K_RIGHT", // &H27 - true, //L"K_DOWN", // &H28 - true, //L"K_SEL", // &H29 - true, //L"K_PRINT", // &H2A - true, //L"K_EXEC", // &H2B - true, //L"K_PRTSCN", // &H2C - false, //L"K_INS", // &H2D - true, //L"K_DEL", // &H2E - true, //L"K_HELP", // &H2F - false, //L"K_0", // &H30 - false, //L"K_1", // &H31 - false, //L"K_2", // &H32 - false, //L"K_3", // &H33 - false, //L"K_4", // &H34 - false, //L"K_5", // &H35 - false, //L"K_6", // &H36 - false, //L"K_7", // &H37 - false, //L"K_8", // &H38 - false, //L"K_9", // &H39 - false, //L"K_?3A", // &H3A - false, //L"K_?3B", // &H3B - false, //L"K_?3C", // &H3C - false, //L"K_?3D", // &H3D - false, //L"K_?3E", // &H3E - false, //L"K_?3F", // &H3F - false, //L"K_?40", // &H40 - - false, //L"K_A", // &H41 - false, //L"K_B", // &H42 - false, //L"K_C", // &H43 - false, //L"K_D", // &H44 - false, //L"K_E", // &H45 - false, //L"K_F", // &H46 - false, //L"K_G", // &H47 - false, //L"K_H", // &H48 - false, //L"K_I", // &H49 - false, //L"K_J", // &H4A - false, //L"K_K", // &H4B - false, //L"K_L", // &H4C - false, //L"K_M", // &H4D - false, //L"K_N", // &H4E - false, //L"K_O", // &H4F - false, //L"K_P", // &H50 - false, //L"K_Q", // &H51 - false, //L"K_R", // &H52 - false, //L"K_S", // &H53 - false, //L"K_T", // &H54 - false, //L"K_U", // &H55 - false, //L"K_V", // &H56 - false, //L"K_W", // &H57 - false, //L"K_X", // &H58 - false, //L"K_Y", // &H59 - false, //L"K_Z", // &H5A - false, //L"K_?5B", // &H5B - false, //L"K_?5C", // &H5C - false, //L"K_?5D", // &H5D - false, //L"K_?5E", // &H5E - false, //L"K_?5F", // &H5F - false, //L"K_NP0", // &H60 - false, //L"K_NP1", // &H61 - false, //L"K_NP2", // &H62 - false, //L"K_NP3", // &H63 - false, //L"K_NP4", // &H64 - false, //L"K_NP5", // &H65 - false, //L"K_NP6", // &H66 - false, //L"K_NP7", // &H67 - false, //L"K_NP8", // &H68 - false, //L"K_NP9", // &H69 - false, //L"K_NPSTAR", // &H6A - false, //L"K_NPPLUS", // &H6B - false, //L"K_SEPARATOR", // &H6C - false, //L"K_NPMINUS", // &H6D - false, //L"K_NPDOT", // &H6E - false, //L"K_NPSLASH", // &H6F - true, //L"K_F1", // &H70 - true, //L"K_F2", // &H71 - true, //L"K_F3", // &H72 - true, //L"K_F4", // &H73 - true, //L"K_F5", // &H74 - true, //L"K_F6", // &H75 - true, //L"K_F7", // &H76 - true, //L"K_F8", // &H77 - true, //L"K_F9", // &H78 - true, //L"K_F10", // &H79 - true, //L"K_F11", // &H7A - true, //L"K_F12", // &H7B - true, //L"K_F13", // &H7C - true, //L"K_F14", // &H7D - true, //L"K_F15", // &H7E - true, //L"K_F16", // &H7F - true, //L"K_F17", // &H80 - true, //L"K_F18", // &H81 - true, //L"K_F19", // &H82 - true, //L"K_F20", // &H83 - true, //L"K_F21", // &H84 - true, //L"K_F22", // &H85 - true, //L"K_F23", // &H86 - true, //L"K_F24", // &H87 - - false, //L"K_?88", // &H88 - false, //L"K_?89", // &H89 - false, //L"K_?8A", // &H8A - false, //L"K_?8B", // &H8B - false, //L"K_?8C", // &H8C - false, //L"K_?8D", // &H8D - false, //L"K_?8E", // &H8E - false, //L"K_?8F", // &H8F - - false, //L"K_NUMLOCK", // &H90 - false, //L"K_SCROLL", // &H91 - - false, //L"K_?92", // &H92 - false, //L"K_?93", // &H93 - false, //L"K_?94", // &H94 - false, //L"K_?95", // &H95 - false, //L"K_?96", // &H96 - false, //L"K_?97", // &H97 - false, //L"K_?98", // &H98 - false, //L"K_?99", // &H99 - false, //L"K_?9A", // &H9A - false, //L"K_?9B", // &H9B - false, //L"K_?9C", // &H9C - false, //L"K_?9D", // &H9D - false, //L"K_?9E", // &H9E - false, //L"K_?9F", // &H9F - false, //L"K_?A0", // &HA0 - false, //L"K_?A1", // &HA1 - false, //L"K_?A2", // &HA2 - false, //L"K_?A3", // &HA3 - false, //L"K_?A4", // &HA4 - false, //L"K_?A5", // &HA5 - false, //L"K_?A6", // &HA6 - false, //L"K_?A7", // &HA7 - false, //L"K_?A8", // &HA8 - false, //L"K_?A9", // &HA9 - false, //L"K_?AA", // &HAA - false, //L"K_?AB", // &HAB - false, //L"K_?AC", // &HAC - false, //L"K_?AD", // &HAD - false, //L"K_?AE", // &HAE - false, //L"K_?AF", // &HAF - false, //L"K_?B0", // &HB0 - false, //L"K_?B1", // &HB1 - false, //L"K_?B2", // &HB2 - false, //L"K_?B3", // &HB3 - false, //L"K_?B4", // &HB4 - false, //L"K_?B5", // &HB5 - false, //L"K_?B6", // &HB6 - false, //L"K_?B7", // &HB7 - false, //L"K_?B8", // &HB8 - false, //L"K_?B9", // &HB9 - - false, //L"K_COLON", // &HBA - false, //L"K_EQUAL", // &HBB - false, //L"K_COMMA", // &HBC - false, //L"K_HYPHEN", // &HBD - false, //L"K_PERIOD", // &HBE - false, //L"K_SLASH", // &HBF - false, //L"K_BKQUOTE", // &HC0 - - false, //L"K_?C1", // &HC1 - false, //L"K_?C2", // &HC2 - false, //L"K_?C3", // &HC3 - false, //L"K_?C4", // &HC4 - false, //L"K_?C5", // &HC5 - false, //L"K_?C6", // &HC6 - false, //L"K_?C7", // &HC7 - false, //L"K_?C8", // &HC8 - false, //L"K_?C9", // &HC9 - false, //L"K_?CA", // &HCA - false, //L"K_?CB", // &HCB - false, //L"K_?CC", // &HCC - false, //L"K_?CD", // &HCD - false, //L"K_?CE", // &HCE - false, //L"K_?CF", // &HCF - false, //L"K_?D0", // &HD0 - false, //L"K_?D1", // &HD1 - false, //L"K_?D2", // &HD2 - false, //L"K_?D3", // &HD3 - false, //L"K_?D4", // &HD4 - false, //L"K_?D5", // &HD5 - false, //L"K_?D6", // &HD6 - false, //L"K_?D7", // &HD7 - false, //L"K_?D8", // &HD8 - false, //L"K_?D9", // &HD9 - false, //L"K_?DA", // &HDA - - false, //L"K_LBRKT", // &HDB - false, //L"K_BKSLASH", // &HDC - false, //L"K_RBRKT", // &HDD - false, //L"K_QUOTE", // &HDE - false, //L"K_oDF", // &HDF - false, //L"K_oE0", // &HE0 - false, //L"K_oE1", // &HE1 - false, //L"K_oE2", // &HE2 - false, //L"K_oE3", // &HE3 - false, //L"K_oE4", // &HE4 - - false, //L"K_?E5", // &HE5 - - false, //L"K_oE6", // &HE6 - - false, //L"K_?E7", // &HE7 - false, //L"K_?E8", // &HE8 - - false, //L"K_oE9", // &HE9 - false, //L"K_oEA", // &HEA - false, //L"K_oEB", // &HEB - false, //L"K_oEC", // &HEC - false, //L"K_oED", // &HED - false, //L"K_oEE", // &HEE - false, //L"K_oEF", // &HEF - false, //L"K_oF0", // &HF0 - false, //L"K_oF1", // &HF1 - false, //L"K_oF2", // &HF2 - false, //L"K_oF3", // &HF3 - false, //L"K_oF4", // &HF4 - false, //L"K_oF5", // &HF5 - - false, //L"K_?F6", // &HF6 - false, //L"K_?F7", // &HF7 - false, //L"K_?F8", // &HF8 - false, //L"K_?F9", // &HF9 - false, //L"K_?FA", // &HFA - false, //L"K_?FB", // &HFB - false, //L"K_?FC", // &HFC - false, //L"K_?FD", // &HFD - false, //L"K_?FE", // &HFE - false, //L"K_?FF" // &HFF -}; - - } // namespace kmx } // namespace core } // namespace km diff --git a/core/src/kmx/kmx_processevent.cpp b/core/src/kmx/kmx_processevent.cpp index 4b98312c369..604c6f6fe2e 100644 --- a/core/src/kmx/kmx_processevent.cpp +++ b/core/src/kmx/kmx_processevent.cpp @@ -276,7 +276,6 @@ KMX_BOOL KMX_ProcessEvent::ProcessGroup(LPGROUP gp, KMX_BOOL *pOutputKeystroke) // If there is now no character in the context, we want to // emit the backspace for application to use if(!pdeletecontext || *pdeletecontext == 0) { // I4933 - m_actions.QueueAction(QIT_INVALIDATECONTEXT, 0); if(m_debug_items) { m_debug_items->push_group_exit(m_actions.Length(), KM_CORE_DEBUG_FLAG_NOMATCH, gp); } @@ -301,7 +300,6 @@ KMX_BOOL KMX_ProcessEvent::ProcessGroup(LPGROUP gp, KMX_BOOL *pOutputKeystroke) return FALSE; } else { // I4024 // I4128 // I4287 // I4290 DebugLog(" ... IsLegacy = FALSE; IsTIP = TRUE"); // I4128 - m_actions.QueueAction(QIT_INVALIDATECONTEXT, 0); if(m_debug_items) { m_debug_items->push_group_exit(m_actions.Length(), KM_CORE_DEBUG_FLAG_NOMATCH, gp); } diff --git a/core/src/kmx/kmx_processevent.h b/core/src/kmx/kmx_processevent.h index 681c1782acc..50e84c996d8 100644 --- a/core/src/kmx/kmx_processevent.h +++ b/core/src/kmx/kmx_processevent.h @@ -126,9 +126,6 @@ struct char_to_vkey { extern const struct char_to_vkey s_char_to_vkey[]; -/** for vkeys 0..FF, 'true' if a context reset should be performed before emit */ -extern const bool vkey_to_contextreset[]; - } // namespace kmx } // namespace core } // namespace km diff --git a/core/src/state.hpp b/core/src/state.hpp index 5d1e5355254..6b0aa6ba8cf 100644 --- a/core/src/state.hpp +++ b/core/src/state.hpp @@ -184,3 +184,16 @@ struct km_core_state : public km::core::state km_core_state(Args&&... args) : km::core::state(std::forward(args)...) {} }; + + +/** @return true if this is a state which should clear the context */ +bool +km_core_state_should_clear_context(km_core_state *state, + km_core_virtual_key vk, + uint16_t modifier_state, + uint8_t is_key_down, + uint16_t event_flags); + +/** @return true if there are any actions of the type */ +bool +km_core_state_has_type(km_core_state *state, uint8_t type); diff --git a/core/tests/unit/ldml/ldml.cpp b/core/tests/unit/ldml/ldml.cpp index bef485a8783..92b50b2f116 100644 --- a/core/tests/unit/ldml/ldml.cpp +++ b/core/tests/unit/ldml/ldml.cpp @@ -239,7 +239,7 @@ verify_context(std::u16string& text_store, km_core_state* &test_state, std::vect // Verify that both our local test_context and the core's test_state.context have // not diverged auto ci = citems; - for (auto test_ci = test_context.begin(); ci->type != KM_CORE_CT_END || test_ci != test_context.end(); ci++, test_ci++) { + for (auto test_ci = test_context.begin(); ; ci++, test_ci++) { // skip over markers, they won't be in test_context while (ci->type == KM_CORE_CT_MARKER) { ci++; @@ -254,13 +254,13 @@ verify_context(std::u16string& text_store, km_core_state* &test_state, std::vect assert(test_ci->type == ci->type && test_ci->marker == ci->marker); } - km_core_context_items_dispose(citems); - if (text_store != buf) { - std::cerr << "text store has diverged from buf" << std::endl; - std::cerr << "text store: " << string_to_hex(text_store) << " [" << text_store << "]" << std::endl; - assert(false); - } - delete[] buf; + km_core_context_items_dispose(citems); + if (text_store != buf) { + std::cerr << "text store has diverged from buf" << std::endl; + std::cerr << "text store: " << string_to_hex(text_store) << " [" << text_store << "]" << std::endl; + assert(false); + } + delete[] buf; } int @@ -329,6 +329,11 @@ run_test(const km::core::path &source, const km::core::path &compiled, km::tests test_state, p.vk, p.modifier_state | test_source.caps_lock_state(), key_down, KM_CORE_EVENT_FLAG_DEFAULT)); // TODO-LDML: for now. Should send touch and hardware events. + if (km_core_state_should_clear_context(test_state, p.vk, p.modifier_state | test_source.caps_lock_state(), key_down, + KM_CORE_EVENT_FLAG_DEFAULT)) { + test_context.clear(); + text_store.clear(); + } for (auto act = km_core_state_action_items(test_state, nullptr); act->type != KM_CORE_IT_END; act++) { apply_action(test_state, *act, text_store, test_context, test_source, test_context); } From f1b0d8c83703aee4fd2a4f581e02dcc162b16a57 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Fri, 5 Apr 2024 11:58:47 -0500 Subject: [PATCH 03/20] fix(core): core to automatically reset context if a frame key pressed - move the reset table into its own cpp - update function signatures per review comments Fixes: #10955 --- core/src/km_core_processevent_api.cpp | 2 +- core/src/km_core_state_api.cpp | 17 +++++++---------- core/src/meson.build | 1 + core/src/state.hpp | 11 +++++------ ...ontextreset.hpp => vkey_to_contextreset.cpp} | 4 ++-- core/src/vkey_to_contextreset.hpp | 10 ++++++++++ core/tests/unit/ldml/ldml.cpp | 2 +- 7 files changed, 27 insertions(+), 20 deletions(-) rename core/src/{km_vkey_to_contextreset.hpp => vkey_to_contextreset.cpp} (99%) create mode 100644 core/src/vkey_to_contextreset.hpp diff --git a/core/src/km_core_processevent_api.cpp b/core/src/km_core_processevent_api.cpp index 4b5b1fd715f..8ccf0e4fa73 100644 --- a/core/src/km_core_processevent_api.cpp +++ b/core/src/km_core_processevent_api.cpp @@ -52,7 +52,7 @@ km_core_process_event(km_core_state *state, } km_core_status status = state->processor().process_event(state, vk, modifier_state, is_key_down, event_flags); - if (km_core_state_should_clear_context(state, vk, modifier_state, is_key_down, event_flags)) { + if (state_should_clear_context(state, vk, modifier_state, is_key_down, event_flags)) { state->context().clear(); } diff --git a/core/src/km_core_state_api.cpp b/core/src/km_core_state_api.cpp index 7f12aa7a66a..f9449fcb51f 100644 --- a/core/src/km_core_state_api.cpp +++ b/core/src/km_core_state_api.cpp @@ -20,13 +20,10 @@ #include "processor.hpp" #include "state.hpp" - +#include "vkey_to_contextreset.hpp" using namespace km::core; -// pull in the reset table -#include "km_vkey_to_contextreset.hpp" - // Forward declarations class context; @@ -368,24 +365,24 @@ km_core_cp * km_core_state_context_debug( return result; } -bool -km_core_state_has_type(km_core_state *state, uint8_t type) { +static bool +state_has_action_type(km_core_state *state, uint8_t type) { return std::any_of( state->actions().begin(), state->actions().end(), [type](const km::core::action &a) { return a.type == type; }); } bool -km_core_state_should_clear_context(km_core_state *state, +state_should_clear_context(km_core_state *state, km_core_virtual_key vk, uint16_t modifier_state, uint8_t is_key_down, uint16_t event_flags) { // if emit_keystroke is present, check if a context reset is needed - if (km_core_state_has_type(state, KM_CORE_IT_EMIT_KEYSTROKE)) { - if (km::core::vkey_to_contextreset[vk]) { + if (state_has_action_type(state, KM_CORE_IT_EMIT_KEYSTROKE)) { + if (vkey_to_contextreset[vk]) { return true; - } else if (vk == KM_CORE_VKEY_BKSP && km_core_state_has_type(state, KM_CORE_IT_BACK)) { + } else if (vk == KM_CORE_VKEY_BKSP && state_has_action_type(state, KM_CORE_IT_BACK)) { return true; } } diff --git a/core/src/meson.build b/core/src/meson.build index 9943c2fd070..7027136dd4c 100644 --- a/core/src/meson.build +++ b/core/src/meson.build @@ -49,6 +49,7 @@ kmx_files = files( 'keyboard.cpp', 'state.cpp', 'debuglog.cpp', + 'vkey_to_contextreset.cpp', 'km_core_action_api.cpp', 'km_core_context_api.cpp', 'km_core_keyboard_api.cpp', diff --git a/core/src/state.hpp b/core/src/state.hpp index 6b0aa6ba8cf..ffdbb2deb72 100644 --- a/core/src/state.hpp +++ b/core/src/state.hpp @@ -186,14 +186,13 @@ struct km_core_state : public km::core::state }; -/** @return true if this is a state which should clear the context */ +/** + * Evaluate the + * @return true if this is a state which should clear the context + */ bool -km_core_state_should_clear_context(km_core_state *state, +state_should_clear_context(km_core_state *state, km_core_virtual_key vk, uint16_t modifier_state, uint8_t is_key_down, uint16_t event_flags); - -/** @return true if there are any actions of the type */ -bool -km_core_state_has_type(km_core_state *state, uint8_t type); diff --git a/core/src/km_vkey_to_contextreset.hpp b/core/src/vkey_to_contextreset.cpp similarity index 99% rename from core/src/km_vkey_to_contextreset.hpp rename to core/src/vkey_to_contextreset.cpp index 0f8ae7cf05c..cbfd8497faf 100644 --- a/core/src/km_vkey_to_contextreset.hpp +++ b/core/src/vkey_to_contextreset.cpp @@ -1,9 +1,9 @@ -#pragma once +#include "vkey_to_contextreset.hpp" namespace km { namespace core { -static bool vkey_to_contextreset[256] = { +bool vkey_to_contextreset[256] = { true, //L"K_?00", // &H0 true, //L"K_LBUTTON", // &H1 true, //L"K_RBUTTON", // &H2 diff --git a/core/src/vkey_to_contextreset.hpp b/core/src/vkey_to_contextreset.hpp new file mode 100644 index 00000000000..fd183ad9330 --- /dev/null +++ b/core/src/vkey_to_contextreset.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace km { +namespace core { + +/** true for any vkeys which require a context reset (such as frame keys) */ +extern bool vkey_to_contextreset[256]; + +} +} diff --git a/core/tests/unit/ldml/ldml.cpp b/core/tests/unit/ldml/ldml.cpp index 92b50b2f116..fffdfbd08ae 100644 --- a/core/tests/unit/ldml/ldml.cpp +++ b/core/tests/unit/ldml/ldml.cpp @@ -329,7 +329,7 @@ run_test(const km::core::path &source, const km::core::path &compiled, km::tests test_state, p.vk, p.modifier_state | test_source.caps_lock_state(), key_down, KM_CORE_EVENT_FLAG_DEFAULT)); // TODO-LDML: for now. Should send touch and hardware events. - if (km_core_state_should_clear_context(test_state, p.vk, p.modifier_state | test_source.caps_lock_state(), key_down, + if (state_should_clear_context(test_state, p.vk, p.modifier_state | test_source.caps_lock_state(), key_down, KM_CORE_EVENT_FLAG_DEFAULT)) { test_context.clear(); text_store.clear(); From 628d13d7a6ef5dd0b726faa66f2caf31b1584516 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Fri, 5 Apr 2024 12:05:57 -0500 Subject: [PATCH 04/20] fix(core): core to automatically reset context if a frame key pressed - update comments per review Fixes: #10955 --- core/src/km_core_state_api.cpp | 4 ++-- core/src/state.hpp | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/core/src/km_core_state_api.cpp b/core/src/km_core_state_api.cpp index f9449fcb51f..a7773219393 100644 --- a/core/src/km_core_state_api.cpp +++ b/core/src/km_core_state_api.cpp @@ -380,9 +380,9 @@ state_should_clear_context(km_core_state *state, uint16_t event_flags) { // if emit_keystroke is present, check if a context reset is needed if (state_has_action_type(state, KM_CORE_IT_EMIT_KEYSTROKE)) { - if (vkey_to_contextreset[vk]) { + if (vk == KM_CORE_VKEY_BKSP && state_has_action_type(state, KM_CORE_IT_BACK)) { return true; - } else if (vk == KM_CORE_VKEY_BKSP && state_has_action_type(state, KM_CORE_IT_BACK)) { + } else if (vkey_to_contextreset[vk]) { return true; } } diff --git a/core/src/state.hpp b/core/src/state.hpp index ffdbb2deb72..d2840fe49c6 100644 --- a/core/src/state.hpp +++ b/core/src/state.hpp @@ -187,7 +187,14 @@ struct km_core_state : public km::core::state /** - * Evaluate the + * Evaluate the state and vkey used. + * Determine whether the context should be cleared. + * @param state A pointer to the opaque state object. + * @param vk A virtual key that was processed. + * @param modifier_state The combinations of modifier keys set at the time key `vk` was pressed, bitmask + from the km_core_modifier_state enum. + * @param is_key_down 1 if it was a key-down event + * @param event_flags Event level flags, see km_core_event_flags * @return true if this is a state which should clear the context */ bool From 784a994f12d62a0439e854d9674ab5d680cacfa1 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Fri, 5 Apr 2024 13:22:47 -0500 Subject: [PATCH 05/20] fix(core): update ldml test source to handle reset Fixes: #10955 --- .../unit/ldml/keyboards/k_102_keytest.xml | 33 ++++++++++++------- core/tests/unit/ldml/ldml_test_source.cpp | 30 +++++++++++------ core/tests/unit/ldml/ldml_test_source.hpp | 5 +-- 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/core/tests/unit/ldml/keyboards/k_102_keytest.xml b/core/tests/unit/ldml/keyboards/k_102_keytest.xml index 907295bac40..ad0f1131fa4 100644 --- a/core/tests/unit/ldml/keyboards/k_102_keytest.xml +++ b/core/tests/unit/ldml/keyboards/k_102_keytest.xml @@ -1,19 +1,28 @@ +Note that the 'expected' lines are cumulative unless there's a reset event. + +@@keys: [K_BKQUOTE][K_1][K_ENTER][K_Z] +@@expected: z +Comment: 1=gap, enter=not mapped/mappable - reset. (z used as a subtest separator) + +@@keys: [K_Q][K_BKQUOTE][K_Z] +@@expected: zAz +Comment: q\m{q}a => A due to transform + +@@keys: [K_Q][K_2][K_BKQUOTE][K_Z] +@@expected: zAzAz +Comment: 2=not mapped, but NO reset. + +@@keys: [K_Q][K_1][K_BKQUOTE][K_Z] +@@expected: zAzAzAz +Comment: 1 is a gap (no effect) so no ctx reset + +@@keys: [K_Q][K_ENTER][K_BKQUOTE][K_Z] +@@expected: az +Comment: enter=not mappable, causes ctx reset. - diff --git a/core/tests/unit/ldml/ldml_test_source.cpp b/core/tests/unit/ldml/ldml_test_source.cpp index 71c5a7ee4e0..f171116aace 100644 --- a/core/tests/unit/ldml/ldml_test_source.cpp +++ b/core/tests/unit/ldml/ldml_test_source.cpp @@ -280,13 +280,15 @@ LdmlEmbeddedTestSource::load_source( const km::core::path &path ) { if (!line.length()) continue; if (line.compare(0, s_keys.length(), s_keys) == 0) { - keys = line.substr(s_keys.length()); - trim(keys); + auto k = line.substr(s_keys.length()); + trim(k); + keys.emplace_back(k); } else if (is_token(s_expected, line)) { if (line == "\\b") { expected_beep = true; } else { - expected = parse_source_string(line); + // allow multiple expected lines + expected.emplace_back(parse_source_string(line)); } } else if (is_token(s_expecterror, line)) { expected_error = true; @@ -297,8 +299,12 @@ LdmlEmbeddedTestSource::load_source( const km::core::path &path ) { } } - if (keys == "") { + if (keys.empty()) { // We must at least have a key sequence to run the test + std::cerr << "Need at least one key sequence." << std::endl; + return __LINE__; + } else if(keys.size() != expected.size()) { + std::cerr << "Need the same number of " << s_keys << " and " << s_expected << " lines." << std::endl; return __LINE__; } @@ -387,15 +393,19 @@ LdmlEmbeddedTestSource::vkey_to_event(std::string const &vk_event) { void LdmlEmbeddedTestSource::next_action(ldml_action &fillin) { - if (is_done) { + if (is_done || keys.empty()) { // We were already done. return done. fillin.type = LDML_ACTION_DONE; return; - } else if(keys.empty()) { - // Got to the end of the keys. time to check + } else if(keys[0].empty()) { + // Got to the end of a key set. time to check fillin.type = LDML_ACTION_CHECK_EXPECTED; - fillin.string = expected; // copy expected - is_done = true; // so we get DONE next time + fillin.string = expected[0]; // copy expected + expected.pop_front(); + keys.pop_front(); + if (keys.empty()) { + is_done = true; // so we get DONE next time + } } else { fillin.type = LDML_ACTION_KEY_EVENT; fillin.k = next_key(); @@ -406,7 +416,7 @@ LdmlEmbeddedTestSource::next_action(ldml_action &fillin) { key_event LdmlEmbeddedTestSource::next_key() { // mutate this->keys - return next_key(keys); + return next_key(keys[0]); } key_event diff --git a/core/tests/unit/ldml/ldml_test_source.hpp b/core/tests/unit/ldml/ldml_test_source.hpp index a0eed2ec8e1..4637af9bd44 100644 --- a/core/tests/unit/ldml/ldml_test_source.hpp +++ b/core/tests/unit/ldml/ldml_test_source.hpp @@ -149,8 +149,9 @@ class LdmlEmbeddedTestSource : public LdmlTestSource { key_event next_key(std::string &keys); key_event next_key(); - std::string keys = ""; - std::u16string expected = u"", context = u""; + std::deque keys; + std::deque expected; + std::u16string context = u""; bool expected_beep = false; bool expected_error = false; bool is_done = false; From 55483e4ccc83c80985ee2a2884e7c908889b55bc Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Fri, 5 Apr 2024 14:42:52 -0500 Subject: [PATCH 06/20] fix(core): update ldml test source to handle reset - correct invalidate logic Fixes: #10955 --- core/src/km_core_processevent_api.cpp | 8 +++++++- core/src/km_core_state_api.cpp | 8 +++++--- core/src/state.hpp | 4 ++-- .../unit/ldml/invalid-keyboards/ik_000_null_invalid.xml | 2 +- core/tests/unit/ldml/ldml.cpp | 2 +- core/tests/unit/ldml/ldml_test_source.cpp | 2 +- 6 files changed, 17 insertions(+), 9 deletions(-) diff --git a/core/src/km_core_processevent_api.cpp b/core/src/km_core_processevent_api.cpp index 8ccf0e4fa73..93ba9afbe43 100644 --- a/core/src/km_core_processevent_api.cpp +++ b/core/src/km_core_processevent_api.cpp @@ -52,8 +52,14 @@ km_core_process_event(km_core_state *state, } km_core_status status = state->processor().process_event(state, vk, modifier_state, is_key_down, event_flags); - if (state_should_clear_context(state, vk, modifier_state, is_key_down, event_flags)) { + if (state_should_invalidate_context(state, vk, modifier_state, is_key_down, event_flags)) { state->context().clear(); + // we are already committed. So we need to un-commit (remove the end of the vector) + if (state->actions().back().type == KM_CORE_IT_END) { + state->actions().pop_back(); + } + state->actions().push_invalidate_context(); + state->actions().commit(); } state->apply_actions_and_merge_app_context(); diff --git a/core/src/km_core_state_api.cpp b/core/src/km_core_state_api.cpp index a7773219393..abc835fd524 100644 --- a/core/src/km_core_state_api.cpp +++ b/core/src/km_core_state_api.cpp @@ -373,15 +373,17 @@ state_has_action_type(km_core_state *state, uint8_t type) { } bool -state_should_clear_context(km_core_state *state, +state_should_invalidate_context(km_core_state *state, km_core_virtual_key vk, uint16_t modifier_state, uint8_t is_key_down, uint16_t event_flags) { // if emit_keystroke is present, check if a context reset is needed if (state_has_action_type(state, KM_CORE_IT_EMIT_KEYSTROKE)) { - if (vk == KM_CORE_VKEY_BKSP && state_has_action_type(state, KM_CORE_IT_BACK)) { - return true; + if (vk == KM_CORE_VKEY_BKSP) { + if (!state_has_action_type(state, KM_CORE_IT_BACK)) { + return true; + } } else if (vkey_to_contextreset[vk]) { return true; } diff --git a/core/src/state.hpp b/core/src/state.hpp index d2840fe49c6..38795cd2325 100644 --- a/core/src/state.hpp +++ b/core/src/state.hpp @@ -188,7 +188,7 @@ struct km_core_state : public km::core::state /** * Evaluate the state and vkey used. - * Determine whether the context should be cleared. + * Determine whether the context should be invalidated. * @param state A pointer to the opaque state object. * @param vk A virtual key that was processed. * @param modifier_state The combinations of modifier keys set at the time key `vk` was pressed, bitmask @@ -198,7 +198,7 @@ struct km_core_state : public km::core::state * @return true if this is a state which should clear the context */ bool -state_should_clear_context(km_core_state *state, +state_should_invalidate_context(km_core_state *state, km_core_virtual_key vk, uint16_t modifier_state, uint8_t is_key_down, diff --git a/core/tests/unit/ldml/invalid-keyboards/ik_000_null_invalid.xml b/core/tests/unit/ldml/invalid-keyboards/ik_000_null_invalid.xml index a16eb613468..6e10b734e97 100644 --- a/core/tests/unit/ldml/invalid-keyboards/ik_000_null_invalid.xml +++ b/core/tests/unit/ldml/invalid-keyboards/ik_000_null_invalid.xml @@ -1,4 +1,4 @@ -