* Copyright (c) 2025 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.
*/
#include "inputConsumer_keyOptions_impl.h"
#include "inputConsumer_hotkeyOptions_impl.h"
#include "inputConsumer_keyPressed_impl.h"
#include "mmi_api_metrics_histograms.h"
#include "permission_helper.h"
#include "trigger_event_dispatcher.h"
#undef MMI_LOG_TAG
#define MMI_LOG_TAG "AniConsumerImpl"
using namespace taihe;
using namespace ohos::multimodalInput::inputConsumer;
using namespace OHOS::MMI;
namespace {
using HotkeyOptions_t = ::ohos::multimodalInput::inputConsumer::HotkeyOptions;
static constexpr size_t PRE_KEYS_SIZE { 4 };
static constexpr int32_t INVALID_SUBSCRIBER_ID { -1 };
static constexpr int32_t OCCUPIED_BY_SYSTEM = -3;
static constexpr int32_t OCCUPIED_BY_OTHER = -4;
constexpr size_t FIRST_INDEX { 0 };
constexpr size_t SECOND_INDEX { 1 };
constexpr size_t THIRD_INDEX { 2 };
constexpr size_t FOURTH_INDEX { 3 };
const int64_t MILLISECONDS_IN_SECOND = 1000;
constexpr int32_t TRIGGER_TYPE_MIN { 1 };
constexpr int32_t TRIGGER_TYPE_MAX { 3 };
enum ETS_CALLBACK_EVENT {
ETS_CALLBACK_EVENT_FAILED = -1,
ETS_CALLBACK_EVENT_SUCCESS = 1,
ETS_CALLBACK_EVENT_EXIST = 2,
ETS_CALLBACK_EVENT_NOT_EXIST = 3,
};
enum EtsErrorCode : int32_t {
OTHER_ERROR = -1,
COMMON_PERMISSION_CHECK_ERROR = 201,
COMMON_USE_SYSAPI_ERROR = 202,
COMMON_PARAMETER_ERROR = 401,
INPUT_DEVICE_NOT_SUPPORTED = 801,
COMMON_DEVICE_NOT_EXIST = 3900001,
COMMON_KEYBOARD_DEVICE_NOT_EXIST = 3900002,
COMMON_NON_INPUT_APPLICATION = 3900003,
PRE_KEY_NOT_SUPPORTED = 4100001,
INPUT_OCCUPIED_BY_SYSTEM = 4200002,
INPUT_OCCUPIED_BY_OTHER = 4200003,
ERROR_WINDOW_ID_PERMISSION_DENIED = 26500001,
};
struct KeyMonitor {
int32_t subscriberId { -1 };
KeyMonitorOption keyOption {};
};
struct KeyEventMonitorInfo {
std::string eventType;
int32_t subscribeId{ 0 };
std::shared_ptr<KeyOption> keyOption{ nullptr };
~KeyEventMonitorInfo();
};
typedef std::map<std::string, std::list<std::shared_ptr<KeyEventMonitorInfo>>> Callbacks;
static Callbacks hotkeyCallbacks = {};
static Callbacks keyCallbacks = {};
using callbackType = std::variant<
taihe::callback<void(KeyOptions const&)>,
taihe::callback<void(HotkeyOptions const&)>,
taihe::callback<void(ohos::multimodalInput::keyEvent::KeyEvent const&)>,
taihe::callback<void(KeyOptions const&, ohos::multimodalInput::keyEvent::KeyEvent const&)>
>;
struct CallbackObject {
CallbackObject(callbackType cb, ani_ref ref) : callback(cb), ref(ref)
{
CALL_DEBUG_ENTER;
}
~CallbackObject()
{
CALL_DEBUG_ENTER;
if (auto *env = taihe::get_env()) {
if (ref) {
env->GlobalReference_Delete(ref);
ref = nullptr;
}
}
}
callbackType callback;
ani_ref ref;
};
class GlobalRefGuard {
ani_env *env_ = nullptr;
ani_ref ref_ = nullptr;
public:
GlobalRefGuard(ani_env *env, ani_object obj) : env_(env)
{
if (!env_) {
return;
}
if (ANI_OK != env_->GlobalReference_Create(obj, &ref_)) {
ref_ = nullptr;
}
}
explicit operator bool() const
{
return ref_ != nullptr;
}
ani_ref get() const
{
return ref_;
}
~GlobalRefGuard()
{
if (env_ && ref_) {
env_->GlobalReference_Delete(ref_);
}
}
GlobalRefGuard(const GlobalRefGuard &) = delete;
GlobalRefGuard &operator=(const GlobalRefGuard &) = delete;
};
std::map<size_t, KeyMonitor> monitors_;
std::map<std::string, std::vector<std::shared_ptr<CallbackObject>>> jsCbMap_;
std::mutex g_mutex;
std::mutex sCallBacksMutex;
std::mutex jsCbMapMutex;
std::atomic<size_t> g_baseId { 0 };
KeyEventMonitorInfo::~KeyEventMonitorInfo() {}
void HandleCommonErrors(int32_t ret, std::function<void(int32_t)> histogramError)
{
int32_t errorCode = std::abs(ret);
if (errorCode == COMMON_USE_SYSAPI_ERROR) {
MMI_HILOGE("Non system applications use system API");
taihe::set_business_error(COMMON_USE_SYSAPI_ERROR, "Non system applications use system API");
histogramError(COMMON_USE_SYSAPI_ERROR);
} else if (errorCode == COMMON_PERMISSION_CHECK_ERROR) {
MMI_HILOGE("Shield api need ohos.permission.INPUT_CONTROL_DISPATCHING");
taihe::set_business_error(COMMON_PERMISSION_CHECK_ERROR,
"Shield api need ohos.permission.INPUT_CONTROL_DISPATCHING");
histogramError(COMMON_PERMISSION_CHECK_ERROR);
} else if (errorCode == COMMON_PARAMETER_ERROR) {
MMI_HILOGE("Parameter error");
taihe::set_business_error(COMMON_PARAMETER_ERROR, "Parameter error");
histogramError(COMMON_PARAMETER_ERROR);
} else if (errorCode != RET_OK) {
MMI_HILOGE("Unknown error, errorCode:%{public}d", errorCode);
taihe::set_business_error(COMMON_PARAMETER_ERROR, "Parameter error.unknown error");
histogramError(COMMON_PARAMETER_ERROR);
}
}
int32_t RegisterListener(std::string const &type, callbackType &&cb, uintptr_t opq)
{
std::lock_guard<std::mutex> lock(jsCbMapMutex);
ani_object callbackObj = reinterpret_cast<ani_object>(opq);
ani_ref callbackRef;
ani_env *env = taihe::get_env();
if (env == nullptr || ANI_OK != env->GlobalReference_Create(callbackObj, &callbackRef)) {
MMI_HILOGE("ani_env is nullptr or GlobalReference_Create failed");
return ETS_CALLBACK_EVENT_FAILED;
}
auto &cbVec = jsCbMap_[type];
bool isDuplicate = std::any_of(cbVec.begin(), cbVec.end(),
[env, callbackRef](std::shared_ptr<CallbackObject> &obj) {
ani_boolean isEqual = false;
return (ANI_OK == env->Reference_StrictEquals(callbackRef, obj->ref, &isEqual)) && isEqual;
});
if (isDuplicate) {
env->GlobalReference_Delete(callbackRef);
MMI_HILOGD("callback already registered");
return ETS_CALLBACK_EVENT_EXIST;
}
cbVec.emplace_back(std::make_shared<CallbackObject>(cb, callbackRef));
MMI_HILOGI("register callback success, type: %{public}s", type.c_str());
return ETS_CALLBACK_EVENT_SUCCESS;
}
bool UnregisterListener(std::string const &type, taihe::optional_view<uintptr_t> opq)
{
std::lock_guard<std::mutex> lock(jsCbMapMutex);
const auto iter = jsCbMap_.find(type);
if (iter == jsCbMap_.end()) {
MMI_HILOGE("Already unRegistered!");
return false;
}
if (!opq.has_value()) {
jsCbMap_.erase(iter);
MMI_HILOGE("callback is nullptr!");
return false;
}
ani_env *env = taihe::get_env();
if (env == nullptr) {
MMI_HILOGE("ani_env is nullptr!");
return false;
}
GlobalRefGuard guard(env, reinterpret_cast<ani_object>(opq.value()));
if (!guard) {
MMI_HILOGE("GlobalRefGuard is false!");
return false;
}
const auto pred = [env, targetRef = guard.get()](std::shared_ptr<CallbackObject> &obj) {
ani_boolean isEqual = false;
return (ANI_OK == env->Reference_StrictEquals(targetRef, obj->ref, &isEqual)) && isEqual;
};
auto &callbacks = iter->second;
const auto it = std::find_if(callbacks.begin(), callbacks.end(), pred);
if (it != callbacks.end()) {
callbacks.erase(it);
} else {
return false;
}
if (callbacks.empty()) {
jsCbMap_.erase(iter);
}
MMI_HILOGI("Unregister callback success, type: %{public}s", type.c_str());
return true;
}
size_t GenerateId()
{
return g_baseId++;
}
void EmitKeyPerssedCallbackWork(size_t keyMonitorId, std::shared_ptr<KeyEvent> keyEvent)
{
CALL_DEBUG_ENTER;
std::lock_guard<std::mutex> lock(jsCbMapMutex);
auto &cbVec = jsCbMap_[std::to_string(keyMonitorId)];
for (auto &cb : cbVec) {
if (cb == nullptr) {
continue;
}
size_t typeIndex = cb->callback.index();
if (typeIndex == THIRD_INDEX) {
auto &func = std::get<
taihe::callback<void(ohos::multimodalInput::keyEvent::KeyEvent const&)>>(cb->callback);
auto keyPresseds = ConvertTaiheKeyPressed(keyEvent);
func(keyPresseds);
}
}
}
void OnSubscribeKeyMonitor(size_t keyMonitorId, std::shared_ptr<KeyEvent> keyEvent)
{
CALL_DEBUG_ENTER;
CHKPV(keyEvent);
std::lock_guard guard(g_mutex);
auto mIter = monitors_.find(keyMonitorId);
if (mIter == monitors_.end()) {
MMI_HILOGE("No key monitor with ID(%{public}zu)", keyMonitorId);
return;
}
EmitKeyPerssedCallbackWork(keyMonitorId, keyEvent);
}
bool CheckKeyMonitorOption(const KeyMonitorOption &keyOption)
{
return ((allowedKeys_.find(keyOption.GetKey()) != allowedKeys_.cend()) &&
((keyOption.GetAction() == KeyEvent::KEY_ACTION_DOWN) ||
(keyOption.GetAction() == KeyEvent::KEY_ACTION_UP)));
}
bool ParseKeyMonitorOption(KeyPressedConfig const& options, KeyMonitor &keyMonitor)
{
CALL_DEBUG_ENTER;
keyMonitor.keyOption.SetKey(options.key);
keyMonitor.keyOption.SetAction(EtsKeyActionToKeyAction(options.action));
keyMonitor.keyOption.SetRepeat(options.isRepeat);
if (!CheckKeyMonitorOption(keyMonitor.keyOption)) {
MMI_HILOGE("Input for KeyPressedConfig is invalid");
taihe::set_business_error(COMMON_PARAMETER_ERROR, "Input for KeyPressedConfig is invalid");
return false;
}
return true;
}
void SubscribeKeyMonitor(KeyPressedConfig const& options,
callback_view<void(ohos::multimodalInput::keyEvent::KeyEvent const&)> f, uintptr_t opq)
{
std::lock_guard guard(g_mutex);
KeyMonitor keyMonitor {};
if (!ParseKeyMonitorOption(options, keyMonitor)) {
MMI_HILOGE("Invalid KeyMonitorOption");
return;
}
MMI_HILOGI("[ETS] Subscribe key monitor");
auto keyMonitorId = GenerateId();
auto result = RegisterListener(std::to_string(keyMonitorId), f, opq);
if (result == ETS_CALLBACK_EVENT_FAILED) {
MMI_HILOGE("Register listener failed");
return;
}
if (result == ETS_CALLBACK_EVENT_EXIST) {
MMI_HILOGE("Callback already exist");
return;
}
auto subscriberId = InputManager::GetInstance()->SubscribeKeyMonitor(keyMonitor.keyOption,
[keyMonitorId](std::shared_ptr<KeyEvent> keyEvent) {
OnSubscribeKeyMonitor(keyMonitorId, keyEvent);
});
if (subscriberId < 0) {
if (subscriberId == -CAPABILITY_NOT_SUPPORTED) {
MMI_HILOGE("Capability not supported");
taihe::set_business_error(INPUT_DEVICE_NOT_SUPPORTED, "Capability not supported.");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.on_keyPressed.Error", INPUT_DEVICE_NOT_SUPPORTED);
} else if (subscriberId == -PARAM_INPUT_INVALID) {
MMI_HILOGE("Input is invalid");
taihe::set_business_error(COMMON_PARAMETER_ERROR, "Input is invalid");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.on_keyPressed.Error", COMMON_PARAMETER_ERROR);
} else {
MMI_HILOGE("SubscribeKeyMonitor fail, error:%{public}d", subscriberId);
}
{
std::lock_guard<std::mutex> lock(jsCbMapMutex);
jsCbMap_.erase(std::to_string(keyMonitorId));
}
return;
}
MMI_HILOGI("[ETS] Subscribe key monitor(ID:%{public}zu, subscriberId:%{public}d)", keyMonitorId, subscriberId);
if (result == ETS_CALLBACK_EVENT_SUCCESS) {
keyMonitor.subscriberId = subscriberId;
monitors_.emplace(keyMonitorId, keyMonitor);
}
}
void UnsubscribeKeyMonitor(taihe::optional_view<uintptr_t> opq)
{
std::lock_guard guard(g_mutex);
for (auto iter = monitors_.begin(); iter != monitors_.end(); ++iter) {
if (!UnregisterListener(std::to_string(iter->first), opq)) {
MMI_HILOGE("UnregisterListener fail");
continue;
}
MMI_HILOGI("[NAPI] Unsubscribe key monitor(ID:%{public}zu, subscriberId:%{public}d)",
iter->first, iter->second.subscriberId);
auto ret = InputManager::GetInstance()->UnsubscribeKeyMonitor(iter->second.subscriberId);
if (ret == -CAPABILITY_NOT_SUPPORTED) {
MMI_HILOGE("Capability not supported");
taihe::set_business_error(INPUT_DEVICE_NOT_SUPPORTED, "Capability not supported.");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.off_keyPressed.Error", INPUT_DEVICE_NOT_SUPPORTED);
} else if (ret == -PARAM_INPUT_INVALID) {
MMI_HILOGE("Input is invalid");
taihe::set_business_error(COMMON_PARAMETER_ERROR, "Input is invalid");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.off_keyPressed.Error", COMMON_PARAMETER_ERROR);
} else if (ret != RET_OK) {
MMI_HILOGE("UnsubscribeKeyMonitor fail, error:%{public}d", ret);
}
monitors_.erase(iter);
return;
}
auto ret = InputManager::GetInstance()->UnsubscribeKeyMonitor(INVALID_SUBSCRIBER_ID);
if (ret == -CAPABILITY_NOT_SUPPORTED) {
MMI_HILOGE("Capability not supported");
taihe::set_business_error(INPUT_DEVICE_NOT_SUPPORTED, "Capability not supported.");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.off_keyPressed.Error", INPUT_DEVICE_NOT_SUPPORTED);
} else {
MMI_HILOGE("Input is invalid");
taihe::set_business_error(COMMON_PARAMETER_ERROR, "Input is invalid");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.off_keyPressed.Error", COMMON_PARAMETER_ERROR);
}
}
void UnsubscribeKeyMonitors()
{
std::lock_guard guard(g_mutex);
if (monitors_.empty()) {
auto ret = InputManager::GetInstance()->UnsubscribeKeyMonitor(INVALID_SUBSCRIBER_ID);
if (ret == -CAPABILITY_NOT_SUPPORTED) {
MMI_HILOGE("Capability not supported");
taihe::set_business_error(INPUT_DEVICE_NOT_SUPPORTED, "Capability not supported.");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.off_keyPressed.Error", INPUT_DEVICE_NOT_SUPPORTED);
}
return;
}
for (auto &[monitorId, monitor] : monitors_) {
MMI_HILOGI("[NAPI] Unsubscribe key monitor(ID:%{public}zu, subscriberId:%{public}d)",
monitorId, monitor.subscriberId);
auto ret = InputManager::GetInstance()->UnsubscribeKeyMonitor(monitor.subscriberId);
if (ret != RET_OK) {
MMI_HILOGE("UnsubscribeKeyMonitor fail, error:%{public}d", ret);
}
}
monitors_.clear();
}
int32_t GetPreSubscribeId(Callbacks &callbacks, std::shared_ptr<KeyEventMonitorInfo> event)
{
CHKPR(event, ERROR_NULL_POINTER);
std::lock_guard guard(sCallBacksMutex);
auto it = callbacks.find(event->eventType);
if (it == callbacks.end() || it->second.empty()) {
MMI_HILOGE("The callbacks is empty");
return ETS_CALLBACK_EVENT_FAILED;
}
CHKPR(it->second.front(), ERROR_NULL_POINTER);
return it->second.front()->subscribeId;
}
int32_t GetPreKeys(std::vector<int32_t> &preKeys, std::set<int32_t> ¶ms)
{
CALL_DEBUG_ENTER;
std::size_t arrayLength = preKeys.size();
for (std::size_t i = 0; i < arrayLength; i++) {
MMI_HILOGD("Get int array number:%{public}d", preKeys[i]);
if (!params.insert(preKeys[i]).second) {
MMI_HILOGE("Params insert value failed");
return RET_ERR;
}
}
return RET_OK;
}
bool IsMatchKeyAction(bool isFinalKeydown, int32_t keyAction)
{
CALL_DEBUG_ENTER;
MMI_HILOGD("isFinalKeydown:%{public}d, keyAction:%{public}d", isFinalKeydown, keyAction);
if (isFinalKeydown && keyAction == KeyEvent::KEY_ACTION_DOWN) {
return true;
}
if (!isFinalKeydown && keyAction == KeyEvent::KEY_ACTION_UP) {
return true;
}
MMI_HILOGE("isFinalKeydown not matched with keyAction");
return false;
}
bool MatchCombinationKeys(std::shared_ptr<KeyEventMonitorInfo> monitorInfo, std::shared_ptr<KeyEvent> keyEvent)
{
CALL_DEBUG_ENTER;
CHKPF(monitorInfo);
CHKPF(keyEvent);
auto keyOption = monitorInfo->keyOption;
CHKPF(keyOption);
std::vector<KeyEvent::KeyItem> items = keyEvent->GetKeyItems();
int32_t infoFinalKey = keyOption->GetFinalKey();
int32_t keyEventFinalKey = keyEvent->GetKeyCode();
bool isFinalKeydown = keyOption->IsFinalKeyDown();
MMI_HILOGD("InfoFinalKey:%{private}d,keyEventFinalKey:%{private}d", infoFinalKey, keyEventFinalKey);
if (infoFinalKey != keyEventFinalKey || items.size() > PRE_KEYS_SIZE ||
!IsMatchKeyAction(isFinalKeydown, keyEvent->GetKeyAction())) {
MMI_HILOGD("key Param invalid");
return false;
}
std::set<int32_t> infoPreKeys = keyOption->GetPreKeys();
int32_t infoSize = 0;
for (auto it = infoPreKeys.begin(); it != infoPreKeys.end(); ++it) {
if (*it >= 0) {
infoSize++;
}
}
int32_t count = 0;
for (const auto &item : items) {
if (item.GetKeyCode() == keyEventFinalKey) {
continue;
}
auto iter = find(infoPreKeys.begin(), infoPreKeys.end(), item.GetKeyCode());
if (iter == infoPreKeys.end()) {
MMI_HILOGW("No keyCode in preKeys");
return false;
}
count++;
}
MMI_HILOGD("keyEventSize:%{public}d, infoSize:%{public}d", count, infoSize);
std::optional<KeyEvent::KeyItem> keyItem = keyEvent->GetKeyItem();
if (!keyItem) {
MMI_HILOGE("The keyItem is nullopt");
return false;
}
auto downTime = keyItem->GetDownTime();
auto upTime = keyEvent->GetActionTime();
auto curDurationTime = keyOption->GetFinalKeyDownDuration();
if (curDurationTime > 0 && (upTime - downTime >=
(static_cast<int64_t>(curDurationTime) * MILLISECONDS_IN_SECOND))) {
MMI_HILOGE("Skip, upTime - downTime >= duration");
return false;
}
return count == infoSize;
}
using callbackType = std::variant<
taihe::callback<void(KeyOptions const&)>,
taihe::callback<void(HotkeyOptions const&)>,
taihe::callback<void(ohos::multimodalInput::keyEvent::KeyEvent const&)>,
taihe::callback<void(KeyOptions const&, ohos::multimodalInput::keyEvent::KeyEvent const&)>
>;
void EmitHotkeyCallbackWork(std::shared_ptr<KeyEventMonitorInfo> reportEvent)
{
CALL_DEBUG_ENTER;
if (!reportEvent || !reportEvent->keyOption) {
MMI_HILOGE("reportEvent or keyOption value is null");
return;
}
std::lock_guard<std::mutex> lock(jsCbMapMutex);
auto &cbVec = jsCbMap_[reportEvent->eventType];
for (auto &cb : cbVec) {
if (cb == nullptr) {
continue;
}
size_t typeIndex = cb->callback.index();
if (typeIndex == SECOND_INDEX) {
auto &func = std::get<taihe::callback<void(HotkeyOptions const&)>>(cb->callback);
auto hotkeyOptions = ConvertTaiheHotkeyOptions(reportEvent->keyOption);
func(hotkeyOptions);
}
}
}
static void SubHotkeyEventCallback(std::shared_ptr<KeyEvent> keyEvent)
{
CALL_DEBUG_ENTER;
CHKPV(keyEvent);
std::lock_guard guard(sCallBacksMutex);
auto iter = hotkeyCallbacks.begin();
while (iter != hotkeyCallbacks.end()) {
auto &list = iter->second;
++iter;
MMI_HILOGD("Callback list size:%{public}zu", list.size());
auto infoIter = list.begin();
while (infoIter != list.end()) {
auto monitorInfo = *infoIter;
if (MatchCombinationKeys(monitorInfo, keyEvent)) {
EmitHotkeyCallbackWork(monitorInfo);
MMI_HILOGD("need to async callback");
}
++infoIter;
}
}
}
int32_t AddEventHotkeyCallback(Callbacks &callbacks, std::shared_ptr<KeyEventMonitorInfo> event,
callback_view<void(HotkeyOptions const&)> f, uintptr_t opq)
{
CALL_DEBUG_ENTER;
std::lock_guard guard(sCallBacksMutex);
CHKPR(event, RET_ERR);
auto result = RegisterListener(event->eventType, f, opq);
if (result == ETS_CALLBACK_EVENT_FAILED) {
MMI_HILOGE("Register listener failed");
return RET_ERR;
}
if (result == ETS_CALLBACK_EVENT_EXIST) {
MMI_HILOGE("Callback already exist");
return RET_ERR;
}
if (result == ETS_CALLBACK_EVENT_SUCCESS) {
hotkeyCallbacks[event->eventType].push_back(event);
}
return RET_OK;
}
int32_t GetHotkeyEventInfo(HotkeyOptions const& hotkeyOptions,
std::shared_ptr<KeyEventMonitorInfo> event, std::shared_ptr<KeyOption> keyOption,
std::function<void(int32_t)> histogramError)
{
CALL_DEBUG_ENTER;
CHKPR(event, RET_ERR);
CHKPR(keyOption, RET_ERR);
if (hotkeyOptions.preKeys.empty()) {
taihe::set_business_error(COMMON_PARAMETER_ERROR, "PreKeys not found");
histogramError(COMMON_PARAMETER_ERROR);
return RET_ERR;
}
std::set<int32_t> preKeys;
std::vector<int32_t> etsPreKeys(hotkeyOptions.preKeys.begin(), hotkeyOptions.preKeys.end());
if (GetPreKeys(etsPreKeys, preKeys) != RET_OK) {
MMI_HILOGE("Get preKeys failed");
return RET_ERR;
}
if (preKeys.size() > PRE_KEYS_SIZE) {
MMI_HILOGE("PreKeys size invalid");
taihe::set_business_error(COMMON_PARAMETER_ERROR, "PreKeys size invalid");
histogramError(COMMON_PARAMETER_ERROR);
return RET_ERR;
}
MMI_HILOGD("PreKeys size:%{public}zu", preKeys.size());
keyOption->SetPreKeys(preKeys);
std::ostringstream oss;
for (const auto &item : preKeys) {
if (item < 0) {
taihe::set_business_error(COMMON_PARAMETER_ERROR, "element of preKeys must be greater than or equal to 0");
histogramError(COMMON_PARAMETER_ERROR);
return RET_ERR;
}
auto it = std::find(pressKeyCodes.begin(), pressKeyCodes.end(), item);
if (it == pressKeyCodes.end()) {
MMI_HILOGE("PreKeys is not expect");
taihe::set_business_error(COMMON_PARAMETER_ERROR, "PreKey not expected");
histogramError(COMMON_PARAMETER_ERROR);
return RET_ERR;
}
oss << item << ",";
MMI_HILOGD("PreKeys:%{private}d", item);
}
if (hotkeyOptions.finalKey < 0) {
MMI_HILOGE("FinalKey:%{private}d is less 0, can not process", hotkeyOptions.finalKey);
taihe::set_business_error(COMMON_PARAMETER_ERROR, "FinalKey must be greater than or equal to 0");
histogramError(COMMON_PARAMETER_ERROR);
return RET_ERR;
}
auto it = std::find(finalKeyCodes.begin(), finalKeyCodes.end(), hotkeyOptions.finalKey);
if (it != finalKeyCodes.end()) {
MMI_HILOGE("FinalKey is not expect");
taihe::set_business_error(COMMON_PARAMETER_ERROR, "FinalKey is not expect");
histogramError(COMMON_PARAMETER_ERROR);
return RET_ERR;
}
oss << hotkeyOptions.finalKey << ",";
keyOption->SetFinalKey(hotkeyOptions.finalKey);
MMI_HILOGD("FinalKey:%{private}d", hotkeyOptions.finalKey);
bool isFinalKeyDown = true;
oss << isFinalKeyDown << ",";
keyOption->SetFinalKeyDown(isFinalKeyDown);
MMI_HILOGD("IsFinalKeyDown:%{private}d,", (isFinalKeyDown == true ? 1 : 0));
int32_t finalKeyDownDuration = 0;
oss << finalKeyDownDuration << ",";
keyOption->SetFinalKeyDownDuration(finalKeyDownDuration);
bool isRepeat = true;
if (!hotkeyOptions.isRepeat.has_value()) {
MMI_HILOGD("IsRepeat field is default");
} else {
isRepeat = hotkeyOptions.isRepeat.value();
}
oss << isRepeat;
keyOption->SetRepeat(isRepeat);
MMI_HILOGD("IsRepeat:%{public}s", (isRepeat ? "true" : "false"));
event->eventType = oss.str();
return RET_OK;
}
void SubscribeHotkey(HotkeyOptions const& hotkeyOptions, callback_view<void(HotkeyOptions const&)> f, uintptr_t opq)
{
CALL_DEBUG_ENTER;
std::shared_ptr<KeyEventMonitorInfo> event = std::make_shared<KeyEventMonitorInfo>();
CHKPV(event);
auto keyOption = std::make_shared<KeyOption>();
CHKPV(keyOption);
auto histogramError = [](int32_t errorCode) {
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.on_hotkeyChange.Error", errorCode);
};
if (GetHotkeyEventInfo(hotkeyOptions, event, keyOption, histogramError) != RET_OK) {
MMI_HILOGE("GetHotkeyEventInfo failed");
return;
}
event->keyOption = keyOption;
int32_t preSubscribeId = GetPreSubscribeId(hotkeyCallbacks, event);
if (preSubscribeId < 0) {
MMI_HILOGD("EventType:%{private}s", event->eventType.c_str());
int32_t subscribeId = InputManager::GetInstance()->SubscribeHotkey(keyOption, SubHotkeyEventCallback);
if (subscribeId == ERROR_UNSUPPORT) {
MMI_HILOGE("SubscribeId invalid:%{public}d", subscribeId);
taihe::set_business_error(INPUT_DEVICE_NOT_SUPPORTED, "Hotkey occupied by other");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.on_hotkeyChange.Error", INPUT_DEVICE_NOT_SUPPORTED);
return;
}
if (subscribeId == OCCUPIED_BY_SYSTEM) {
MMI_HILOGE("SubscribeId invalid:%{public}d", subscribeId);
taihe::set_business_error(INPUT_OCCUPIED_BY_SYSTEM, "Hotkey occupied by system");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.on_hotkeyChange.Error", INPUT_OCCUPIED_BY_SYSTEM);
return;
}
if (subscribeId == OCCUPIED_BY_OTHER) {
MMI_HILOGE("SubscribeId invalid:%{public}d", subscribeId);
taihe::set_business_error(INPUT_OCCUPIED_BY_OTHER, "Hotkey occupied by other");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.on_hotkeyChange.Error", INPUT_OCCUPIED_BY_OTHER);
return;
}
MMI_HILOGD("SubscribeId:%{public}d", subscribeId);
event->subscribeId = subscribeId;
} else {
event->subscribeId = preSubscribeId;
}
if (AddEventHotkeyCallback(hotkeyCallbacks, event, f, opq) != RET_OK) {
MMI_HILOGE("AddEventHotkeyCallback failed");
taihe::set_business_error(COMMON_PARAMETER_ERROR, "AddEventHotkeyCallback failed");
}
}
int32_t DelEventCallbackRef(std::list<std::shared_ptr<KeyEventMonitorInfo>> &info, std::string const &type,
optional_view<uintptr_t> opq, int32_t &subscribeId)
{
CALL_DEBUG_ENTER;
for (auto iter = info.begin(); iter != info.end();) {
if (*iter == nullptr) {
info.erase(iter++);
continue;
}
if (opq.has_value()) {
if (UnregisterListener(type, opq)) {
std::shared_ptr<KeyEventMonitorInfo> monitorInfo = *iter;
info.erase(iter++);
if (info.empty()) {
subscribeId = monitorInfo->subscribeId;
}
MMI_HILOGD("Callback has deleted, size:%{public}zu", info.size());
return ETS_CALLBACK_EVENT_SUCCESS;
}
++iter;
continue;
}
std::shared_ptr<KeyEventMonitorInfo> monitorInfo = *iter;
info.erase(iter++);
if (info.empty()) {
subscribeId = monitorInfo->subscribeId;
}
MMI_HILOGD("Callback has deleted, size:%{public}zu", info.size());
}
MMI_HILOGD("Callback size:%{public}zu", info.size());
return ETS_CALLBACK_EVENT_SUCCESS;
}
int32_t DelEventCallback(Callbacks &callbacks, std::shared_ptr<KeyEventMonitorInfo> event,
optional_view<uintptr_t> opq, int32_t &subscribeId)
{
CALL_DEBUG_ENTER;
std::lock_guard guard(sCallBacksMutex);
CHKPR(event, ERROR_NULL_POINTER);
if (callbacks.count(event->eventType) <= 0) {
MMI_HILOGE("Callback doesn't exists");
return ETS_CALLBACK_EVENT_FAILED;
}
auto &info = callbacks[event->eventType];
MMI_HILOGD("EventType:%{private}s, keyEventMonitorInfos:%{public}zu", event->eventType.c_str(), info.size());
return DelEventCallbackRef(info, event->eventType, opq, subscribeId);
}
void UnsubscribeHotkey(HotkeyOptions const& hotkeyOptions, optional_view<uintptr_t> opq)
{
CALL_DEBUG_ENTER;
std::shared_ptr<KeyEventMonitorInfo> event = std::make_shared<KeyEventMonitorInfo>();
CHKPV(event);
auto keyOption = std::make_shared<KeyOption>();
CHKPV(keyOption);
auto histogramError = [](int32_t errorCode) {
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.off_hotkeyChange.Error", errorCode);
};
int32_t subscribeId = -1;
if (GetHotkeyEventInfo(hotkeyOptions, event, keyOption, histogramError) != RET_OK) {
MMI_HILOGE("GetHotkeyEventInfo failed");
return;
}
if (DelEventCallback(hotkeyCallbacks, event, opq, subscribeId) < 0) {
MMI_HILOGE("DelEventCallback failed");
return;
}
MMI_HILOGI("Unsubscribe hot key(%{public}d)", subscribeId);
InputManager::GetInstance()->UnsubscribeHotkey(subscribeId);
}
void EmitKeyCallbackWork(std::shared_ptr<KeyEventMonitorInfo> reportEvent)
{
CALL_DEBUG_ENTER;
if (!reportEvent || !reportEvent->keyOption) {
MMI_HILOGE("reportEvent or keyOption value is null");
return;
}
std::lock_guard<std::mutex> lock(jsCbMapMutex);
auto &cbVec = jsCbMap_[reportEvent->eventType];
for (auto &cb : cbVec) {
if (cb == nullptr) {
continue;
}
size_t typeIndex = cb->callback.index();
if (typeIndex == FIRST_INDEX) {
auto &func = std::get<taihe::callback<void(KeyOptions const&)>>(cb->callback);
auto keyOptions = ConvertTaiheKeyOptions(reportEvent->keyOption);
func(keyOptions);
}
}
}
static void SubKeyEventCallback(std::shared_ptr<KeyEvent> keyEvent, const std::string& keyOptionKey)
{
CALL_DEBUG_ENTER;
CHKPV(keyEvent);
std::lock_guard guard(sCallBacksMutex);
auto iter = keyCallbacks.find(keyOptionKey);
if (iter != keyCallbacks.end()) {
auto &list = iter->second;
MMI_HILOGD("list size:%{public}zu", list.size());
for (auto monitorInfo : list) {
if (MatchCombinationKeys(monitorInfo, keyEvent)) {
EmitKeyCallbackWork(monitorInfo);
}
}
} else {
MMI_HILOGE("No Matches found for SubKeyEventCallback");
}
}
int32_t AddEventKeyCallback(Callbacks &callbacks, std::shared_ptr<KeyEventMonitorInfo> event,
callback_view<void(KeyOptions const&)> f, uintptr_t opq)
{
CALL_DEBUG_ENTER;
std::lock_guard guard(sCallBacksMutex);
CHKPR(event, RET_ERR);
auto result = RegisterListener(event->eventType, f, opq);
if (result == ETS_CALLBACK_EVENT_FAILED) {
MMI_HILOGE("Register listener failed");
return RET_ERR;
}
if (result == ETS_CALLBACK_EVENT_SUCCESS) {
keyCallbacks[event->eventType].push_back(event);
}
return RET_OK;
}
int32_t GetEventInfoAPI9(KeyOptions const& keyOptions, std::shared_ptr<KeyEventMonitorInfo> event,
std::shared_ptr<KeyOption> keyOption, std::function<void(int32_t)> histogramError)
{
CALL_DEBUG_ENTER;
CHKPR(event, RET_ERR);
CHKPR(keyOption, RET_ERR);
std::set<int32_t> preKeys;
std::vector<int32_t> etsPreKeys(keyOptions.preKeys.begin(), keyOptions.preKeys.end());
if (GetPreKeys(etsPreKeys, preKeys) != RET_OK) {
MMI_HILOGE("Get preKeys failed");
return RET_ERR;
}
if (preKeys.size() > PRE_KEYS_SIZE) {
MMI_HILOGE("PreKeys size invalid");
taihe::set_business_error(COMMON_PARAMETER_ERROR, "PreKeys size invalid");
histogramError(COMMON_PARAMETER_ERROR);
return RET_ERR;
}
MMI_HILOGD("PreKeys size:%{public}zu", preKeys.size());
keyOption->SetPreKeys(preKeys);
std::string subKeyNames = "";
for (const auto &item : preKeys) {
if (item < 0) {
taihe::set_business_error(COMMON_PARAMETER_ERROR, "element of preKeys must be greater than or equal to 0");
histogramError(COMMON_PARAMETER_ERROR);
return RET_ERR;
}
subKeyNames += std::to_string(item);
subKeyNames += ",";
MMI_HILOGD("preKeys:%{private}d", item);
}
if (keyOptions.finalKey < 0) {
MMI_HILOGE("finalKey:%{private}d is less 0, can not process", keyOptions.finalKey);
taihe::set_business_error(COMMON_PARAMETER_ERROR, "finalKey must be greater than or equal to 0");
histogramError(COMMON_PARAMETER_ERROR);
return RET_ERR;
}
subKeyNames += std::to_string(keyOptions.finalKey);
subKeyNames += ",";
keyOption->SetFinalKey(keyOptions.finalKey);
MMI_HILOGD("FinalKey:%{private}d", keyOptions.finalKey);
subKeyNames += std::to_string(keyOptions.isFinalKeyDown);
subKeyNames += ",";
keyOption->SetFinalKeyDown(keyOptions.isFinalKeyDown);
MMI_HILOGD("IsFinalKeyDown:%{private}d,map_key:%{private}s",
(keyOptions.isFinalKeyDown == true ? 1 : 0), subKeyNames.c_str());
if (keyOptions.finalKeyDownDuration < 0) {
MMI_HILOGE("finalKeyDownDuration:%{public}d is less 0, can not process", keyOptions.finalKeyDownDuration);
taihe::set_business_error(COMMON_PARAMETER_ERROR, "finalKeyDownDuration must be greater than or equal to 0");
histogramError(COMMON_PARAMETER_ERROR);
return RET_ERR;
}
subKeyNames += std::to_string(keyOptions.finalKeyDownDuration);
subKeyNames += ",";
keyOption->SetFinalKeyDownDuration(keyOptions.finalKeyDownDuration);
MMI_HILOGD("FinalKeyDownDuration:%{public}d", keyOptions.finalKeyDownDuration);
bool isRepeat = true;
if (!keyOptions.isRepeat.has_value()) {
MMI_HILOGD("IsRepeat field is default");
} else {
isRepeat = keyOptions.isRepeat.value();
}
subKeyNames += std::to_string(isRepeat);
keyOption->SetRepeat(isRepeat);
MMI_HILOGD("IsRepeat:%{public}s", (isRepeat ? "true" : "false"));
event->eventType = subKeyNames;
return RET_OK;
}
int32_t ParseAPI26PreKeys(KeyOptions const& keyOptions, std::shared_ptr<KeyOption> keyOption,
std::string& subKeyNames)
{
CALL_DEBUG_ENTER;
std::set<int32_t> preKeys;
std::vector<int32_t> etsPreKeys(keyOptions.preKeys.begin(), keyOptions.preKeys.end());
if (GetPreKeys(etsPreKeys, preKeys) != RET_OK) {
MMI_HILOGE("Get preKeys failed");
return RET_ERR;
}
if (preKeys.size() > PRE_KEYS_SIZE) {
taihe::set_business_error(COMMON_PARAMETER_ERROR, "preKeys size invalid");
return RET_ERR;
}
keyOption->SetPreKeys(preKeys);
for (const auto &item : preKeys) {
if (item < 0) {
taihe::set_business_error(COMMON_PARAMETER_ERROR,
"element of preKeys must be greater than or equal to 0");
return RET_ERR;
}
subKeyNames += std::to_string(item) + ",";
}
return RET_OK;
}
int32_t ParseAPI26TriggerTypeAndLegacy(KeyOptions const& keyOptions, std::shared_ptr<KeyOption> keyOption,
std::string& subKeyNames)
{
CALL_DEBUG_ENTER;
if (keyOptions.triggerType.has_value()) {
int32_t triggerType = static_cast<int32_t>(keyOptions.triggerType.value().get_value());
if (triggerType >= TRIGGER_TYPE_MIN && triggerType <= TRIGGER_TYPE_MAX) {
keyOption->SetTriggerType(triggerType);
subKeyNames += std::to_string(triggerType) + ",";
} else {
MMI_HILOGE("triggerType:%{public}d is invalid, must be [1, 3]", triggerType);
taihe::set_business_error(COMMON_PARAMETER_ERROR,
"triggerType must be one of KeyCommandTriggerType values "
"(PRESSED=1, REPEAT_PRESSED=2, ALL_RELEASED=3)");
return RET_ERR;
}
} else {
MMI_HILOGE("triggerType is required for onKey/offKey API");
taihe::set_business_error(COMMON_PARAMETER_ERROR,
"triggerType is required and must be one of KeyCommandTriggerType values");
return RET_ERR;
}
subKeyNames += "false,";
keyOption->SetFinalKeyDown(false);
keyOption->SetRepeat(false);
return RET_OK;
}
int32_t GetEventInfoAPI26(KeyOptions const& keyOptions, std::shared_ptr<KeyEventMonitorInfo> event,
std::shared_ptr<KeyOption> keyOption)
{
CALL_DEBUG_ENTER;
CHKPR(event, RET_ERR);
CHKPR(keyOption, RET_ERR);
std::string subKeyNames;
if (ParseAPI26PreKeys(keyOptions, keyOption, subKeyNames) != RET_OK) {
return RET_ERR;
}
if (keyOptions.finalKey < 0) {
taihe::set_business_error(COMMON_PARAMETER_ERROR, "finalKey must be greater than or equal to 0");
return RET_ERR;
}
subKeyNames += std::to_string(keyOptions.finalKey) + ",";
keyOption->SetFinalKey(keyOptions.finalKey);
subKeyNames += std::to_string(keyOptions.finalKeyDownDuration) + ",";
keyOption->SetFinalKeyDownDuration(keyOptions.finalKeyDownDuration);
if (ParseAPI26TriggerTypeAndLegacy(keyOptions, keyOption, subKeyNames) != RET_OK) {
MMI_HILOGE("ParseAPI26TriggerTypeAndLegacy failed");
return RET_ERR;
}
event->eventType = subKeyNames;
return RET_OK;
}
void SubKeyCommandEventCallback(std::shared_ptr<KeyEvent> keyEvent, const std::string& keyOptionKey,
std::shared_ptr<KeyOption> keyOption);
void EmitKeyCommandCallbackWork(std::shared_ptr<KeyEventMonitorInfo> reportEvent,
std::shared_ptr<KeyEvent> keyEvent)
{
CALL_DEBUG_ENTER;
if (!reportEvent || !reportEvent->keyOption) {
MMI_HILOGE("reportEvent or keyOption value is null");
return;
}
std::lock_guard<std::mutex> lock(jsCbMapMutex);
auto &cbVec = jsCbMap_[reportEvent->eventType];
for (auto &cb : cbVec) {
if (cb == nullptr) {
continue;
}
size_t typeIndex = cb->callback.index();
if (typeIndex == FOURTH_INDEX) {
auto &func = std::get<taihe::callback<void(KeyOptions const&,
ohos::multimodalInput::keyEvent::KeyEvent const&)>>(cb->callback);
auto keyOptions = ConvertTaiheKeyOptions(reportEvent->keyOption);
auto keyEventEts = ConvertTaiheKeyPressed(keyEvent);
func(keyOptions, keyEventEts);
}
}
}
void SubKeyCommandEventCallback(std::shared_ptr<KeyEvent> keyEvent, const std::string& keyOptionKey,
std::shared_ptr<KeyOption> keyOption)
{
CALL_DEBUG_ENTER;
CHKPV(keyEvent);
std::lock_guard guard(sCallBacksMutex);
auto iter = keyCallbacks.find(keyOptionKey);
if (iter == keyCallbacks.end()) {
MMI_HILOGE("No matches found for SubKeyCommandEventCallback");
return;
}
auto &list = iter->second;
for (auto monitorInfo : list) {
EmitKeyCommandCallbackWork(monitorInfo, keyEvent);
}
}
void SubscribeKeyCommand(KeyOptions const& keyOptions,
callback_view<void(KeyOptions const&, ohos::multimodalInput::keyEvent::KeyEvent const&)> f,
uintptr_t opq)
{
CALL_DEBUG_ENTER;
std::shared_ptr<KeyEventMonitorInfo> event = std::make_shared<KeyEventMonitorInfo>();
CHKPV(event);
auto keyOption = std::make_shared<KeyOption>();
CHKPV(keyOption);
if (!PER_HELPER->VerifySystemApp()) {
auto histogramError = [](int32_t errorCode) {};
HandleCommonErrors(COMMON_USE_SYSAPI_ERROR, histogramError);
return;
}
if (GetEventInfoAPI26(keyOptions, event, keyOption) != RET_OK) {
MMI_HILOGE("GetEventInfoAPI26 failed");
return;
}
event->keyOption = keyOption;
int32_t preSubscribeId = GetPreSubscribeId(keyCallbacks, event);
if (preSubscribeId < 0) {
MMI_HILOGD("EventType:%{private}s", event->eventType.c_str());
int32_t subscribeId = InputManager::GetInstance()->SubscribeKeyEvent(keyOption,
[keyOption](std::shared_ptr<KeyEvent> keyEvent) {
auto* dispatcher = TriggerEventDispatcher::GetInstance();
if (dispatcher != nullptr && dispatcher->ShouldDispatch(keyOption, keyEvent)) {
std::string keyOptionKey = GenerateKeyOptionKey(keyOption);
SubKeyCommandEventCallback(keyEvent, keyOptionKey, keyOption);
}
});
if (subscribeId < 0) {
MMI_HILOGE("SubscribeId invalid:%{public}d", subscribeId);
return;
}
MMI_HILOGD("SubscribeId:%{public}d", subscribeId);
event->subscribeId = subscribeId;
} else {
event->subscribeId = preSubscribeId;
}
auto result = RegisterListener(event->eventType, f, opq);
if (result == ETS_CALLBACK_EVENT_FAILED) {
MMI_HILOGE("Register listener failed");
return;
}
if (result == ETS_CALLBACK_EVENT_EXIST) {
MMI_HILOGE("Callback already exist");
return;
}
if (result == ETS_CALLBACK_EVENT_SUCCESS) {
keyCallbacks[event->eventType].push_back(event);
}
}
void UnsubscribeKeyCommand(KeyOptions const& keyOptions, optional_view<uintptr_t> opq)
{
CALL_DEBUG_ENTER;
std::shared_ptr<KeyEventMonitorInfo> event = std::make_shared<KeyEventMonitorInfo>();
CHKPV(event);
auto keyOption = std::make_shared<KeyOption>();
CHKPV(keyOption);
int32_t subscribeId = -1;
if (!PER_HELPER->VerifySystemApp()) {
auto histogramError = [](int32_t errorCode) {};
HandleCommonErrors(COMMON_USE_SYSAPI_ERROR, histogramError);
return;
}
if (GetEventInfoAPI26(keyOptions, event, keyOption) != RET_OK) {
MMI_HILOGE("GetEventInfoAPI26 failed");
return;
}
if (DelEventCallback(keyCallbacks, event, opq, subscribeId) < 0) {
MMI_HILOGE("DelEventCallback failed");
return;
}
MMI_HILOGI("Unsubscribe key command(%{public}d)", subscribeId);
InputManager::GetInstance()->UnsubscribeKeyEvent(subscribeId);
TriggerEventDispatcher::GetInstance()->ClearSubscribeState(keyOption);
}
void SubscribeKey(KeyOptions const& keyOptions, callback_view<void(KeyOptions const&)> f, uintptr_t opq)
{
CALL_DEBUG_ENTER;
std::shared_ptr<KeyEventMonitorInfo> event = std::make_shared<KeyEventMonitorInfo>();
CHKPV(event);
auto keyOption = std::make_shared<KeyOption>();
CHKPV(keyOption);
auto histogramError = [](int32_t errorCode) {
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.on_key.Error", errorCode);
};
if (!PER_HELPER->VerifySystemApp()) {
HandleCommonErrors(COMMON_USE_SYSAPI_ERROR, histogramError);
return;
}
if (GetEventInfoAPI9(keyOptions, event, keyOption, histogramError) != RET_OK) {
MMI_HILOGE("GetEventInfoAPI9 failed");
return;
}
event->keyOption = keyOption;
int32_t preSubscribeId = GetPreSubscribeId(keyCallbacks, event);
if (preSubscribeId < 0) {
CALL_DEBUG_ENTER;
MMI_HILOGD("EventType:%{private}s", event->eventType.c_str());
int32_t subscribeId = -1;
subscribeId = InputManager::GetInstance()->SubscribeKeyEvent(keyOption,
[keyOption](std::shared_ptr<KeyEvent> keyEvent) {
CALL_DEBUG_ENTER;
std::string keyOptionKey = GenerateKeyOptionKey(keyOption);
SubKeyEventCallback(keyEvent, keyOptionKey);
});
if (subscribeId < 0) {
MMI_HILOGE("SubscribeId invalid:%{public}d", subscribeId);
return;
}
MMI_HILOGD("SubscribeId:%{public}d", subscribeId);
event->subscribeId = subscribeId;
} else {
event->subscribeId = preSubscribeId;
}
if (AddEventKeyCallback(keyCallbacks, event, f, opq) != RET_OK) {
MMI_HILOGE("AddEventKeyCallback failed");
taihe::set_business_error(COMMON_PARAMETER_ERROR, "AddEventKeyCallback failed");
}
}
void UnsubscribeKey(KeyOptions const& keyOptions, optional_view<uintptr_t> opq)
{
CALL_DEBUG_ENTER;
std::shared_ptr<KeyEventMonitorInfo> event = std::make_shared<KeyEventMonitorInfo>();
CHKPV(event);
auto keyOption = std::make_shared<KeyOption>();
CHKPV(keyOption);
auto histogramError = [](int32_t errorCode) {
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.off_key.Error", errorCode);
};
int32_t subscribeId = -1;
if (!PER_HELPER->VerifySystemApp()) {
HandleCommonErrors(COMMON_USE_SYSAPI_ERROR, histogramError);
return;
}
if (GetEventInfoAPI9(keyOptions, event, keyOption, histogramError) != RET_OK) {
MMI_HILOGE("GetEventInfoAPI9 failed");
return;
}
if (DelEventCallback(keyCallbacks, event, opq, subscribeId) < 0) {
MMI_HILOGE("DelEventCallback failed");
return;
}
MMI_HILOGI("Unsubscribe key event(%{public}d)", subscribeId);
InputManager::GetInstance()->UnsubscribeKeyEvent(subscribeId);
}
void onKeyImpl(KeyOptions const& keyOptions, callback_view<void(KeyOptions const&)> f, uintptr_t opq)
{
MMI_HISTOGRAM_BOOLEAN("InputKit.inputConsumer.on_key.Call", true);
SubscribeKey(keyOptions, f, opq);
}
void offKeyImpl(KeyOptions const& keyOptions, optional_view<uintptr_t> opq)
{
MMI_HISTOGRAM_BOOLEAN("InputKit.inputConsumer.off_key.Call", true);
UnsubscribeKey(keyOptions, opq);
}
void onKeyCommandImpl(KeyOptions const& keyOptions,
callback_view<void(KeyOptions const&, ohos::multimodalInput::keyEvent::KeyEvent const&)> f,
uintptr_t opq)
{
SubscribeKeyCommand(keyOptions, f, opq);
}
void offKeyCommandImpl(KeyOptions const& keyOptions, optional_view<uintptr_t> opq)
{
CALL_DEBUG_ENTER;
if (!opq.has_value() || opq.value() == 0) {
MMI_HILOGE("callback cannot be null or undefined");
taihe::set_business_error(COMMON_PARAMETER_ERROR, "callback cannot be null or undefined");
return;
}
UnsubscribeKeyCommand(keyOptions, opq);
}
void onHotkeyChangeImpl(HotkeyOptions const& hotkeyOptions, callback_view<void(HotkeyOptions const&)> f, uintptr_t opq)
{
MMI_HISTOGRAM_BOOLEAN("InputKit.inputConsumer.on_hotkeyChange.Call", true);
SubscribeHotkey(hotkeyOptions, f, opq);
}
void offHotkeyChangeImpl(HotkeyOptions const& hotkeyOptions, optional_view<uintptr_t> opq)
{
MMI_HISTOGRAM_BOOLEAN("InputKit.inputConsumer.off_hotkeyChange.Call", true);
UnsubscribeHotkey(hotkeyOptions, opq);
}
void onKeyPressedImpl(KeyPressedConfig const& options,
callback_view<void(ohos::multimodalInput::keyEvent::KeyEvent const&)> f, uintptr_t opq)
{
MMI_HISTOGRAM_BOOLEAN("InputKit.inputConsumer.on_keyPressed.Call", true);
SubscribeKeyMonitor(options, f, opq);
}
void offKeyPressedImpl(optional_view<uintptr_t> opq)
{
MMI_HISTOGRAM_BOOLEAN("InputKit.inputConsumer.off_keyPressed.Call", true);
if (opq.has_value()) {
MMI_HILOGI("[ETS] Unsubscribe key monitor");
UnsubscribeKeyMonitor(opq);
} else {
UnsubscribeKeyMonitors();
}
}
void SetShieldStatus(::ohos::multimodalInput::inputConsumer::ShieldMode shieldMode, bool isShield)
{
MMI_HISTOGRAM_BOOLEAN("InputKit.inputConsumer.setShieldStatus.Call", true);
OHOS::MMI::SHIELD_MODE mode = static_cast<OHOS::MMI::SHIELD_MODE>(shieldMode.get_value());
if (mode < FACTORY_MODE || mode > OOBE_MODE) {
MMI_HILOGE("Undefined shield mode");
taihe::set_business_error(COMMON_PARAMETER_ERROR, "Shield mode does not exist");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.setShieldStatus.Error", COMMON_PARAMETER_ERROR);
return;
}
int32_t ret = InputManager::GetInstance()->SetShieldStatus(shieldMode, isShield);
auto histogramError = [](int32_t errorCode) {
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.setShieldStatus.Error", errorCode);
};
HandleCommonErrors(ret, histogramError);
}
bool GetShieldStatus(::ohos::multimodalInput::inputConsumer::ShieldMode shieldMode)
{
MMI_HISTOGRAM_BOOLEAN("InputKit.inputConsumer.getShieldStatus.Call", true);
bool isShield { false };
OHOS::MMI::SHIELD_MODE mode = static_cast<OHOS::MMI::SHIELD_MODE>(shieldMode.get_value());
if (mode < FACTORY_MODE || mode > OOBE_MODE) {
MMI_HILOGE("Undefined shield mode");
taihe::set_business_error(COMMON_PARAMETER_ERROR, "Shield mode does not exist");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.getShieldStatus.Error", COMMON_PARAMETER_ERROR);
return isShield;
}
auto ret = InputManager::GetInstance()->GetShieldStatus(shieldMode, isShield);
if (ret != RET_OK) {
auto histogramError = [](int32_t errorCode) {
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.getShieldStatus.Error", errorCode);
};
HandleCommonErrors(ret, histogramError);
return false;
}
return isShield;
}
::taihe::array<inputConsumer::HotkeyOptions> GetAllSystemHotkeysSync()
{
MMI_HISTOGRAM_BOOLEAN("InputKit.inputConsumer.getAllSystemHotkeys.Call", true);
std::vector<std::unique_ptr<KeyOption>> keyOptions;
int32_t count = 0;
std::vector<inputConsumer::HotkeyOptions> result;
auto ret = InputManager::GetInstance()->GetAllSystemHotkeys(keyOptions, count);
if (ret != RET_OK) {
int32_t errorCode = std::abs(ret);
if (errorCode == COMMON_USE_SYSAPI_ERROR) {
MMI_HILOGE("Non system applications use system API");
taihe::set_business_error(COMMON_USE_SYSAPI_ERROR,
"Permission denied, non-system application called system api.");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.getAllSystemHotkeys.Error", COMMON_USE_SYSAPI_ERROR);
} else if (errorCode == COMMON_PERMISSION_CHECK_ERROR) {
MMI_HILOGE("Shield api need ohos.permission.INPUT_CONTROL_DISPATCHING");
taihe::set_business_error(COMMON_PERMISSION_CHECK_ERROR,
"Permission denied,forbidden by permission");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.getAllSystemHotkeys.Error", COMMON_PERMISSION_CHECK_ERROR);
} else {
taihe::set_business_error(COMMON_PARAMETER_ERROR, "Parameter error.");
MMI_HISTOGRAM_ERROR("InputKit.inputConsumer.getAllSystemHotkeys.Error", COMMON_PARAMETER_ERROR);
}
return taihe::array<inputConsumer::HotkeyOptions>(result);
}
for (auto &iter : keyOptions) {
auto tmpOpts = ConvertTaiheHotkeyOptions(std::move(iter));
result.push_back(tmpOpts);
}
return taihe::array<inputConsumer::HotkeyOptions>(result);
}
}
TH_EXPORT_CPP_API_onKeyImpl(onKeyImpl);
TH_EXPORT_CPP_API_offKeyImpl(offKeyImpl);
TH_EXPORT_CPP_API_onKeyCommandImpl(onKeyCommandImpl);
TH_EXPORT_CPP_API_offKeyCommandImpl(offKeyCommandImpl);
TH_EXPORT_CPP_API_onHotkeyChangeImpl(onHotkeyChangeImpl);
TH_EXPORT_CPP_API_offHotkeyChangeImpl(offHotkeyChangeImpl);
TH_EXPORT_CPP_API_onKeyPressedImpl(onKeyPressedImpl);
TH_EXPORT_CPP_API_offKeyPressedImpl(offKeyPressedImpl);
TH_EXPORT_CPP_API_SetShieldStatus(SetShieldStatus);
TH_EXPORT_CPP_API_GetShieldStatus(GetShieldStatus);
TH_EXPORT_CPP_API_GetAllSystemHotkeysSync(GetAllSystemHotkeysSync);