From aee55993453598f97b1b87c6ea1745414f10d8e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=85=E6=88=8E=E6=B0=8F?= Date: Thu, 9 Jun 2022 23:09:13 +0800 Subject: [PATCH] feat(api): get_state_label returns the state label for UI display enable the frontend to display a message when an arbitrary option defined in the schema is updated. Closes #447 the option name eg. ascii_mode is passed to the notification handler function, there, get_state_label gives IME frontend the access to the human readable label for the current state of the option defined in *.schema:/switches/@*/states. when selection is changed in a radio group, more than one option in the group is updated so it only returns a non-empty label while querying the selected option. --- src/rime_api.cc | 226 +++++++++++++++++++++++--------------- src/rime_api.h | 2 + tools/rime_api_console.cc | 11 ++ 3 files changed, 149 insertions(+), 90 deletions(-) diff --git a/src/rime_api.cc b/src/rime_api.cc index 8a2b0b5fc3..1c974139d9 100644 --- a/src/rime_api.cc +++ b/src/rime_api.cc @@ -980,95 +980,141 @@ void RimeSetCaretPos(RimeSessionId session_id, size_t caret_pos) { return ctx->set_caret_pos(caret_pos); } -RIME_API RimeApi* rime_get_api() { - static RimeApi s_api = {0}; - if (!s_api.data_size) { - RIME_STRUCT_INIT(RimeApi, s_api); - s_api.setup = &RimeSetup; - s_api.set_notification_handler = &RimeSetNotificationHandler; - s_api.initialize = &RimeInitialize; - s_api.finalize = &RimeFinalize; - s_api.start_maintenance = &RimeStartMaintenance; - s_api.is_maintenance_mode = &RimeIsMaintenancing; - s_api.join_maintenance_thread = &RimeJoinMaintenanceThread; - s_api.deployer_initialize = &RimeDeployerInitialize; - s_api.prebuild = &RimePrebuildAllSchemas; - s_api.deploy = &RimeDeployWorkspace; - s_api.deploy_schema = &RimeDeploySchema; - s_api.deploy_config_file = &RimeDeployConfigFile; - s_api.sync_user_data = &RimeSyncUserData; - s_api.create_session = &RimeCreateSession; - s_api.find_session = &RimeFindSession; - s_api.destroy_session = &RimeDestroySession; - s_api.cleanup_stale_sessions = &RimeCleanupStaleSessions; - s_api.cleanup_all_sessions = &RimeCleanupAllSessions; - s_api.process_key = &RimeProcessKey; - s_api.commit_composition = &RimeCommitComposition; - s_api.clear_composition = &RimeClearComposition; - s_api.get_commit = &RimeGetCommit; - s_api.free_commit = &RimeFreeCommit; - s_api.get_context = &RimeGetContext; - s_api.free_context = &RimeFreeContext; - s_api.get_status = &RimeGetStatus; - s_api.free_status = &RimeFreeStatus; - s_api.set_option = &RimeSetOption; - s_api.get_option = &RimeGetOption; - s_api.set_property = &RimeSetProperty; - s_api.get_property = &RimeGetProperty; - s_api.get_schema_list = &RimeGetSchemaList; - s_api.free_schema_list = &RimeFreeSchemaList; - s_api.get_current_schema = &RimeGetCurrentSchema; - s_api.select_schema = &RimeSelectSchema; - s_api.schema_open = &RimeSchemaOpen; - s_api.config_open = &RimeConfigOpen; - s_api.user_config_open = &RimeUserConfigOpen; - s_api.config_close = &RimeConfigClose; - s_api.config_get_bool = &RimeConfigGetBool; - s_api.config_get_int = &RimeConfigGetInt; - s_api.config_get_double = &RimeConfigGetDouble; - s_api.config_get_string = &RimeConfigGetString; - s_api.config_get_cstring = &RimeConfigGetCString; - s_api.config_update_signature = &RimeConfigUpdateSignature; - s_api.config_begin_map = &RimeConfigBeginMap; - s_api.config_next = &RimeConfigNext; - s_api.config_end = &RimeConfigEnd; - s_api.simulate_key_sequence = &RimeSimulateKeySequence; - s_api.register_module = &RimeRegisterModule; - s_api.find_module = &RimeFindModule; - s_api.run_task = &RimeRunTask; - s_api.get_shared_data_dir = &RimeGetSharedDataDir; - s_api.get_user_data_dir = &RimeGetUserDataDir; - s_api.get_sync_dir = &RimeGetSyncDir; - s_api.get_user_id = &RimeGetUserId; - s_api.get_user_data_sync_dir = &RimeGetUserDataSyncDir; - s_api.config_init = &RimeConfigInit; - s_api.config_load_string = &RimeConfigLoadString; - s_api.config_set_bool = &RimeConfigSetBool; - s_api.config_set_int = &RimeConfigSetInt; - s_api.config_set_double = &RimeConfigSetDouble; - s_api.config_set_string = &RimeConfigSetString; - s_api.config_get_item = &RimeConfigGetItem; - s_api.config_set_item = &RimeConfigSetItem; - s_api.config_clear = &RimeConfigClear; - s_api.config_create_list = &RimeConfigCreateList; - s_api.config_create_map = &RimeConfigCreateMap; - s_api.config_list_size = &RimeConfigListSize; - s_api.config_begin_list = &RimeConfigBeginList; - s_api.get_input = &RimeGetInput; - s_api.get_caret_pos = &RimeGetCaretPos; - s_api.select_candidate = &RimeSelectCandidate; - s_api.get_version = &RimeGetVersion; - s_api.set_caret_pos = &RimeSetCaretPos; - s_api.select_candidate_on_current_page = &RimeSelectCandidateOnCurrentPage; - s_api.candidate_list_begin = &RimeCandidateListBegin; - s_api.candidate_list_next = &RimeCandidateListNext; - s_api.candidate_list_end = &RimeCandidateListEnd; - s_api.candidate_list_from_index = &RimeCandidateListFromIndex; - s_api.get_prebuilt_data_dir = &RimeGetPrebuiltDataDir; - s_api.get_staging_dir = &RimeGetStagingDir; - s_api.commit_proto = nullptr; - s_api.context_proto = nullptr; - s_api.status_proto = nullptr; +const char* RimeGetStateLabel(RimeSessionId session_id, + const char* option_name, + Bool state) { + an session(Service::instance().GetSession(session_id)); + if (!session) + return nullptr; + Config* config = session->schema()->config(); + if (!config) + return nullptr; + auto switches = (*config)["switches"]; + if (!switches.IsList()) + return nullptr; + string query = option_name; + for (size_t i = 0; i < switches.size(); ++i) { + auto item = switches[i]; + if (!item.IsMap()) + continue; + auto states = item["states"]; + if (!states.IsList()) + continue; + auto name = item["name"]; + if (name.IsValue() && name.ToString() == query) { + size_t j = static_cast(state); + return states.size() > j + ? As(*states[j])->str().c_str() + : nullptr; + } + auto options = item["options"]; + if (options.IsList()) { + // if the query is a deselected option among the radio group, do not + // display its state label; only show the selected option. + if (!state) + return nullptr; + for (size_t j = 0; j < options.size(); ++j) { + if (options[j].IsValue() && options[j].ToString() == query) { + return states.size() > j + ? As(*states[j])->str().c_str() + : nullptr; + } + } } - return &s_api; + } + return nullptr; +} + +RIME_API RimeApi* rime_get_api() { + static RimeApi s_api = {0}; + if (!s_api.data_size) { + RIME_STRUCT_INIT(RimeApi, s_api); + s_api.setup = &RimeSetup; + s_api.set_notification_handler = &RimeSetNotificationHandler; + s_api.initialize = &RimeInitialize; + s_api.finalize = &RimeFinalize; + s_api.start_maintenance = &RimeStartMaintenance; + s_api.is_maintenance_mode = &RimeIsMaintenancing; + s_api.join_maintenance_thread = &RimeJoinMaintenanceThread; + s_api.deployer_initialize = &RimeDeployerInitialize; + s_api.prebuild = &RimePrebuildAllSchemas; + s_api.deploy = &RimeDeployWorkspace; + s_api.deploy_schema = &RimeDeploySchema; + s_api.deploy_config_file = &RimeDeployConfigFile; + s_api.sync_user_data = &RimeSyncUserData; + s_api.create_session = &RimeCreateSession; + s_api.find_session = &RimeFindSession; + s_api.destroy_session = &RimeDestroySession; + s_api.cleanup_stale_sessions = &RimeCleanupStaleSessions; + s_api.cleanup_all_sessions = &RimeCleanupAllSessions; + s_api.process_key = &RimeProcessKey; + s_api.commit_composition = &RimeCommitComposition; + s_api.clear_composition = &RimeClearComposition; + s_api.get_commit = &RimeGetCommit; + s_api.free_commit = &RimeFreeCommit; + s_api.get_context = &RimeGetContext; + s_api.free_context = &RimeFreeContext; + s_api.get_status = &RimeGetStatus; + s_api.free_status = &RimeFreeStatus; + s_api.set_option = &RimeSetOption; + s_api.get_option = &RimeGetOption; + s_api.set_property = &RimeSetProperty; + s_api.get_property = &RimeGetProperty; + s_api.get_schema_list = &RimeGetSchemaList; + s_api.free_schema_list = &RimeFreeSchemaList; + s_api.get_current_schema = &RimeGetCurrentSchema; + s_api.select_schema = &RimeSelectSchema; + s_api.schema_open = &RimeSchemaOpen; + s_api.config_open = &RimeConfigOpen; + s_api.user_config_open = &RimeUserConfigOpen; + s_api.config_close = &RimeConfigClose; + s_api.config_get_bool = &RimeConfigGetBool; + s_api.config_get_int = &RimeConfigGetInt; + s_api.config_get_double = &RimeConfigGetDouble; + s_api.config_get_string = &RimeConfigGetString; + s_api.config_get_cstring = &RimeConfigGetCString; + s_api.config_update_signature = &RimeConfigUpdateSignature; + s_api.config_begin_map = &RimeConfigBeginMap; + s_api.config_next = &RimeConfigNext; + s_api.config_end = &RimeConfigEnd; + s_api.simulate_key_sequence = &RimeSimulateKeySequence; + s_api.register_module = &RimeRegisterModule; + s_api.find_module = &RimeFindModule; + s_api.run_task = &RimeRunTask; + s_api.get_shared_data_dir = &RimeGetSharedDataDir; + s_api.get_user_data_dir = &RimeGetUserDataDir; + s_api.get_sync_dir = &RimeGetSyncDir; + s_api.get_user_id = &RimeGetUserId; + s_api.get_user_data_sync_dir = &RimeGetUserDataSyncDir; + s_api.config_init = &RimeConfigInit; + s_api.config_load_string = &RimeConfigLoadString; + s_api.config_set_bool = &RimeConfigSetBool; + s_api.config_set_int = &RimeConfigSetInt; + s_api.config_set_double = &RimeConfigSetDouble; + s_api.config_set_string = &RimeConfigSetString; + s_api.config_get_item = &RimeConfigGetItem; + s_api.config_set_item = &RimeConfigSetItem; + s_api.config_clear = &RimeConfigClear; + s_api.config_create_list = &RimeConfigCreateList; + s_api.config_create_map = &RimeConfigCreateMap; + s_api.config_list_size = &RimeConfigListSize; + s_api.config_begin_list = &RimeConfigBeginList; + s_api.get_input = &RimeGetInput; + s_api.get_caret_pos = &RimeGetCaretPos; + s_api.select_candidate = &RimeSelectCandidate; + s_api.get_version = &RimeGetVersion; + s_api.set_caret_pos = &RimeSetCaretPos; + s_api.select_candidate_on_current_page = &RimeSelectCandidateOnCurrentPage; + s_api.candidate_list_begin = &RimeCandidateListBegin; + s_api.candidate_list_next = &RimeCandidateListNext; + s_api.candidate_list_end = &RimeCandidateListEnd; + s_api.candidate_list_from_index = &RimeCandidateListFromIndex; + s_api.get_prebuilt_data_dir = &RimeGetPrebuiltDataDir; + s_api.get_staging_dir = &RimeGetStagingDir; + s_api.commit_proto = nullptr; + s_api.context_proto = nullptr; + s_api.status_proto = nullptr; + s_api.get_state_label = &RimeGetStateLabel; + } + return &s_api; } diff --git a/src/rime_api.h b/src/rime_api.h index 5a881280d0..91d8a02307 100644 --- a/src/rime_api.h +++ b/src/rime_api.h @@ -550,6 +550,8 @@ typedef struct rime_api_t { void (*commit_proto)(RimeSessionId session_id, RIME_PROTO_BUILDER* commit_builder); void (*context_proto)(RimeSessionId session_id, RIME_PROTO_BUILDER* context_builder); void (*status_proto)(RimeSessionId session_id, RIME_PROTO_BUILDER* status_builder); + + const char* (*get_state_label)(RimeSessionId session_id, const char *option_name, Bool state); } RimeApi; //! API entry diff --git a/tools/rime_api_console.cc b/tools/rime_api_console.cc index f17f15334e..31ce6c23d6 100644 --- a/tools/rime_api_console.cc +++ b/tools/rime_api_console.cc @@ -167,6 +167,17 @@ void on_message(void* context_object, const char* message_type, const char* message_value) { printf("message: [%lu] [%s] %s\n", session_id, message_type, message_value); + RimeApi* rime = rime_get_api(); + if (RIME_API_AVAILABLE(rime, get_state_label) && + !strcmp(message_type, "option")) { + Bool state = message_value[0] != '!'; + const char* option_name = message_value + !state; + const char* state_label = + rime->get_state_label(session_id, option_name, state); + if (state_label) { + printf("updated state: %s = %d // %s\n", option_name, state, state_label); + } + } } int main(int argc, char *argv[]) {