输入法框架(IMF)模块
1. 模块概述
源码:https://gitee.com/openharmony/inputmethod_imf
1.1 功能与目标
主要功能
输入法框架(Input Method Framework,简称IMF)是OpenHarmony系统中负责输入法管理的核心子系统,其主要功能包括:
- 应用与输入法的桥梁:拉通应用程序和输入法应用,保证应用可以通过输入法进行文本输入
- 输入法生命周期管理:管理输入法的启动、停止、切换等生命周期
- 软键盘面板管理:控制软键盘面板的显示、隐藏、大小调整等
- 多用户会话管理:支持多用户场景下的输入法会话管理
- 输入法切换:支持用户在多个输入法之间进行切换
- 安全输入:支持密码输入等安全场景的特殊处理
- 代理输入法:支持ProxyIME模式,允许第三方应用代理输入
设计目标
- 提供统一、稳定的输入法接口
- 支持多种输入类型(文本、数字、密码等)
- 保证输入法切换的流畅性
- 确保安全输入场景的数据安全
- 支持多屏幕、多用户场景
1.2 系统位置
在系统中的位置
输入法框架位于OpenHarmony系统的系统基础服务层,作为Misc软件服务的一部分,为上层应用提供输入能力支持。
系统基础服务层
框架层
应用层
Misc软件服务
Frameworks
APIs
桌面
设置
其他系统应用
扩展应用/三方应用
API
IDL
输入法服务 IMF模块
模块角色
- 核心模块:作为系统输入能力的核心提供者
- 服务提供者:以System Ability形式提供服务(SA ID: 3703)
- 中间层:连接应用程序和输入法应用
1.3 设计思路与模式
设计思路
-
分层架构:采用Client-Service-IME三层架构
- Client层:应用客户端(InputMethodController)
- Service层:输入法服务(InputMethodSystemAbility)
- IME层:输入法应用(InputMethodAbility)
-
IPC通信:基于OpenHarmony的IPC机制实现跨进程通信
- 使用IDL定义接口
- 通过Proxy-Stub模式实现远程调用
-
事件驱动:采用消息队列和事件处理机制
- 异步处理输入事件
- 支持事件监听和回调
-
会话管理:基于用户的会话管理
- 每个用户独立的PerUserSession
- 支持多客户端并发
设计模式
| 设计模式 | 应用场景 | 说明 |
|---|---|---|
| 单例模式 | InputMethodController、InputMethodAbility | 保证全局唯一实例 |
| 代理模式 | IPC通信的Proxy-Stub | 实现远程对象的本地代理 |
| 观察者模式 | 事件监听机制 | 监听输入法状态变化、面板状态等 |
| 工厂模式 | ImeStateManagerFactory | 创建不同类型的状态管理器 |
| 状态模式 | ImeStatus、ClientState | 管理输入法和客户端的状态转换 |
| 策略模式 | 输入类型处理 | 根据不同输入类型采用不同策略 |
1.4 系统框图
输入法应用进程 (IMA)
输入法服务进程 (IMSA)
应用程序进程
IPC (IInputMethodSystemAbility)
IPC (IInputMethodCore)
InputMethodAbility (IMA)
InputMethodPanel
KeyboardListener
ImeEngineListener
InputDataChannel
InputMethodSystemAbility (SA 3703)
PerUserSession
ClientGroup
ImeData
SwitchQueue
UserSessionMgr
ImeInfoInquirer
ImeCfgManager
InputMethodController (IMC)
Attach
ShowInput
Close
OnTextChangedListener
2. 模块结构
2.1 源文件与头文件
目录结构
/base/inputmethod/imf
├── common/ # 公共模块
│ ├── include/ # 公共头文件
│ │ ├── global.h # 全局定义和错误码
│ │ ├── message.h # 消息定义
│ │ ├── block_queue.h # 阻塞队列
│ │ └── ...
│ └── src/ # 公共源文件
│
├── frameworks/ # 框架层
│ ├── native/
│ │ ├── inputmethod_controller/ # 应用客户端模块
│ │ │ ├── include/
│ │ │ │ ├── input_method_controller.h
│ │ │ │ ├── input_client_info.h
│ │ │ │ └── ...
│ │ │ └── src/
│ │ │ ├── input_method_controller.cpp
│ │ │ └── ...
│ │ │
│ │ └── inputmethod_ability/ # 输入法客户端模块
│ │ ├── include/
│ │ │ ├── input_method_ability.h
│ │ │ ├── input_method_panel.h
│ │ │ └── ...
│ │ └── src/
│ │ ├── input_method_ability.cpp
│ │ └── ...
│ │
│ ├── js/napi/ # JS接口层
│ └── cj/ # CJ接口层
│
├── services/ # 服务层
│ ├── include/
│ │ ├── input_method_system_ability.h
│ │ ├── peruser_session.h
│ │ ├── client_group.h
│ │ └── ...
│ └── src/
│ ├── input_method_system_ability.cpp
│ ├── peruser_session.cpp
│ └── ...
│
└── interfaces/ # 接口定义
├── inner_api/ # 内部API
└── kits/c/ # C接口
核心文件说明
| 文件路径 | 功能描述 |
|---|---|
common/include/global.h |
全局错误码定义、日志宏定义 |
frameworks/native/inputmethod_controller/include/input_method_controller.h |
应用客户端接口定义 |
frameworks/native/inputmethod_ability/include/input_method_ability.h |
输入法能力接口定义 |
frameworks/native/inputmethod_ability/include/input_method_panel.h |
输入法面板管理 |
services/include/input_method_system_ability.h |
系统服务主类定义 |
services/include/peruser_session.h |
用户会话管理 |
services/include/client_group.h |
客户端组管理 |
2.2 类、结构体、函数与方法
2.2.1 核心类
InputMethodController(应用客户端)
cpp
class InputMethodController : public RefBase, public PrivateCommandInterface {
public:
// 单例获取
static sptr<InputMethodController> GetInstance();
// 绑定输入法
int32_t Attach(sptr<OnTextChangedListener> listener,
bool isShowKeyboard,
const TextConfig &textConfig,
ClientType type = ClientType::INNER_KIT);
// 显示/隐藏软键盘
int32_t ShowTextInput(ClientType type = ClientType::INNER_KIT);
int32_t HideTextInput();
int32_t ShowSoftKeyboard(ClientType type = ClientType::INNER_KIT);
int32_t HideSoftKeyboard();
// 关闭输入法
int32_t Close();
// 光标和选择更新
int32_t OnCursorUpdate(CursorInfo cursorInfo);
int32_t OnSelectionChange(std::u16string text, int start, int end);
// 输入法切换
int32_t SwitchInputMethod(SwitchTrigger trigger,
const std::string &name,
const std::string &subName = "");
// 输入法列表
int32_t ListInputMethod(std::vector<Property> &props);
int32_t ListInputMethodSubtype(const Property &property,
std::vector<SubProperty> &subProperties);
// 获取当前输入法信息
std::shared_ptr<Property> GetCurrentInputMethod();
std::shared_ptr<SubProperty> GetCurrentInputMethodSubtype();
// 键盘事件分发
int32_t DispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> keyEvent,
KeyEventCallback callback);
// 私有命令
int32_t SendPrivateCommand(const std::unordered_map<std::string,
PrivateDataValue> &privateCommand) override;
// 文本预览
int32_t SetPreviewText(const std::string &text, const Range &range);
int32_t FinishTextPreview();
private:
InputMethodController();
~InputMethodController();
// 成员变量
static sptr<InputMethodController> instance_;
sptr<IInputMethodSystemAbility> abilityManager_;
sptr<OnTextChangedListener> textListener_;
InputClientInfo clientInfo_;
TextConfig textConfig_;
// ...
};
InputMethodAbility(输入法能力)
cpp
class InputMethodAbility : public RefBase, public PrivateCommandInterface {
public:
static InputMethodAbility &GetInstance();
// 核心连接
int32_t SetCoreAndAgent();
int32_t InitConnect();
// 文本操作
int32_t InsertText(const std::string &text,
const AsyncIpcCallBack &callback = nullptr);
int32_t DeleteForward(int32_t length,
const AsyncIpcCallBack &callback = nullptr);
int32_t DeleteBackward(int32_t length,
const AsyncIpcCallBack &callback = nullptr);
// 获取文本
int32_t GetTextBeforeCursor(int32_t number, std::u16string &text);
int32_t GetTextAfterCursor(int32_t number, std::u16string &text);
// 软键盘控制
int32_t HideKeyboardSelf();
// 面板管理
int32_t CreatePanel(const std::shared_ptr<AbilityRuntime::Context> &context,
const PanelInfo &panelInfo,
std::shared_ptr<InputMethodPanel> &inputMethodPanel);
int32_t DestroyPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel);
int32_t ShowPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel);
int32_t HidePanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel);
// 监听器设置
void SetImeListener(std::shared_ptr<InputMethodEngineListener> imeListener);
void SetKdListener(std::shared_ptr<KeyboardListener> kdListener);
// 状态查询
bool IsCurrentIme();
bool IsEnable();
// 安全模式
int32_t GetSecurityMode(int32_t &security);
private:
InputMethodAbility();
~InputMethodAbility();
// 成员变量
sptr<IInputMethodSystemAbility> abilityManager_;
std::shared_ptr<InputMethodEngineListener> imeListener_;
std::shared_ptr<KeyboardListener> kdListener_;
ConcurrentMap<PanelType, std::shared_ptr<InputMethodPanel>> panels_;
// ...
};
InputMethodSystemAbility(系统服务)
cpp
class InputMethodSystemAbility : public SystemAbility,
public InputMethodSystemAbilityStub {
DECLARE_SYSTEM_ABILITY(InputMethodSystemAbility);
public:
InputMethodSystemAbility(int32_t systemAbilityId, bool runOnCreate);
// 输入控制
ErrCode StartInput(const InputClientInfoInner &inputClientInfoInner,
std::vector<sptr<IRemoteObject>> &agents,
std::vector<BindImeInfo> &imeInfos) override;
ErrCode ShowCurrentInput(uint32_t type) override;
ErrCode HideCurrentInput() override;
ErrCode ShowInput(const sptr<IInputClient>& client, uint32_t type) override;
ErrCode HideInput(const sptr<IInputClient>& client) override;
ErrCode ReleaseInput(const sptr<IInputClient>& client, uint32_t sessionId) override;
// 输入法管理
ErrCode GetCurrentInputMethod(Property& resultValue) override;
ErrCode GetCurrentInputMethodSubtype(SubProperty& resultValue) override;
ErrCode ListInputMethod(uint32_t status, std::vector<Property> &props) override;
ErrCode SwitchInputMethod(const std::string &bundleName,
const std::string &subName,
uint32_t trigger) override;
// 面板状态
ErrCode PanelStatusChange(uint32_t status, const ImeWindowInfo &info) override;
ErrCode IsPanelShown(const PanelInfo &panelInfo, bool &isShown) override;
// IME核心设置
ErrCode SetCoreAndAgent(const sptr<IInputMethodCore> &core,
const sptr<IRemoteObject> &agent) override;
protected:
void OnStart() override;
void OnStop() override;
private:
ServiceRunningState state_;
std::shared_ptr<IdentityChecker> identityChecker_;
int32_t userId_;
// ...
};
PerUserSession(用户会话)
cpp
class PerUserSession {
public:
explicit PerUserSession(int userId);
// 输入控制
int32_t OnPrepareInput(const InputClientInfo &clientInfo);
int32_t OnStartInput(const InputClientInfo &inputClientInfo,
std::vector<sptr<IRemoteObject>> &agents,
std::vector<BindImeInfo> &imeInfos);
int32_t OnReleaseInput(const sptr<IInputClient> &client, uint32_t sessionId);
// 显示/隐藏
int32_t OnShowCurrentInput(uint64_t displayId);
int32_t OnHideCurrentInput(uint64_t displayId);
int32_t OnShowInput(sptr<IInputClient> client, int32_t requestKeyboardReason = 0);
int32_t OnHideInput(sptr<IInputClient> client);
// IME生命周期
int32_t StartCurrentIme(bool isStopCurrentIme = false);
int32_t StopCurrentIme();
bool RestartIme();
// 代理IME
int32_t OnRegisterProxyIme(const sptr<IInputMethodCore> &core,
const sptr<IRemoteObject> &agent, int32_t pid);
int32_t OnUnRegisteredProxyIme(UnRegisteredType type,
const sptr<IInputMethodCore> &core, pid_t pid);
// 焦点管理
void OnFocused(uint64_t displayId, int32_t pid, int32_t uid);
void OnUnfocused(uint64_t displayId, int32_t pid, int32_t uid);
private:
int32_t userId_;
std::unordered_map<ImeType, std::vector<std::shared_ptr<ImeData>>> imeData_;
std::unordered_map<uint64_t, std::shared_ptr<ClientGroup>> clientGroupMap_;
BlockQueue<SwitchInfo> switchQueue_;
// ...
};
2.2.2 关键结构体
cpp
// 输入法状态
enum class ImeStatus : uint32_t {
STARTING, // 正在启动
READY, // 就绪
EXITING // 正在退出
};
// IME事件
enum class ImeEvent : uint32_t {
START_IME,
START_IME_TIMEOUT,
STOP_IME,
SET_CORE_AND_AGENT,
};
// 客户端状态
enum class ClientState : uint32_t {
INACTIVE,
ACTIVE
};
// IME数据
struct ImeData {
sptr<IInputMethodCore> core{ nullptr };
sptr<IRemoteObject> agent{ nullptr };
sptr<InputDeathRecipient> deathRecipient{ nullptr };
pid_t pid;
std::shared_ptr<ImeStateManager> imeStateManager;
ImeStatus imeStatus{ ImeStatus::STARTING };
std::pair<std::string, std::string> ime; // bundleName, extName
int64_t startTime{ 0 };
};
// 输入客户端信息
struct InputClientInfo {
sptr<IInputClient> client;
sptr<IRemoteObject> channel;
InputAttribute attribute;
TextTotalConfig config;
uint32_t eventFlag;
bool isShowKeyboard;
ClientState state;
ClientType type;
// ...
};
// 面板信息
struct PanelInfo {
PanelType panelType;
PanelFlag panelFlag;
};
// 文本配置
struct TextConfig {
InputAttribute inputAttribute;
CursorInfo cursorInfo;
Range range;
uint32_t windowId;
double positionY;
double height;
// ...
};
2.2.3 继承与多态
RefBase
InputMethodController
+GetInstance()
+Attach()
+Close()
+ShowTextInput()
InputMethodAbility
+GetInstance()
+InsertText()
+CreatePanel()
<<abstract>>
OnTextChangedListener
+InsertText()
+DeleteForward()
+DeleteBackward()
PrivateCommandInterface
TextInputClient
SystemAbility
InputMethodSystemAbility
InputMethodSystemAbilityStub
IInputMethodSystemAbility
<<abstract>>
ImeStateManager
+IsIpcNeeded()
+BeforeIpc()
+AfterIpc()
FreezeManager
2.3 类图
uses
IPC
manages
contains
stores
IPC
creates
1 1 1 * * * InputMethodController
-instance_ : sptr<InputMethodController>
-abilityManager_ : sptr<IInputMethodSystemAbility>
-textListener_ : sptr<OnTextChangedListener>
-clientInfo_ : InputClientInfo
+GetInstance() : sptr<InputMethodController>
+Attach() : int32_t
+Close() : int32_t
+ShowTextInput() : int32_t
+HideTextInput() : int32_t
+OnCursorUpdate() : int32_t
+OnSelectionChange() : int32_t
<<interface>>
OnTextChangedListener
+InsertText(text)
+DeleteForward(length)
+DeleteBackward(length)
+MoveCursor(direction)
+HandleExtendAction(action)
TextInputClient
+InsertText(text)
+DeleteForward(length)
InputMethodSystemAbility
-state_ : ServiceRunningState
-identityChecker_ : shared_ptr<IdentityChecker>
-userId_ : int32_t
+StartInput() : ErrCode
+ShowCurrentInput() : ErrCode
+HideCurrentInput() : ErrCode
+SwitchInputMethod() : ErrCode
+ListInputMethod() : ErrCode
PerUserSession
-userId_ : int32_t
-imeData_ : unordered_map
-clientGroupMap_ : unordered_map
-switchQueue_ : BlockQueue
+OnStartInput() : int32_t
+OnShowInput() : int32_t
+OnHideInput() : int32_t
+StartCurrentIme() : int32_t
+StopCurrentIme() : int32_t
ClientGroup
-displayGroupId_ : uint64_t
-mapClients_ : map
-currentClient_ : sptr<IInputClient>
+AddClientInfo() : int32_t
+RemoveClientInfo() : void
+GetCurrentClient() : sptr<IInputClient>
InputClientInfo
+client : sptr<IInputClient>
+channel : sptr<IRemoteObject>
+attribute : InputAttribute
+state : ClientState
InputMethodAbility
-abilityManager_ : sptr<IInputMethodSystemAbility>
-imeListener_ : shared_ptr<InputMethodEngineListener>
-kdListener_ : shared_ptr<KeyboardListener>
-panels_ : ConcurrentMap
+GetInstance() : InputMethodAbility&
+SetCoreAndAgent() : int32_t
+InsertText() : int32_t
+DeleteForward() : int32_t
+CreatePanel() : int32_t
+ShowPanel() : int32_t
InputMethodPanel
-window_ : sptr<Window>
-panelType_ : PanelType
-panelFlag_ : PanelFlag
-windowId_ : uint32_t
+CreatePanel() : int32_t
+DestroyPanel() : int32_t
+ShowPanel() : int32_t
+HidePanel() : int32_t
+Resize() : int32_t
+MoveTo() : int32_t
2.4 模块内部依赖框图
Service Layer
Framework Layer
IPC
IPC
IPC
InputMethodSystemAbility Module
InputMethodSystemAbility
UserSessionManager
ImeInfoInquirer
PerUserSession
ClientGroup
ImeData
ImeStateManager
ImeCfgManager
FullImeInfoManager
InputMethodAbility Module
InputMethodAbility
InputCoreImpl
InputAgentImpl
InputMethodPanel
InputMethodController Module
InputMethodController
InputClientImpl
DataChannelImpl
KeyEventHandler
Common Layer
global.h
message.h
block_queue.h
itypes_util.h
3. 模块间交互
3.1 交互描述
3.1.1 与外部模块的交互
| 外部模块 | 交互方式 | 说明 |
|---|---|---|
| ability_runtime | 依赖调用 | 用于启动输入法ExtensionAbility |
| window_manager | 依赖调用 | 用于创建和管理软键盘窗口 |
| ipc | IPC通信 | 跨进程通信基础设施 |
| samgr | 服务注册 | 注册InputMethodSystemAbility服务 |
| bundle_framework | 依赖调用 | 查询输入法应用信息 |
| common_event_service | 事件订阅 | 订阅系统事件(用户切换、包安装等) |
| access_token | 权限检查 | 验证调用者权限 |
| input | 键盘事件 | 处理物理键盘输入 |
| os_account | 用户管理 | 多用户场景支持 |
| graphic_2d | 图形渲染 | 软键盘UI渲染 |
3.1.2 IPC通信机制
输入法进程 服务进程 应用进程 输入法进程 服务进程 应用进程 IPC通信流程 IInputMethodSystemAbility (StartInput/ShowInput) IInputMethodCore (StartInput) SetCoreAndAgent 返回Agent代理 IInputMethodAgent (InsertText等) IInputDataChannel (GetTextBeforeCursor)
3.1.3 异步处理与事件驱动
-
消息队列机制
- 使用
BlockQueue实现异步消息传递 - 支持超时等待和阻塞操作
- 使用
-
事件处理器
- 基于
EventHandler实现异步任务调度 - 支持延迟任务和优先级调度
- 基于
-
事件监听
ImeEventListener:监听输入法状态变化OnTextChangedListener:监听文本变化PanelStatusListener:监听面板状态变化
3.1.4 多线程处理
cpp
// 工作线程
std::thread workThreadHandler; // 消息处理线程
// 线程安全机制
std::mutex abilityLock_; // 服务代理锁
std::mutex agentLock_; // Agent锁
std::recursive_mutex clientInfoLock_; // 客户端信息锁
std::mutex textConfigLock_; // 文本配置锁
// 原子操作
std::atomic_bool isEditable_; // 可编辑状态
std::atomic_bool isBound_; // 绑定状态
3.2 外部依赖框图
基础依赖
graphic_2d
图形渲染/显示管理
hilog
日志记录/调试追踪
系统依赖
window_manager
窗口创建/管理/键盘面板
os_account
多用户支持/用户ID获取
input
键盘事件处理/按键分发
功能依赖
bundle_framework
包信息查询/应用安装状态
common_event_service
系统事件订阅/用户切换事件
access_token
权限检查/身份验证
核心依赖
ability_runtime
ExtAbility/Context
samgr
SystemAbility注册/发现
ipc
IPC通信/Proxy/Stub
InputMethod IMF
InputMethodSystemAbility
InputMethodController
InputMethodAbility
4. 状态机转换图
4.1 状态机模型
4.1.1 IME状态机
输入法引擎(IME)的生命周期由三个主要状态组成:
cpp
enum class ImeStatus : uint32_t {
STARTING, // 正在启动
READY, // 就绪
EXITING // 正在退出
};
enum class ImeEvent : uint32_t {
START_IME, // 启动IME
START_IME_TIMEOUT, // 启动超时
STOP_IME, // 停止IME
SET_CORE_AND_AGENT, // 设置Core和Agent
};
enum class ImeAction : uint32_t {
DO_NOTHING,
HANDLE_STARTING_IME,
FORCE_STOP_IME,
STOP_READY_IME,
START_AFTER_FORCE_STOP,
DO_SET_CORE_AND_AGENT,
DO_ACTION_IN_NULL_IME_DATA,
DO_ACTION_IN_IME_EVENT_CONVERT_FAILED,
};
4.2 状态机树图
IME States
Root
STARTING
正在启动中
READY
就绪可用
EXITING
正在退出
等待IME连接
超时检测
处理输入请求
响应用户操作
等待IME停止
清理资源
4.3 状态机切换规则
状态转换表
| 当前状态 | 触发事件 | 目标状态 | 执行动作 |
|---|---|---|---|
| READY | START_IME | READY | DO_NOTHING |
| STARTING | START_IME | STARTING | HANDLE_STARTING_IME |
| EXITING | START_IME | EXITING | START_AFTER_FORCE_STOP |
| READY | START_IME_TIMEOUT | READY | DO_NOTHING |
| STARTING | START_IME_TIMEOUT | EXITING | START_AFTER_FORCE_STOP |
| EXITING | START_IME_TIMEOUT | EXITING | START_AFTER_FORCE_STOP |
| READY | STOP_IME | EXITING | STOP_READY_IME |
| STARTING | STOP_IME | EXITING | FORCE_STOP_IME |
| EXITING | STOP_IME | EXITING | FORCE_STOP_IME |
| READY | SET_CORE_AND_AGENT | READY | DO_NOTHING |
| STARTING | SET_CORE_AND_AGENT | READY | DO_SET_CORE_AND_AGENT |
| EXITING | SET_CORE_AND_AGENT | EXITING | DO_NOTHING |
状态转换代码定义
cpp
static inline const std::map<std::pair<ImeStatus, ImeEvent>,
std::pair<ImeStatus, ImeAction>> imeEventConverter_ = {
// READY状态的转换
{ { ImeStatus::READY, ImeEvent::START_IME },
{ ImeStatus::READY, ImeAction::DO_NOTHING } },
{ { ImeStatus::READY, ImeEvent::START_IME_TIMEOUT },
{ ImeStatus::READY, ImeAction::DO_NOTHING } },
{ { ImeStatus::READY, ImeEvent::STOP_IME },
{ ImeStatus::EXITING, ImeAction::STOP_READY_IME } },
{ { ImeStatus::READY, ImeEvent::SET_CORE_AND_AGENT },
{ ImeStatus::READY, ImeAction::DO_NOTHING } },
// STARTING状态的转换
{ { ImeStatus::STARTING, ImeEvent::START_IME },
{ ImeStatus::STARTING, ImeAction::HANDLE_STARTING_IME } },
{ { ImeStatus::STARTING, ImeEvent::START_IME_TIMEOUT },
{ ImeStatus::EXITING, ImeAction::START_AFTER_FORCE_STOP } },
{ { ImeStatus::STARTING, ImeEvent::STOP_IME },
{ ImeStatus::EXITING, ImeAction::FORCE_STOP_IME } },
{ { ImeStatus::STARTING, ImeEvent::SET_CORE_AND_AGENT },
{ ImeStatus::READY, ImeAction::DO_SET_CORE_AND_AGENT } },
// EXITING状态的转换
{ { ImeStatus::EXITING, ImeEvent::START_IME },
{ ImeStatus::EXITING, ImeAction::START_AFTER_FORCE_STOP } },
{ { ImeStatus::EXITING, ImeEvent::START_IME_TIMEOUT },
{ ImeStatus::EXITING, ImeAction::START_AFTER_FORCE_STOP } },
{ { ImeStatus::EXITING, ImeEvent::STOP_IME },
{ ImeStatus::EXITING, ImeAction::FORCE_STOP_IME } },
{ { ImeStatus::EXITING, ImeEvent::SET_CORE_AND_AGENT },
{ ImeStatus::EXITING, ImeAction::DO_NOTHING } }
};
4.4 状态机转换图
START_IME
(启动请求)
SET_CORE_AND_AGENT
(成功连接)
START_IME_TIMEOUT
(启动超时)
STOP_IME
(停止请求)
START_IME
(重复启动)
SET_CORE_AND_AGENT
(已连接)
STOP_IME
(停止请求)
START_IME_TIMEOUT
(超时重启)
FORCE_STOP完成
STARTING
READY
EXITING
等待IME连接
超时时间: 8秒
处理输入请求
响应用户操作
清理资源
等待停止完成
4.5 客户端状态机
Attach()
绑定成功
Close()
或 失焦
INACTIVE
ACTIVE
客户端未与输入法服务绑定
-
不能进行文本输入
-
等待Attach调用
客户端已与输入法服务绑定 -
可以进行文本输入
-
可以显示/隐藏软键盘
-
可以接收输入法的回调
4.6 状态转换触发条件
状态转换触发条件
START_IME
• 用户点击输入框
• 应用调用Attach()
• 系统启动默认输入法
SET_CORE_AND_AGENT
• IME成功启动并回调
• 建立Core和Agent连接
START_IME_TIMEOUT
• IME启动超时(8秒)
• 需要强制停止并重启
STOP_IME
• 用户切换输入法
• 应用调用Close()
• 系统要求停止
5. 接口设计
5.1 公共接口
5.1.1 InputMethodController API
| 接口名称 | 功能描述 | 参数 | 返回值 |
|---|---|---|---|
GetInstance() |
获取单例实例 | 无 | sptr<InputMethodController> |
Attach() |
绑定输入法 | listener, isShowKeyboard, textConfig, type | int32_t 错误码 |
Close() |
关闭输入法 | 无 | int32_t 错误码 |
ShowTextInput() |
显示软键盘 | type | int32_t 错误码 |
HideTextInput() |
隐藏软键盘 | 无 | int32_t 错误码 |
ShowSoftKeyboard() |
显示软键盘(需权限) | type | int32_t 错误码 |
HideSoftKeyboard() |
隐藏软键盘(需权限) | 无 | int32_t 错误码 |
OnCursorUpdate() |
更新光标位置 | cursorInfo | int32_t 错误码 |
OnSelectionChange() |
更新选择范围 | text, start, end | int32_t 错误码 |
SwitchInputMethod() |
切换输入法 | trigger, name, subName | int32_t 错误码 |
ListInputMethod() |
列出输入法 | props | int32_t 错误码 |
GetCurrentInputMethod() |
获取当前输入法 | 无 | shared_ptr<Property> |
DispatchKeyEvent() |
分发键盘事件 | keyEvent, callback | int32_t 错误码 |
SendPrivateCommand() |
发送私有命令 | privateCommand | int32_t 错误码 |
SetPreviewText() |
设置预览文本 | text, range | int32_t 错误码 |
FinishTextPreview() |
完成文本预览 | 无 | int32_t 错误码 |
5.1.2 InputMethodAbility API
| 接口名称 | 功能描述 | 参数 | 返回值 |
|---|---|---|---|
GetInstance() |
获取单例实例 | 无 | InputMethodAbility& |
SetCoreAndAgent() |
设置Core和Agent | 无 | int32_t 错误码 |
InsertText() |
插入文本 | text, callback | int32_t 错误码 |
DeleteForward() |
向前删除 | length, callback | int32_t 错误码 |
DeleteBackward() |
向后删除 | length, callback | int32_t 错误码 |
GetTextBeforeCursor() |
获取光标前文本 | number, text, callback | int32_t 错误码 |
GetTextAfterCursor() |
获取光标后文本 | number, text, callback | int32_t 错误码 |
MoveCursor() |
移动光标 | keyCode, callback | int32_t 错误码 |
CreatePanel() |
创建面板 | context, panelInfo, panel | int32_t 错误码 |
DestroyPanel() |
销毁面板 | panel | int32_t 错误码 |
ShowPanel() |
显示面板 | panel | int32_t 错误码 |
HidePanel() |
隐藏面板 | panel | int32_t 错误码 |
HideKeyboardSelf() |
隐藏自身键盘 | 无 | int32_t 错误码 |
SetImeListener() |
设置IME监听器 | imeListener | 无 |
SetKdListener() |
设置键盘监听器 | kdListener | 无 |
IsCurrentIme() |
是否当前输入法 | 无 | bool |
GetSecurityMode() |
获取安全模式 | security | int32_t 错误码 |
5.1.3 错误码定义
cpp
namespace ErrorCode {
enum {
NO_ERROR = 0, // 成功
ERROR_NULL_POINTER, // 空指针
ERROR_BAD_PARAMETERS, // 参数错误
ERROR_STATUS_PERMISSION_DENIED, // 权限拒绝
ERROR_PARAMETER_CHECK_FAILED, // 参数检查失败
ERROR_SERVICE_START_FAILED, // 服务启动失败
ERROR_CLIENT_NOT_EDITABLE, // 客户端不可编辑
ERROR_CLIENT_NOT_BOUND, // 客户端未绑定
ERROR_IME_NOT_STARTED, // 输入法未启动
ERROR_IME_NOT_FOUND, // 输入法未找到
ERROR_TEXT_PREVIEW_NOT_SUPPORTED, // 不支持文本预览
ERROR_INVALID_PRIVATE_COMMAND_SIZE, // 私有命令大小无效
ERROR_INVALID_RANGE, // 范围无效
// ...
};
}
5.2 数据交换接口
5.2.1 IDL接口定义
IInputMethodSystemAbility.idl
idl
interface IInputMethodSystemAbility {
ErrCode StartInput([in] InputClientInfoInner inputClientInfoInner,
[out] IRemoteObject[] agents,
[out] BindImeInfo[] imeInfos);
ErrCode ShowCurrentInput([in] unsigned int type);
ErrCode HideCurrentInput();
ErrCode ShowInput([in] IInputClient client, [in] unsigned int type);
ErrCode HideInput([in] IInputClient client);
ErrCode ReleaseInput([in] IInputClient client, [in] unsigned int sessionId);
ErrCode SwitchInputMethod([in] String bundleName,
[in] String subName,
[in] unsigned int trigger);
// ...
}
IInputMethodCore.idl
idl
interface IInputMethodCore {
int StartInput([in] InputClientInfo clientInfo, [in] boolean isBindFromClient);
int StopInput([in] IRemoteObject channel, [in] unsigned int sessionId);
int ShowKeyboard([in] int requestKeyboardReason);
int HideKeyboard();
void OnSetSubtype([in] SubProperty subProperty);
// ...
}
IInputMethodAgent.idl
idl
interface IInputMethodAgent {
void OnCursorUpdate([in] int positionX, [in] int positionY, [in] int height);
void OnSelectionChange([in] String text, [in] int oldBegin,
[in] int oldEnd, [in] int newBegin, [in] int newEnd);
void OnAttributeChange([in] InputAttributeInner attribute);
int DispatchKeyEvent([in] KeyEventValue keyEvent,
[in] unsigned long cbId,
[in] IRemoteObject channel);
int SendPrivateCommand([in] Value value);
// ...
}
5.3 接口调用时序图
5.3.1 应用绑定输入法时序
InputMethodAbility InputMethodSystemAbility InputMethodController App InputMethodAbility InputMethodSystemAbility InputMethodController App 1. Attach(listener, textConfig) 2. StartInput(clientInfo) 3. StartCurrentIme() 4. SetCoreAndAgent() 5. Return(agents, imeInfos) 6. SetAgent(agent) 7. Return NO_ERROR 8. StartInput(clientInfo) 9. ShowKeyboard()
5.3.2 文本输入时序
InputMethodAbility InputMethodController App InputMethodAbility InputMethodController App 1. InsertText("hello") 2. InsertText("hello") (IInputDataChannel) 3. OnTextChangedListener ::InsertText("hello") 4. 更新UI显示 5. OnSelectionChange() (IInputMethodAgent)
5.3.3 输入法切换时序
NewIME OldIME InputMethodSystemAbility InputMethodController App NewIME OldIME InputMethodSystemAbility InputMethodController App 1. SwitchInputMethod(bundleName) 2. SwitchInputMethod() 3. StopInput() 4. HideKeyboard() 5. StopCurrentIme() 6. StartIme(newIme) 7. SetCoreAndAgent() 8. StartInput() 9. ShowKeyboard() 10. NotifyImeChange() 11. Return
附录
A. 术语表
| 术语 | 全称 | 说明 |
|---|---|---|
| IMF | Input Method Framework | 输入法框架 |
| IMC | Input Method Controller | 输入法控制器(应用侧) |
| IMA | Input Method Ability | 输入法能力(输入法侧) |
| IMSA | Input Method System Ability | 输入法系统服务 |
| IME | Input Method Engine | 输入法引擎 |
| SA | System Ability | 系统能力 |
| IPC | Inter-Process Communication | 进程间通信 |
| IDL | Interface Definition Language | 接口定义语言 |