From a37de668c05a957ba8546b4659d8d61695fda258 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 14 Jun 2025 11:29:26 +0200 Subject: [PATCH] enable hardware keyboard handling again, with improved handling --- .../java/helium314/keyboard/event/Event.kt | 4 +- .../event/HardwareKeyboardEventDecoder.kt | 4 +- .../keyboard_parser/floris/KeyCode.kt | 124 +++++++++--------- .../keyboard/latin/define/ProductionFlags.kt | 8 +- .../keyboard/latin/inputlogic/InputLogic.java | 33 +++-- 5 files changed, 86 insertions(+), 87 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/event/Event.kt b/app/src/main/java/helium314/keyboard/event/Event.kt index 75fda0535..5903b0c9f 100644 --- a/app/src/main/java/helium314/keyboard/event/Event.kt +++ b/app/src/main/java/helium314/keyboard/event/Event.kt @@ -256,10 +256,8 @@ class Event private constructor( source.mX, source.mY, source.mSuggestedWordInfo, source.mFlags or FLAG_COMBINING, source.mNextEvent) } - fun createNotHandledEvent(): Event { - return Event(EVENT_TYPE_NOT_HANDLED, null, NOT_A_CODE_POINT, NOT_A_KEY_CODE, 0, + val notHandledEvent = Event(EVENT_TYPE_NOT_HANDLED, null, NOT_A_CODE_POINT, NOT_A_KEY_CODE, 0, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, null, FLAG_NONE, null) - } } // This method is private - to create a new event, use one of the create* utility methods. diff --git a/app/src/main/java/helium314/keyboard/event/HardwareKeyboardEventDecoder.kt b/app/src/main/java/helium314/keyboard/event/HardwareKeyboardEventDecoder.kt index 2742ee193..45dcc27b4 100644 --- a/app/src/main/java/helium314/keyboard/event/HardwareKeyboardEventDecoder.kt +++ b/app/src/main/java/helium314/keyboard/event/HardwareKeyboardEventDecoder.kt @@ -48,6 +48,8 @@ class HardwareKeyboardEventDecoder(val mDeviceId: Int) : HardwareEventDecoder { } else Event.createHardwareKeypressEvent(codePointAndFlags, keyCode, metaState, null, isKeyRepeat) // If not Enter, then this is just a regular keypress event for a normal character // that can be committed right away, taking into account the current state. - } else Event.createNotHandledEvent() + } else { + Event.notHandledEvent + } } } diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt index 1488faaf5..cf34b4228 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt @@ -210,66 +210,11 @@ object KeyCode { // todo: there are many more keys, see near https://developer.android.com/reference/android/view/KeyEvent#KEYCODE_0 /** - * Convert a keyCode / codePoint to a KeyEvent.KEYCODE_. - * Fallback to KeyEvent.KEYCODE_UNKNOWN. + * Convert an internal keyCode to a KeyEvent.KEYCODE_. + * Positive codes are passed through, unknown negative codes result in KeyEvent.KEYCODE_UNKNOWN. * To be uses for fake hardware key press. - * */ - fun Int.toKeyEventCode(): Int = if (this > 0) - when (this.toChar().uppercaseChar()) { - '/' -> KeyEvent.KEYCODE_SLASH - '\\' -> KeyEvent.KEYCODE_BACKSLASH - ';' -> KeyEvent.KEYCODE_SEMICOLON - ',' -> KeyEvent.KEYCODE_COMMA - '.' -> KeyEvent.KEYCODE_PERIOD - '\'' -> KeyEvent.KEYCODE_APOSTROPHE - '`' -> KeyEvent.KEYCODE_GRAVE - '*' -> KeyEvent.KEYCODE_STAR - ']' -> KeyEvent.KEYCODE_RIGHT_BRACKET - '[' -> KeyEvent.KEYCODE_LEFT_BRACKET - '+' -> KeyEvent.KEYCODE_PLUS - '-' -> KeyEvent.KEYCODE_MINUS - '=' -> KeyEvent.KEYCODE_EQUALS - '\n' -> KeyEvent.KEYCODE_ENTER - '\t' -> KeyEvent.KEYCODE_TAB - '0' -> KeyEvent.KEYCODE_0 - '1' -> KeyEvent.KEYCODE_1 - '2' -> KeyEvent.KEYCODE_2 - '3' -> KeyEvent.KEYCODE_3 - '4' -> KeyEvent.KEYCODE_4 - '5' -> KeyEvent.KEYCODE_5 - '6' -> KeyEvent.KEYCODE_6 - '7' -> KeyEvent.KEYCODE_7 - '8' -> KeyEvent.KEYCODE_8 - '9' -> KeyEvent.KEYCODE_9 - 'A' -> KeyEvent.KEYCODE_A - 'B' -> KeyEvent.KEYCODE_B - 'C' -> KeyEvent.KEYCODE_C - 'D' -> KeyEvent.KEYCODE_D - 'E' -> KeyEvent.KEYCODE_E - 'F' -> KeyEvent.KEYCODE_F - 'G' -> KeyEvent.KEYCODE_G - 'H' -> KeyEvent.KEYCODE_H - 'I' -> KeyEvent.KEYCODE_I - 'J' -> KeyEvent.KEYCODE_J - 'K' -> KeyEvent.KEYCODE_K - 'L' -> KeyEvent.KEYCODE_L - 'M' -> KeyEvent.KEYCODE_M - 'N' -> KeyEvent.KEYCODE_N - 'O' -> KeyEvent.KEYCODE_O - 'P' -> KeyEvent.KEYCODE_P - 'Q' -> KeyEvent.KEYCODE_Q - 'R' -> KeyEvent.KEYCODE_R - 'S' -> KeyEvent.KEYCODE_S - 'T' -> KeyEvent.KEYCODE_T - 'U' -> KeyEvent.KEYCODE_U - 'V' -> KeyEvent.KEYCODE_V - 'W' -> KeyEvent.KEYCODE_W - 'X' -> KeyEvent.KEYCODE_X - 'Y' -> KeyEvent.KEYCODE_Y - 'Z' -> KeyEvent.KEYCODE_Z - else -> KeyEvent.KEYCODE_UNKNOWN - } - else when (this) { + */ + @JvmStatic fun keyCodeToKeyEventCode(keyCode: Int) = when (keyCode) { ARROW_UP -> KeyEvent.KEYCODE_DPAD_UP ARROW_RIGHT -> KeyEvent.KEYCODE_DPAD_RIGHT ARROW_DOWN -> KeyEvent.KEYCODE_DPAD_DOWN @@ -303,6 +248,67 @@ object KeyCode { F10 -> KeyEvent.KEYCODE_F10 F11 -> KeyEvent.KEYCODE_F11 F12 -> KeyEvent.KEYCODE_F12 + else -> if (keyCode < 0) KeyEvent.KEYCODE_UNKNOWN else keyCode + } + + // todo: there are many more keys, see near https://developer.android.com/reference/android/view/KeyEvent#KEYCODE_0 + /** + * Convert a codePoint to a KeyEvent.KEYCODE_. + * Fallback to KeyEvent.KEYCODE_UNKNOWN. + * To be uses for fake hardware key press. + */ + @JvmStatic fun codePointToKeyEventCode(codePoint: Int): Int = when (codePoint.toChar().uppercaseChar()) { + '/' -> KeyEvent.KEYCODE_SLASH + '\\' -> KeyEvent.KEYCODE_BACKSLASH + ';' -> KeyEvent.KEYCODE_SEMICOLON + ',' -> KeyEvent.KEYCODE_COMMA + '.' -> KeyEvent.KEYCODE_PERIOD + '\'' -> KeyEvent.KEYCODE_APOSTROPHE + '`' -> KeyEvent.KEYCODE_GRAVE + '*' -> KeyEvent.KEYCODE_STAR + ']' -> KeyEvent.KEYCODE_RIGHT_BRACKET + '[' -> KeyEvent.KEYCODE_LEFT_BRACKET + '+' -> KeyEvent.KEYCODE_PLUS + '-' -> KeyEvent.KEYCODE_MINUS + '=' -> KeyEvent.KEYCODE_EQUALS + '\n' -> KeyEvent.KEYCODE_ENTER + '\t' -> KeyEvent.KEYCODE_TAB + '0' -> KeyEvent.KEYCODE_0 + '1' -> KeyEvent.KEYCODE_1 + '2' -> KeyEvent.KEYCODE_2 + '3' -> KeyEvent.KEYCODE_3 + '4' -> KeyEvent.KEYCODE_4 + '5' -> KeyEvent.KEYCODE_5 + '6' -> KeyEvent.KEYCODE_6 + '7' -> KeyEvent.KEYCODE_7 + '8' -> KeyEvent.KEYCODE_8 + '9' -> KeyEvent.KEYCODE_9 + 'A' -> KeyEvent.KEYCODE_A + 'B' -> KeyEvent.KEYCODE_B + 'C' -> KeyEvent.KEYCODE_C + 'D' -> KeyEvent.KEYCODE_D + 'E' -> KeyEvent.KEYCODE_E + 'F' -> KeyEvent.KEYCODE_F + 'G' -> KeyEvent.KEYCODE_G + 'H' -> KeyEvent.KEYCODE_H + 'I' -> KeyEvent.KEYCODE_I + 'J' -> KeyEvent.KEYCODE_J + 'K' -> KeyEvent.KEYCODE_K + 'L' -> KeyEvent.KEYCODE_L + 'M' -> KeyEvent.KEYCODE_M + 'N' -> KeyEvent.KEYCODE_N + 'O' -> KeyEvent.KEYCODE_O + 'P' -> KeyEvent.KEYCODE_P + 'Q' -> KeyEvent.KEYCODE_Q + 'R' -> KeyEvent.KEYCODE_R + 'S' -> KeyEvent.KEYCODE_S + 'T' -> KeyEvent.KEYCODE_T + 'U' -> KeyEvent.KEYCODE_U + 'V' -> KeyEvent.KEYCODE_V + 'W' -> KeyEvent.KEYCODE_W + 'X' -> KeyEvent.KEYCODE_X + 'Y' -> KeyEvent.KEYCODE_Y + 'Z' -> KeyEvent.KEYCODE_Z else -> KeyEvent.KEYCODE_UNKNOWN } } diff --git a/app/src/main/java/helium314/keyboard/latin/define/ProductionFlags.kt b/app/src/main/java/helium314/keyboard/latin/define/ProductionFlags.kt index d476a0426..9aeb7cc3d 100644 --- a/app/src/main/java/helium314/keyboard/latin/define/ProductionFlags.kt +++ b/app/src/main/java/helium314/keyboard/latin/define/ProductionFlags.kt @@ -7,15 +7,11 @@ package helium314.keyboard.latin.define object ProductionFlags { - const val IS_HARDWARE_KEYBOARD_SUPPORTED = false - // todo: make it work - // was set to true in hangul branch (and there is the hangul hardware event decoder in latinIme) - // but disabled again because this breaks ctrl+c / ctrl+v, and most likely other things - // so it looks like the HardwareKeyboardEventDecoder needs some work before it's ready + const val IS_HARDWARE_KEYBOARD_SUPPORTED = true /** * Include all suggestions from all dictionaries in * [helium314.keyboard.latin.SuggestedWords.mRawSuggestions]. */ const val INCLUDE_RAW_SUGGESTIONS = false -} \ No newline at end of file +} diff --git a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java index b1f8b5bca..3aeb602d9 100644 --- a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java +++ b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java @@ -643,7 +643,8 @@ public final class InputLogic { */ private void handleFunctionalEvent(final Event event, final InputTransaction inputTransaction, final String currentKeyboardScript, final LatinIME.UIHandler handler) { - switch (event.getMKeyCode()) { + final int keyCode = event.getMKeyCode(); + switch (keyCode) { case KeyCode.DELETE: handleBackspaceEvent(event, inputTransaction, currentKeyboardScript); // Backspace is a functional key, but it affects the contents of the editor. @@ -686,7 +687,7 @@ public final class InputLogic { case KeyCode.SHIFT_ENTER: // todo: try using sendDownUpKeyEventWithMetaState() and remove the key code maybe final Event tmpEvent = Event.createSoftwareKeypressEvent(Constants.CODE_ENTER, - event.getMKeyCode(), 0, event.getMX(), event.getMY(), event.isKeyRepeat()); + keyCode, 0, event.getMX(), event.getMY(), event.isKeyRepeat()); handleNonSpecialCharacterEvent(tmpEvent, inputTransaction, handler); // Shift + Enter is treated as a functional key but it results in adding a new // line, so that does affect the contents of the editor. @@ -777,23 +778,19 @@ public final class InputLogic { case KeyCode.CAPS_LOCK, KeyCode.EMOJI, KeyCode.TOGGLE_ONE_HANDED_MODE, KeyCode.SWITCH_ONE_HANDED_MODE: break; default: - if (KeyCode.INSTANCE.isModifier(event.getMKeyCode())) - return; // continuation of previous switch case, but modifiers are in a separate place - if (event.getMMetaState() != 0) { - // need to convert codepoint to KeyEvent.KEYCODE_ - final int codeToConvert = event.getMKeyCode() < 0 ? event.getMKeyCode() : event.getMCodePoint(); - int keyEventCode = KeyCode.INSTANCE.toKeyEventCode(codeToConvert); - if (keyEventCode != KeyEvent.KEYCODE_UNKNOWN) - sendDownUpKeyEventWithMetaState(keyEventCode, event.getMMetaState()); - return; // never crash if user inputs sth we don't have a KeyEvent.KEYCODE for - } else if (event.getMKeyCode() < 0) { - int keyEventCode = KeyCode.INSTANCE.toKeyEventCode(event.getMKeyCode()); - if (keyEventCode != KeyEvent.KEYCODE_UNKNOWN) { - sendDownUpKeyEvent(keyEventCode); - return; - } + if (KeyCode.INSTANCE.isModifier(keyCode)) + return; // continuation of previous switch case above, but modifiers are held in a separate place + final int keyEventCode = event.getMCodePoint() <= 0 + ? KeyCode.keyCodeToKeyEventCode(keyCode) + : KeyCode.codePointToKeyEventCode(event.getMCodePoint()); + if (keyEventCode != KeyEvent.KEYCODE_UNKNOWN) { + sendDownUpKeyEventWithMetaState(keyEventCode, event.getMMetaState()); + return; } - throw new RuntimeException("Unknown key code : " + event.getMKeyCode()); + // unknown event + Log.e(TAG, "unknown event, key code: "+keyCode+", functional: "+event.isFunctionalKeyEvent()+", meta: "+event.getMMetaState()); + if (DebugFlags.DEBUG_ENABLED) + throw new RuntimeException("Unknown event"); } }