1# InputMethodExtensionAbility 2 3## When to Use 4[InputMethodExtensionAbility](../reference/apis/js-apis-inputmethod-extension-ability.md), inherited from [ExtensionAbility](extensionability-overview.md), is used for developing input method applications. 5 6The entire lifecycle of the [InputMethodExtensionAbility](../reference/apis/js-apis-inputmethod-extension-ability.md) instance and the owning ExtensionAbility process is scheduled and managed by the input method framework. The input method framework provides the [InputMethodExtensionAbility](../reference/apis/js-apis-inputmethod-extension-ability.md) base class. Derive this base class to implement initialization and resource clearing. 7 8[InputMethodExtensionAbility](../reference/apis/js-apis-inputmethod-extension-ability.md) provides related capabilities through [InputMethodExtensionContext](../reference/apis/js-apis-inputmethod-extension-context.md). 9 10 11## Implementing an Input Method Application 12 13InputMethodExtensionAbility provides the **onCreate()** and **onDestory()** callbacks, as described below. Override them as required. 14 15- **onCreate** 16 This callback is triggered when a service is created for the first time. You can perform initialization operations, for example, registering a common event listener. 17 18 > **NOTE** 19 > 20 > If a service has been created, starting it again does not trigger the **onCreate()** callback. 21 22- **onDestroy** 23 This callback is triggered when the service is no longer used and the instance is ready for destruction. You can clear resources in this callback, for example, deregister the listener. 24 25 26## How to Develop 27 28To implement an input method application, manually create an InputMethodExtensionAbility component in DevEco Studio. The procedure is as follows: 29 30In the **ets** directory of the target module, right-click and choose **New** > **Extension Ability** > **InputMethod** to a minimum template of InputMethodExtensionAbility. 31 32> **NOTE** 33> 34> When compiling the input method application, use the signature at the system_basic level. Otherwise, the application will not be able to start the keyboard. 35 36The minimum template implements an input method application with the most basic features, such as starting the keyboard, entering text, and deleting input. You can diversify the feature set of the application by, for example, adding the feature to hide the keyboard. 37 38The minimum template contains four files: **KeyboardController.ts**, **InputMethodService.ts**, **Index.ets**, and **KeyboardKeyData.ts**. The file directory is as follows: 39 40``` 41/src/main/ 42├── ets/inputmethodextability 43│ └──model/KeyboardController.ts # Shows the keyboard. 44│ └──InputMethodService.ts # Customizes a class that inherits from InputMethodExtensionAbility and add the required lifecycle callbacks. 45│ └──pages 46│ └── Index.ets # Draws the keyboard and adds the input and deletion features. 47│ └── KeyboardKeyData.ts # Defines keyboard attributes. 48├── resources/base/profile/main_pages.json 49``` 50 51## File Introduction 52 531. **InputMethodService.ts** file: 54 55 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. 56 57 ```ts 58 import InputMethodExtensionAbility from '@ohos.InputMethodExtensionAbility'; 59 import { KeyboardController } from './model/KeyboardController' 60 61 export default class InputDemoService extends InputMethodExtensionAbility { 62 private keyboardController: KeyboardController; 63 64 onCreate(want) { 65 this.keyboardController = new KeyboardController(this.context); 66 this.keyboardController.onCreate(); // Initialize the window and register an event listener for the input method framework. 67 } 68 69 onDestroy() { 70 console.log("onDestroy."); 71 this.keyboardController.onDestroy(); // Destroy the window and deregister the event listener. 72 } 73 } 74 ``` 75 762. **KeyboardController.ts** file: 77 78 ```ts 79 import inputMethodEngine from '@ohos.inputMethodEngine'; 80 import display from '@ohos.display'; 81 import windowManager from '@ohos.window'; 82 83 // Call the getInputMethodAbility API to obtain an instance, and then call the other APIs of the input method framework based on the instance. 84 globalThis.inputAbility = inputMethodEngine.getInputMethodAbility(); 85 86 export class KeyboardController { 87 mContext; // Save the context attribute in InputMethodExtensionAbility. 88 WINDOW_TYPE_INPUT_METHOD_FLOAT = 2105; // Define the window type. The value 2105 indicates the input method window type, which is used to create an input method application window. 89 windowName = 'inputApp'; 90 private windowHeight: number = 0; 91 private windowWidth: number = 0; 92 private nonBarPosition: number = 0; 93 private isWindowShowing: boolean = false; 94 95 constructor(context) { 96 this.mContext = context; 97 } 98 99 public onCreate(): void 100 { 101 this.initWindow(); // Initialize the window. 102 this.registerListener(); // Register an event listener for the input method framework. 103 } 104 105 public onDestroy(): void // Destroy the instance. 106 { 107 this.unRegisterListener(); // Deregister the event listener. 108 let win = windowManager.findWindow(this.windowName); 109 win.destroyWindow(); // Destroy the window. 110 } 111 112 private initWindow(): void // Initialize the window. 113 { 114 let dis = display.getDefaultDisplaySync(); 115 let dWidth = dis.width; 116 let dHeight = dis.height; 117 let keyHeightRate = 0.47; 118 let keyHeight = dHeight * keyHeightRate; 119 this.windowWidth = dWidth; 120 this.windowHeight = keyHeight; 121 this.nonBarPosition = dHeight - keyHeight; 122 123 let config = { 124 name: this.windowName, 125 windowType: this.WINDOW_TYPE_INPUT_METHOD_FLOAT, 126 ctx: this.mContext 127 } 128 windowManager.createWindow(config).then((win) => { // Create a window of the specified type. 129 win.resize(dWidth, keyHeight).then(() => { 130 win.moveWindowTo(0, this.nonBarPosition).then(() => { 131 win.setUIContent('pages/InputMethodExtAbility/Index').then(() => { 132 }); 133 }); 134 }); 135 }); 136 } 137 138 private registerListener(): void 139 { 140 this.registerInputListener(); // Register an event listener for the input method framework service. 141 globalThis.inputAbility.on('keyboardShow', () => {// Register an event listener for the keyboard . 142 if (this.isWindowShowing) { 143 return; 144 } 145 this.isWindowShowing = true; 146 this.showHighWindow(); // Show the window. 147 }); 148 ... 149 // Register a listener for keyboard hiding. 150 } 151 152 private registerInputListener() { // Register a listener for the enabling and disabling events of the input method framework service. 153 globalThis.inputAbility.on('inputStart', (kbController, textInputClient) => { 154 globalThis.textInputClient = textInputClient; // This is an input method client instance, based on which you can call the functional APIs that the input method framework provides for the input method application. 155 globalThis.keyboardController = kbController; 156 }) 157 globalThis.inputAbility.on('inputStop', (imeId) => { 158 if (imeId == "Bundle name/Ability name") { 159 this.mContext.destroy(); // Destroy the InputMethodExtensionAbility service. 160 } 161 }); 162 } 163 164 private unRegisterListener(): void 165 { 166 globalThis.inputAbility.off('inputStart'); 167 globalThis.inputAbility.off('inputStop', () => {}); 168 globalThis.inputAbility.off('keyboardShow'); 169 } 170 171 private showHighWindow() { 172 let win = windowManager.findWindow(this.windowName) 173 win.resize(this.windowWidth, this.windowHeight).then(() => { 174 win.moveWindowTo(0, this.nonBarPosition).then(() => { 175 win.showWindow().then(() => { 176 this.isWindowShowing = false; 177 }) 178 }) 179 }) 180 } 181 } 182 ``` 183 1843. **KeyboardKeyData.ts** file: 185 186 In this file you can define the content displayed on the soft keyboard. 187 188 ```ts 189 export interface sourceListType { 190 content: string, 191 } 192 193 export let numberSourceListData: sourceListType[] = [ 194 { 195 content: '1' 196 }, 197 { 198 content: '2' 199 }, 200 { 201 content: '3' 202 }, 203 { 204 content: '4' 205 }, 206 { 207 content: '5' 208 }, 209 { 210 content: '6' 211 }, 212 { 213 content: '7' 214 }, 215 { 216 content: '8' 217 }, 218 { 219 content: '9' 220 }, 221 { 222 content: '0' 223 } 224 ] 225 ``` 226 2274. **Index.ets** file: 228 229 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. 230 231 Add the path to this file to the **src** field in the **resources/base/profile/main_pages.json** file. 232 233 ```ets 234 import { numberSourceListData, sourceListType } from './keyboardKeyData' 235 236 @Component 237 struct keyItem { 238 private keyValue: sourceListType 239 @State keyBgc: string = "#fff" 240 @State keyFontColor: string = "#000" 241 242 build() { 243 Column() { 244 Flex({ direction: FlexDirection.Column, 245 alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 246 Text(this.keyValue.content).fontSize(20).fontColor(this.keyFontColor) 247 } 248 } 249 .backgroundColor(this.keyBgc) 250 .borderRadius(6) 251 .width("8%") 252 .height("65%") 253 .onTouch((event: TouchEvent) => { 254 if (event.type === TouchType.Down) { 255 globalThis.textInputClient.insertText(this.keyValue.content); 256 } 257 }) 258 } 259 } 260 261 // Component used for deletion. 262 @Component 263 export struct deleteItem { 264 @State keyBgc: string = "#fff" 265 @State keyFontColor: string = "#000" 266 267 build() { 268 Column() { 269 Flex({ direction: FlexDirection.Column, 270 alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 271 Text("Delete").fontSize(20).fontColor(this.keyFontColor) 272 } 273 } 274 .backgroundColor(this.keyBgc) 275 .width("13%") 276 .borderRadius(6) 277 .onTouch((event: TouchEvent) => { 278 if (event.type === TouchType.Down) { 279 globalThis.textInputClient.deleteForward(1); 280 } 281 }) 282 } 283 } 284 285 // Numeric keyboard 286 @Component 287 struct numberMenu { 288 private numberList: sourceListType[] 289 290 build() { 291 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceEvenly }) { 292 Flex({ justifyContent: FlexAlign.SpaceBetween }) { 293 ForEach(this.numberList, (item: sourceListType) => { // First row on the numeric keyboard 294 keyItem({ keyValue: item }) 295 }, (item: sourceListType) => item.content); 296 } 297 .padding({ top: "2%" }) 298 .width("96%") 299 .height("25%") 300 301 Flex({ justifyContent: FlexAlign.SpaceBetween }) { 302 deleteItem() 303 } 304 .width("96%") 305 .height("25%") 306 } 307 } 308 } 309 310 @Entry 311 @Component 312 struct Index { 313 private numberList: sourceListType[] = numberSourceListData 314 315 build() { 316 Stack() { 317 Flex({ 318 direction: FlexDirection.Column, 319 alignItems: ItemAlign.Center, 320 justifyContent: FlexAlign.End 321 }) { 322 Flex({ 323 direction: FlexDirection.Column, 324 alignItems: ItemAlign.Center, 325 justifyContent: FlexAlign.SpaceBetween 326 }) { 327 numberMenu({ 328 numberList: this.numberList 329 }) 330 } 331 .align(Alignment.End) 332 .width("100%") 333 .height("75%") 334 } 335 .height("100%").align(Alignment.End).backgroundColor("#cdd0d7") 336 } 337 .position({ x: 0, y: 0 }).zIndex(99999) 338 } 339 } 340 ``` 341 3425. Register the InputMethodExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) corresponding to the **Module** project. Set **type** to **"inputMethod"** and **srcEntry** to the code path of the InputMethodExtensionAbility component. 343 344 ```ts 345 { 346 "module": { 347 ... 348 "extensionAbilities": [ 349 { 350 "description": "inputMethod", 351 "icon": "$media:icon", 352 "name": "InputMethodExtAbility", 353 "srcEntry": "./ets/inputmethodextability/InputMethodService.ts", 354 "type": "inputMethod", 355 "exported": true, 356 } 357 ] 358 } 359 } 360 ``` 361 362 363