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

fix(core): implement ldml_processor::get_key_list() #12644

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 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
3 changes: 1 addition & 2 deletions core/src/ldml/ldml_processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,8 +348,7 @@ km_core_attr const & ldml_processor::attributes() const {
}

km_core_keyboard_key * ldml_processor::get_key_list() const {
km_core_keyboard_key* key_list = new km_core_keyboard_key(KM_CORE_KEYBOARD_KEY_LIST_END);
return key_list;
return keys.get_key_list();
}

km_core_keyboard_imx * ldml_processor::get_imx_list() const {
Expand Down
16 changes: 16 additions & 0 deletions core/src/ldml/ldml_vkeys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@ vkeys::add(km_core_virtual_key vk, km_core_ldml_modifier_state modifier_state, s
const vkey_id id(vk, modifier_state);
// assign the string
vkey_to_string[id] = output;
if (!output.empty()) {
// empty string = gap key, etc.
all_vkeys.insert(id);
}
}

km_core_keyboard_key *
vkeys::get_key_list() const {
km_core_keyboard_key *list = new km_core_keyboard_key[all_vkeys.size() + 1];
std::size_t n = 0;
for (const auto &k : all_vkeys) {
list[n ].key = k.first;
list[n++].modifier_flag = k.second;
}
list[n++] = KM_CORE_KEYBOARD_KEY_LIST_END;
return list;
}

static const uint16_t BOTH_ALT = LALTFLAG | RALTFLAG;
Expand Down
7 changes: 7 additions & 0 deletions core/src/ldml/ldml_vkeys.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <unordered_map>
#include <utility>
#include <vector>
#include <set>

#include "keyman_core.h"

Expand All @@ -37,6 +38,7 @@ typedef std::pair<km_core_virtual_key, km_core_ldml_modifier_state> vkey_id;
class vkeys {
private:
std::map<vkey_id, std::u16string> vkey_to_string;
std::set<vkey_id> all_vkeys;

public:
vkeys();
Expand All @@ -53,6 +55,11 @@ class vkeys {
std::u16string
lookup(km_core_virtual_key vk, uint16_t modifier_state, bool &found) const;

/**
* For implementing ldml_processor::get_key_list()
*/
km_core_keyboard_key* get_key_list() const;

private:
/**
* Non-recursive internal lookup of a specific ID
Expand Down
1 change: 1 addition & 0 deletions core/tests/unit/ldml/keyboards/k_004_tinyshift.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

@@keys: [SHIFT K_BKQUOTE][K_1][K_BKQUOTE]
@@expected: \u0037\u1790\u17B6\u0127
@@keylist: [SHIFT K_BKQUOTE][SHIFT K_1][K_BKQUOTE][K_1]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just picked this because it's a smaller keyboard.


-->
<keyboard3 xmlns="https://schemas.unicode.org/cldr/45/keyboard3" locale="mt" conformsTo="45">
Expand Down
51 changes: 51 additions & 0 deletions core/tests/unit/ldml/ldml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <sstream>
#include <string>
#include <type_traits>
#include <set>

#include "path.hpp"
#include "state.hpp"
Expand Down Expand Up @@ -267,6 +268,45 @@ verify_context(std::u16string &text_store, km_core_state *&test_state, std::vect
delete[] buf;
}


bool
verify_key_list(std::set<km::tests::key_event> &actual, std::set<km::tests::key_event> &expected) {
bool equals = true;
for(const auto &akey : actual) {
if (expected.count(akey) == 0) {
equals = false;
std::u16string dump = convert<char, char16_t>(akey.dump()); // akey.dump()
std::wcout << console_color::fg(console_color::BRIGHT_RED) << "- FAIL - key_map had extra key " << dump << console_color::reset() << std::endl;
}
}
for(const auto &ekey : expected) {
if (actual.count(ekey) == 0) {
equals = false;
std::u16string dump = convert<char, char16_t>(ekey.dump()); // akey.dump()
std::wcout << console_color::fg(console_color::BRIGHT_RED) << "- FAIL - key_map had missing key " << dump << console_color::reset() << std::endl;
}
}
return equals;
}

bool
verify_key_list(const km_core_keyboard_key *actual_list, const std::u16string &expected_list) {
std::set<km::tests::key_event> actual, expected;
std::string expected_str = convert<char16_t, char>(expected_list);
// convert actual list
while (actual_list != nullptr && !(actual_list->key == 0 && actual_list->modifier_flag == 0)) {
km::tests::key_event k(actual_list->key, (uint16_t)actual_list->modifier_flag);
actual.insert(k);
actual_list++; // advance pointer
}
// parse expected_str
while (!expected_str.empty()) {
km::tests::key_event event = km::tests::LdmlEmbeddedTestSource::parse_next_key(expected_str);
expected.insert(event);
}
return verify_key_list(actual, expected);
}

int
run_test(const km::core::path &source, const km::core::path &compiled, km::tests::LdmlTestSource& test_source) {
km_core_keyboard * test_kb = nullptr;
Expand Down Expand Up @@ -372,6 +412,17 @@ run_test(const km::core::path &source, const km::core::path &compiled, km::tests
errorLine = __LINE__;
}
} break;
case km::tests::LDML_ACTION_CHECK_KEYLIST: {
std::cout << "- checking keylist " << action.string << std::endl;
// get keylist from kbd
const km_core_keyboard_key* actual_list = test_kb->get_key_list();
if (!verify_key_list(actual_list, action.string)) {
errorLine = __LINE__;
} else {
std::cout << " .. matches." << std::endl;
}
delete [] actual_list;
} break;
case km::tests::LDML_ACTION_FAIL: {
// test requested failure
std::wcout << console_color::fg(console_color::BRIGHT_RED) << "- FAIL: " << action.string << console_color::reset()
Expand Down
36 changes: 25 additions & 11 deletions core/tests/unit/ldml/ldml_test_source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ LdmlEmbeddedTestSource::load_source( const km::core::path &path ) {
const std::string s_context = "@@context: ";
const std::string s_capsLock = "@@capsLock: ";
const std::string s_expecterror = "@@expect-error: ";
const std::string s_keylist = "@@keylist: ";

// Parse out the header statements in file.kmn that tell us (a) environment, (b) key sequence, (c) start context, (d) expected
// result
Expand Down Expand Up @@ -300,6 +301,10 @@ LdmlEmbeddedTestSource::load_source( const km::core::path &path ) {
context = parse_source_string(line);
} else if (is_token(s_capsLock, line)) {
set_caps_lock_on(parse_source_string(line).compare(u"1") == 0);
} else if (is_token(s_keylist, line)) {
set_keylist(line);
} else if (line[0] == '@') {
std::cerr << path << " warning, unknown @-command " << line << std::endl;
}
}

Expand Down Expand Up @@ -356,7 +361,7 @@ LdmlTestSource::char_to_event(char ch) {
}

uint16_t
LdmlTestSource::get_modifier(std::string const m) {
LdmlTestSource::get_modifier(std::string const &m) {
for (int i = 0; km::core::kmx::s_modifier_names[i].name; i++) {
if (m == km::core::kmx::s_modifier_names[i].name) {
return km::core::kmx::s_modifier_names[i].modifier;
Expand All @@ -365,6 +370,12 @@ LdmlTestSource::get_modifier(std::string const m) {
return 0;
}

std::string key_event::dump() const {
std::stringstream f;
f << "Key: {" << km::core::kmx::Debug_VirtualKey(vk) << ", " << km::core::kmx::Debug_ModifierName(modifier_state) << "}";
return f.str();
}

key_event
LdmlEmbeddedTestSource::vkey_to_event(std::string const &vk_event) {
// vkey format is MODIFIER MODIFIER K_NAME
Expand Down Expand Up @@ -400,34 +411,37 @@ LdmlEmbeddedTestSource::vkey_to_event(std::string const &vk_event) {

void
LdmlEmbeddedTestSource::next_action(ldml_action &fillin) {
if (is_done || keys.empty()) {
// We were already done. return done.
fillin.type = LDML_ACTION_DONE;
return;
if (keys.empty()) {
// #3 we are almost done, let's run the key check if needed
if (!check_keylist.empty()) {
fillin.type = LDML_ACTION_CHECK_KEYLIST;
fillin.string = check_keylist;
check_keylist.clear();
} else {
fillin.type = LDML_ACTION_DONE;
}
} else if(keys[0].empty()) {
// #2. Then, when we finish a key set, we check the 'expected' at the end of it.
// Got to the end of a key set. time to check
fillin.type = LDML_ACTION_CHECK_EXPECTED;
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 {
// #1 First, we process each key
fillin.type = LDML_ACTION_KEY_EVENT;
fillin.k = next_key();
}
}


key_event
LdmlEmbeddedTestSource::next_key() {
// mutate this->keys
return next_key(keys[0]);
return parse_next_key(keys[0]);
}

key_event
LdmlEmbeddedTestSource::next_key(std::string &keys) {
LdmlEmbeddedTestSource::parse_next_key(std::string &keys) {
// Parse the next element of the string, chop it off, and return it
// mutates keys
if (keys.length() == 0)
Expand Down
53 changes: 48 additions & 5 deletions core/tests/unit/ldml/ldml_test_source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,34 @@ namespace tests {
struct key_event {
km_core_virtual_key vk;
uint16_t modifier_state;
public:
key_event() : vk(0), modifier_state(0) {
}
key_event(km_core_virtual_key k, uint16_t m) :vk(k), modifier_state(m) {
}
std::string dump() const;
int compare(const key_event &other) const {
if (vk < other.vk) return -1;
if (vk > other.vk) return 1;
if (modifier_state < other.modifier_state) return -1;
if (modifier_state > other.modifier_state) return 1;
return 0;
}

bool operator<(const key_event &other) const {
return compare(other) < 0;
}
bool operator>(const key_event &other) const {
return compare(other) > 0;
}
bool operator==(const key_event &other) const {
return compare(other) == 0;
}
/** true if unset (null) key */
bool empty() const {
return vk == 0 && modifier_state == 0;
}

};

enum ldml_action_type {
Expand All @@ -37,6 +65,10 @@ enum ldml_action_type {
* expected text
*/
LDML_ACTION_CHECK_EXPECTED,
/**
* string - keylist to check
*/
LDML_ACTION_CHECK_KEYLIST,
// TODO-LDML: gestures, etc? Depends on touch.

/**
Expand Down Expand Up @@ -80,7 +112,7 @@ class LdmlTestSource {

// helper functions
static key_event char_to_event(char ch);
static uint16_t get_modifier(std::string const m);
static uint16_t get_modifier(std::string const &m);
static std::u16string parse_source_string(std::string const &s);
static std::u16string parse_u8_source_string(std::string const &s);

Expand Down Expand Up @@ -143,18 +175,29 @@ class LdmlEmbeddedTestSource : public LdmlTestSource {
virtual void next_action(ldml_action &fillin);

private:

bool is_token(const std::string token, std::string &line);
key_event vkey_to_event(std::string const &vk_event);
key_event next_key(std::string &keys);
key_event next_key();

void set_keylist(std::string const &s) {
check_keylist = parse_source_string(s);
}

std::u16string check_keylist;
std::deque<std::string> keys;
std::deque<std::u16string> expected;
std::u16string context = u"";
bool expected_beep = false;
bool expected_error = false;
bool is_done = false;

/** returns false on fail and updates the message */
bool handle_check_keylist(std::string &message) const;

// utility
static key_event vkey_to_event(std::string const &vk_event);
static bool is_token(const std::string token, std::string &line);

public:
static key_event parse_next_key(std::string &keys);
};

} // namespace tests
Expand Down
Loading