编辑文本相关处理排队处理

Signed-off-by: cy7717 <chenyu301@huawei.com>
This commit is contained in:
cy7717 2023-07-08 18:13:05 +08:00
parent ba8c941ddb
commit 06dbe5c373
9 changed files with 123 additions and 42 deletions

71
common/queue.h Normal file
View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OHOS_INPUTMETHOD_QUEUE_H
#define OHOS_INPUTMETHOD_QUEUE_H
#include <condition_variable>
#include <mutex>
#include <queue>
namespace OHOS {
namespace MiscServices {
template<typename T> class Queue {
public:
explicit Queue(uint32_t interval) : INTERVAL(interval)
{
}
~Queue()
{
}
void Pop()
{
std::lock_guard<std::mutex> lock(queuesMutex_);
queues_.pop();
execCv_.notify_all();
}
void Push(const T &data)
{
std::lock_guard<std::mutex> lock(queuesMutex_);
queues_.push(data);
}
void WaitExec(const T &data)
{
if (!IsReadyToExec(data)) {
std::unique_lock<std::mutex> lock(execMutex_);
execCv_.wait_for(
lock, std::chrono::milliseconds(INTERVAL), [&data, this]() { return IsReadyToExec(data); });
}
}
bool IsReadyToExec(const T &data)
{
std::lock_guard<std::mutex> lock(queuesMutex_);
return data == queues_.front();
}
private:
const uint32_t INTERVAL;
std::mutex queuesMutex_;
std::queue<T> queues_;
std::mutex execMutex_;
std::condition_variable execCv_;
};
} // namespace MiscServices
} // namespace OHOS
#endif // OHOS_INPUTMETHOD_QUEUE_H

View File

@ -19,6 +19,7 @@
#include <mutex>
namespace OHOS {
namespace MiscServices {
template<typename T> class BlockData {
public:
explicit BlockData(uint32_t interval, const T &invalid = T()) : INTERVAL(interval), data_(invalid)
@ -67,5 +68,6 @@ private:
std::mutex mutex_;
std::condition_variable cv_;
};
} // namespace MiscServices
} // namespace OHOS
#endif // OHOS_INPUTMETHOD_IMF_FRAMEWORKS_BLOCK_DATA_H

View File

