mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-12 02:27:42 +00:00
feat(windows): add cached actions
This commit is contained in:
parent
118466f6b2
commit
2b0950617d
3 changed files with 115 additions and 19 deletions
|
|
@ -212,6 +212,8 @@ typedef struct tagKEYMAN64THREADDATA
|
|||
BOOL TIPFUpdateable, TIPFPreserved; // I4290
|
||||
|
||||
BOOL CoreProcessEventRun; // True if core process event has been run
|
||||
// TODO: #10583 remove core_actions cache
|
||||
km_core_actions const *core_actions;
|
||||
|
||||
BOOL FInRefreshKeyboards;
|
||||
BOOL RefreshRequired;
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ Process_Event_Core(PKEYMAN64THREADDATA _td) {
|
|||
if (_td->app->ReadContext(application_context)) {
|
||||
km_core_context_status result;
|
||||
result = km_core_state_context_set_if_needed(_td->lpActiveKeyboard->lpCoreKeyboardState, reinterpret_cast<const km_core_cp *>(application_context));
|
||||
// TODO remove debuging set if needed
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "Process_Event_Core: km_core_state_context_set_if_needed returned [%d]", result);
|
||||
if (result == KM_CORE_CONTEXT_STATUS_ERROR || result == KM_CORE_CONTEXT_STATUS_INVALID_ARGUMENT) {
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "Process_Event_Core: km_core_state_context_set_if_needed returned [%d]", result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,37 +23,105 @@ static void processAlert(AITIP* app) {
|
|||
app->QueueAction(QIT_BELL, 0);
|
||||
}
|
||||
|
||||
// TODO: #10583
|
||||
// Remove extra debuging code
|
||||
static void
|
||||
processDebugDeleteContext(const km_core_usv* delete_context) {
|
||||
km_core_usv const* delete_context_ptr = delete_context;
|
||||
while (*delete_context_ptr) {
|
||||
delete_context_ptr++;
|
||||
}
|
||||
delete_context_ptr--;
|
||||
for (; delete_context_ptr >= delete_context; delete_context_ptr--) {
|
||||
if (Uni_IsSMP(*delete_context_ptr)) {
|
||||
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "processDebugContext: s1 U+%04x", Uni_UTF32ToSurrogate1(*delete_context_ptr));
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "processDebugContext: s2 U+%04x", Uni_UTF32ToSurrogate2(*delete_context_ptr));
|
||||
} else {
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "processDebugContext: U+%04x", *delete_context_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
static BOOL
|
||||
processBack(AITIP* app, const unsigned int code_points_to_delete, const km_core_usv* delete_context) {
|
||||
if (app->IsLegacy()) {
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "processBack: Legacy app cptd [%d].", code_points_to_delete);
|
||||
for (unsigned int i = 0; i < code_points_to_delete; i++) {
|
||||
app->QueueAction(QIT_BACK, BK_DEFAULT);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
if (!app->IsLegacy()) {
|
||||
while (*delete_context) {
|
||||
if (Uni_IsSMP(*delete_context)) {
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "processBack: TSF app cptd [%d].", code_points_to_delete);
|
||||
km_core_usv const* delete_context_ptr = delete_context;
|
||||
while (*delete_context_ptr) {
|
||||
delete_context_ptr++;
|
||||
}
|
||||
delete_context_ptr--;
|
||||
for (; delete_context_ptr >= delete_context; delete_context_ptr--) {
|
||||
if (Uni_IsSMP(*delete_context_ptr)) {
|
||||
app->QueueAction(QIT_BACK, BK_DEFAULT | BK_SURROGATE);
|
||||
}
|
||||
else {
|
||||
app->QueueAction(QIT_BACK, BK_DEFAULT);
|
||||
}
|
||||
delete_context++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// TODO remove reading the applications context
|
||||
static BOOL
|
||||
processBack2(AITIP* app, const unsigned int code_points_to_delete) {
|
||||
if (app->IsLegacy()) {
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "processBack2: Legacy app cptd [%d].", code_points_to_delete);
|
||||
for (unsigned int i = 0; i < code_points_to_delete; i++) {
|
||||
//app->QueueAction(QIT_BACK, BK_DEFAULT);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!app->IsLegacy()) {
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "processBack2: TSF app cptd [%d].", code_points_to_delete);
|
||||
WCHAR application_context[MAXCONTEXT];
|
||||
DWORD cp_to_delete = code_points_to_delete;
|
||||
if (!app->ReadContext(application_context)) {
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "processBack2: Error reading context from application.");
|
||||
} else {
|
||||
// Find the length of the string
|
||||
int length = 0;
|
||||
while (application_context[length] != L'\0') {
|
||||
length++;
|
||||
}
|
||||
// Read each character starting from caret
|
||||
for (int i = length - 1; i >= 0 && cp_to_delete > 0; i--) {
|
||||
// Need to consider malformed context where only one surrogate is present, at either the start or end of the context.
|
||||
// In both these scenarios just perform one backspace one the same as if it was a non surrogate pair.
|
||||
if ((i > 0) && (Uni_IsSurrogate1(application_context[i - 1]) && Uni_IsSurrogate2(application_context[i]))) {
|
||||
//app->QueueAction(QIT_BACK, BK_DEFAULT | BK_SURROGATE);
|
||||
i--;
|
||||
cp_to_delete--;
|
||||
} else {
|
||||
//app->QueueAction(QIT_BACK, BK_DEFAULT);
|
||||
cp_to_delete--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
processPersistOpt(km_core_actions const* actions, LPINTKEYBOARDINFO activeKeyboard
|
||||
) {
|
||||
for (auto option = actions->persist_options; option->key; option++) {
|
||||
// Put the keyboard option into Windows Registry
|
||||
// log"Saving keyboard option to registry");
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessHook: Saving option to registry for keyboard [%s].", activeKeyboard->Name);
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessPersistOpt: Saving option to registry for keyboard [%s].", activeKeyboard->Name);
|
||||
size_t value_length = wcslen(reinterpret_cast<LPCWSTR>(option->value));
|
||||
LPWSTR value = new WCHAR[value_length + 1];
|
||||
wcscpy_s(value, value_length + 1, reinterpret_cast<LPCWSTR>(option->value));
|
||||
|
|
@ -101,24 +169,38 @@ BOOL ProcessActions(BOOL* emitKeyStroke)
|
|||
{
|
||||
PKEYMAN64THREADDATA _td = ThreadGlobals();
|
||||
if (!_td) return FALSE;
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessActions: Enter");
|
||||
|
||||
// TODO: #10583 Remove caching action_struct
|
||||
if (!_td->core_actions) {
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessActions: core_actions not set");
|
||||
_td->core_actions = km_core_state_get_actions(_td->lpActiveKeyboard->lpCoreKeyboardState);
|
||||
}
|
||||
|
||||
_td->CoreProcessEventRun = FALSE;
|
||||
|
||||
|
||||
|
||||
// Process the action items from the core. This actions will modify the windows context (AppContext).
|
||||
// Therefore it is not required to copy the context from the core to the windows context.
|
||||
km_core_actions const* actions = km_core_state_get_actions(_td->lpActiveKeyboard->lpCoreKeyboardState);
|
||||
|
||||
processBack(_td->app, actions->code_points_to_delete, actions->deleted_context);
|
||||
processUnicodeChar(_td->app, actions->output);
|
||||
if (actions->persist_options != NULL) {
|
||||
processPersistOpt(actions, _td->lpActiveKeyboard);
|
||||
processDebugDeleteContext(_td->core_actions->deleted_context);
|
||||
processBack(_td->app, _td->core_actions->code_points_to_delete, _td->core_actions->deleted_context);
|
||||
processBack2(_td->app, _td->core_actions->code_points_to_delete);
|
||||
processUnicodeChar(_td->app, _td->core_actions->output);
|
||||
if (_td->core_actions->persist_options != NULL) {
|
||||
processPersistOpt(_td->core_actions, _td->lpActiveKeyboard);
|
||||
}
|
||||
if (actions->do_alert) {
|
||||
if (_td->core_actions->do_alert) {
|
||||
processAlert(_td->app);
|
||||
}
|
||||
if (actions->emit_keystroke) {
|
||||
if (_td->core_actions->emit_keystroke) {
|
||||
*emitKeyStroke = TRUE;
|
||||
}
|
||||
processCapsLock(actions->new_caps_lock_state, !_td->state.isDown, _td->TIPFUpdateable, FALSE);
|
||||
processCapsLock(_td->core_actions->new_caps_lock_state, !_td->state.isDown, _td->TIPFUpdateable, FALSE);
|
||||
// TODO: #10583 remove dispose
|
||||
km_core_actions_dispose(_td->core_actions);
|
||||
_td->core_actions = nullptr;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -128,15 +210,21 @@ ProcessActionsNonUpdatableParse(BOOL* emitKeyStroke) {
|
|||
if (!_td) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessActionsNonUpdatableParse: Enter");
|
||||
if (_td->TIPFUpdateable) { // ensure only run when not updateable
|
||||
return FALSE;
|
||||
}
|
||||
_td->CoreProcessEventRun = TRUE;
|
||||
// TODO: #10583 remove dispose
|
||||
if (_td->core_actions) {
|
||||
km_core_actions_dispose(_td->core_actions);
|
||||
_td->core_actions = nullptr;
|
||||
}
|
||||
|
||||
km_core_actions const* acts = km_core_state_get_actions(_td->lpActiveKeyboard->lpCoreKeyboardState);
|
||||
processCapsLock(acts->new_caps_lock_state, !_td->state.isDown, _td->TIPFUpdateable, FALSE);
|
||||
if (acts->emit_keystroke) {
|
||||
_td->core_actions = km_core_state_get_actions(_td->lpActiveKeyboard->lpCoreKeyboardState);
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessActionsNonUpdatableParse: km_core_state_get_actions");
|
||||
processCapsLock(_td->core_actions->new_caps_lock_state, !_td->state.isDown, _td->TIPFUpdateable, FALSE);
|
||||
if (_td->core_actions->emit_keystroke) {
|
||||
*emitKeyStroke = TRUE;
|
||||
SendDebugMessageFormat(0, sdmGlobal, 0, "ProcessActionsNonUpdatableParse EMIT_KEYSTROKE");
|
||||
_td->CoreProcessEventRun = FALSE; // If we emit the key stroke on this parse we don't need the second parse
|
||||
|
|
@ -150,7 +238,11 @@ ProcessActionsExternalEvent() {
|
|||
if (!_td) {
|
||||
return FALSE;
|
||||
}
|
||||
km_core_actions const* acts = km_core_state_get_actions(_td->lpActiveKeyboard->lpCoreKeyboardState);
|
||||
processCapsLock(acts->new_caps_lock_state, !_td->state.isDown, FALSE, TRUE);
|
||||
if (!_td->core_actions) { // when ideponent we will not need this
|
||||
return FALSE;
|
||||
}
|
||||
// TODO: #10583 remove dispose
|
||||
//km_core_actions const* acts = km_core_state_get_actions(_td->lpActiveKeyboard->lpCoreKeyboardState);
|
||||
processCapsLock(_td->core_actions->new_caps_lock_state, !_td->state.isDown, FALSE, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue