-
InputMethodService.ts file:
In the InputMethodService.ts file, add the dependency package for importing InputMethodExtensionAbility. Customize a class that inherits from InputMethodExtensionAbility and add the required lifecycle callbacks.
import { Want } from '@kit.AbilityKit';
import keyboardController from './model/KeyboardController';
import { InputMethodExtensionAbility } from '@kit.IMEKit';
export default class InputDemoService extends InputMethodExtensionAbility {
onCreate(want: Want): void {
keyboardController.onCreate(this.context); // Initialize the window and register an event listener for the input method framework.
}
onDestroy(): void {
console.log("onDestroy.");
keyboardController.onDestroy(); // Destroy the window and deregister the event listener.
}
} -
KeyboardController.ts file:
import { display } from '@kit.ArkUI';
import { inputMethodEngine, InputMethodExtensionContext } from '@kit.IMEKit';
// Call the getInputMethodAbility API to obtain an instance, and then call the other APIs of the input method framework based on the instance.
const inputMethodAbility: inputMethodEngine.InputMethodAbility = inputMethodEngine.getInputMethodAbility();
export class KeyboardController {
private mContext: InputMethodExtensionContext | undefined = undefined; // Save the context attribute in InputMethodExtensionAbility.
private panel: inputMethodEngine.Panel | undefined = undefined;
private textInputClient: inputMethodEngine.InputClient | undefined = undefined;
private keyboardController: inputMethodEngine.KeyboardController | undefined = undefined;
constructor() {
}
public onCreate(context: InputMethodExtensionContext): void
{
this.mContext = context;
this.initWindow(); // Initialize the window.
this.registerListener(); // Register an event listener for the input method framework.
}
public onDestroy(): void // Destroy the instance.
{
this.unRegisterListener(); // Deregister the event listener.
if(this.panel) { // Destroy the window.
inputMethodAbility.destroyPanel(this.panel);
}
if(this.mContext) {
this.mContext.destroy();
}
}
public insertText(text: string): void {
if(this.textInputClient) {
this.textInputClient.insertText(text);
}
}
public deleteForward(length: number): void {
if(this.textInputClient) {
this.textInputClient.deleteForward(length);
}
}
private initWindow(): void // Initialize the window.
{
if(this.mContext === undefined) {
return;
}
let dis = display.getDefaultDisplaySync();
let dWidth = dis.width;
let dHeight = dis.height;
let keyHeightRate = 0.47;
let keyHeight = dHeight * keyHeightRate;
let nonBarPosition = dHeight - keyHeight;
let panelInfo: inputMethodEngine.PanelInfo = {
type: inputMethodEngine.PanelType.SOFT_KEYBOARD,
flag: inputMethodEngine.PanelFlag.FLG_FIXED
};
inputMethodAbility.createPanel(this.mContext, panelInfo).then(async (inputPanel: inputMethodEngine.Panel) => {
this.panel = inputPanel;
if(this.panel) {
await this.panel.resize(dWidth, keyHeight);
await this.panel.moveTo(0, nonBarPosition);
await this.panel.setUiContent('InputMethodExtensionAbility/pages/Index');
}
});
}
private registerListener(): void
{
this.registerInputListener(); // Register an event listener for the input method framework service.
// Register a listener for keyboard hiding.
}
private registerInputListener(): void { // Register a listener for the enabling and disabling events of the input method framework service.
inputMethodAbility.on('inputStart', (kbController, textInputClient) => {
this.textInputClient = textInputClient; // This is an input method client instance, based on which you can call the APIs that the input method framework provides for the input method.
this.keyboardController = kbController;
})
inputMethodAbility.on('inputStop', () => {
this.onDestroy (); // Destroy the KeyboardController instance.
});
}
private unRegisterListener(): void
{
inputMethodAbility.off('inputStart');
inputMethodAbility.off('inputStop', () => {});
}
}
const keyboardController = new KeyboardController();
export default keyboardController; -
KeyboardKeyData.ts file:
In this file you can define the content displayed on the soft keyboard.
export interface sourceListType {
content: string,
}
export let numberSourceListData: sourceListType[] = [
{
content: '1'
},
{
content: '2'
},
{
content: '3'
},
{
content: '4'
},
{
content: '5'
},
{
content: '6'
},
{
content: '7'
},
{
content: '8'
},
{
content: '9'
},
{
content: '0'
}
] -
Index.ets file:
This file describes the functions of keys. For example, the number keys print numbers in the text box, and the delete key deletes what's entered.
Add the path to this file to the src field in the resources/base/profile/main_pages.json file.
import { numberSourceListData, sourceListType } from './KeyboardKeyData';
import keyboardController from '../model/KeyboardController';
@Component
struct keyItem {
private keyValue: sourceListType = numberSourceListData[0];
@State keyBgc: string = "#fff"
@State keyFontColor: string = "#000"
build() {
Column() {
Flex({ direction: FlexDirection.Column,
alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text(this.keyValue.content).fontSize(20).fontColor(this.keyFontColor)
}
}
.backgroundColor(this.keyBgc)
.borderRadius(6)
.width("8%")
.height("65%")
.onClick(() => {
keyboardController.insertText(this.keyValue.content);
})
}
}
// Component used for deletion
@Component
export struct deleteItem {
@State keyBgc: string = "#fff"
@State keyFontColor: string = "#000"
build() {
Column() {
Flex({ direction: FlexDirection.Column,
alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text("Delete").fontSize(20).fontColor(this.keyFontColor)
}
}
.backgroundColor(this.keyBgc)
.width("13%")
.borderRadius(6)
.onClick(() => {
keyboardController.deleteForward(1);
})
}
}
// Numeric keyboard
@Component
struct numberMenu {
private numberList: sourceListType[] = numberSourceListData;
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceEvenly }) {
Flex({ justifyContent: FlexAlign.SpaceBetween }) {
ForEach(this.numberList, (item: sourceListType) => { // First row on the numeric keyboard
keyItem({ keyValue: item })
}, (item: sourceListType) => item.content);
}
.padding({ top: "2%" })
.width("96%")
.height("25%")
Flex({ justifyContent: FlexAlign.SpaceBetween }) {
deleteItem()
}
.width("96%")
.height("25%")
}
}
}
@Entry
@Component
struct Index {
private numberList: sourceListType[] = numberSourceListData
build() {
Stack() {
Flex({
direction: FlexDirection.Column,
alignItems: ItemAlign.Center,
justifyContent: FlexAlign.End
}) {
Flex({
direction: FlexDirection.Column,
alignItems: ItemAlign.Center,
justifyContent: FlexAlign.SpaceBetween
}) {
numberMenu({
numberList: this.numberList
})
}
.align(Alignment.End)
.width("100%")
.height("75%")
}
.height("100%").align(Alignment.End).backgroundColor("#cdd0d7")
}
.position({ x: 0, y: 0 }).zIndex(99999)
}
} -
module.json5 file:
Register the InputMethodExtensionAbility in the module.json5 file corresponding to the Module project. Set type to "inputMethod" and srcEntry to the code path of the InputMethodExtensionAbility component.
{
"module": {
...
"extensionAbilities": [
{
"description": "inputMethod",
"name": "InputMethodExtensionAbility",
"icon": "$media:app_icon",
"srcEntry": "./ets/InputMethodExtensionAbility/InputMethodService.ts",
"type": "inputMethod",
"exported": true,
}
]
}
}