@ -18,6 +18,7 @@ config("inputmethodengine_native_config") {
visibility = [ ":*" ]
include_dirs = [
"include",
"${inputmethod_path}/common",
"${inputmethod_path}/frameworks/common",
"${inputmethod_path}/frameworks/native/inputmethod_ability/include",
"${inputmethod_path}/frameworks/native/inputmethod_controller/include",
@ -35,6 +36,7 @@ config("inputmethodengine_native_public_config") {
visibility = [ "./*" ]
include_dirs = [
"include",
"${inputmethod_path}/common",
"${inputmethod_path}/frameworks/common",
"${inputmethod_path}/frameworks/js/napi/inputmethodclient",
"${inputmethod_path}/frameworks/js/napi/inputmethodability",

View File

@ -18,13 +18,17 @@ config("imf_config") {
visibility = [ ":*" ]
include_dirs = [
"include",
"../inputmethodability",
"${inputmethod_path}/common",
"${inputmethod_path}/frameworks/js/napi/inputmethodability",
]
}
config("imf_public_config") {
visibility = [ "./*" ]
include_dirs = [ "include" ]
include_dirs = [
"include",
"${inputmethod_path}/common",
]
ldflags = [ "-Wl,--exclude-libs=ALL" ]
cflags = [
"-fdata-sections",

View File

@ -16,6 +16,7 @@
#include "async_call.h"
#include <algorithm>
#include <set>
#include "global.h"
#include "js_utils.h"
@ -23,6 +24,10 @@
namespace OHOS {
namespace MiscServices {
constexpr size_t ARGC_MAX = 6;
constexpr int32_t MAX_WAIT_TIME = 1000;
std::shared_ptr<Queue<EventInfo>> AsyncCall::queues_ = std::make_shared<Queue<EventInfo>>(MAX_WAIT_TIME);
const std::set<std::string> QUEUE_EVENT_TYPE{ "moveCursor", "deleteForward", "deleteBackward", "insertText",
"getForward", "getBackward", "selectByRange", "selectByMovement", "sendExtendAction", "getTextIndexAtCursor" };
AsyncCall::AsyncCall(napi_env env, napi_callback_info info, std::shared_ptr<Context> context, size_t maxParamCount)
: env_(env)
{
@ -75,6 +80,10 @@ napi_value AsyncCall::Call(napi_env env, Context::ExecAction exec, const std::st
napi_value resource = nullptr;
std::string name = "IMF_" + resourceName;
napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &resource);
if (QUEUE_EVENT_TYPE.find(resourceName) != QUEUE_EVENT_TYPE.end()) {
context_->ctx->eventInfo = { std::chrono::system_clock::now(), resourceName };
queues_->Push(context_->ctx->eventInfo);
}
napi_create_async_work(env, nullptr, resource, AsyncCall::OnExecute, AsyncCall::OnComplete, context_, &work);
context_->work = work;
context_ = nullptr;
@ -103,7 +112,13 @@ napi_value AsyncCall::SyncCall(napi_env env, AsyncCall::Context::ExecAction exec
void AsyncCall::OnExecute(napi_env env, void *data)
{
AsyncContext *context = reinterpret_cast<AsyncContext *>(data);
if (QUEUE_EVENT_TYPE.find(context->ctx->eventInfo.type) != QUEUE_EVENT_TYPE.end()) {
queues_->WaitExec(context->ctx->eventInfo);
}
context->ctx->Exec();
if (QUEUE_EVENT_TYPE.find(context->ctx->eventInfo.type) != QUEUE_EVENT_TYPE.end()) {
queues_->Pop();
}
}
void AsyncCall::OnComplete(napi_env env, napi_status status, void *data)

View File

@ -15,15 +15,24 @@
#ifndef ASYN_CALL_H
#define ASYN_CALL_H
#include "input_method_info.h"
#include "global.h"
#include "input_method_info.h"
#include "js_utils.h"
#include "napi/native_api.h"
#include "napi/native_common.h"
#include "napi/native_node_api.h"
#include "queue.h"
namespace OHOS {
namespace MiscServices {
struct EventInfo {
std::chrono::system_clock::time_point timestamp{};
std::string type;
bool operator==(const EventInfo &info) const
{
return (timestamp == info.timestamp && type == info.type);
}
};
class AsyncCall final {
public:
class Context {
@ -91,6 +100,7 @@ public:
ExecAction exec_ = nullptr;
napi_status status_ = napi_generic_failure;
int32_t errorCode_ = 0;
EventInfo eventInfo;
};
AsyncCall(napi_env env, napi_callback_info info, std::shared_ptr<Context> context, size_t maxParamCount);
~AsyncCall();
@ -111,6 +121,7 @@ private:
static void DeleteContext(napi_env env, AsyncContext *context);
AsyncContext *context_ = nullptr;
napi_env env_ = nullptr;
static std::shared_ptr<Queue<EventInfo>> queues_;
};
} // namespace MiscServices
} // namespace OHOS

View File

@ -18,6 +18,7 @@ config("inputmethod_services_native_config") {
visibility = [ ":*" ]
include_dirs = [
"include",
"${inputmethod_path}/common",
"${inputmethod_path}/frameworks/common",
"${inputmethod_path}/frameworks/native/inputmethod_ability/include",
"${inputmethod_path}/frameworks/native/inputmethod_controller/include",

View File

@ -30,6 +30,7 @@
#include "inputmethod_dump.h"
#include "inputmethod_trace.h"
#include "peruser_session.h"
#include "queue.h"
#include "system_ability.h"
namespace OHOS {
@ -113,15 +114,8 @@ private:
static constexpr const char *SELECT_DIALOG_ACTION = "action.system.inputmethodchoose";
static constexpr const char *SELECT_DIALOG_HAP = "cn.openharmony.inputmethodchoosedialog";
static constexpr const char *SELECT_DIALOG_ABILITY = "InputMethod";
std::mutex switchMutex_;
std::condition_variable switchCV_;
std::mutex switchQueueMutex_;
std::queue<SwitchInfo> switchQueue_;
void PopSwitchQueue();
void PushToSwitchQueue(const SwitchInfo &info);
bool CheckReadyToSwitch(const SwitchInfo &info);
static constexpr int32_t MAX_WAIT_TIME = 1000;
std::shared_ptr<Queue<SwitchInfo>> switchQueues_{ nullptr };
int32_t InitKeyEventMonitor();
bool InitFocusChangeMonitor();
int32_t SwitchByCombinationKey(uint32_t state);

View File

@ -180,6 +180,7 @@ void InputMethodSystemAbility::Initialize()
workThreadHandler = std::thread([this] { WorkThread(); });
userSession_ = std::make_shared<PerUserSession>(MAIN_USER_ID);
userId_ = MAIN_USER_ID;
switchQueues_ = std::make_shared<Queue<SwitchInfo>>(MAX_WAIT_TIME);
}
void InputMethodSystemAbility::StartUserIdListener()
@ -357,39 +358,19 @@ int32_t InputMethodSystemAbility::DisplayOptionalInputMethod()
return OnDisplayOptionalInputMethod();
};
void InputMethodSystemAbility::PushToSwitchQueue(const SwitchInfo &info)
{
std::lock_guard<std::mutex> lock(switchQueueMutex_);
switchQueue_.push(info);
}
void InputMethodSystemAbility::PopSwitchQueue()
{
std::lock_guard<std::mutex> lock(switchQueueMutex_);
switchQueue_.pop();
switchCV_.notify_all();
}
bool InputMethodSystemAbility::CheckReadyToSwitch(const SwitchInfo &info)
{
std::lock_guard<std::mutex> lock(switchQueueMutex_);
return info == switchQueue_.front();
}
int32_t InputMethodSystemAbility::SwitchInputMethod(const std::string &bundleName, const std::string &subName)
{
SwitchInfo switchInfo = { std::chrono::system_clock::now(), bundleName, subName };
PushToSwitchQueue(switchInfo);
switchQueues_->Push(switchInfo);
return OnSwitchInputMethod(switchInfo, true);
}
int32_t InputMethodSystemAbility::OnSwitchInputMethod(const SwitchInfo &switchInfo, bool isCheckPermission)
{
IMSA_HILOGD("run in, switchInfo: %{public}s|%{public}s", switchInfo.bundleName.c_str(), switchInfo.subName.c_str());
if (!CheckReadyToSwitch(switchInfo)) {
if (!switchQueues_->IsReadyToExec(switchInfo)) {
IMSA_HILOGD("start wait");
std::unique_lock<std::mutex> lock(switchMutex_);
switchCV_.wait(lock, [this, &switchInfo]() { return CheckReadyToSwitch(switchInfo); });
switchQueues_->WaitExec(switchInfo);
usleep(SWITCH_BLOCK_TIME);
}
IMSA_HILOGD("start switch %{public}s", (switchInfo.bundleName + '/' + switchInfo.subName).c_str());
@ -399,21 +380,21 @@ int32_t InputMethodSystemAbility::OnSwitchInputMethod(const SwitchInfo &switchIn
&& !BundleChecker::CheckPermission(IPCSkeleton::GetCallingTokenID(), PERMISSION_CONNECT_IME_ABILITY)
&& !(switchInfo.bundleName == currentIme
&& BundleChecker::IsCurrentIme(IPCSkeleton::GetCallingTokenID(), currentIme))) {
PopSwitchQueue();
switchQueues_->Pop();
return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
}
if (!IsNeedSwitch(switchInfo.bundleName, switchInfo.subName)) {
PopSwitchQueue();
switchQueues_->Pop();
return ErrorCode::NO_ERROR;
}
ImeInfo info;
int32_t ret = ImeInfoInquirer::GetInstance().GetImeInfo(userId_, switchInfo.bundleName, switchInfo.subName, info);
if (ret != ErrorCode::NO_ERROR) {
PopSwitchQueue();
switchQueues_->Pop();
return ret;
}
ret = info.isNewIme ? Switch(switchInfo.bundleName, info) : SwitchExtension(info);
PopSwitchQueue();
switchQueues_->Pop();
return ret;
}
@ -710,7 +691,7 @@ int32_t InputMethodSystemAbility::SwitchMode()
return ErrorCode::ERROR_BAD_PARAMETERS;
}
SwitchInfo switchInfo = { std::chrono::system_clock::now(), target->name, target->id };
PushToSwitchQueue(switchInfo);
switchQueues_->Push(switchInfo);
return OnSwitchInputMethod(switchInfo, false);
}
@ -734,7 +715,7 @@ int32_t InputMethodSystemAbility::SwitchLanguage()
return ErrorCode::ERROR_BAD_PARAMETERS;
}
SwitchInfo switchInfo = { std::chrono::system_clock::now(), target->name, target->id };
PushToSwitchQueue(switchInfo);
switchQueues_->Push(switchInfo);
return OnSwitchInputMethod(switchInfo, false);
}
@ -751,7 +732,7 @@ int32_t InputMethodSystemAbility::SwitchType()
[&currentImeBundle](const Property &property) { return property.name != currentImeBundle; });
if (iter != props.end()) {
SwitchInfo switchInfo = { std::chrono::system_clock::now(), iter->name, "" };
PushToSwitchQueue(switchInfo);
switchQueues_->Push(switchInfo);
return OnSwitchInputMethod(switchInfo, false);
}
return ErrorCode::NO_ERROR;