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.destroyWindow(); 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 destroyWindow(): void { 116 this.inputHandle.addLog('destroyWindow'); 117 try { 118 let win = windowManager.findWindow(this.windowName); 119 win.destroyWindow((err) => { 120 if (err) { 121 this.inputHandle.addLog('Failed to destroy the window. Cause:' + JSON.stringify(err)); 122 return; 123 } 124 }); 125 } catch (exception) { 126 this.inputHandle.addLog('Failed to find the Window. Cause: ' + JSON.stringify(exception)); 127 } 128 } 129 130 private resizeWindow() { 131 this.inputHandle.addLog('resizeWindow'); 132 133 display.getDefaultDisplay().then(dis => { 134 this.inputHandle.addLog("resizeWindow-oncall display"); 135 136 var dWidth = dis.width; 137 var dHeight = dis.height; 138 var navigationbar_height = dHeight * 0.07; //todo:有些产品导航栏高度为0,默认为0.07 139 var keyHeightRate = 0.47; 140 AppStorage.SetOrCreate<number>('windowWidth', dis.width) 141 AppStorage.SetOrCreate<number>('windowHeight', dis.height) 142 if (dis.width > dis.height) { 143 AppStorage.Set('isLandscape', true) 144 } else { 145 AppStorage.Set('isLandscape', false) 146 } 147 if (dWidth == 1080 && dHeight == 2376) { 148 navigationbar_height = 105 149 keyHeightRate = 35 / 99 150 } else if(dWidth == 720 && dHeight == 1280) { 151 navigationbar_height = 72 152 } else if (dWidth == 2376 && dHeight == 1080) { 153 navigationbar_height = 90 154 keyHeightRate = 0.63 155 } else if (dWidth == 2560 && dHeight == 1600) { 156 navigationbar_height = 88 157 keyHeightRate = 0.5 158 } else if (dWidth == 1600 && dHeight == 2560) { 159 navigationbar_height = 88 160 keyHeightRate = 0.34 161 } 162 var keyHeight = dHeight * keyHeightRate; 163 this.inputHandle.addLog("resizeWindow-dWidth = " + dWidth + ";dHeight = " + dHeight + ";keyboard height = " + keyHeight + ";navibar height = " + navigationbar_height); 164 165 windowManager.find(this.windowName).then((win) => { 166 win.resetSize(dWidth, keyHeight).then(() => { 167 win.moveTo(0, dHeight - keyHeight - navigationbar_height).then(() => { 168 this.inputHandle.addLog('resizeWindow-moveTo success'); 169 }) 170 171 }) 172 }) 173 }); 174 } 175 176 private registerListener(): void { 177 this.inputHandle.addLog('registerListener') 178 179 display.on('change', (screenEvent) => { 180 this.inputHandle.addLog('screenChangeEvent'); 181 this.resizeWindow() 182 }); 183 InputMethodEngine.on('inputStart', (kbController, textInputClient) => { 184 this.inputHandle.addLog('keyboard inputStart'); 185 this.inputHandle.onInputStart(kbController, textInputClient); 186 }) 187 InputMethodEngine.on('inputStop', () => { 188 this.inputHandle.addLog('keyboard inputStop'); 189 this.mContext.destroy(); 190 }); 191 InputMethodEngine.on('keyboardShow', () => { 192 this.inputHandle.addLog('keyboard show'); 193 this.showWindow() 194 }); 195 196 InputMethodEngine.on('keyboardHide', () => { 197 this.inputHandle.addLog('keyboard hide'); 198 this.hideWindow(); 199 }); 200 201 this.mKeyboardDelegate = inputMethodEngine.getKeyboardDelegate(); 202 203 this.mKeyboardDelegate.on('keyDown', (keyEvent) => { 204 if (this.isKeyboardShow) { 205 this.inputHandle.hideKeyboardSelf(); 206 } 207 this.inputHandle.addLog('keyDown: code = ' + keyEvent.keyCode); 208 let result = this.onKeyDown(keyEvent); 209 this.inputHandle.addLog('keyDown: result = ' + result); 210 return result 211 }); 212 213 this.mKeyboardDelegate.on('keyUp', (keyEvent) => { 214 this.inputHandle.addLog('keyUp: code = ' + keyEvent.keyCode); 215 let result = this.onKeyUp(keyEvent); 216 this.inputHandle.addLog('keyUp: result = ' + result); 217 return result 218 }); 219 220 if (isDebug) { 221 this.mKeyboardDelegate.on('cursorContextChange', (x, y, height) => { 222 this.inputHandle.setCursorInfo('cursorInfo:(' + x + ',' + y + '), h = ' + height); 223 }); 224 225 this.mKeyboardDelegate.on('selectionChange', (oldBegin, oldEnd, newBegin, newEnd) => { 226 this.inputHandle.setSelectInfo('selectInfo: from(' + oldBegin + ',' + oldEnd + ') to (' + newBegin + ',' + newEnd + ')'); 227 }); 228 229 this.mKeyboardDelegate.on('textChange', (text) => { 230 this.inputHandle.setTextInfo('textInfo: ' + text); 231 }); 232 } 233 } 234 235 public isShiftKeyHold(): boolean { 236 if (this.keyCodes.length === 0) { 237 return false 238 } 239 let preDownKey = this.keyCodes[0] 240 return preDownKey === KeyCode.KEYCODE_SHIFT_LEFT || preDownKey === KeyCode.KEYCODE_SHIFT_RIGHT 241 } 242 243 public onKeyDown(keyEvent): boolean { 244 this.inputHandle.addLog('onKeyDown: code = ' + keyEvent.keyCode); 245 var keyCode = keyEvent.keyCode 246 let idx = this.keyCodes.indexOf(keyCode) 247 if (idx == -1) { 248 this.keyCodes.push(keyCode) 249 } else { 250 this.inputHandle.addLog("keyCode down is intercepted: " + keyCode); 251 } 252 this.inputHandle.addLog('onKeyDown: this.keyCodes = ' + JSON.stringify(this.keyCodes)); 253 if (this.isShiftKeyHold() && this.keyCodes.length == 2 && !this.isKeyCodeAZ(keyCode)) { 254 this.isSpecialKeyPress = true; 255 return false 256 } 257 if (this.isSpecialKeyPress || keyCode === KeyCode.KEYCODE_ALT_LEFT || keyCode === KeyCode.KEYCODE_ALT_RIGHT) { 258 return false 259 } 260 var keyValue = GetHardKeyValue(keyCode, this.isShiftKeyHold()); 261 if (!keyValue) { 262 this.inputHandle.addLog('onKeyDown: unknown keyCode' ); 263 this.isSpecialKeyPress = true; 264 return false; 265 } 266 try { 267 return this.inputHardKeyCode(keyValue, keyCode) 268 } catch (ex) { 269 //方向键api需要优化 270 this.inputHandle.addLog("inputHardKeyCode error: " + ex); 271 return false 272 } 273 } 274 275 public onKeyUp(keyEvent): boolean { 276 this.inputHandle.addLog('OnKeyUp: code = ' + keyEvent.keyCode); 277 var keyCode = keyEvent.keyCode; 278 let idx = this.keyCodes.indexOf(keyCode) 279 if (idx != -1) { 280 this.keyCodes.splice(idx, 1) 281 } else { 282 this.inputHandle.addLog("keyCode KeyUp is intercepted: " + keyCode); 283 } 284 this.inputHandle.addLog('OnKeyUp: this.keyCodes = ' + JSON.stringify(this.keyCodes)); 285 286 // For KEYCODE_DEL/KEYCODE_FORWARD_DEL, processed in OnKeyDown, so just intercept it 287 if (keyCode == 2055 || keyCode == 2071 || (keyCode >= 2012 && keyCode <= 2016)) { 288 this.inputHandle.addLog('special code: ' + keyCode); 289 return true 290 } 291 292 if (this.isSpecialKeyPress) { 293 var keyValue = GetHardKeyValue(keyCode, this.isShiftKeyHold()) 294 if (!keyValue) { 295 this.isSpecialKeyPress = true; 296 } 297 if (this.keyCodes.length == 0) { 298 this.isSpecialKeyPress = false; 299 } 300 this.inputHandle.addLog('OnKeyUp: this.isSpecialKeyPress: ' + this.isSpecialKeyPress); 301 return false 302 } 303 return true; 304 } 305 306 public isKeyCodeAZ(keyCode: number) { 307 return keyCode >= KeyCode.KEYCODE_A && keyCode <= KeyCode.KEYCODE_Z 308 } 309 310 public isKeyCodeNumber(keyCode: number) { 311 return (keyCode >= KeyCode.KEYCODE_0 && keyCode <= KeyCode.KEYCODE_9) || (keyCode >= KeyCode.KEYCODE_NUMPAD_0 && keyCode <= KeyCode.KEYCODE_NUMPAD_9) 312 } 313 314 public inputHardKeyCode(keyValue: string, keyCode: number): boolean { 315 this.inputHandle.addLog("keyValue is: " + keyValue); 316 if (this.processFunctionKeys(keyValue)) { 317 return true 318 } 319 if (this.shiftKeys(keyValue)) { 320 return false 321 } 322 this.inputHandle.insertText(keyValue); 323 return true 324 } 325 326 public shiftKeys(keyValue: string): boolean { 327 this.inputHandle.addLog("processFunctionKeys keyValue is: " + keyValue); 328 switch (keyValue) { 329 case 'KEYCODE_SHIFT_LEFT': 330 case 'KEYCODE_SHIFT_RIGHT': 331 return true 332 default: 333 return false 334 } 335 } 336 337 public processFunctionKeys(keyValue: string): boolean { 338 this.inputHandle.addLog("processFunctionKeys keyValue is: " + keyValue); 339 switch (keyValue) { 340 case "KEYCODE_DEL": 341 this.inputHandle.deleteBackward(1); 342 return true 343 case "KEYCODE_FORWARD_DEL": 344 this.inputHandle.deleteForward(1); 345 return true 346 case "KEYCODE_DPAD_UP": 347 inputMethodEngine.MoveCursor(inputMethodEngine.CURSOR_UP); 348 return true 349 case "KEYCODE_DPAD_DOWN": 350 inputMethodEngine.MoveCursor(inputMethodEngine.CURSOR_DOWN); 351 return true 352 case "KEYCODE_DPAD_LEFT": 353 inputMethodEngine.MoveCursor(inputMethodEngine.CURSOR_LEFT); 354 return true 355 case "KEYCODE_DPAD_RIGHT": 356 inputMethodEngine.MoveCursor(inputMethodEngine.CURSOR_RIGHT); 357 return true 358 default: 359 return false 360 } 361 } 362 363 private unRegisterListener(): void{ 364 this.inputHandle.addLog('unRegisterListener') 365 366 InputMethodEngine.off('inputStop', ()=> { 367 this.inputHandle.addLog('inputStop off'); 368 }); 369 370 InputMethodEngine.off('keyboardShow'); 371 372 InputMethodEngine.off('keyboardHide'); 373 374 this.mKeyboardDelegate.off('keyDown'); 375 376 this.mKeyboardDelegate.off('keyUp'); 377 378 if (isDebug) { 379 this.mKeyboardDelegate.off('cursorContextChange'); 380 381 this.mKeyboardDelegate.off('selectionChange'); 382 383 this.mKeyboardDelegate.off('textChange'); 384 } 385 } 386 387 private showWindow() { 388 try { 389 this.getValue('settings.display.navigationbar_status') 390 } catch (err) { 391 Log.showError(TAG, "get value failed" + err) 392 } 393 Log.showInfo(TAG, 'current navigation state is' + this.getValueRes) 394 this.inputHandle.addLog('showWindow'); 395 windowManager.find(this.windowName).then((win) => { 396 win.show().then(() => { 397 this.inputHandle.addLog('showWindow finish'); 398 this.isKeyboardShow = true; 399 }) 400 }) 401 } 402 403 private hideWindow() { 404 this.inputHandle.addLog('hideWindow'); 405 windowManager.find(this.windowName).then((win) => { 406 win.hide().then(() => { 407 this.isKeyboardShow = false; 408 this.inputHandle.addLog('hideWindow finish'); 409 }) 410 }) 411 } 412} 413 414export class InputHandler { 415 private static instance: InputHandler; 416 private mKbController; 417 private mTextInputClient; 418 private mEditorAttribute; 419 private cursorInfo; 420 private selectInfo; 421 private textInfo; 422 private inputInfo; 423 private constructor() { 424 425 } 426 427 public static getInstance() { 428 if (globalThis.instance == null) { 429 globalThis.instance = new InputHandler(); 430 } 431 return globalThis.instance; 432 } 433 434 public onInputStart(kbController, textInputClient) { 435 globalThis.mKbController = kbController; 436 globalThis.mTextInputClient = textInputClient; 437 globalThis.mEditorAttribute = globalThis.mTextInputClient.getEditorAttribute(); 438 this.addLog("onInputStart mEditorAttribute = " + globalThis.mEditorAttribute); 439 globalThis.mEditorAttribute.then(res => { 440 globalThis.enterKeyType = res.enterKeyType; 441 globalThis.inputPattern = res.inputPattern; 442 this.setInputInfo("EditorInfo:enterKeyType = " + globalThis.enterKeyType + ";inputPattern = " + globalThis.inputPattern); 443 }) 444 } 445 446 public hideKeyboardSelf() { 447 this.addLog('hideKeyboardSelf') 448 if (globalThis.mKbController != undefined) { 449 globalThis.mKbController.hideKeyboard(); 450 } else { 451 this.addLog('hideKeyboardSelf globalThis.mKbController is undefined') 452 } 453 } 454 455 public sendKeyFunction() { 456 this.addLog('sendKeyFunction') 457 if (globalThis.mTextInputClient != undefined) { 458 globalThis.mTextInputClient.sendKeyFunction(globalThis.enterKeyType); 459 } else { 460 this.addLog('sendKeyFunction globalThis.mTextInputClient is undefined') 461 } 462 } 463 464 public deleteBackward(length: number) { 465 this.addLog('deleteBackward') 466 if (globalThis.mTextInputClient != undefined) { 467 globalThis.mTextInputClient.deleteBackward(length); 468 } else { 469 this.addLog('deleteBackward globalThis.mTextInputClient is undefined') 470 } 471 if (isDebug) { 472 this.refreshInfo(); 473 } 474 } 475 476 public deleteForward(length: number) { 477 this.addLog('deleteForward') 478 if (globalThis.mTextInputClient != undefined) { 479 globalThis.mTextInputClient.deleteForward(length); 480 } else { 481 this.addLog('deleteForward globalThis.mTextInputClient is undefined') 482 } 483 if (isDebug) { 484 this.refreshInfo(); 485 } 486 } 487 488 public insertText(text: string) { 489 this.addLog('insertText') 490 if (globalThis.mTextInputClient != undefined) { 491 globalThis.mTextInputClient.insertText(text); 492 } else { 493 this.addLog('insertText globalThis.mTextInputClient is undefined') 494 } 495 if (isDebug) { 496 this.refreshInfo(); 497 } 498 } 499 500 public addLog(message): void { 501 Log.showInfo(TAG, "kikaInput-js: " + message) 502 } 503 504 public setCursorInfo(info) { 505 globalThis.cursorInfo = info; 506 this.addLog("setCursorInfo info = " + info); 507 } 508 509 public setSelectInfo(info) { 510 globalThis.selectInfo = info; 511 this.addLog("setSelectInfo info = " + info); 512 } 513 514 public setTextInfo(info) { 515 globalThis.textInfo = info; 516 this.addLog("setTextInfo info = " + info); 517 } 518 519 public setInputInfo(info) { 520 globalThis.inputInfo = info; 521 this.addLog("setInputInfo info = " + info); 522 } 523 524 public refreshInfo() { 525 this.addLog('refreshInfo'); 526 var showText = ''; 527 this.addLog('refreshInfo1'); 528 showText += 'five chars: before:[' + globalThis.mTextInputClient.getForward(5) + '];after:[' + globalThis.mTextInputClient.getBackward(5) + ']\n'; 529 this.addLog('refreshInfo2'); 530 showText += globalThis.cursorInfo + "\n"; 531 this.addLog('refreshInfo3'); 532 showText += globalThis.selectInfo + "\n"; 533 this.addLog('refreshInfo4'); 534 showText += globalThis.textInfo + "\n"; 535 this.addLog('refreshInfo5'); 536 showText += globalThis.inputInfo; 537 this.addLog('refreshInfo6'); 538 AppStorage.Set<string>('showLog', showText); 539 this.addLog('refreshInfo7'); 540 this.addLog('result is = ' + showText); 541 } 542} 543