diff --git a/entry/src/main/cpp/napi_init.cpp b/entry/src/main/cpp/napi_init.cpp index 1f47871..0ae1cbc 100644 --- a/entry/src/main/cpp/napi_init.cpp +++ b/entry/src/main/cpp/napi_init.cpp @@ -39,11 +39,12 @@ API(toggle) { } API(processKey) { - GET_ARGS(3) + GET_ARGS(4) GET_U32(unicode, 0) GET_I32(keyCode, 1) - GET_BOOL(isRelease, 2) - auto state = fcitx::processKey(unicode, keyCode, isRelease); + GET_U32(states, 2) + GET_BOOL(isRelease, 3) + auto state = fcitx::processKey(unicode, keyCode, states, isRelease); OBJECT(ret) SET(ret, "commit", state.commit) SET(ret, "preedit", state.preedit) diff --git a/entry/src/main/cpp/src/fcitx.cpp b/entry/src/main/cpp/src/fcitx.cpp index 8f6145f..51857e8 100644 --- a/entry/src/main/cpp/src/fcitx.cpp +++ b/entry/src/main/cpp/src/fcitx.cpp @@ -1,4 +1,5 @@ #include "fcitx.h" +#include #include #include #include @@ -98,9 +99,9 @@ InputContextState reset() { return with_fcitx([] { return frontend->reset(); }); } -InputContextState processKey(uint32_t unicode, int32_t keyCode, bool isRelease) { - return with_fcitx([unicode, keyCode, isRelease] { - auto key = ohKeyToFcitxKey(unicode, keyCode); +InputContextState processKey(uint32_t unicode, int32_t keyCode, uint32_t states, bool isRelease) { + return with_fcitx([unicode, keyCode, states, isRelease] { + auto key = ohKeyToFcitxKey(unicode, keyCode, states); return frontend->keyEvent(key, isRelease); }); } diff --git a/entry/src/main/cpp/src/fcitx.h b/entry/src/main/cpp/src/fcitx.h index 05824d1..1fbc671 100644 --- a/entry/src/main/cpp/src/fcitx.h +++ b/entry/src/main/cpp/src/fcitx.h @@ -19,7 +19,7 @@ void init(const std::string &bundle, const std::string &resfile); void focusIn(bool clientPreedit); void focusOut(); InputContextState reset(); -InputContextState processKey(uint32_t unicode, int32_t keyCode, bool isRelease); +InputContextState processKey(uint32_t unicode, int32_t keyCode, uint32_t states, bool isRelease); void selectCandidate(int index); void askCandidateAction(int index); void activateCandidateAction(int index, int id); diff --git a/entry/src/main/cpp/src/keycode.cpp b/entry/src/main/cpp/src/keycode.cpp index a25f714..b789d16 100644 --- a/entry/src/main/cpp/src/keycode.cpp +++ b/entry/src/main/cpp/src/keycode.cpp @@ -1,3 +1,4 @@ +#include #include #include "keycode.h" #include "ohkeycode.h" @@ -273,8 +274,8 @@ uint16_t ohKeyCodeToFcitxKeyCode(int32_t keyCode) { return 0; } -Key ohKeyToFcitxKey(uint32_t unicode, int32_t keyCode) { +Key ohKeyToFcitxKey(uint32_t unicode, int32_t keyCode, uint32_t states) { auto keysym = unicode ? Key::keySymFromUnicode(unicode) : ohKeyCodeToFcitxKeySym(keyCode); - return Key{keysym, KeyStates{}, ohKeyCodeToFcitxKeyCode(keyCode)}; + return Key{keysym, KeyStates{states}, ohKeyCodeToFcitxKeyCode(keyCode)}; } } // namespace fcitx diff --git a/entry/src/main/cpp/src/keycode.h b/entry/src/main/cpp/src/keycode.h index a65c07c..fbe5c50 100644 --- a/entry/src/main/cpp/src/keycode.h +++ b/entry/src/main/cpp/src/keycode.h @@ -1,7 +1,8 @@ #pragma once +#include #include namespace fcitx { -Key ohKeyToFcitxKey(uint32_t unicode, int32_t keyCode); +Key ohKeyToFcitxKey(uint32_t unicode, int32_t keyCode, uint32_t states); } diff --git a/entry/src/main/cpp/types/libentry/Index.d.ts b/entry/src/main/cpp/types/libentry/Index.d.ts index 3d40b9c..706f063 100644 --- a/entry/src/main/cpp/types/libentry/Index.d.ts +++ b/entry/src/main/cpp/types/libentry/Index.d.ts @@ -9,7 +9,7 @@ export interface InputContextState { cursorPos: number accepted: boolean } -export const processKey: (unicode: number, keyCode: number, isRelease: boolean) => InputContextState +export const processKey: (unicode: number, keyCode: number, states: number, isRelease: boolean) => InputContextState export const reset: () => InputContextState export const toggle: () => void export const selectCandidate: (index: number) => void diff --git a/entry/src/main/ets/InputMethodExtensionAbility/model/KeyState.ets b/entry/src/main/ets/InputMethodExtensionAbility/model/KeyState.ets new file mode 100644 index 0000000..33cde82 --- /dev/null +++ b/entry/src/main/ets/InputMethodExtensionAbility/model/KeyState.ets @@ -0,0 +1,47 @@ +import { KeyEvent } from "@kit.InputKit"; + +/** + * translated from + * [fcitx-utils/keysym.h](https://github.com/fcitx/fcitx5/blob/0346e58/src/lib/fcitx-utils/keysym.h) + */ +export enum KeyState { + NO_STATE = 0, + SHIFT = 1 << 0, + CAPS_LOCK = 1 << 1, + CTRL = 1 << 2, + ALT = 1 << 3, + MOD_1 = ALT, + ALT_SHIFT = ALT | SHIFT, + CTRL_SHIFT = CTRL | SHIFT, + CTRL_ALT = CTRL | ALT, + CTRL_ALT_SHIFT = CTRL | ALT | SHIFT, + NUM_LOCK = 1 << 4, + MOD_2 = NUM_LOCK, + HYPER = 1 << 5, + MOD_3 = HYPER, + SUPER = 1 << 6, + MOD_4 = SUPER, + MOD_5 = 1 << 7, + MOUSE_PRESSED = 1 << 8, + HANDLED_MASK = 1 << 24, + IGNORED_MASK = 1 << 25, + SUPER_2 = 1 << 26, // Gtk virtual Super + HYPER_2 = 1 << 27, // Gtk virtual Hyper + META = 1 << 28, + VIRTUAL = 1 << 29, + + REPEAT = 1 << 31, + USED_MASK = 0x5c001fff, + SIMPLE_MASK = CTRL_ALT_SHIFT | SUPER | SUPER_2 | HYPER | META +} + +export function statesFromKeyEvent(e: KeyEvent): number { + let states = KeyState.NO_STATE + if (e.altKey) states |= KeyState.ALT + if (e.ctrlKey) states |= KeyState.CTRL + if (e.shiftKey) states |= KeyState.SHIFT + if (e.capsLock) states |= KeyState.CAPS_LOCK + if (e.numLock) states |= KeyState.NUM_LOCK + if (e.logoKey) states |= KeyState.META + return states +} \ No newline at end of file diff --git a/entry/src/main/ets/InputMethodExtensionAbility/model/KeyboardController.ets b/entry/src/main/ets/InputMethodExtensionAbility/model/KeyboardController.ets index 13f3bf0..6289e1e 100644 --- a/entry/src/main/ets/InputMethodExtensionAbility/model/KeyboardController.ets +++ b/entry/src/main/ets/InputMethodExtensionAbility/model/KeyboardController.ets @@ -2,12 +2,13 @@ import { webview } from '@kit.ArkWeb'; import type { InputMethodExtensionContext } from '@kit.IMEKit'; import { inputMethodEngine } from '@kit.IMEKit'; import { display } from '@kit.ArkUI'; -import { KeyCode } from '@kit.InputKit'; +import { Action, KeyAction, KeyCode, KeyEvent } from '@kit.InputKit'; import { SystemEvent, VirtualKeyboardEvent } from '../../../fcitx5-keyboard-web/src/api'; import fcitx, { InputContextState } from 'libentry.so'; import { FcitxEvent } from './FcitxEvent'; import { convertCode } from './keycode'; import { onTextChange, redo, resetStacks, undo } from './TextOperation'; +import { KeyState, statesFromKeyEvent } from './KeyState'; const ability: inputMethodEngine.InputMethodAbility = inputMethodEngine.getInputMethodAbility(); const keyboardDelegate = inputMethodEngine.getKeyboardDelegate() // Physical keyboard @@ -278,7 +279,7 @@ export class KeyboardController { } public handleKey(key: string, keyCode?: number): void { - const res = fcitx.processKey(key ? key.charCodeAt(0) : 0, keyCode ?? 0, false) + const res = fcitx.processKey(key ? key.charCodeAt(0) : 0, keyCode ?? 0, KeyState.VIRTUAL, false) if (!this.processResult(res)) { switch (keyCode) { // Check code first as enter has to be handled differently, which has key \r. case KeyCode.KEYCODE_DEL: @@ -391,10 +392,19 @@ export class KeyboardController { }) } - private physicalKeyEventHandler(e: inputMethodEngine.KeyEvent): boolean { - const isRelease = e.keyAction === 3 - const res = fcitx.processKey(0, e.keyCode, isRelease) - return this.processResult(res) + private physicalKeyEventHandler(e: KeyEvent): boolean { + const isRelease = e.action.valueOf() === Action.UP + const states = statesFromKeyEvent(e) + const charCode = e.unicodeChar + if (charCode > 0 && charCode !== '\t'.charCodeAt(0) && charCode !== '\n'.charCodeAt(0)) { + const res = fcitx.processKey(charCode, 0, states, isRelease) + return this.processResult(res) + } + if (e.key.code != KeyCode.KEYCODE_UNKNOWN) { + const res = fcitx.processKey(0, e.key.code, states, isRelease) + return this.processResult(res) + } + return false } private initHelper() { @@ -414,10 +424,7 @@ export class KeyboardController { private registerListener(): void { this.registerInputListener(); - keyboardDelegate.on('keyDown', (e) => { - return this.physicalKeyEventHandler(e) - }) - keyboardDelegate.on('keyUp', (e) => { + keyboardDelegate.on('keyEvent', (e) => { return this.physicalKeyEventHandler(e) }) // This is not called on focus. @@ -471,8 +478,7 @@ export class KeyboardController { ability.off('inputStart'); ability.off('inputStop', () => { }); - keyboardDelegate.off('keyDown') - keyboardDelegate.off('keyUp') + keyboardDelegate.off('keyEvent') keyboardDelegate.off('textChange') this.panel?.off('show') this.panel?.off('hide')