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