1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import commonEventManager from '@ohos.commonEventManager'; 17import display from '@ohos.display'; 18import inputMethodEngine from '@ohos.inputMethodEngine'; 19import InputMethodExtensionContext from '@ohos.InputMethodExtensionContext'; 20 21// Call the getInputMethodAbility method of the input method framework to get the instance 22const inputMethodAbility: inputMethodEngine.InputMethodAbility = inputMethodEngine.getInputMethodAbility(); 23const DEFAULT_DIRECTION: number = 1; 24const DEFAULT_LENGTH: number = 1; 25const DEFAULT_SELECT_RANGE: number = 10; 26 27enum TEST_RESULT_CODE { 28 SUCCESS, 29 FAILED 30} 31 32enum TEST_FUNCTION { 33 INSERT_TEXT_SYNC, 34 MOVE_CURSOR_SYNC, 35 GET_ATTRIBUTE_SYNC, 36 SELECT_BY_RANGE_SYNC, 37 SELECT_BY_MOVEMENT_SYNC, 38 GET_INDEX_AT_CURSOR_SYNC, 39 DELETE_FORWARD_SYNC, 40 DELETE_BACKWARD_SYNC, 41 GET_FORWARD_SYNC, 42 GET_BACKWARD_SYNC, 43 CHANGE_FLAG_TO_FIXED, 44 CHANGE_FLAG_TO_FLOATING, 45 SETPRIVACYMODE_WITHOUT_PERMISSION, 46 SETPRIVACYMODE_ERROR_PARAM, 47} 48 49export class KeyboardController { 50 private TAG: string = 'inputDemo: KeyboardController '; 51 private mContext: InputMethodExtensionContext | undefined = undefined; // save the context property of InputMethodExtensionAbility 52 private panel: inputMethodEngine.Panel | undefined = undefined; 53 private subscriber = undefined; 54 55 constructor() { 56 } 57 58 public onCreate(context: InputMethodExtensionContext): void { 59 this.mContext = context; 60 this.initWindow(); // init window 61 this.registerListener(); //register input listener 62 } 63 64 public onDestroy(): void { 65 this.unRegisterListener(); 66 if (this.panel) { 67 this.panel.hide(); 68 inputMethodAbility.destroyPanel(this.panel); 69 } 70 this.mContext.destroy(); 71 } 72 73 private initWindow(): void { 74 if (this.mContext === undefined) { 75 return; 76 } 77 let dis = display.getDefaultDisplaySync(); 78 let dWidth = dis.width; 79 let dHeight = dis.height; 80 let keyHeightRate = 0.47; 81 let keyHeight = dHeight * keyHeightRate; 82 let nonBarPosition = dHeight - keyHeight; 83 let panelInfo: inputMethodEngine.PanelInfo = { 84 type: inputMethodEngine.PanelType.SOFT_KEYBOARD, 85 flag: inputMethodEngine.PanelFlag.FLG_FIXED 86 }; 87 inputMethodAbility.createPanel(this.mContext, panelInfo).then(async (inputPanel: inputMethodEngine.Panel) => { 88 this.panel = inputPanel; 89 if (this.panel) { 90 await this.panel.resize(dWidth, keyHeight); 91 await this.panel.moveTo(0, nonBarPosition); 92 await this.panel.setUiContent('pages/Index'); 93 } 94 }); 95 } 96 97 publishCommonEvent(event: string, codeNumber: number): void { 98 this.addLog(`[inputDemo] publish event, event= ${event}, codeNumber= ${codeNumber}`); 99 commonEventManager.publish(event, { code: codeNumber }, (err) => { 100 if (err) { 101 this.addLog(`inputDemo publish ${event} failed, err = ${JSON.stringify(err)}`); 102 } else { 103 this.addLog(`inputDemo publish ${event} success`); 104 } 105 }) 106 } 107 108 private registerListener(): void { 109 this.registerInputListener(); 110 let subscribeInfo = { 111 events: ['syncTestFunction'] 112 } 113 commonEventManager.createSubscriber(subscribeInfo).then((data) => { 114 this.subscriber = data; 115 commonEventManager.subscribe(this.subscriber, (err, eventData) => { 116 this.addLog(`[inputDemo] subscribe, eventData.code = ${eventData.code}`); 117 if (globalThis.textInputClient === undefined) { 118 return; 119 } 120 switch (eventData.code) { 121 case TEST_FUNCTION.INSERT_TEXT_SYNC: 122 globalThis.textInputClient.insertTextSync("text"); 123 break; 124 case TEST_FUNCTION.MOVE_CURSOR_SYNC: 125 globalThis.textInputClient.moveCursorSync(DEFAULT_DIRECTION); 126 break; 127 case TEST_FUNCTION.GET_ATTRIBUTE_SYNC: 128 this.getAttributeSync(); 129 break; 130 case TEST_FUNCTION.SELECT_BY_RANGE_SYNC: 131 globalThis.textInputClient.selectByRangeSync({ start: 0, end: DEFAULT_SELECT_RANGE }); 132 break; 133 case TEST_FUNCTION.SELECT_BY_MOVEMENT_SYNC: 134 globalThis.textInputClient.selectByMovementSync({ direction: inputMethodEngine.CURSOR_LEFT }); 135 break; 136 case TEST_FUNCTION.GET_INDEX_AT_CURSOR_SYNC: 137 this.getIndexAtCursorSync() 138 break; 139 case TEST_FUNCTION.DELETE_FORWARD_SYNC: 140 globalThis.textInputClient.deleteForwardSync(DEFAULT_LENGTH); 141 break; 142 case TEST_FUNCTION.DELETE_BACKWARD_SYNC: 143 globalThis.textInputClient.deleteBackwardSync(DEFAULT_LENGTH); 144 break; 145 case TEST_FUNCTION.GET_FORWARD_SYNC: 146 this.getForwardSync(); 147 break; 148 case TEST_FUNCTION.GET_BACKWARD_SYNC: 149 this.getBackwardSync(); 150 break; 151 case TEST_FUNCTION.CHANGE_FLAG_TO_FIXED: 152 this.changePanelFlag(inputMethodEngine.PanelFlag.FLG_FIXED); 153 break; 154 case TEST_FUNCTION.CHANGE_FLAG_TO_FLOATING: 155 this.changePanelFlag(inputMethodEngine.PanelFlag.FLG_FLOATING); 156 break; 157 case TEST_FUNCTION.SETPRIVACYMODE_WITHOUT_PERMISSION: 158 this.setPrivacyModeWithoutPermission(); 159 break; 160 case TEST_FUNCTION.SETPRIVACYMODE_ERROR_PARAM: 161 this.setPrivacyModeErrorParam(); 162 break; 163 default: 164 break; 165 } 166 }) 167 }) 168 } 169 170 private registerInputListener(): void { // 注册对输入法框架服务的开启及停止事件监听 171 inputMethodAbility.on('inputStart', (kbController, textInputClient) => { 172 globalThis.textInputClient = textInputClient; // 此为输入法客户端实例,由此调用输入法框架提供给输入法应用的功能接口 173 globalThis.keyboardController = kbController; 174 }) 175 inputMethodAbility.on('inputStop', () => { 176 this.onDestroy(); 177 }); 178 } 179 180 private unRegisterListener(): void { 181 inputMethodAbility.off('inputStart'); 182 inputMethodAbility.off('inputStop', () => { 183 }); 184 } 185 186 getBackwardSync() { 187 let backward: string = globalThis.textInputClient.getBackwardSync(1); 188 if (backward.length >= 0) { 189 this.publishCommonEvent('getBackwardSyncResult', TEST_RESULT_CODE.SUCCESS); 190 } else { 191 this.publishCommonEvent('getBackwardSyncResult', TEST_RESULT_CODE.FAILED); 192 } 193 } 194 195 getForwardSync() { 196 let forward: string = globalThis.textInputClient.getForwardSync(1); 197 if (forward.length >= 0) { 198 this.publishCommonEvent('getForwardSyncResult', TEST_RESULT_CODE.SUCCESS); 199 } else { 200 this.publishCommonEvent('getForwardSyncResult', TEST_RESULT_CODE.FAILED); 201 } 202 } 203 204 async getAttributeSync() { 205 try { 206 let editAttribute = globalThis.textInputClient.getEditorAttributeSync(); 207 let editAttribute1 = await globalThis.textInputClient.getEditorAttribute(); 208 this.addLog(`[inputDemo] publish getEditorAttributeSync editAttribute= ${JSON.stringify(editAttribute)}`); 209 if(editAttribute.inputPattern == editAttribute1.inputPattern && editAttribute.enterKeyType == editAttribute1.enterKeyType) { 210 this.publishCommonEvent('getEditorAttributeSyncResult', TEST_RESULT_CODE.SUCCESS); 211 } else{ 212 this.publishCommonEvent('getEditorAttributeSyncResult', TEST_RESULT_CODE.FAILED); 213 } 214 } catch (err) { 215 this.publishCommonEvent('getEditorAttributeSyncResult', TEST_RESULT_CODE.FAILED); 216 } 217 } 218 219 getIndexAtCursorSync() { 220 try { 221 let index = globalThis.textInputClient.getTextIndexAtCursorSync(); 222 this.addLog(`[inputDemo] publish getTextIndexAtCursorSync index= ${index}`); 223 this.publishCommonEvent('getTextIndexAtCursorSyncResult', TEST_RESULT_CODE.SUCCESS); 224 } catch (err) { 225 this.publishCommonEvent('getTextIndexAtCursorSyncResult', TEST_RESULT_CODE.FAILED); 226 } 227 } 228 229 changePanelFlag(panelFlag: inputMethodEngine.PanelFlag) { 230 try { 231 this.panel.hide((err) => { 232 if (err) { 233 this.addLog(`Failed to hide panel: ${JSON.stringify(err)}`); 234 this.publishCommonEvent('changeFlag', TEST_RESULT_CODE.FAILED); 235 return; 236 } 237 this.panel.changeFlag(panelFlag); 238 this.panel.show((err) => { 239 this.addLog(`Failed to show panel: ${JSON.stringify(err)}`); 240 this.publishCommonEvent('changeFlag', TEST_RESULT_CODE.SUCCESS); 241 }); 242 }); 243 } catch (err) { 244 this.addLog(`failed: ${JSON.stringify(err)}`); 245 this.publishCommonEvent('changeFlag', TEST_RESULT_CODE.FAILED); 246 } 247 } 248 249 setPrivacyModeWithoutPermission() { 250 try { 251 let isSetPrivacyMode: boolean = true; 252 this.panel.setPrivacyMode(isSetPrivacyMode); 253 this.publishCommonEvent('setPrivacyModeWithoutPermissionResult', TEST_RESULT_CODE.FAILED); 254 } catch (err) { 255 this.addLog(`failed: ${JSON.stringify(err)}`); 256 if (err.code === 201) { 257 this.publishCommonEvent('setPrivacyModeWithoutPermissionResult', TEST_RESULT_CODE.SUCCESS); 258 return; 259 } 260 } 261 } 262 263 setPrivacyModeErrorParam() { 264 try { 265 this.panel.setPrivacyMode(undefined); 266 this.publishCommonEvent('setPrivacyModeErrorParamResult', TEST_RESULT_CODE.FAILED); 267 } catch (err) { 268 this.addLog(`failed: ${JSON.stringify(err)}`); 269 if (err.code === 401) { 270 this.publishCommonEvent('setPrivacyModeErrorParamResult', TEST_RESULT_CODE.SUCCESS); 271 return; 272 } 273 } 274 } 275 276 private addLog(message): void { 277 console.log(this.TAG + message) 278 } 279} 280 281const keyboardController = new KeyboardController(); 282 283export default keyboardController;