1// @ts-nocheck 2/* 3 * Copyright (c) 2022 Huawei Device Co., Ltd. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16import { GetHardKeyValue } from './HardKeyUtils.ets' 17import inputMethodEngine from '@ohos.inputMethodEngine' 18import settings from '@ohos.settings'; 19import display from '@ohos.display' 20import windowManager from '@ohos.window' 21import featureAbility from '@ohos.ability.featureAbility' 22import { KeyCode } from '@ohos.multimodalInput.keyCode'; 23import Log from './Log' 24 25let InputMethodEngine = inputMethodEngine.getInputMethodAbility(); 26let isDebug = false; 27let TAG: string = 'KeyboardController->'; 28export class KeyboardController { 29 private readonly uri = 'dataability:///com.ohos.settingsdata.DataAbility' 30 private helper: any = null 31 private getValueRes: string = "1" 32 private nonBarPosition: number = 0 33 private barPosition: number = 0 34 private keyCodes: Array<number> = [] 35 mContext 36 WINDOW_TYPE_INPUT_METHOD_FLOAT= 2105 37 windowName = 'imeWindow'; 38 isSpecialKeyPress = false; 39 keySum = 0; 40 isKeyboardShow = false; 41 inputHandle= InputHandler.getInstance(); 42 mKeyboardDelegate; 43 constructor(context) { 44 this.inputHandle.addLog('constructor') 45 this.mContext = context; 46 this.helper = featureAbility.acquireDataAbilityHelper(this.mContext, this.uri) 47 } 48 49 public getValue(settingDataKey: string) { 50 this.getValueRes = settings.getValueSync(this.helper, settingDataKey, "1") 51 } 52 53 public onCreate(): void { 54 this.inputHandle.addLog('onCreate') 55 this.initWindow(); 56 this.registerListener() 57 } 58 59 public onDestroy(): void { 60 this.inputHandle.addLog('onDestroy') 61 this.unRegisterListener(); 62 this.mContext.terminateSelf(); 63 } 64 65 private initWindow(): void { 66 this.inputHandle.addLog('initWindow') 67 display.getDefaultDisplay().then(dis => { 68 this.inputHandle.addLog("initWindow-oncall display"); 69 var dWidth = dis.width; 70 var dHeight = dis.height; 71 var navigationbar_height = 75; 72 var keyHeightRate = 0.43; 73 AppStorage.SetOrCreate<number>('windowWidth', dis.width) 74 AppStorage.SetOrCreate<number>('windowHeight', dis.height) 75 if (dis.width > dis.height) { 76 AppStorage.SetOrCreate('isLandscape', true) 77 } else { 78 AppStorage.SetOrCreate('isLandscape', false) 79 } 80 if (dWidth == 1080 && dHeight == 2376) { 81 navigationbar_height = 105 82 keyHeightRate = 35 / 99 83 } else if(dWidth == 720 && dHeight == 1280) { 84 navigationbar_height = 72 85 AppStorage.SetOrCreate('isRkDevice', true) 86 } else if (dWidth == 2376 && dHeight == 1080) { 87 navigationbar_height = 90 88 keyHeightRate = 0.63 89 } else if (dWidth == 2560 && dHeight == 1600) { 90 navigationbar_height = 88 91 keyHeightRate = 0.5 92 } else if (dWidth == 1600 && dHeight == 2560) { 93 navigationbar_height = 88 94 keyHeightRate = 0.34 95 } 96 var keyHeight = dHeight * keyHeightRate; 97 this.barPosition = dHeight - keyHeight - navigationbar_height 98 this.nonBarPosition = dHeight - keyHeight 99 this.inputHandle.addLog("initWindow-dWidth = " + dWidth + ";dHeight = " + dHeight + ";keyboard height = " + keyHeight + ";navibar height = " + navigationbar_height); 100 101 this.inputHandle.addLog(typeof (this.mContext)) 102 this.inputHandle.addLog('initWindow-window = ' + typeof (windowManager)) 103 windowManager.create(this.mContext, this.windowName, this.WINDOW_TYPE_INPUT_METHOD_FLOAT).then((win) => { 104 win.resetSize(dWidth, keyHeight).then(() => { 105 win.moveTo(0, this.barPosition).then(() => { 106 win.loadContent('pages/index').then(() => { 107 this.inputHandle.addLog('loadContent finished') 108 }) 109 }) 110 }) 111 }) 112 }); 113 } 114 115 private resizeWindow() { 116 this.inputHandle.addLog('resizeWindow'); 117 118 display.getDefaultDisplay().then(dis => { 119 this.inputHandle.addLog("resizeWindow-oncall display"); 120 121 var dWidth = dis.width; 122 var dHeight = dis.height; 123 var navigationbar_height = dHeight * 0.07; //todo:有些产品导航栏高度为0,默认为0.07 124 var keyHeightRate = 0.47; 125 AppStorage.SetOrCreate<number>('windowWidth', dis.width) 126 AppStorage.SetOrCreate<number>('windowHeight', dis.height) 127 if (dis.width > dis.height) { 128 AppStorage.Set('isLandscape', true) 129 } else { 130 AppStorage.Set('isLandscape', false) 131 } 132 if (dWidth == 1080 && dHeight == 2376) { 133 navigationbar_height = 105 134 keyHeightRate = 35 / 99 135 } else if(dWidth == 720 && dHeight == 1280) { 136 navigationbar_height = 72 137 } else if (dWidth == 2376 && dHeight == 1080) { 138 navigationbar_height = 90 139 keyHeightRate = 0.63 140 } else if (dWidth == 2560 && dHeight == 1600) { 141 navigationbar_height = 88 142 keyHeightRate = 0.5 143 } else if (dWidth == 1600 && dHeight == 2560) { 144 navigationbar_height = 88 145 keyHeightRate = 0.34 146 } 147 var keyHeight = dHeight * keyHeightRate; 148 this.inputHandle.addLog("resizeWindow-dWidth = " + dWidth + ";dHeight = " + dHeight + ";keyboard height = " + keyHeight + ";navibar height = " + navigationbar_height); 149 150 windowManager.find(this.windowName).then((win) => { 151 win.resetSize(dWidth, keyHeight).then(() => { 152 win.moveTo(0, dHeight - keyHeight - navigationbar_height).then(() => { 153 this.inputHandle.addLog('resizeWindow-moveTo success'); 154 }) 155 156 }) 157 }) 158 }); 159 } 160 161 private registerListener(): void { 162 this.inputHandle.addLog('registerListener') 163 164 display.on('change', (screenEvent) => { 165 this.inputHandle.addLog('screenChangeEvent'); 166 this.resizeWindow() 167 }); 168 InputMethodEngine.on('inputStart', (kbController, textInputClient) => { 169 this.inputHandle.addLog('keyboard inputStart'); 170 this.inputHandle.onInputStart(kbController, textInputClient); 171 }) 172 InputMethodEngine.on('inputStop', () => { 173 this.inputHandle.addLog('keyboard inputStop'); 174 this.onDestroy(); 175 }); 176 InputMethodEngine.on('keyboardShow', () => { 177 this.inputHandle.addLog('keyboard show'); 178 this.showWindow() 179 }); 180 181 InputMethodEngine.on('keyboardHide', () => { 182 this.inputHandle.addLog('keyboard hide'); 183 this.hideWindow(); 184 }); 185 186 this.mKeyboardDelegate = inputMethodEngine.getKeyboardDelegate(); 187 188 this.mKeyboardDelegate.on('keyDown', (keyEvent) => { 189 if (this.isKeyboardShow) { 190 this.inputHandle.hideKeyboardSelf(); 191 } 192 this.inputHandle.addLog('keyDown: code = ' + keyEvent.keyCode); 193 let result = this.onKeyDown(keyEvent); 194 this.inputHandle.addLog('keyDown: result = ' + result); 195 return result 196 }); 197 198 this.mKeyboardDelegate.on('keyUp', (keyEvent) => { 199 this.inputHandle.addLog('keyUp: code = ' + keyEvent.keyCode); 200 let result = this.onKeyUp(keyEvent); 201 this.inputHandle.addLog('keyUp: result = ' + result); 202 return result 203 }); 204 205 if (isDebug) { 206 this.mKeyboardDelegate.on('cursorContextChange', (x, y, height) => { 207 this.inputHandle.setCursorInfo('cursorInfo:(' + x + ',' + y + '), h = ' + height); 208 }); 209 210 this.mKeyboardDelegate.on('selectionChange', (oldBegin, oldEnd, newBegin, newEnd) => { 211 this.inputHandle.setSelectInfo('selectInfo: from(' + oldBegin + ',' + oldEnd + ') to (' + newBegin + ',' + newEnd + ')'); 212 }); 213 214 this.mKeyboardDelegate.on('textChange', (text) => { 215 this.inputHandle.setTextInfo('textInfo: ' + text); 216 }); 217 } 218 } 219 220 public isShiftKeyHold(): boolean { 221 if (this.keyCodes.length === 0) { 222 return false 223 } 224 let preDownKey = this.keyCodes[0] 225 return preDownKey === KeyCode.KEYCODE_SHIFT_LEFT || preDownKey === KeyCode.KEYCODE_SHIFT_RIGHT 226 } 227 228 public onKeyDown(keyEvent): boolean { 229 this.inputHandle.addLog('onKeyDown: code = ' + keyEvent.keyCode); 230 var keyCode = keyEvent.keyCode 231 let idx = this.keyCodes.indexOf(keyCode) 232 if (idx == -1) { 233 this.keyCodes.push(keyCode) 234 } else { 235 this.inputHandle.addLog("keyCode down is intercepted: " + keyCode); 236 } 237 this.inputHandle.addLog('onKeyDown: this.keyCodes = ' + JSON.stringify(this.keyCodes)); 238 if (this.isShiftKeyHold() && this.keyCodes.length == 2 && !this.isKeyCodeAZ(keyCode)) { 239 this.isSpecialKeyPress = true; 240 return false 241 } 242 if (this.isSpecialKeyPress || keyCode === KeyCode.KEYCODE_ALT_LEFT || keyCode === KeyCode.KEYCODE_ALT_RIGHT) { 243 return false 244 } 245 var keyValue = GetHardKeyValue(keyCode, this.isShiftKeyHold()); 246 if (!keyValue) { 247 this.inputHandle.addLog('onKeyDown: unknown keyCode' ); 248 this.isSpecialKeyPress = true; 249 return false; 250 } 251 try { 252 return this.inputHardKeyCode(keyValue, keyCode) 253 } catch (ex) { 254 //方向键api需要优化 255 this.inputHandle.addLog("inputHardKeyCode error: " + ex); 256 return false 257 } 258 } 259 260 public onKeyUp(keyEvent): boolean { 261 this.inputHandle.addLog('OnKeyUp: code = ' + keyEvent.keyCode); 262 var keyCode = keyEvent.keyCode; 263 let idx = this.keyCodes.indexOf(keyCode) 264 if (idx != -1) { 265 this.keyCodes.splice(idx, 1) 266 } else { 267 this.inputHandle.addLog("keyCode KeyUp is intercepted: " + keyCode); 268 } 269 this.inputHandle.addLog('OnKeyUp: this.keyCodes = ' + JSON.stringify(this.keyCodes)); 270 271 // For KEYCODE_DEL/KEYCODE_FORWARD_DEL, processed in OnKeyDown, so just intercept it 272 if (keyCode == 2055 || keyCode == 2071 || (keyCode >= 2012 && keyCode <= 2016)) { 273 this.inputHandle.addLog('special code: ' + keyCode); 274 return true 275 } 276 277 if (this.isSpecialKeyPress) { 278 var keyValue = GetHardKeyValue(keyCode, this.isShiftKeyHold()) 279 if (!keyValue) { 280 this.isSpecialKeyPress = true; 281 } 282 if (this.keyCodes.length == 0) { 283 this.isSpecialKeyPress = false; 284 } 285 this.inputHandle.addLog('OnKeyUp: this.isSpecialKeyPress: ' + this.isSpecialKeyPress); 286 return false 287 } 288 return true; 289 } 290 291 public isKeyCodeAZ(keyCode: number) { 292 return keyCode >= KeyCode.KEYCODE_A && keyCode <= KeyCode.KEYCODE_Z 293 } 294 295 public isKeyCodeNumber(keyCode: number) { 296 return (keyCode >= KeyCode.KEYCODE_0 && keyCode <= KeyCode.KEYCODE_9) || (keyCode >= KeyCode.KEYCODE_NUMPAD_0 && keyCode <= KeyCode.KEYCODE_NUMPAD_9) 297 } 298 299 public inputHardKeyCode(keyValue: string, keyCode: number): boolean { 300 this.inputHandle.addLog("keyValue is: " + keyValue); 301 if (this.processFunctionKeys(keyValue)) { 302 return true 303 } 304 if (this.shiftKeys(keyValue)) { 305 return false 306 } 307 this.inputHandle.insertText(keyValue); 308 return true 309 } 310 311 public shiftKeys(keyValue: string): boolean { 312 this.inputHandle.addLog("processFunctionKeys keyValue is: " + keyValue); 313 switch (keyValue) { 314 case 'KEYCODE_SHIFT_LEFT': 315 case 'KEYCODE_SHIFT_RIGHT': 316 return true 317 default: 318 return false 319 } 320 } 321 322 public processFunctionKeys(keyValue: string): boolean { 323 this.inputHandle.addLog("processFunctionKeys keyValue is: " + keyValue); 324 switch (keyValue) { 325 case "KEYCODE_DEL": 326 this.inputHandle.deleteBackward(1); 327 return true 328 case "KEYCODE_FORWARD_DEL": 329 this.inputHandle.deleteForward(1); 330 return true 331 case "KEYCODE_DPAD_UP": 332 inputMethodEngine.MoveCursor(inputMethodEngine.CURSOR_UP); 333 return true 334 case "KEYCODE_DPAD_DOWN": 335 inputMethodEngine.MoveCursor(inputMethodEngine.CURSOR_DOWN); 336 return true 337 case "KEYCODE_DPAD_LEFT": 338 inputMethodEngine.MoveCursor(inputMethodEngine.CURSOR_LEFT); 339 return true 340 case "KEYCODE_DPAD_RIGHT": 341 inputMethodEngine.MoveCursor(inputMethodEngine.CURSOR_RIGHT); 342 return true 343 default: 344 return false 345 } 346 } 347 348 private unRegisterListener(): void{ 349 this.inputHandle.addLog('unRegisterListener') 350 351 InputMethodEngine.off('inputStop', ()=> { 352 this.inputHandle.addLog('inputStop off'); 353 }); 354 355 InputMethodEngine.off('keyboardShow'); 356 357 InputMethodEngine.off('keyboardHide'); 358 359 this.mKeyboardDelegate.off('keyDown'); 360 361 this.mKeyboardDelegate.off('keyUp'); 362 363 if (isDebug) { 364 this.mKeyboardDelegate.off('cursorContextChange'); 365 366 this.mKeyboardDelegate.off('selectionChange'); 367 368 this.mKeyboardDelegate.off('textChange'); 369 } 370 } 371 372 private showWindow() { 373 try { 374 this.getValue('settings.display.navigationbar_status') 375 } catch (err) { 376 Log.showError(TAG, "get value failed" + err) 377 } 378 Log.showInfo(TAG, 'current navigation state is' + this.getValueRes) 379 this.inputHandle.addLog('showWindow'); 380 windowManager.find(this.windowName).then((win) => { 381 win.show().then(() => { 382 this.inputHandle.addLog('showWindow finish'); 383 this.isKeyboardShow = true; 384 }) 385 }) 386 } 387 388 private hideWindow() { 389 this.inputHandle.addLog('hideWindow'); 390 windowManager.find(this.windowName).then((win) => { 391 win.hide().then(() => { 392 this.isKeyboardShow = false; 393 this.inputHandle.addLog('hideWindow finish'); 394 }) 395 }) 396 } 397} 398 399export class InputHandler { 400 private static instance: InputHandler; 401 private mKbController; 402 private mTextInputClient; 403 private mEditorAttribute; 404 private cursorInfo; 405 private selectInfo; 406 private textInfo; 407 private inputInfo; 408 private constructor() { 409 410 } 411 412 public static getInstance() { 413 if (globalThis.instance == null) { 414 globalThis.instance = new InputHandler(); 415 } 416 return globalThis.instance; 417 } 418 419 public onInputStart(kbController, textInputClient) { 420 globalThis.mKbController = kbController; 421 globalThis.mTextInputClient = textInputClient; 422 globalThis.mEditorAttribute = globalThis.mTextInputClient.getEditorAttribute(); 423 this.addLog("onInputStart mEditorAttribute = " + globalThis.mEditorAttribute); 424 globalThis.mEditorAttribute.then(res => { 425 globalThis.enterKeyType = res.enterKeyType; 426 globalThis.inputPattern = res.inputPattern; 427 this.setInputInfo("EditorInfo:enterKeyType = " + globalThis.enterKeyType + ";inputPattern = " + globalThis.inputPattern); 428 }) 429 } 430 431 public hideKeyboardSelf() { 432 this.addLog('hideKeyboardSelf') 433 if (globalThis.mKbController != undefined) { 434 globalThis.mKbController.hideKeyboard(); 435 } else { 436 this.addLog('hideKeyboardSelf globalThis.mKbController is undefined') 437 } 438 } 439 440 public sendKeyFunction() { 441 this.addLog('sendKeyFunction') 442 if (globalThis.mTextInputClient != undefined) { 443 globalThis.mTextInputClient.sendKeyFunction(globalThis.enterKeyType); 444 } else { 445 this.addLog('sendKeyFunction globalThis.mTextInputClient is undefined') 446 } 447 } 448 449 public deleteBackward(length: number) { 450 this.addLog('deleteBackward') 451 if (globalThis.mTextInputClient != undefined) { 452 globalThis.mTextInputClient.deleteBackward(length); 453 } else { 454 this.addLog('deleteBackward globalThis.mTextInputClient is undefined') 455 } 456 if (isDebug) { 457 this.refreshInfo(); 458 } 459 } 460 461 public deleteForward(length: number) { 462 this.addLog('deleteForward') 463 if (globalThis.mTextInputClient != undefined) { 464 globalThis.mTextInputClient.deleteForward(length); 465 } else { 466 this.addLog('deleteForward globalThis.mTextInputClient is undefined') 467 } 468 if (isDebug) { 469 this.refreshInfo(); 470 } 471 } 472 473 public insertText(text: string) { 474 this.addLog('insertText') 475 if (globalThis.mTextInputClient != undefined) { 476 globalThis.mTextInputClient.insertText(text); 477 } else { 478 this.addLog('insertText globalThis.mTextInputClient is undefined') 479 } 480 if (isDebug) { 481 this.refreshInfo(); 482 } 483 } 484 485 public addLog(message): void { 486 Log.showInfo(TAG, "kikaInput-js: " + message) 487 } 488 489 public setCursorInfo(info) { 490 globalThis.cursorInfo = info; 491 this.addLog("setCursorInfo info = " + info); 492 } 493 494 public setSelectInfo(info) { 495 globalThis.selectInfo = info; 496 this.addLog("setSelectInfo info = " + info); 497 } 498 499 public setTextInfo(info) { 500 globalThis.textInfo = info; 501 this.addLog("setTextInfo info = " + info); 502 } 503 504 public setInputInfo(info) { 505 globalThis.inputInfo = info; 506 this.addLog("setInputInfo info = " + info); 507 } 508 509 public refreshInfo() { 510 this.addLog('refreshInfo'); 511 var showText = ''; 512 this.addLog('refreshInfo1'); 513 showText += 'five chars: before:[' + globalThis.mTextInputClient.getForward(5) + '];after:[' + globalThis.mTextInputClient.getBackward(5) + ']\n'; 514 this.addLog('refreshInfo2'); 515 showText += globalThis.cursorInfo + "\n"; 516 this.addLog('refreshInfo3'); 517 showText += globalThis.selectInfo + "\n"; 518 this.addLog('refreshInfo4'); 519 showText += globalThis.textInfo + "\n"; 520 this.addLog('refreshInfo5'); 521 showText += globalThis.inputInfo; 522 this.addLog('refreshInfo6'); 523 AppStorage.Set<string>('showLog', showText); 524 this.addLog('refreshInfo7'); 525 this.addLog('result is = ' + showText); 526 } 527} 528