* Copyright (C) 2021-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 FRAMEWORKS_INPUTMETHOD_CONTROLLER_INCLUDE_INPUT_METHOD_UTILS_H
#define FRAMEWORKS_INPUTMETHOD_CONTROLLER_INCLUDE_INPUT_METHOD_UTILS_H
#include <stdint.h>
#include <variant>
#include "global.h"
#include "input_attribute.h"
#include "input_window_info.h"
#include "iremote_object.h"
#include "key_event.h"
#include "panel_info.h"
namespace OHOS {
namespace MiscServices {
constexpr uint32_t INVALID_WINDOW_ID = 0;
constexpr int32_t INVALID_VALUE = -1;
constexpr size_t MAX_PRIVATE_COMMAND_SIZE = 32 * 1024;
constexpr size_t MAX_PRIVATE_COMMAND_COUNT = 5;
constexpr size_t MAX_SYS_PRIVATE_COMMAND_COUNT = MAX_PRIVATE_COMMAND_COUNT + 1;
constexpr size_t MAX_VALUE_MAP_COUNT = 256;
constexpr size_t MAX_ARRAY_BUFFER_MSG_ID_SIZE = 256;
constexpr size_t MAX_ARRAY_BUFFER_MSG_PARAM_SIZE = 128 * 1024;
static constexpr uint64_t INVALID_DISPLAY_ID = -1ULL;
const constexpr char *SYSTEM_CMD_KEY = "sys_cmd";
enum class EnterKeyType {
UNSPECIFIED = 0,
NONE,
GO,
SEARCH,
SEND,
NEXT,
DONE,
PREVIOUS,
NEW_LINE,
};
enum class TextInputType {
NONE = -1,
TEXT = 0,
MULTILINE,
NUMBER,
PHONE,
DATETIME,
EMAIL_ADDRESS,
URL,
VISIBLE_PASSWORD,
NUMBER_PASSWORD,
SCREEN_LOCK_PASSWORD,
USER_NAME,
NEW_PASSWORD,
NUMBER_DECIMAL,
ONE_TIME_CODE,
};
enum class Direction {
NONE = 0,
UP = 1,
DOWN,
LEFT,
RIGHT,
};
enum class SecurityMode : int32_t {
BASIC = 0,
FULL = 1,
};
enum class ExtendAction {
SELECT_ALL = 0,
CUT = 3,
COPY,
PASTE,
};
enum class CapacityType: int32_t {
IMMERSIVE_EFFECT,
SYSTEM_PANEL,
DISABLE_IMMERSIVE_MODE,
SUPPORT_PC_MODE,
DISABLE_PC_MODE_IMMERSIVE_MODE,
IS_PC_MODE,
END,
};
class Configuration {
public:
EnterKeyType GetEnterKeyType() const
{
return enterKeyType;
}
void SetEnterKeyType(EnterKeyType keyType)
{
enterKeyType = keyType;
}
TextInputType GetTextInputType() const
{
return textInputType;
}
void SetTextInputType(TextInputType textType)
{
textInputType = textType;
}
bool GetConsumeKeyEvents() const
{
return consumeKeyEvents;
}
bool HasConsumeKeyEvents() const
{
return hasConsumeKeyEvents;
}
void SetConsumeKeyEvents(bool support)
{
consumeKeyEvents = support;
hasConsumeKeyEvents = true;
}
private:
EnterKeyType enterKeyType = EnterKeyType::UNSPECIFIED;
TextInputType textInputType = TextInputType::TEXT;
bool consumeKeyEvents = false;
bool hasConsumeKeyEvents = false;
};
struct CursorInfo {
double left = -1.0;
double top = -1.0;
double width = -1.0;
double height = -1.0;
uint64_t displayId = 0;
bool operator==(const CursorInfo &info) const
{
return (left == info.left && top == info.top && width == info.width && height == info.height &&
displayId == info.displayId);
}
};
struct CursorInfoInner : public Parcelable {
double left = -1.0;
double top = -1.0;
double width = -1.0;
double height = -1.0;
uint64_t displayId = 0;
bool operator==(const CursorInfoInner &info) const
{
return (left == info.left && top == info.top && width == info.width && height == info.height &&
displayId == info.displayId);
}
bool ReadFromParcel(Parcel &in)
{
left = in.ReadDouble();
top = in.ReadDouble();
width = in.ReadDouble();
height = in.ReadDouble();
displayId = in.ReadUint64();
return true;
}
bool Marshalling(Parcel &out) const
{
if (!out.WriteDouble(left)) {
return false;
}
if (!out.WriteDouble(top)) {
return false;
}
if (!out.WriteDouble(width)) {
return false;
}
if (!out.WriteDouble(height)) {
return false;
}
if (!out.WriteUint64(displayId)) {
return false;
}
return true;
}
static CursorInfoInner *Unmarshalling(Parcel &in)
{
CursorInfoInner *data = new (std::nothrow) CursorInfoInner();
if (data && !data->ReadFromParcel(in)) {
delete data;
data = nullptr;
}
return data;
}
};
class KeyEvent { };
enum class KeyboardStatus : int32_t {
NONE = 0,
HIDE,
SHOW
};
enum Trigger : int32_t {
IME_APP,
IMF,
END
};
enum class InputType : int32_t {
NONE = -1,
CAMERA_INPUT = 0,
SECURITY_INPUT,
VOICE_INPUT,
VOICEKB_INPUT,
END
};
struct PanelStatusInfo {
PanelInfo panelInfo;
InputType inputType = InputType::NONE;
bool visible { false };
Trigger trigger { END };
uint32_t sessionId { 0 };
int32_t clientSessionId { -1 };
bool operator==(const PanelStatusInfo &info) const
{
return info.panelInfo.panelFlag == panelInfo.panelFlag && info.panelInfo.panelType == panelInfo.panelType &&
info.visible == visible && info.trigger == trigger;
}
};
struct PanelStatusInfoInner : public Parcelable {
PanelInfo panelInfo;
InputType inputType = InputType::NONE;
bool visible { false };
Trigger trigger { END };
uint32_t sessionId { 0 };
int32_t clientSessionId { -1 };
bool operator==(const PanelStatusInfoInner &info) const
{
return info.panelInfo.panelFlag == panelInfo.panelFlag && info.panelInfo.panelType == panelInfo.panelType &&
info.visible == visible && info.trigger == trigger;
}
bool ReadFromParcel(Parcel &in);
bool Marshalling(Parcel &out) const;
static PanelStatusInfoInner *Unmarshalling(Parcel &in);
};
class FunctionKey {
public:
EnterKeyType GetEnterKeyType() const
{
return enterKeyType;
}
void SetEnterKeyType(EnterKeyType keyType)
{
enterKeyType = keyType;
}
private:
EnterKeyType enterKeyType = EnterKeyType::UNSPECIFIED;
};
struct Range {
int32_t start = INVALID_VALUE;
int32_t end = INVALID_VALUE;
bool operator==(const Range &range) const
{
return start == range.start && end == range.end;
}
};
struct RangeInner : public Parcelable {
int32_t start = INVALID_VALUE;
int32_t end = INVALID_VALUE;
bool operator==(const RangeInner &range) const
{
return start == range.start && end == range.end;
}
bool ReadFromParcel(Parcel &in)
{
start = in.ReadInt32();
end = in.ReadInt32();
return true;
}
bool Marshalling(Parcel &out) const
{
if (!out.WriteInt32(start)) {
return false;
}
if (!out.WriteInt32(end)) {
return false;
}
return true;
}
static RangeInner *Unmarshalling(Parcel &in)
{
RangeInner *data = new (std::nothrow) RangeInner();
if (data && !data->ReadFromParcel(in)) {
delete data;
data = nullptr;
}
return data;
}
};
struct TextSelection {
int32_t oldBegin = INVALID_VALUE;
int32_t oldEnd = INVALID_VALUE;
int32_t newBegin = INVALID_VALUE;
int32_t newEnd = INVALID_VALUE;
};
struct TextSelectionInner : public Parcelable {
int32_t oldBegin = INVALID_VALUE;
int32_t oldEnd = INVALID_VALUE;
int32_t newBegin = INVALID_VALUE;
int32_t newEnd = INVALID_VALUE;
bool ReadFromParcel(Parcel &in);
bool Marshalling(Parcel &out) const;
static TextSelectionInner *Unmarshalling(Parcel &in);
};
enum PrivateDataValueType : int32_t {
VALUE_TYPE_STRING = 0,
VALUE_TYPE_BOOL,
VALUE_TYPE_NUMBER
};
using PrivateDataValue = std::variant<std::string, bool, int32_t>;
enum class RequestKeyboardReason : int32_t {
NONE = 0,
MOUSE = 1,
TOUCH = 2,
OTHER = 20
};
using ValueMap = std::unordered_map<std::string, PrivateDataValue>;
struct Value : public Parcelable {
Value(const std::unordered_map<std::string, PrivateDataValue>& map) : valueMap(map) {}
Value() = default;
bool ReadFromParcel(Parcel &in);
bool Marshalling(Parcel &out) const override;
static Value *Unmarshalling(Parcel &in);
ValueMap valueMap;
};
struct KeyEventValue : public Parcelable {
bool ReadFromParcel(Parcel &in);
bool Marshalling(Parcel &out) const override;
static KeyEventValue *Unmarshalling(Parcel &in);
std::shared_ptr<MMI::KeyEvent> event;
};
struct TextTotalConfig {
public:
InputAttribute inputAttribute = {};
CursorInfo cursorInfo = {};
TextSelection textSelection = {};
uint32_t windowId = INVALID_WINDOW_ID;
double positionY = 0;
double height = 0;
std::unordered_map<std::string, PrivateDataValue> privateCommand = {};
RequestKeyboardReason requestKeyboardReason = RequestKeyboardReason::NONE;
sptr<IRemoteObject> abilityToken { nullptr };
bool isSimpleKeyboardEnabled { false };
std::string ToString() const
{
std::string config;
config.append("pattern/enterKey/preview: " + std::to_string(inputAttribute.inputPattern) + "/" +
std::to_string(inputAttribute.enterKeyType) + "/" + std::to_string(inputAttribute.isTextPreviewSupported));
config.append(" windowId/y/height: " + std::to_string(windowId) + "/" + std::to_string(positionY) + "/" +
std::to_string(height));
config.append(
" oldRange: " + std::to_string(textSelection.oldBegin) + "/" + std::to_string(textSelection.oldEnd));
config.append(
" newRange: " + std::to_string(textSelection.newBegin) + "/" + std::to_string(textSelection.newEnd));
config.append(" cursor: " + std::to_string(cursorInfo.left) + "/" + std::to_string(cursorInfo.top) + "/" +
std::to_string(cursorInfo.width) + "/" + std::to_string(cursorInfo.height) + "/" +
std::to_string(cursorInfo.displayId));
config.append(" consumeKeyEvents:" + std::to_string(inputAttribute.consumeKeyEvents));
return config;
}
};
struct TextTotalConfigInner : public Parcelable {
public:
InputAttributeInner inputAttribute = {};
CursorInfoInner cursorInfo = {};
TextSelectionInner textSelection = {};
uint32_t windowId = INVALID_WINDOW_ID;
double positionY = 0;
double height = 0;
Value commandValue;
RequestKeyboardReason requestKeyboardReason = RequestKeyboardReason::NONE;
bool isSimpleKeyboardEnabled = false;
sptr<IRemoteObject> abilityToken { nullptr };
bool ReadFromParcel(Parcel &parcel);
bool Marshalling(Parcel &parcel) const override;
static TextTotalConfigInner *Unmarshalling(Parcel &parcel);
std::string ToString() const
{
std::string config;
config.append("pattern/enterKey/preview: " + std::to_string(inputAttribute.inputPattern) + "/" +
std::to_string(inputAttribute.enterKeyType) + "/" + std::to_string(inputAttribute.isTextPreviewSupported));
config.append(" windowId/y/height: " + std::to_string(windowId) + "/" + std::to_string(positionY) + "/" +
std::to_string(height));
config.append(
" oldRange: " + std::to_string(textSelection.oldBegin) + "/" + std::to_string(textSelection.oldEnd));
config.append(
" newRange: " + std::to_string(textSelection.newBegin) + "/" + std::to_string(textSelection.newEnd));
config.append(" cursor: " + std::to_string(cursorInfo.left) + "/" + std::to_string(cursorInfo.top) + "/" +
std::to_string(cursorInfo.width) + "/" + std::to_string(cursorInfo.height));
config.append(" consumeKeyEvents:" + std::to_string(inputAttribute.consumeKeyEvents));
return config;
}
};
struct TextConfig {
InputAttribute inputAttribute = {};
CursorInfo cursorInfo = {};
Range range = {};
uint32_t windowId = INVALID_WINDOW_ID;
double positionY = 0;
double height = 0;
bool newEditBox = false;
std::unordered_map<std::string, PrivateDataValue> privateCommand = {};
sptr<IRemoteObject> abilityToken { nullptr };
std::string ToString() const
{
std::string config;
config.append("pattern/enterKey/preview: " + std::to_string(inputAttribute.inputPattern) + "/" +
std::to_string(inputAttribute.enterKeyType) + "/" + std::to_string(inputAttribute.isTextPreviewSupported));
config.append(" windowId/y/height: " + std::to_string(windowId) + "/" + std::to_string(positionY) + "/" +
std::to_string(height));
config.append(" range: " + std::to_string(range.start) + "/" + std::to_string(range.end));
config.append(" cursor: " + std::to_string(cursorInfo.left) + "/" + std::to_string(cursorInfo.top) + "/" +
std::to_string(cursorInfo.width) + "/" + std::to_string(cursorInfo.height));
config.append(" consumeKeyEvents:" + std::to_string(inputAttribute.consumeKeyEvents));
return config;
}
static bool IsPrivateCommandValid(const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
{
size_t privateCommandSize = privateCommand.size();
size_t maxSize =
IsSystemPrivateCommand(privateCommand) ? MAX_SYS_PRIVATE_COMMAND_COUNT : MAX_PRIVATE_COMMAND_COUNT;
if (privateCommandSize == 0 || privateCommandSize > maxSize) {
IMSA_HILOGE("privateCommand size must more than 0 and less than 5.");
return false;
}
size_t totalSize = 0;
for (const auto &iter : privateCommand) {
size_t keySize = iter.first.size();
size_t idx = iter.second.index();
size_t valueSize = 0;
if (idx == static_cast<size_t>(PrivateDataValueType::VALUE_TYPE_STRING)) {
auto stringValue = std::get_if<std::string>(&iter.second);
if (stringValue == nullptr) {
IMSA_HILOGE("get stringValue failed.");
return false;
}
valueSize = (*stringValue).size();
} else if (idx == static_cast<size_t>(PrivateDataValueType::VALUE_TYPE_BOOL)) {
valueSize = sizeof(bool);
} else if (idx == static_cast<size_t>(PrivateDataValueType::VALUE_TYPE_NUMBER)) {
valueSize = sizeof(int32_t);
}
totalSize = totalSize + keySize + valueSize;
}
if (totalSize > MAX_PRIVATE_COMMAND_SIZE) {
IMSA_HILOGE("totalSize : %{public}zu", totalSize);
return false;
}
return true;
}
static bool IsSystemPrivateCommand(const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
{
IMSA_HILOGD("in.");
size_t privateCommandSize = privateCommand.size();
if (privateCommandSize == 0 || privateCommandSize > MAX_PRIVATE_COMMAND_COUNT) {
IMSA_HILOGE("privateCommand size must more than 0 and less than 5.");
return false;
}
auto it = privateCommand.find(SYSTEM_CMD_KEY);
if (it != privateCommand.end()) {
if (it->second.index() == static_cast<size_t>(PrivateDataValueType::VALUE_TYPE_NUMBER)) {
auto numberValue = std::get_if<int32_t>(&it->second);
if (numberValue == nullptr) {
IMSA_HILOGE("get stringValue failed.");
return false;
}
return *numberValue == 1;
}
}
return false;
}
};
enum class SwitchTrigger : uint32_t {
CURRENT_IME = 0,
SYSTEM_APP,
IMSA,
NATIVE_SA
};
struct ArrayBuffer : public Parcelable {
size_t jsArgc = 0;
std::string msgId;
std::vector<uint8_t> msgParam;
static bool IsSizeValid(const ArrayBuffer &arrayBuffer)
{
if (arrayBuffer.msgId.size() > MAX_ARRAY_BUFFER_MSG_ID_SIZE) {
IMSA_HILOGE("Invalid msgId size: %{public}zu.", arrayBuffer.msgId.size());
return false;
}
if (arrayBuffer.msgParam.size() > MAX_ARRAY_BUFFER_MSG_PARAM_SIZE) {
IMSA_HILOGE("Invalid msgParam size: %{public}zu.", arrayBuffer.msgParam.size());
return false;
}
return true;
}
bool operator==(const ArrayBuffer &arrayBuffer) const
{
return jsArgc == arrayBuffer.jsArgc && msgId == arrayBuffer.msgId && msgParam == arrayBuffer.msgParam;
}
bool ReadFromParcel(Parcel &in);
bool Marshalling(Parcel &out) const;
static ArrayBuffer *Unmarshalling(Parcel &in);
};
struct AttachOptions {
bool isShowKeyboard = false;
bool isSimpleKeyboardEnabled = false;
RequestKeyboardReason requestKeyboardReason { RequestKeyboardReason::NONE };
};
struct ImfCallingWindowInfo {
uint32_t windowId = INVALID_WINDOW_ID;
uint64_t displayId = 0;
};
struct DetachOptions {
uint32_t sessionId{ 0 };
int32_t clientSessionId{ -1 };
bool isUnbindFromClient{ false };
bool isInactiveClient{ false };
bool isNotifyClientAsync{ false };
bool needNotifyClient{ false };
bool isSendKeyboardStatus{ true };
bool isStopByMultiPreemptInProc{ false };
};
enum class ResponseDataType : uint64_t { NONE_TYPE = 0, STRING_TYPE, INT32_TYPE };
using ResponseData = std::variant<std::monostate, std::string, int32_t>;
struct ResponseDataInner : public Parcelable {
bool ReadFromParcel(Parcel &in);
bool Marshalling(Parcel &out) const override;
static ResponseDataInner *Unmarshalling(Parcel &in)
{
ResponseDataInner *data = new (std::nothrow) ResponseDataInner();
if (data != nullptr && !data->ReadFromParcel(in)) {
delete data;
data = nullptr;
}
return data;
}
ResponseData rspData = std::monostate{};
};
struct FocusedInfo : public Parcelable {
uint32_t windowId{ ImfCommonConst::INVALID_WINDOW_ID };
uint64_t displayId{ ImfCommonConst::DEFAULT_DISPLAY_ID };
uint64_t displayGroupId{ ImfCommonConst::DEFAULT_DISPLAY_GROUP_ID };
uint32_t keyboardWindowId{ ImfCommonConst::INVALID_WINDOW_ID };
uint64_t keyboardDisplayId{ ImfCommonConst::DEFAULT_DISPLAY_ID };
uint64_t keyboardDisplayGroupId{ ImfCommonConst::DEFAULT_DISPLAY_GROUP_ID };
pid_t uiExtensionHostPid{ ImfCommonConst::INVALID_PID };
std::string ToString() const
{
std::string config;
config.append("editorWindowId/editorDisplayId/editorDisplayGroupId: " + std::to_string(windowId) + "/"
+ std::to_string(displayId) + "/" + std::to_string(displayGroupId));
config.append(" keyboardWindowId/keyboardDisplayId/keyboardDisplayGroupId: " + std::to_string(keyboardWindowId)
+ "/" + std::to_string(keyboardDisplayId) + "/" + std::to_string(keyboardDisplayGroupId));
config.append(" uiExtensionHostPid: " + std::to_string(uiExtensionHostPid));
return config;
}
bool ReadFromParcel(Parcel &in)
{
windowId = in.ReadUint32();
displayId = in.ReadUint64();
displayGroupId = in.ReadUint64();
keyboardWindowId = in.ReadUint32();
keyboardDisplayId = in.ReadUint64();
keyboardDisplayGroupId = in.ReadUint64();
return true;
}
bool Marshalling(Parcel &out) const
{
if (!out.WriteUint32(windowId)) {
return false;
}
if (!out.WriteUint64(displayId)) {
return false;
}
if (!out.WriteUint64(displayGroupId)) {
return false;
}
if (!out.WriteUint32(keyboardWindowId)) {
return false;
}
if (!out.WriteUint64(keyboardDisplayId)) {
return false;
}
return out.WriteUint64(keyboardDisplayGroupId);
}
static FocusedInfo *Unmarshalling(Parcel &in)
{
FocusedInfo *data = new (std::nothrow) FocusedInfo();
if (data && !data->ReadFromParcel(in)) {
delete data;
data = nullptr;
}
return data;
}
};
}
}
#endif