diff --git a/entry/src/main/ets/InputMethodExtensionAbility/FcitxInputMethodService.ts b/entry/src/main/ets/InputMethodExtensionAbility/FcitxInputMethodService.ts new file mode 100644 index 0000000..1635d11 --- /dev/null +++ b/entry/src/main/ets/InputMethodExtensionAbility/FcitxInputMethodService.ts @@ -0,0 +1,13 @@ +import { InputMethodExtensionAbility } from "@kit.IMEKit"; +import Want from "@ohos.app.ability.Want"; +import keyboardController from "./model/KeyboardController"; + +export default class FcitxInputMethodService extends InputMethodExtensionAbility { + onCreate(want: Want): void { + keyboardController.onCreate(this.context) + } + + onDestroy(): void { + keyboardController.onDestroy() + } +} diff --git a/entry/src/main/ets/InputMethodExtensionAbility/model/KeyboardController.ts b/entry/src/main/ets/InputMethodExtensionAbility/model/KeyboardController.ts new file mode 100644 index 0000000..a0187d1 --- /dev/null +++ b/entry/src/main/ets/InputMethodExtensionAbility/model/KeyboardController.ts @@ -0,0 +1,93 @@ +import { inputMethodEngine, InputMethodExtensionContext } from '@kit.IMEKit' +import { display } from '@kit.ArkUI'; +import { KeyCode } from '@kit.InputKit'; + +const ability: inputMethodEngine.InputMethodAbility = inputMethodEngine.getInputMethodAbility(); + +export class KeyboardController { + private ctx: InputMethodExtensionContext | undefined = undefined; + private panel: inputMethodEngine.Panel | undefined = undefined; + private textInputClient: inputMethodEngine.InputClient | undefined = undefined; + private keyboardController: inputMethodEngine.KeyboardController | undefined = undefined; + + constructor() { + } + + public onCreate(context: InputMethodExtensionContext): void { + this.ctx = context; + this.initWindow(); + this.registerListener(); + } + + public onDestroy(): void { + this.unRegisterListener(); + if (this.panel) { + ability.destroyPanel(this.panel); + } + if (this.ctx) { + this.ctx.destroy(); + } + } + + public insertText(text: string): void { + if (this.textInputClient) { + this.textInputClient.insertText(text); + } + } + + public deleteForward(length: number): void { + if (this.textInputClient) { + this.textInputClient.deleteForward(length); + } + } + + private initWindow(): void { + if (this.ctx === undefined) { + return; + } + let dis = display.getDefaultDisplaySync(); + let dWidth = dis.width; + let dHeight = dis.height; + let keyHeightRate = 0.3; + let keyHeight = dHeight * keyHeightRate; + let nonBarPosition = dHeight - keyHeight; + let panelInfo: inputMethodEngine.PanelInfo = { + type: inputMethodEngine.PanelType.SOFT_KEYBOARD, + flag: inputMethodEngine.PanelFlag.FLG_FIXED + }; + ability.createPanel(this.ctx, panelInfo).then(async (inputPanel: inputMethodEngine.Panel) => { + this.panel = inputPanel; + if (this.panel) { + await this.panel.resize(dWidth, keyHeight); + await this.panel.moveTo(0, nonBarPosition); + await this.panel.setUiContent('InputMethodExtensionAbility/pages/Index'); + } + }); + } + + private registerListener(): void { + this.registerInputListener(); + } + + private registerInputListener(): + void { + ability.on('inputStart', (kbController, textInputClient) => { + this.textInputClient = textInputClient; + this.keyboardController = kbController; + }) + ability.on('inputStop', () => { + this.onDestroy(); + }); + } + + private unRegisterListener(): + void { + ability.off('inputStart'); + ability.off('inputStop', () => { + }); + } +} + +const keyboardController = new KeyboardController(); + +export default keyboardController; diff --git a/entry/src/main/ets/InputMethodExtensionAbility/pages/Index.ets b/entry/src/main/ets/InputMethodExtensionAbility/pages/Index.ets new file mode 100644 index 0000000..5cb6803 --- /dev/null +++ b/entry/src/main/ets/InputMethodExtensionAbility/pages/Index.ets @@ -0,0 +1,130 @@ +import { textLayoutData } from './keyboard/LayoutData'; +import keyboardController from '../model/KeyboardController'; +import { TextKey } from './keyboard/KeyType'; + +@Component +struct KeyItem { + @State keyValue: TextKey = textLayoutData[0][0]; + @State keyBgc: string = "#fff" + @State keyFontColor: string = "#000" + + build() { + Column() { + Flex({ + direction: FlexDirection.Column, + alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center + }) { + Text(this.keyValue.character).fontSize(20).fontColor(this.keyFontColor) + } + } + .backgroundColor(this.keyBgc) + .borderRadius(6) + .width("8%") + .height("65%") + .onClick(() => { + keyboardController.insertText(this.keyValue.character.toLowerCase()); + }) + } +} + +@Component +export struct BackspaceItem { + @State keyValue: TextKey = { character: '⌫' } + @State keyBgc: string = "#9f9f9f" + @State keyFontColor: string = "#000" + + build() { + Column() { + Flex({ + direction: FlexDirection.Column, + alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center + }) { + Text(this.keyValue.character).fontSize(20).fontColor(this.keyFontColor) + } + } + .backgroundColor(this.keyBgc) + .width("13%") + .height("65%") + .borderRadius(6) + .onClick(() => { + keyboardController.deleteForward(1); + }) + } +} + +@Component +export struct SpaceItem { + @State keyValue: TextKey = { character: '␣' } + @State keyBgc: string = "#fff" + @State keyFontColor: string = "#000" + + build() { + Column() { + Flex({ + direction: FlexDirection.Column, + alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center + }) { + Text(this.keyValue.character).fontSize(20).fontColor(this.keyFontColor) + } + } + .backgroundColor(this.keyBgc) + .width("40%") + .height("65%") + .borderRadius(6) + .onClick(() => { + keyboardController.insertText(' '); + }) + } +} + +@Component +struct TextKeyboard { + private textList: TextKey[][] = textLayoutData; + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceAround }) { + ForEach(this.textList, (row: TextKey[]) => { + Flex({ justifyContent: FlexAlign.SpaceAround }) { + ForEach(row, (column: TextKey) => { + if (column.character == "⌫") { + BackspaceItem(); + } else if (column.character == "␣") { + SpaceItem(); + } else { + KeyItem({ keyValue: column }); + } + }, (column: TextKey) => column.character); + } + .width('96%') + .height('20%') + }, (row: TextKey[]) => textLayoutData.indexOf(row).toString()); + } + } +} + +@Entry +@Component +struct Index { + build() { + Stack() { + Flex({ + direction: FlexDirection.Column, + alignItems: ItemAlign.Center, + justifyContent: FlexAlign.End + }) { + Flex({ + direction: FlexDirection.Column, + alignItems: ItemAlign.Center, + justifyContent: FlexAlign.SpaceBetween + }) { + TextKeyboard(); + } + .align(Alignment.End) + .width("100%") + .height("96%") + } + .height("100%").align(Alignment.End).backgroundColor("#cdd0d7") + } + .position({ x: 0, y: 0 }).zIndex(99999) + } +} diff --git a/entry/src/main/ets/InputMethodExtensionAbility/pages/keyboard/KeyType.ts b/entry/src/main/ets/InputMethodExtensionAbility/pages/keyboard/KeyType.ts new file mode 100644 index 0000000..4f512e3 --- /dev/null +++ b/entry/src/main/ets/InputMethodExtensionAbility/pages/keyboard/KeyType.ts @@ -0,0 +1,3 @@ +export interface TextKey { + character: string; +} diff --git a/entry/src/main/ets/InputMethodExtensionAbility/pages/keyboard/LayoutData.ts b/entry/src/main/ets/InputMethodExtensionAbility/pages/keyboard/LayoutData.ts new file mode 100644 index 0000000..0bd3f0a --- /dev/null +++ b/entry/src/main/ets/InputMethodExtensionAbility/pages/keyboard/LayoutData.ts @@ -0,0 +1,55 @@ +import { TextKey } from "./KeyType" + +export let textLayoutData: TextKey[][] = [ + [ + { character: '1' }, + { character: '2' }, + { character: '3' }, + { character: '4' }, + { character: '5' }, + { character: '6' }, + { character: '7' }, + { character: '8' }, + { character: '9' }, + { character: '0' } + ], + [ + { character: 'Q' }, + { character: 'W' }, + { character: 'E' }, + { character: 'R' }, + { character: 'T' }, + { character: 'Y' }, + { character: 'U' }, + { character: 'I' }, + { character: 'O' }, + { character: 'P' } + ], + [ + { character: 'A' }, + { character: 'S' }, + { character: 'D' }, + { character: 'F' }, + { character: 'G' }, + { character: 'H' }, + { character: 'J' }, + { character: 'K' }, + { character: 'L' }, + ], + [ + { character: '`' }, + { character: 'Z' }, + { character: 'X' }, + { character: 'C' }, + { character: 'V' }, + { character: 'B' }, + { character: 'N' }, + { character: 'M' }, + { character: '⌫' }, + ], + [ + { character: ',' }, + { character: '␣' }, + { character: '.' }, + ] +] diff --git a/entry/src/main/module.json5 b/entry/src/main/module.json5 index aeeb348..359bf3e 100644 --- a/entry/src/main/module.json5 +++ b/entry/src/main/module.json5 @@ -46,6 +46,14 @@ "resource": "$profile:backup_config" } ] + }, + { + "description": "inputMethod", + "name": "InputMethodExtensionAbility", + "icon": "$media:app_icon", + "srcEntry": "./ets/InputMethodExtensionAbility/FcitxInputMethodService.ts", + "type": "inputMethod", + "exported": true, } ] } diff --git a/entry/src/main/resources/base/profile/main_pages.json b/entry/src/main/resources/base/profile/main_pages.json index 1898d94..5ae0380 100644 --- a/entry/src/main/resources/base/profile/main_pages.json +++ b/entry/src/main/resources/base/profile/main_pages.json @@ -1,5 +1,6 @@ { "src": [ - "pages/Index" + "pages/Index", + "InputMethodExtensionAbility/pages/Index" ] }