diff --git a/shell/platform/ohos/flutter_embedding/.gitignore b/shell/platform/ohos/flutter_embedding/.gitignore index c5c48a55d35b577e3812111c745f37f9a3b56e44..c837164ae81179285dbc1ecb343ec163171ae17e 100644 --- a/shell/platform/ohos/flutter_embedding/.gitignore +++ b/shell/platform/ohos/flutter_embedding/.gitignore @@ -1,5 +1,5 @@ /node_modules -/oh_modules +**/oh_modules /.idea **/build /.hvigor diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TextInputChannel.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TextInputChannel.ets index 99a9d4f39cbc0712494cd6d49b35f6583cd3f60d..2515a63c4356e93f6a7b70356bda6b8bcf739366 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TextInputChannel.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/systemchannels/TextInputChannel.ets @@ -40,9 +40,10 @@ export default class TextInputChannel { this.channel = new MethodChannel(dartExecutor, TextInputChannel.CHANNEL_NAME, JSONMethodCodec.INSTANCE); } - setTextInputMethodHandler(textInputMethodHandler: TextInputMethodHandler): void { + setTextInputMethodHandler(textInputMethodHandler: TextInputMethodHandler | null): void { this.textInputMethodHandler = textInputMethodHandler; - this.channel.setMethodCallHandler(new TextInputCallback(this.textInputMethodHandler)); + this.channel.setMethodCallHandler(textInputMethodHandler == null + ? null : new TextInputCallback(textInputMethodHandler)); } requestExistingInputState(): void { diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityAndEntryDelegate.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityAndEntryDelegate.ets index 480371d80703aafa8be51b208ed052bb921375bc..48e85d9b34fd1520414ba0759d842ebc0a871e15 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityAndEntryDelegate.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterAbilityAndEntryDelegate.ets @@ -27,7 +27,6 @@ import FlutterInjector from '../../FlutterInjector'; import UIAbility from '@ohos.app.ability.UIAbility'; import ExclusiveAppComponent from './ExclusiveAppComponent'; import AbilityConstant from '@ohos.app.ability.AbilityConstant'; -import TextInputPlugin from '../../plugin/editing/TextInputPlugin'; import { FlutterPlugin } from '../engine/plugins/FlutterPlugin'; import FlutterEngineCache from '../engine/FlutterEngineCache'; import FlutterEngineGroupCache from '../engine/FlutterEngineGroupCache'; @@ -51,7 +50,6 @@ class FlutterAbilityAndEntryDelegate implements ExclusiveAppComponent flutterEngine?: FlutterEngine | null; platformPlugin?: PlatformPlugin; protected context?: common.Context; - protected textInputPlugin?: TextInputPlugin; protected isFlutterEngineFromHostOrCache: boolean = false; private engineGroup?: FlutterEngineGroup; private isHost:boolean = false; @@ -87,7 +85,6 @@ class FlutterAbilityAndEntryDelegate implements ExclusiveAppComponent //configureFlutterEngine this.isAttached = true; if (this.flutterEngine) { - this.textInputPlugin = new TextInputPlugin(this.flutterEngine.getTextInputChannel()!); this.flutterEngine.getSystemLanguages(); } if (this.flutterEngine && this.flutterView && this.host?.attachToEngineAutomatically()) { @@ -271,7 +268,6 @@ class FlutterAbilityAndEntryDelegate implements ExclusiveAppComponent release() { this.host = null; this.flutterEngine = null; - this.textInputPlugin = undefined; this.platformPlugin = undefined; } diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets index 15af51a2dd5fc024975fd30f72561cfd1c8caa34..ddb2fbec75248f2a3bc690db6e71072a8f2583b9 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets @@ -80,9 +80,10 @@ export struct FlutterPage { } }) .onKeyPreIme((event: KeyEvent) => { - Log.d(TAG, "onKeyEvent " + event.type); - this.flutterView?.onKeyEvent(event); - return false; + return this.flutterView?.onKeyPreIme(event) ?? false; + }) + .onKeyEvent((event: KeyEvent) => { + return this.flutterView?.onKeyEvent(event) ?? false; }) } @Builder mouseWheelPage() { @@ -134,9 +135,10 @@ export struct FlutterPage { } }) .onKeyPreIme((event: KeyEvent) => { - Log.d(TAG, "onKeyEvent " + event.type); - this.flutterView?.onKeyEvent(event); - return false; + return this.flutterView?.onKeyPreIme(event) ?? false; + }) + .onKeyEvent((event: KeyEvent) => { + return this.flutterView?.onKeyEvent(event) ?? false; }) .gesture( PanGesture(this.panOption) diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/KeyEventHandler.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/KeyEventHandler.ets new file mode 100644 index 0000000000000000000000000000000000000000..58133fd461d8669580f47c2358ae33739957c70d --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/KeyEventHandler.ets @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { HashMap } from "@kit.ArkTS"; +import deviceInfo from '@ohos.deviceInfo'; +import TextInputPlugin from "../../plugin/editing/TextInputPlugin"; +import Log from "../../util/Log"; +import { KeyCode } from "@kit.InputKit"; + +const TAG = "KeyEventHandler"; + +export class KeyEventHandler { + private textInputPlugin?: TextInputPlugin; + private charMap : HashMap = new HashMap(); + private shiftMap : HashMap = new HashMap(); + private isShiftMode: boolean = false; + + constructor(textInputPlugin?: TextInputPlugin) { + this.textInputPlugin = textInputPlugin; + this.initCharMap(); + this.initShiftMap(); + } + + private initCharMap() { + this.charMap.set(KeyCode.KEYCODE_0, '0') + this.charMap.set(KeyCode.KEYCODE_1, '1') + this.charMap.set(KeyCode.KEYCODE_2, '2') + this.charMap.set(KeyCode.KEYCODE_3, '3') + this.charMap.set(KeyCode.KEYCODE_4, '4') + this.charMap.set(KeyCode.KEYCODE_5, '5') + this.charMap.set(KeyCode.KEYCODE_6, '6') + this.charMap.set(KeyCode.KEYCODE_7, '7') + this.charMap.set(KeyCode.KEYCODE_8, '8') + this.charMap.set(KeyCode.KEYCODE_9, '9') + this.charMap.set(KeyCode.KEYCODE_A, 'a') + this.charMap.set(KeyCode.KEYCODE_B, 'b') + this.charMap.set(KeyCode.KEYCODE_C, 'c') + this.charMap.set(KeyCode.KEYCODE_D, 'd') + this.charMap.set(KeyCode.KEYCODE_E, 'e') + this.charMap.set(KeyCode.KEYCODE_F, 'f') + this.charMap.set(KeyCode.KEYCODE_G, 'g') + this.charMap.set(KeyCode.KEYCODE_H, 'h') + this.charMap.set(KeyCode.KEYCODE_I, 'i') + this.charMap.set(KeyCode.KEYCODE_J, 'j') + this.charMap.set(KeyCode.KEYCODE_K, 'k') + this.charMap.set(KeyCode.KEYCODE_L, 'l') + this.charMap.set(KeyCode.KEYCODE_M, 'm') + this.charMap.set(KeyCode.KEYCODE_N, 'n') + this.charMap.set(KeyCode.KEYCODE_O, 'o') + this.charMap.set(KeyCode.KEYCODE_P, 'p') + this.charMap.set(KeyCode.KEYCODE_Q, 'q') + this.charMap.set(KeyCode.KEYCODE_R, 'r') + this.charMap.set(KeyCode.KEYCODE_S, 's') + this.charMap.set(KeyCode.KEYCODE_T, 't') + this.charMap.set(KeyCode.KEYCODE_U, 'u') + this.charMap.set(KeyCode.KEYCODE_V, 'v') + this.charMap.set(KeyCode.KEYCODE_W, 'w') + this.charMap.set(KeyCode.KEYCODE_X, 'x') + this.charMap.set(KeyCode.KEYCODE_Y, 'y') + this.charMap.set(KeyCode.KEYCODE_Z, 'z') + this.charMap.set(KeyCode.KEYCODE_GRAVE, '`') + this.charMap.set(KeyCode.KEYCODE_MINUS, '-') + this.charMap.set(KeyCode.KEYCODE_EQUALS, '=') + this.charMap.set(KeyCode.KEYCODE_LEFT_BRACKET, '[') + this.charMap.set(KeyCode.KEYCODE_RIGHT_BRACKET, ']') + this.charMap.set(KeyCode.KEYCODE_BACKSLASH, '\\') + this.charMap.set(KeyCode.KEYCODE_SEMICOLON, ';') + this.charMap.set(KeyCode.KEYCODE_APOSTROPHE, '\'') + this.charMap.set(KeyCode.KEYCODE_COMMA, ',') + this.charMap.set(KeyCode.KEYCODE_PERIOD, '.') + this.charMap.set(KeyCode.KEYCODE_SLASH, '/') + this.charMap.set(KeyCode.KEYCODE_SPACE, ' ') + } + + private initShiftMap() { + this.shiftMap.set(KeyCode.KEYCODE_0, ')') + this.shiftMap.set(KeyCode.KEYCODE_1, '!') + this.shiftMap.set(KeyCode.KEYCODE_2, '@') + this.shiftMap.set(KeyCode.KEYCODE_3, '#') + this.shiftMap.set(KeyCode.KEYCODE_4, '$') + this.shiftMap.set(KeyCode.KEYCODE_5, '%') + this.shiftMap.set(KeyCode.KEYCODE_6, '^') + this.shiftMap.set(KeyCode.KEYCODE_7, '&') + this.shiftMap.set(KeyCode.KEYCODE_8, '*') + this.shiftMap.set(KeyCode.KEYCODE_9, '(') + this.shiftMap.set(KeyCode.KEYCODE_A, 'A') + this.shiftMap.set(KeyCode.KEYCODE_B, 'B') + this.shiftMap.set(KeyCode.KEYCODE_C, 'C') + this.shiftMap.set(KeyCode.KEYCODE_D, 'D') + this.shiftMap.set(KeyCode.KEYCODE_E, 'E') + this.shiftMap.set(KeyCode.KEYCODE_F, 'F') + this.shiftMap.set(KeyCode.KEYCODE_G, 'G') + this.shiftMap.set(KeyCode.KEYCODE_H, 'H') + this.shiftMap.set(KeyCode.KEYCODE_I, 'I') + this.shiftMap.set(KeyCode.KEYCODE_J, 'J') + this.shiftMap.set(KeyCode.KEYCODE_K, 'K') + this.shiftMap.set(KeyCode.KEYCODE_L, 'L') + this.shiftMap.set(KeyCode.KEYCODE_M, 'M') + this.shiftMap.set(KeyCode.KEYCODE_N, 'N') + this.shiftMap.set(KeyCode.KEYCODE_O, 'O') + this.shiftMap.set(KeyCode.KEYCODE_P, 'P') + this.shiftMap.set(KeyCode.KEYCODE_Q, 'Q') + this.shiftMap.set(KeyCode.KEYCODE_R, 'R') + this.shiftMap.set(KeyCode.KEYCODE_S, 'S') + this.shiftMap.set(KeyCode.KEYCODE_T, 'T') + this.shiftMap.set(KeyCode.KEYCODE_U, 'U') + this.shiftMap.set(KeyCode.KEYCODE_V, 'V') + this.shiftMap.set(KeyCode.KEYCODE_W, 'W') + this.shiftMap.set(KeyCode.KEYCODE_X, 'X') + this.shiftMap.set(KeyCode.KEYCODE_Y, 'Y') + this.shiftMap.set(KeyCode.KEYCODE_Z, 'Z') + this.shiftMap.set(KeyCode.KEYCODE_GRAVE, '~') + this.shiftMap.set(KeyCode.KEYCODE_MINUS, '_') + this.shiftMap.set(KeyCode.KEYCODE_EQUALS, '+') + this.shiftMap.set(KeyCode.KEYCODE_LEFT_BRACKET, '{') + this.shiftMap.set(KeyCode.KEYCODE_RIGHT_BRACKET, '}') + this.shiftMap.set(KeyCode.KEYCODE_BACKSLASH, '|') + this.shiftMap.set(KeyCode.KEYCODE_SEMICOLON, ':') + this.shiftMap.set(KeyCode.KEYCODE_APOSTROPHE, '"') + this.shiftMap.set(KeyCode.KEYCODE_COMMA, '<') + this.shiftMap.set(KeyCode.KEYCODE_PERIOD, '>') + this.shiftMap.set(KeyCode.KEYCODE_SLASH, '?') + this.shiftMap.set(KeyCode.KEYCODE_SPACE, ' ') + } + + getCharByEvent(event: KeyEvent) : string { + let key = event.keyCode; + if (this.isShiftMode) { + return this.shiftMap.hasKey(key) ? this.shiftMap.get(key) : '' + } else { + return this.charMap.hasKey(key) ? this.charMap.get(key) : '' + } + } + + handleKeyEvent(event: KeyEvent) { + Log.i(TAG, JSON.stringify({ + "name": "handleKeyEvent", + "event": event + })); + if (event.type == KeyType.Up) { + // 处理字符按键相关逻辑 + if (this.charMap.hasKey(event.keyCode)) { + this.textInputPlugin?.getEditingState().handleInsertTextEvent(this.getCharByEvent(event)) + } + // 处理非字符按键 + if (event.keyCode == KeyCode.KEYCODE_DEL) { + this.textInputPlugin?.getEditingState().handleDeleteEvent(false, 0) + } + } + this.isShiftMode = event.keyCode == KeyCode.KEYCODE_SHIFT_LEFT + } +} diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/KeyboardManager.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/KeyboardManager.ets index ec4a02ff789087a3afd90f1a850d295856243e24..21b5c88934ba7443f6dc5ead7fd8974e40db2ac3 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/KeyboardManager.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/KeyboardManager.ets @@ -12,21 +12,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import TextInputPlugin from '../../plugin/editing/TextInputPlugin'; import FlutterEngine from '../engine/FlutterEngine'; import KeyEventChannel, { FlutterKeyEvent } from '../engine/systemchannels/KeyEventChannel'; +import { KeyEventHandler } from './KeyEventHandler'; export default class KeyboardManager { private keyEventChannel: KeyEventChannel | null = null + private keyEventHandler: KeyEventHandler; - constructor(engine: FlutterEngine) { + constructor(engine: FlutterEngine, textInputPlugin: TextInputPlugin) { this.keyEventChannel = new KeyEventChannel(engine.dartExecutor) + this.keyEventHandler = new KeyEventHandler(textInputPlugin); } - handleKeyEvent(event: KeyEvent) { + onKeyPreIme(event: KeyEvent) : boolean { this.keyEventChannel?.sendFlutterKeyEvent(new FlutterKeyEvent(event), event.type == KeyType.Up, { onFrameworkResponse: (isEventHandled: boolean): void => { } }) + return false; + } + + onKeyEvent(event: KeyEvent) : boolean { + this.keyEventHandler.handleKeyEvent(event); + return false; } } \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextInputPlugin.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextInputPlugin.ets index c64f1d88f9467c72b0b4c1837df723b631ed343d..5f3a67c3628f4209dce770b382a28fc442b66431 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextInputPlugin.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/plugin/editing/TextInputPlugin.ets @@ -46,6 +46,10 @@ export default class TextInputPlugin implements EditingStateWatcher { } + getEditingState() { + return this.mTextInputHandler.mEditable; + } + didChangeEditingState(textChanged: boolean, selectionChanged: boolean, composingRegionChanged: boolean): void { let editable = this.mTextInputHandler.mEditable; let inputTarget = this.mTextInputHandler.inputTarget; @@ -68,6 +72,10 @@ export default class TextInputPlugin implements EditingStateWatcher { } }) } + + destroy() { + this.textInputChannel.setTextInputMethodHandler(null); + } } class TextInputMethodHandlerImpl implements TextInputMethodHandler { diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterView.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterView.ets index 5af7b9cf9dd2343f47f2bbbec760715144062454..853ce08722b2b9cf63d4d71e7dd004f24c93203d 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterView.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/view/FlutterView.ets @@ -25,6 +25,7 @@ import ArrayList from '@ohos.util.ArrayList'; import { EmbeddingNodeController } from '../embedding/ohos/EmbeddingNodeController'; import PlatformView, { Params } from '../plugin/platform/PlatformView'; import { JSON } from '@kit.ArkTS'; +import TextInputPlugin from '../plugin/editing/TextInputPlugin'; const TAG = "FlutterViewTag"; @@ -120,6 +121,7 @@ export class FlutterView { private keyboardManager: KeyboardManager | null = null; private mainWindow: window.Window | null = null; private mouseCursorPlugin?: MouseCursorPlugin; + private textInputPlugin?: TextInputPlugin; private uiContext?: UIContext | undefined; private settings?: Settings; private mFirstFrameListeners: ArrayList; @@ -285,7 +287,6 @@ export class FlutterView { } Log.i(TAG, "attachToFlutterEngine"); this.flutterEngine = flutterEngine; - this.keyboardManager = new KeyboardManager(flutterEngine); if (this.isSurfaceAvailableForRendering) { this.flutterEngine.getFlutterNapi().xComponentAttachFlutterEngine(this.id) } @@ -306,6 +307,8 @@ export class FlutterView { let windowId = this.mainWindow?.getWindowProperties()?.id ?? 0 this.mouseCursorPlugin = new MouseCursorPlugin(windowId, this.flutterEngine?.getMouseCursorChannel()!); + this.textInputPlugin = new TextInputPlugin(this.flutterEngine?.getTextInputChannel()!); + this.keyboardManager = new KeyboardManager(flutterEngine, this.textInputPlugin!); this.settings = new Settings(this.flutterEngine.getSettingsChannel()!); this.sendSettings(); this.isFlutterUiDisplayed = this.flutterEngine.getFlutterNapi().isDisplayingFlutterUi; @@ -327,6 +330,7 @@ export class FlutterView { this.flutterEngine?.getPlatformViewsController()?.detachFromView(); this.flutterEngine = null; this.keyboardManager = null; + this.textInputPlugin?.destroy(); } onWindowCreated() { @@ -448,8 +452,12 @@ export class FlutterView { return false; } - onKeyEvent(event: KeyEvent) { - this.keyboardManager?.handleKeyEvent(event) + onKeyPreIme(event: KeyEvent) : boolean { + return this.keyboardManager?.onKeyPreIme(event) ?? false; + } + + onKeyEvent(event: KeyEvent) : boolean { + return this.keyboardManager?.onKeyEvent(event) ?? false; } onMouseWheel(eventType: string, event: PanGestureEvent) {