mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-05 00:15:32 +00:00
137 lines
4.6 KiB
C++
137 lines
4.6 KiB
C++
/*
|
|
Copyright: © 2018 SIL International.
|
|
Description: Internal state class and adaptor class for the API.
|
|
Create Date: 2 Oct 2018
|
|
Authors: Tim Eves (TSE), Marc Durdin
|
|
*/
|
|
|
|
#include "state.hpp"
|
|
#include "action.hpp"
|
|
#include "processor.hpp"
|
|
#include <keyman/keyman_core_api_consts.h>
|
|
#include <cstring>
|
|
|
|
|
|
using namespace km::core;
|
|
|
|
void actions::push_persist(option const &opt) {
|
|
assert(empty() || back().type != KM_CORE_IT_END);
|
|
_option_items_stack.emplace_back(opt);
|
|
km_core_action_item ai = {KM_CORE_IT_PERSIST_OPT, {0,}, {0}};
|
|
ai.option = &_option_items_stack.back();
|
|
emplace_back(std::move(ai));
|
|
}
|
|
|
|
void actions::push_persist(option const &&opt) {
|
|
assert(empty() || back().type != KM_CORE_IT_END);
|
|
_option_items_stack.emplace_back(opt);
|
|
km_core_action_item ai = {KM_CORE_IT_PERSIST_OPT, {0,}, {0}};
|
|
ai.option = &_option_items_stack.back();
|
|
emplace_back(std::move(ai));
|
|
}
|
|
|
|
void actions::push_capslock(bool turnOn) {
|
|
assert(empty() || (!empty() && back().type != KM_CORE_IT_END));
|
|
km_core_action_item ai = {KM_CORE_IT_CAPSLOCK, {0,}, {0}};
|
|
ai.capsLock = turnOn;
|
|
emplace_back(std::move(ai));
|
|
}
|
|
|
|
|
|
state::state(km::core::abstract_processor & ap, km_core_option_item const *env)
|
|
: _processor(ap)
|
|
{
|
|
// The app context will never have markers, because it is an exact
|
|
// copy of the context passed in from the application, in whatever
|
|
// normalization form that the app is using.
|
|
_app_ctxt.has_markers = false;
|
|
for (; env && env->key != nullptr; env++) {
|
|
//assert(env->scope == KM_CORE_OPT_ENVIRONMENT); // todo do we need scope? or can we find a way to eliminate it?
|
|
ap.update_option(env->scope
|
|
? km_core_option_scope(env->scope)
|
|
: KM_CORE_OPT_ENVIRONMENT,
|
|
env->key,
|
|
env->value);
|
|
}
|
|
_backspace_handled_internally = false;
|
|
_imx_callback = nullptr;
|
|
_imx_object = nullptr;
|
|
memset(const_cast<km_core_actions*>(&_action_struct), 0, sizeof(km_core_actions));
|
|
// Ensure _action_struct is initialized to the default values
|
|
km_core_action_item no_actions = {KM_CORE_IT_END, {0,}, {0}};
|
|
action_item_list_to_actions_object(&no_actions, &this->_action_struct);
|
|
}
|
|
|
|
void state::imx_register_callback(
|
|
km_core_keyboard_imx_platform imx_callback_fp,
|
|
void *callback_object
|
|
) {
|
|
assert(imx_callback_fp);
|
|
if(!imx_callback_fp) {
|
|
return;
|
|
}
|
|
_imx_callback = imx_callback_fp;
|
|
_imx_object = callback_object;
|
|
}
|
|
|
|
void state::imx_deregister_callback() {
|
|
_imx_callback = nullptr;
|
|
_imx_object = nullptr;
|
|
}
|
|
|
|
void state::imx_callback(uint32_t imx_id) {
|
|
if (_imx_callback==nullptr) {
|
|
return;
|
|
}
|
|
_imx_callback(static_cast<km_core_state *>(this), imx_id, _imx_object);
|
|
}
|
|
|
|
state::state(state const &other)
|
|
: _ctxt(other._ctxt)
|
|
, _app_ctxt(other._app_ctxt)
|
|
, _processor(other._processor)
|
|
, _actions(other._actions)
|
|
, _action_struct(clone_actions_object(other._action_struct))
|
|
, _debug_items(other._debug_items)
|
|
, _imx_callback(other._imx_callback)
|
|
, _imx_object(other._imx_object)
|
|
, _backspace_handled_internally(other._backspace_handled_internally)
|
|
{
|
|
}
|
|
|
|
state::~state() {
|
|
km::core::actions_dispose(this->_action_struct);
|
|
}
|
|
|
|
void state::apply_actions_and_merge_app_context() {
|
|
auto action_items = this->_actions.data();
|
|
|
|
km::core::actions_dispose(this->_action_struct);
|
|
|
|
action_item_list_to_actions_object(action_items, &this->_action_struct);
|
|
|
|
// We keep a copy of the app context before normalization, as the
|
|
// code_points_to_delete value can be updated by normalization, but by the
|
|
// time we get it back from actions_normalize or
|
|
// actions_update_app_context_nfu, app_context has already been updated to
|
|
// remove the necessary codepoints
|
|
km::core::context& app_context = this->app_context();
|
|
km::core::context const& cached_context = this->context();
|
|
km::core::context app_context_for_deletion;
|
|
std::copy(app_context.begin(), app_context.end(), std::back_inserter(app_context_for_deletion));
|
|
|
|
if(this->processor().supports_normalization()) {
|
|
// Normalize to NFC for those keyboard processors that support it
|
|
//if(!km::core::actions_normalize(&cached_context, &app_context, this->_action_struct)) {
|
|
// km::core::actions_dispose(this->_action_struct);
|
|
// return;
|
|
//}
|
|
} else {
|
|
// For all other keyboard processors, we just copy the cached_context to the app_context
|
|
if(!km::core::actions_update_app_context_nfu(&cached_context, &app_context)) {
|
|
km::core::actions_dispose(this->_action_struct);
|
|
return;
|
|
}
|
|
}
|
|
this->_action_struct.deleted_context = km::core::get_deleted_context(app_context_for_deletion, this->_action_struct.code_points_to_delete);
|
|
}
|