mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-07 09:25:33 +00:00
Relates to #9999. Fixes #10384. The context API endpoints should no longer be considered as part of the standard Core API. The only consumers that have a need to access these APIs are the IMX integration in Engine for Windows, and the Keyman Developer Debugger. These symbols are currently used by Developer: * `km_core_context` struct * `km_core_context_type` enum * `km_core_context_item` struct * `KM_CORE_CONTEXT_ITEM_END` macro * `km_core_state_context()` * `km_core_context_set()` * `km_core_context_clear()` These symbols are currently used by Windows IMX: * `km_core_context` struct * `km_core_context_type` enum * `km_core_context_item` struct * `KM_CORE_CONTEXT_ITEM_END` macro * `km_core_context_items_dispose()` * `km_core_context_item_list_size()` * `km_core_state_get_intermediate_context()` The following functions and symbols are moving to keyman_core_api_context.h: * `km_core_context` struct * `km_core_context_type` enum * `km_core_context_item` struct * `KM_CORE_CONTEXT_ITEM_END` macro * `km_core_state_context()` function * `km_core_state_get_intermediate_context()` function * `km_core_context_set()` function * `km_core_context_clear()` function * `km_core_context_get()` function * `km_core_context_items_from_utf16()` function * `km_core_context_items_from_utf8()` function * `km_core_context_items_to_utf8()` function * `km_core_context_items_to_utf16()` function * `km_core_context_items_to_utf32()` function * `km_core_context_items_dispose()` function * `km_core_context_length()` function * `km_core_context_append()` function * `km_core_context_shrink()` function * `km_core_context_item_list_size()` function
190 lines
6.2 KiB
C++
190 lines
6.2 KiB
C++
#include <iostream>
|
|
#include "keyman_core.h"
|
|
#include "kmx/kmx_base.h"
|
|
#include "kmx/kmx_xstring.h"
|
|
|
|
#include <test_assert.h>
|
|
|
|
using namespace km::core::kmx;
|
|
|
|
namespace {
|
|
|
|
// TODO: consider using same const approach in kmx_base.h
|
|
// but this ripples through a whole lot of code
|
|
typedef struct tagDEBUG_GROUP
|
|
{
|
|
KMX_WCHAR const * dpName;
|
|
KEY const * dpKeyArray; // [LPKEY] address of first item in key array
|
|
KMX_WCHAR const * dpMatch;
|
|
KMX_WCHAR const * dpNoMatch;
|
|
KMX_DWORD cxKeyArray; // in array entries
|
|
KMX_BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not
|
|
} DEBUG_GROUP, *LPDEBUG_GROUP;
|
|
|
|
typedef struct tagDEBUG_KEY
|
|
{
|
|
KMX_WCHAR Key;
|
|
KMX_DWORD Line;
|
|
KMX_DWORD ShiftFlags;
|
|
KMX_WCHAR const * dpOutput;
|
|
KMX_WCHAR const * dpContext;
|
|
} DEBUG_KEY, *LPDEBUG_KEY;
|
|
|
|
typedef struct tagDEBUG_STORE
|
|
{
|
|
KMX_DWORD dwSystemID;
|
|
KMX_WCHAR const * dpName;
|
|
KMX_WCHAR const * dpValue;
|
|
} DEBUG_STORE, *LPDEBUG_STORE;
|
|
|
|
const char *debug_item_types[] = {
|
|
"KM_CORE_DEBUG_BEGIN", // = 0,
|
|
"//KM_CORE_DEBUG_BEGIN_ANSI", // = 1, // not supported; instead rewrite ansi keyboards to Unicode with mcompile
|
|
"KM_CORE_DEBUG_GROUP_ENTER", // = 2,
|
|
"KM_CORE_DEBUG_GROUP_EXIT", // = 3,
|
|
"KM_CORE_DEBUG_RULE_ENTER", // = 4,
|
|
"KM_CORE_DEBUG_RULE_EXIT", // = 5,
|
|
"KM_CORE_DEBUG_MATCH_ENTER", // = 6,
|
|
"KM_CORE_DEBUG_MATCH_EXIT", // = 7,
|
|
"KM_CORE_DEBUG_NOMATCH_ENTER", // = 8,
|
|
"KM_CORE_DEBUG_NOMATCH_EXIT", // = 9,
|
|
"KM_CORE_DEBUG_END", // = 10,
|
|
"KM_CORE_DEBUG_SET_OPTION", // = 11
|
|
};
|
|
|
|
void print_debug_item(const char *title, km_core_state_debug_item const & item) {
|
|
LPGROUP gp = static_cast<LPGROUP>(item.kmx_info.group);
|
|
LPKEY rule = static_cast<LPKEY>(item.kmx_info.rule);
|
|
LPSTORE store = static_cast<LPSTORE>(item.kmx_info.option.store);
|
|
|
|
std::cout
|
|
<< "debug_item " << title << std::endl
|
|
<< " type: " << debug_item_types[item.type] << std::endl
|
|
<< " flags: " << item.flags << std::endl
|
|
<< " key_info: (vk: " << item.key_info.vk
|
|
<< " mod: " << item.key_info.modifier_state
|
|
<< " char: " << item.key_info.character << ")" << std::endl;
|
|
|
|
std::cout
|
|
<< " kmx_info: "<< std::endl
|
|
<< " context: '" << item.kmx_info.context << "'" << std::endl
|
|
<< " action: " << item.kmx_info.first_action << std::endl;
|
|
|
|
if(gp) std::cout
|
|
<< " group: " << gp->dpName << std::endl;
|
|
if(rule) std::cout
|
|
<< " rule: " << std::endl
|
|
<< " key: " << rule->Key << std::endl
|
|
<< " shift: " << rule->ShiftFlags << std::endl
|
|
<< " line: " << rule->Line << std::endl;
|
|
std::cout
|
|
<< " offsets: ";
|
|
std::copy(
|
|
std::begin(item.kmx_info.store_offsets),
|
|
std::end(item.kmx_info.store_offsets),
|
|
std::ostream_iterator<uint16_t>(std::cout, " ")
|
|
);
|
|
std::cout << std::endl;
|
|
if(store) std::cout
|
|
<< " option.store: " << std::endl
|
|
<< " name: " << store->dpName << std::endl
|
|
<< " value: " << store->dpString << std::endl;
|
|
if(store) std::cout
|
|
<< " option.value: " << item.kmx_info.option.value << std::endl;
|
|
}
|
|
|
|
bool are_store_offsets_equal(const uint16_t (&lhs)[DEBUG_STORE_OFFSETS_SIZE], const uint16_t (&rhs)[DEBUG_STORE_OFFSETS_SIZE]) {
|
|
return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
|
|
// !memcmp(lhs, rhs, sizeof(lhs));
|
|
}
|
|
|
|
bool operator==(
|
|
km_core_state_debug_item const & lhs,
|
|
km_core_state_debug_item const & rhs
|
|
) {
|
|
auto result = (lhs.type == rhs.type && lhs.flags == rhs.flags && lhs.kmx_info.first_action == rhs.kmx_info.first_action);
|
|
if(result) {
|
|
LPGROUP lgp = static_cast<LPGROUP>(lhs.kmx_info.group), rgp = static_cast<LPGROUP>(rhs.kmx_info.group);
|
|
LPKEY lrule = static_cast<LPKEY>(lhs.kmx_info.rule), rrule = static_cast<LPKEY>(rhs.kmx_info.rule);
|
|
LPSTORE loption_store = static_cast<LPSTORE>(lhs.kmx_info.option.store), roption_store = static_cast<LPSTORE>(rhs.kmx_info.option.store);
|
|
switch(lhs.type) {
|
|
case KM_CORE_DEBUG_BEGIN:
|
|
result = lhs.key_info.character == rhs.key_info.character &&
|
|
lhs.key_info.modifier_state == rhs.key_info.modifier_state &&
|
|
lhs.key_info.vk == rhs.key_info.vk;
|
|
break;
|
|
case KM_CORE_DEBUG_END:
|
|
break;
|
|
case KM_CORE_DEBUG_GROUP_ENTER:
|
|
case KM_CORE_DEBUG_GROUP_EXIT:
|
|
case KM_CORE_DEBUG_MATCH_ENTER:
|
|
case KM_CORE_DEBUG_MATCH_EXIT:
|
|
case KM_CORE_DEBUG_NOMATCH_ENTER:
|
|
case KM_CORE_DEBUG_NOMATCH_EXIT:
|
|
assert(lgp != nullptr);
|
|
assert(rgp != nullptr);
|
|
assert(lgp->dpName != nullptr);
|
|
assert(rgp->dpName != nullptr);
|
|
result = u16cmp(lgp->dpName, rgp->dpName) == 0;
|
|
break;
|
|
case KM_CORE_DEBUG_RULE_ENTER:
|
|
case KM_CORE_DEBUG_RULE_EXIT:
|
|
assert(lgp != nullptr);
|
|
assert(rgp != nullptr);
|
|
assert(lgp->dpName != nullptr);
|
|
assert(rgp->dpName != nullptr);
|
|
assert(lrule != nullptr);
|
|
assert(rrule != nullptr);
|
|
result = u16cmp(lgp->dpName, rgp->dpName) == 0 &&
|
|
lrule->Line == rrule->Line &&
|
|
lrule->Key == rrule->Key &&
|
|
lrule->ShiftFlags == rrule->ShiftFlags &&
|
|
u16cmp(lhs.kmx_info.context, rhs.kmx_info.context) == 0 &&
|
|
are_store_offsets_equal(lhs.kmx_info.store_offsets, rhs.kmx_info.store_offsets);
|
|
break;
|
|
case KM_CORE_DEBUG_SET_OPTION:
|
|
assert(loption_store != nullptr && roption_store != nullptr);
|
|
result =
|
|
u16cmp(loption_store->dpName, roption_store->dpName) == 0 &&
|
|
u16cmp(lhs.kmx_info.option.value, rhs.kmx_info.option.value) == 0;
|
|
break;
|
|
default:
|
|
assert(false);
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
if(!result) {
|
|
print_debug_item("actual", lhs);
|
|
print_debug_item("expected", rhs);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
bool debug_items(
|
|
km_core_state const * state,
|
|
std::initializer_list<km_core_state_debug_item> const & expected
|
|
) {
|
|
size_t n = 0;
|
|
auto act = km_core_state_debug_items(state, &n);
|
|
|
|
for (auto &rhs: expected) {
|
|
if ((int)--n < 0) {
|
|
std::cout << "expected longer than actual" << std::endl;
|
|
print_debug_item("next expected item:", rhs);
|
|
return false;
|
|
}
|
|
if (!(*act++ == rhs)) return false;
|
|
}
|
|
|
|
if(n != 0) {
|
|
std::cout << "actual longer than expected" << std::endl;
|
|
print_debug_item("next actual item:", *act);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
};
|