From d03ab9fef16e5c086c70218cf8382bf81dee83cd Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Mon, 7 Jan 2019 14:26:16 +0700 Subject: [PATCH 1/3] Pass "tab" and "enter" back to Android app to handle Instead of KMW inserting whitespace, pass those keys back to the embedded app to natively handle. --- .../KMEA/app/src/main/assets/keyboard.html | 3 + .../kmea/KMHardwareKeyboardInterpreter.java | 110 +---------------- .../tavultesoft/kmea/KMKeyboardJSHandler.java | 3 + .../java/com/tavultesoft/kmea/KMManager.java | 75 +++++++++++- .../com/tavultesoft/kmea/KMScanCodeMap.java | 115 ++++++++++++++++++ web/source/kmwembedded.ts | 10 +- 6 files changed, 201 insertions(+), 115 deletions(-) create mode 100644 android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMScanCodeMap.java diff --git a/android/KMEA/app/src/main/assets/keyboard.html b/android/KMEA/app/src/main/assets/keyboard.html index 9c3fee21d4..27005362cf 100644 --- a/android/KMEA/app/src/main/assets/keyboard.html +++ b/android/KMEA/app/src/main/assets/keyboard.html @@ -221,6 +221,9 @@ //window.console.log('executeHardwareKeystroke:('+code+', ' + shift + ', ' + lstates + ');'); try { var r = kmw['executeHardwareKeystroke'](code, shift, lstates); + if (r == false) { + var k = window.jsInterface.dispatchKey(code, shift); + } //window.console.log('executeHardwareKeystroke completed with '+r); } catch(e) { window.console.log('executeHardwareKeystroke exception: '+e); diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMHardwareKeyboardInterpreter.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMHardwareKeyboardInterpreter.java index 8346efa266..6d523f903e 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMHardwareKeyboardInterpreter.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMHardwareKeyboardInterpreter.java @@ -4,119 +4,13 @@ package com.tavultesoft.kmea; +import com.tavultesoft.kmea.KMScanCodeMap; import android.content.Context; import android.view.KeyEvent; public class KMHardwareKeyboardInterpreter implements KeyEvent.Callback { - /** - * Maps relevant keycodes from android.view.keyevent to the standard keycodes used by Keyman - * keyboards. Is conveniently based at 0, else we might need to HashMap it instead. - */ - /** - * From reference: https://source.android.com/devices/input#understanding-hid-usages-and-event-codes - * The Android API sometimes refers to the Linux key code associated with a key as its "scan code". - * This is technically incorrect in but it helps to distinguish Linux key codes from Android - * key codes in the API. - * - * Maps relevant Linux key code (LKC) to the standard key codes used by Keyman keyboards - * Table: https://source.android.com/devices/input/keyboard-devices - * - * Limitations: Intentionally not assigning number pad keys - */ - private static final - int scanCodeMap[] = { - 0, // padding = 0x00; - 0, // public static final int KEY_ESC = 0x01; - '1', // public static final int KEY_1 = 0x02; - '2', // public static final int KEY_2 = 0x03; - '3', // public static final int KEY_3 = 0x04; - '4', // public static final int KEY_4 = 0x05; - '5', // public static final int KEY_5 = 0x06; - '6', // public static final int KEY_6 = 0x07; - '7', // public static final int KEY_7 = 0x08; - '8', // public static final int KEY_8 = 0x09; - '9', // public static final int KEY_9 = 0x0A; - '0', // public static final int KEY_0 = 0x0B; - 189, // public static final int KEY_MINUS = 0x0C; - 187, // public static final int KEY_EQUALS = 0x0D; - 8, // public static final int KEY_BACKSPACE = 0x0E; - 9, // public static final int KEY_TAB = 0x0F; - 'Q', // public static final int KEY_Q = 0x10; - 'W', // public static final int KEY_W = 0x11; - 'E', // public static final int KEY_E = 0x12; - 'R', // public static final int KEY_R = 0x13; - 'T', // public static final int KEY_T = 0x14; - 'Y', // public static final int KEY_Y = 0x15; - 'U', // public static final int KEY_U = 0x16; - 'I', // public static final int KEY_I = 0x17; - 'O', // public static final int KEY_O = 0x18; - 'P', // public static final int KEY_P = 0x19; - 219, // public static final int KEY_LEFTBRACE = 0x1A; - 221, // public static final int KEY_RIGHTBRACE = 0x1B; - 13, // public static final int KEY_ENTER = 0x1C; - 0, // public static final int KEY_LEFTCTRL = 0x1D; - 'A', // public static final int KEY_A = 0x1E; - 'S', // public static final int KEY_S = 0x1F; - 'D', // public static final int KEY_D = 0x20; - 'F', // public static final int KEY_F = 0x21; - 'G', // public static final int KEY_G = 0x22; - 'H', // public static final int KEY_H = 0x23; - 'J', // public static final int KEY_J = 0x24; - 'K', // public static final int KEY_K = 0x25; - 'L', // public static final int KEY_L = 0x26; - 186, // public static final int KEY_SEMICOLON = 0x27; - 222, // public static final int KEY_APOSTROPHE = 0x28; - 192, // public static final int KEY_GRAVE = 0x29; - 0, // public static final int KEY_LEFTSHIFT = 0x2A; - 220, // public static final int KEY_BACKSLASH = 0x2B; - 'Z', // public static final int KEY_Z = 0x2C; - 'X', // public static final int KEY_X = 0x2D; - 'C', // public static final int KEY_C = 0x2E; - 'V', // public static final int KEY_V = 0x2F; - 'B', // public static final int KEY_B = 0x30; - 'N', // public static final int KEY_N = 0x31; - 'M', // public static final int KEY_M = 0x32; - 188, // public static final int KEY_COMMA = 0x33; - 190, // public static final int KEY_DOT = 0x34; - 191, // public static final int KEY_SLASH = 0x35; - 0, // public static final int KEY_RIGHTSHIFT = 0x36; - 0, // public static final int KEY_KPASTERISK = 0x37; - 0, // public static final int KEY_LEFTALT = 0x38; - 32, // public static final int KEY_SPACE = 0x39; - 0, // public static final int KEY_CAPSLOCK = 0x3A; - 0, // public static final int KEY_F1 = 0x3B; - 0, // public static final int KEY_F2 = 0x3C; - 0, // public static final int KEY_F3 = 0x3D; - 0, // public static final int KEY_F4 = 0x3E; - 0, // public static final int KEY_F5 = 0x3F; - 0, // public static final int KEY_F6 = 0x40; - 0, // public static final int KEY_F7 = 0x41; - 0, // public static final int KEY_F8 = 0x42; - 0, // public static final int KEY_F9 = 0x43; - 0, // public static final int KEY_F10 = 0x44; - 0, // public static final int KEY_NUMLOCK = 0x45; - 0, // public static final int KEY_SCROLLLOCK = 0x46; - 0, // public static final int KEY_KP7 = 0x47; - 0, // public static final int KEY_KP8 = 0x48; - 0, // public static final int KEY_KP9 = 0x49; - 0, // public static final int KEY_KPMINUS = 0x4A; - 0, // public static final int KEY_KP4 = 0x4B; - 0, // public static final int KEY_KP5 = 0x4C; - 0, // public static final int KEY_KP6 = 0x4D; - 0, // public static final int KEY_KPPLUS = 0x4E; - 0, // public static final int KEY_KP1 = 0x4F; - 0, // public static final int KEY_KP2 = 0x50; - 0, // public static final int KEY_KP3 = 0x51; - 0, // public static final int KEY_KP0 = 0x52; - 0, // public static final int KEY_KPDOT = 0x53; - 0, // padding 0x54; - 0, // public static final int KEY_ZENKAKUHANKAKU = 0x55; - 226 // public static final int KEY_102ND = 0x56; - - // Many more KEYS currently not used by KMW... - }; private final Context context; private final KMManager.KeyboardType keyboardType; @@ -169,7 +63,7 @@ public class KMHardwareKeyboardInterpreter implements KeyEvent.Callback { // Range check scanCode. If it's beyond our expected range, just use "0" int scanCode = event.getScanCode(); - int code = (scanCode >= 0 && scanCode < scanCodeMap.length) ? scanCodeMap[scanCode] : 0 ; + int code = (scanCode >= 0 && scanCode < KMScanCodeMap.scanCodeMap.length) ? KMScanCodeMap.scanCodeMap[scanCode] : 0 ; if (code == 0) { // Not an alphanumeric, punctuation or enter/tab/space key return false; diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardJSHandler.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardJSHandler.java index 9e3025f3e2..83e6b601f0 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardJSHandler.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardJSHandler.java @@ -63,6 +63,9 @@ public abstract class KMKeyboardJSHandler { } } + @JavascriptInterface + public abstract boolean dispatchKey(final int code, final int shift); + // Insert the selected string s @JavascriptInterface public abstract void insertText(final int dn, final String s); diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index fdd9b691ea..8a00e1135a 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -52,6 +52,7 @@ import com.tavultesoft.kmea.KMKeyboardJSHandler; import com.tavultesoft.kmea.KeyboardEventHandler.EventType; import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardEventListener; import com.tavultesoft.kmea.packages.PackageProcessor; +import com.tavultesoft.kmea.KMScanCodeMap; import com.tavultesoft.kmea.util.FileUtils; import org.json.JSONObject; @@ -1461,6 +1462,39 @@ public final class KMManager { KMInAppKeyboardJSHandler(Context context, KMKeyboard k) { super(context, k); } + private static final String HANDLER_TAG = "IAK: JS Handler"; + + @JavascriptInterface + public boolean dispatchKey(final int code, final int shift) { + Handler mainLoop = new Handler(Looper.getMainLooper()); + mainLoop.post(new Runnable() { + public void run() { + if (InAppKeyboard.subKeysWindow != null || KMTextView.activeView == null || KMTextView.activeView.getClass() != KMTextView.class) { + if ((KMTextView.activeView == null) && isDebugMode()) { + Log.w(HANDLER_TAG, "dispatchKey failed: activeView is null"); + } + return; + } + + // Handle tab or enter since KMW didn't process it + Log.d(HANDLER_TAG, "dispatchKey called with code: " + code); + KMTextView textView = (KMTextView) KMTextView.activeView; + KeyEvent event = null; + if (code == KMScanCodeMap.scanCodeMap[KMScanCodeMap.KEY_TAB]) { + Log.d(HANDLER_TAG, "Dispatching KeyEvent.KEYCODE_TAB"); + event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_TAB, 0, 0, 0, 0, 0); + } else if (code == KMScanCodeMap.scanCodeMap[KMScanCodeMap.KEY_ENTER]) { + Log.d(HANDLER_TAG, "Dispatching KeyEvent.KEYCODE_ENTER"); + event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0, 0); + } + + if (event != null) { + textView.dispatchKeyEvent(event); + } + } + }); + return true; + } // This annotation is required in Jelly Bean and later: @JavascriptInterface @@ -1552,6 +1586,45 @@ public final class KMManager { KMSystemKeyboardJSHandler(Context context, KMKeyboard k) { super(context, k); } + private static final String HANDLER_TAG = "SWK: JS Handler"; + + @JavascriptInterface + public boolean dispatchKey(final int code, final int shift) { + Handler mainLoop = new Handler(Looper.getMainLooper()); + mainLoop.post(new Runnable() { + public void run() { + if (SystemKeyboard.subKeysWindow != null) { + return; + } + + InputConnection ic = IMService.getCurrentInputConnection(); + if (ic == null) { + if (isDebugMode()) { + Log.w(HANDLER_TAG, "insertText failed: InputConnection is null"); + } + return; + } + + SystemKeyboard.dismissHelpBubble(); + + // Handle tab or enter since KMW didn't process it + Log.d(HANDLER_TAG, "dispatchKey called with code: " + code + ", shift: " + shift); + if (code == KMScanCodeMap.scanCodeMap[KMScanCodeMap.KEY_TAB]) { + Log.d(HANDLER_TAG, "Dispatching KeyEvent.KEYCODE_TAB"); + int metaState = 0; + if (shift == KMModifierCodes.get("SHIFT")) { + metaState = KeyEvent.META_SHIFT_ON; + } + KeyEvent event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_TAB, 0, metaState, 0, 0, 0); + ic.sendKeyEvent(event); + } else if (code == KMScanCodeMap.scanCodeMap[KMScanCodeMap.KEY_ENTER]) { + Log.d(HANDLER_TAG, "Dispatching KeyEvent.KEYCODE_ENTER"); + keyDownUp(KeyEvent.KEYCODE_ENTER); + } + } + }); + return true; + } // This annotation is required in Jelly Bean and later: @JavascriptInterface @@ -1566,7 +1639,7 @@ public final class KMManager { InputConnection ic = IMService.getCurrentInputConnection(); if (ic == null) { if (isDebugMode()) { - Log.w("SWK: JS Handler", "insertText failed: InputConnection is null"); + Log.w(HANDLER_TAG, "insertText failed: InputConnection is null"); } return; } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMScanCodeMap.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMScanCodeMap.java new file mode 100644 index 0000000000..3ad32fee47 --- /dev/null +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMScanCodeMap.java @@ -0,0 +1,115 @@ +package com.tavultesoft.kmea; + +public final class KMScanCodeMap { + + /** + * Maps relevant keycodes from android.view.keyevent to the standard keycodes used by Keyman + * keyboards. Is conveniently based at 0, else we might need to HashMap it instead. + */ + + /** + * From reference: https://source.android.com/devices/input#understanding-hid-usages-and-event-codes + * The Android API sometimes refers to the Linux key code associated with a key as its "scan code". + * This is technically incorrect in but it helps to distinguish Linux key codes from Android + * key codes in the API. + * + * Maps relevant Linux key code (LKC) to the standard key codes used by Keyman keyboards + * Table: https://source.android.com/devices/input/keyboard-devices + * + * Limitations: Intentionally not assigning number pad keys + */ + final static int scanCodeMap[] = { + 0, // padding = 0x00; + 0, // public static final int KEY_ESC = 0x01; + '1', // public static final int KEY_1 = 0x02; + '2', // public static final int KEY_2 = 0x03; + '3', // public static final int KEY_3 = 0x04; + '4', // public static final int KEY_4 = 0x05; + '5', // public static final int KEY_5 = 0x06; + '6', // public static final int KEY_6 = 0x07; + '7', // public static final int KEY_7 = 0x08; + '8', // public static final int KEY_8 = 0x09; + '9', // public static final int KEY_9 = 0x0A; + '0', // public static final int KEY_0 = 0x0B; + 189, // public static final int KEY_MINUS = 0x0C; + 187, // public static final int KEY_EQUALS = 0x0D; + 8, // public static final int KEY_BACKSPACE = 0x0E; + 9, // public static final int KEY_TAB = 0x0F; + 'Q', // public static final int KEY_Q = 0x10; + 'W', // public static final int KEY_W = 0x11; + 'E', // public static final int KEY_E = 0x12; + 'R', // public static final int KEY_R = 0x13; + 'T', // public static final int KEY_T = 0x14; + 'Y', // public static final int KEY_Y = 0x15; + 'U', // public static final int KEY_U = 0x16; + 'I', // public static final int KEY_I = 0x17; + 'O', // public static final int KEY_O = 0x18; + 'P', // public static final int KEY_P = 0x19; + 219, // public static final int KEY_LEFTBRACE = 0x1A; + 221, // public static final int KEY_RIGHTBRACE = 0x1B; + 13, // public static final int KEY_ENTER = 0x1C; + 0, // public static final int KEY_LEFTCTRL = 0x1D; + 'A', // public static final int KEY_A = 0x1E; + 'S', // public static final int KEY_S = 0x1F; + 'D', // public static final int KEY_D = 0x20; + 'F', // public static final int KEY_F = 0x21; + 'G', // public static final int KEY_G = 0x22; + 'H', // public static final int KEY_H = 0x23; + 'J', // public static final int KEY_J = 0x24; + 'K', // public static final int KEY_K = 0x25; + 'L', // public static final int KEY_L = 0x26; + 186, // public static final int KEY_SEMICOLON = 0x27; + 222, // public static final int KEY_APOSTROPHE = 0x28; + 192, // public static final int KEY_GRAVE = 0x29; + 0, // public static final int KEY_LEFTSHIFT = 0x2A; + 220, // public static final int KEY_BACKSLASH = 0x2B; + 'Z', // public static final int KEY_Z = 0x2C; + 'X', // public static final int KEY_X = 0x2D; + 'C', // public static final int KEY_C = 0x2E; + 'V', // public static final int KEY_V = 0x2F; + 'B', // public static final int KEY_B = 0x30; + 'N', // public static final int KEY_N = 0x31; + 'M', // public static final int KEY_M = 0x32; + 188, // public static final int KEY_COMMA = 0x33; + 190, // public static final int KEY_DOT = 0x34; + 191, // public static final int KEY_SLASH = 0x35; + 0, // public static final int KEY_RIGHTSHIFT = 0x36; + 0, // public static final int KEY_KPASTERISK = 0x37; + 0, // public static final int KEY_LEFTALT = 0x38; + 32, // public static final int KEY_SPACE = 0x39; + 0, // public static final int KEY_CAPSLOCK = 0x3A; + 0, // public static final int KEY_F1 = 0x3B; + 0, // public static final int KEY_F2 = 0x3C; + 0, // public static final int KEY_F3 = 0x3D; + 0, // public static final int KEY_F4 = 0x3E; + 0, // public static final int KEY_F5 = 0x3F; + 0, // public static final int KEY_F6 = 0x40; + 0, // public static final int KEY_F7 = 0x41; + 0, // public static final int KEY_F8 = 0x42; + 0, // public static final int KEY_F9 = 0x43; + 0, // public static final int KEY_F10 = 0x44; + 0, // public static final int KEY_NUMLOCK = 0x45; + 0, // public static final int KEY_SCROLLLOCK = 0x46; + 0, // public static final int KEY_KP7 = 0x47; + 0, // public static final int KEY_KP8 = 0x48; + 0, // public static final int KEY_KP9 = 0x49; + 0, // public static final int KEY_KPMINUS = 0x4A; + 0, // public static final int KEY_KP4 = 0x4B; + 0, // public static final int KEY_KP5 = 0x4C; + 0, // public static final int KEY_KP6 = 0x4D; + 0, // public static final int KEY_KPPLUS = 0x4E; + 0, // public static final int KEY_KP1 = 0x4F; + 0, // public static final int KEY_KP2 = 0x50; + 0, // public static final int KEY_KP3 = 0x51; + 0, // public static final int KEY_KP0 = 0x52; + 0, // public static final int KEY_KPDOT = 0x53; + 0, // padding 0x54; + 0, // public static final int KEY_ZENKAKUHANKAKU = 0x55; + 226 // public static final int KEY_102ND = 0x56; + + // Many more KEYS currently not used by KMW... + }; + + final static int KEY_TAB = 0x0F; + final static int KEY_ENTER = 0x1C; +} \ No newline at end of file diff --git a/web/source/kmwembedded.ts b/web/source/kmwembedded.ts index 6750afea84..c081c2ae3d 100644 --- a/web/source/kmwembedded.ts +++ b/web/source/kmwembedded.ts @@ -579,15 +579,12 @@ * @return {boolean} true if key code successfully processed */ keymanweb.processDefaultMapping = function(code, shift, Lelem, keyName) { + // Default handling for external keys. + // Intentionally not assigning K_TAB or K_ENTER so KMW will pass them back + // to the mobile apps to handle (insert characters or navigate forms). if (code == osk.keyCodes.K_SPACE) { kbdInterface.output(0, Lelem, ' '); return true; - } else if (code == osk.keyCodes.K_ENTER) { - kbdInterface.output(0, Lelem, '\n'); - return true; - } else if (code == osk.keyCodes.K_TAB) { - kbdInterface.output(0, Lelem, '\t'); - return true; } else if (code == osk.keyCodes.K_BKSP) { kbdInterface.defaultBackspace(); return true; @@ -601,6 +598,7 @@ return true; } + // Determine the character from the OSK var ch = osk.defaultKeyOutput(keyName, code, shift, false, undefined); if(ch) { kbdInterface.output(0, Lelem, ch); From 77571ab55594de300172e9fc4956f03748a51789 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Fri, 11 Jan 2019 14:56:11 +0700 Subject: [PATCH 2/3] Pass original eventModifiers to dispatchKey() --- .../KMEA/app/src/main/assets/keyboard.html | 5 ++- .../kmea/KMHardwareKeyboardInterpreter.java | 2 +- .../java/com/tavultesoft/kmea/KMKeyboard.java | 6 +-- .../tavultesoft/kmea/KMKeyboardJSHandler.java | 2 +- .../java/com/tavultesoft/kmea/KMManager.java | 41 +++++++------------ 5 files changed, 23 insertions(+), 33 deletions(-) diff --git a/android/KMEA/app/src/main/assets/keyboard.html b/android/KMEA/app/src/main/assets/keyboard.html index 27005362cf..16871a39de 100644 --- a/android/KMEA/app/src/main/assets/keyboard.html +++ b/android/KMEA/app/src/main/assets/keyboard.html @@ -216,13 +216,14 @@ kmw['executePopupKey'](keyID); } - function executeHardwareKeystroke(code, shift, lstates) { + function executeHardwareKeystroke(code, shift, lstates, eventModifiers) { var kmw=window['keyman']; //window.console.log('executeHardwareKeystroke:('+code+', ' + shift + ', ' + lstates + ');'); try { var r = kmw['executeHardwareKeystroke'](code, shift, lstates); if (r == false) { - var k = window.jsInterface.dispatchKey(code, shift); + // KMW didn't process the key, so have the Android app dispatch the key with the original event modifiers + var k = window.jsInterface.dispatchKey(code, eventModifiers); } //window.console.log('executeHardwareKeystroke completed with '+r); } catch(e) { diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMHardwareKeyboardInterpreter.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMHardwareKeyboardInterpreter.java index 6d523f903e..ab3f0c536d 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMHardwareKeyboardInterpreter.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMHardwareKeyboardInterpreter.java @@ -70,7 +70,7 @@ public class KMHardwareKeyboardInterpreter implements KeyEvent.Callback { } // Send keystroke to KeymanWeb for processing: will return true to swallow the keystroke - return KMManager.executeHardwareKeystroke(code, keymanModifiers, keyboardType, Lstates); + return KMManager.executeHardwareKeystroke(code, keymanModifiers, keyboardType, Lstates, androidModifiers); } @Override diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java index d7005a127f..b60612aed5 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java @@ -175,9 +175,9 @@ final class KMKeyboard extends WebView { loadUrl(jsString); } - public void executeHardwareKeystroke(int code, int shift, int lstates) { - String jsFormat = "javascript:executeHardwareKeystroke(%d,%d, %d)"; - String jsString = String.format(jsFormat, code, shift, lstates); + public void executeHardwareKeystroke(int code, int shift, int lstates, int eventModifiers) { + String jsFormat = "javascript:executeHardwareKeystroke(%d,%d, %d, %d)"; + String jsString = String.format(jsFormat, code, shift, lstates, eventModifiers); loadUrl(jsString); } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardJSHandler.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardJSHandler.java index 83e6b601f0..d766105f9f 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardJSHandler.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardJSHandler.java @@ -64,7 +64,7 @@ public abstract class KMKeyboardJSHandler { } @JavascriptInterface - public abstract boolean dispatchKey(final int code, final int shift); + public abstract boolean dispatchKey(final int code, final int eventModifiers); // Insert the selected string s @JavascriptInterface diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index 8a00e1135a..d0529b8e1e 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -199,23 +199,23 @@ public final class KMManager { IMService = service; } - public static boolean executeHardwareKeystroke(int code, int shift, int lstates) { + public static boolean executeHardwareKeystroke(int code, int shift, int lstates, int eventModifiers) { if (SystemKeyboard != null) { - return executeHardwareKeystroke(code, shift, KeyboardType.KEYBOARD_TYPE_SYSTEM, lstates); + return executeHardwareKeystroke(code, shift, KeyboardType.KEYBOARD_TYPE_SYSTEM, lstates, eventModifiers); } else if (InAppKeyboard != null) { - return executeHardwareKeystroke(code, shift, KeyboardType.KEYBOARD_TYPE_INAPP, lstates); + return executeHardwareKeystroke(code, shift, KeyboardType.KEYBOARD_TYPE_INAPP, lstates, eventModifiers); } return false; } public static boolean executeHardwareKeystroke( - int code, int shift, KeyboardType keyboard, int lstates) { + int code, int shift, KeyboardType keyboard, int lstates, int eventModifiers) { if (keyboard == KeyboardType.KEYBOARD_TYPE_INAPP) { - InAppKeyboard.executeHardwareKeystroke(code, shift, lstates); + InAppKeyboard.executeHardwareKeystroke(code, shift, lstates, eventModifiers); return true; } else if (keyboard == KeyboardType.KEYBOARD_TYPE_SYSTEM) { - SystemKeyboard.executeHardwareKeystroke(code, shift, lstates); + SystemKeyboard.executeHardwareKeystroke(code, shift, lstates, eventModifiers); return true; } @@ -1465,7 +1465,7 @@ public final class KMManager { private static final String HANDLER_TAG = "IAK: JS Handler"; @JavascriptInterface - public boolean dispatchKey(final int code, final int shift) { + public boolean dispatchKey(final int code, final int eventModifiers) { Handler mainLoop = new Handler(Looper.getMainLooper()); mainLoop.post(new Runnable() { public void run() { @@ -1477,18 +1477,12 @@ public final class KMManager { } // Handle tab or enter since KMW didn't process it - Log.d(HANDLER_TAG, "dispatchKey called with code: " + code); KMTextView textView = (KMTextView) KMTextView.activeView; - KeyEvent event = null; if (code == KMScanCodeMap.scanCodeMap[KMScanCodeMap.KEY_TAB]) { - Log.d(HANDLER_TAG, "Dispatching KeyEvent.KEYCODE_TAB"); - event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_TAB, 0, 0, 0, 0, 0); + KeyEvent event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_TAB, 0, eventModifiers, 0, 0, 0); + textView.dispatchKeyEvent(event); } else if (code == KMScanCodeMap.scanCodeMap[KMScanCodeMap.KEY_ENTER]) { - Log.d(HANDLER_TAG, "Dispatching KeyEvent.KEYCODE_ENTER"); - event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0, 0); - } - - if (event != null) { + KeyEvent event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_ENTER, 0, eventModifiers, 0, 0, 0); textView.dispatchKeyEvent(event); } } @@ -1589,7 +1583,7 @@ public final class KMManager { private static final String HANDLER_TAG = "SWK: JS Handler"; @JavascriptInterface - public boolean dispatchKey(final int code, final int shift) { + public boolean dispatchKey(final int code, final int eventModifiers) { Handler mainLoop = new Handler(Looper.getMainLooper()); mainLoop.post(new Runnable() { public void run() { @@ -1608,18 +1602,13 @@ public final class KMManager { SystemKeyboard.dismissHelpBubble(); // Handle tab or enter since KMW didn't process it - Log.d(HANDLER_TAG, "dispatchKey called with code: " + code + ", shift: " + shift); + Log.d(HANDLER_TAG, "dispatchKey called with code: " + code + ", eventModifiers: " + eventModifiers); if (code == KMScanCodeMap.scanCodeMap[KMScanCodeMap.KEY_TAB]) { - Log.d(HANDLER_TAG, "Dispatching KeyEvent.KEYCODE_TAB"); - int metaState = 0; - if (shift == KMModifierCodes.get("SHIFT")) { - metaState = KeyEvent.META_SHIFT_ON; - } - KeyEvent event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_TAB, 0, metaState, 0, 0, 0); + KeyEvent event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_TAB, 0, eventModifiers, 0, 0, 0); ic.sendKeyEvent(event); } else if (code == KMScanCodeMap.scanCodeMap[KMScanCodeMap.KEY_ENTER]) { - Log.d(HANDLER_TAG, "Dispatching KeyEvent.KEYCODE_ENTER"); - keyDownUp(KeyEvent.KEYCODE_ENTER); + KeyEvent event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_ENTER, 0, eventModifiers, 0, 0, 0); + ic.sendKeyEvent(event); } } }); From 8b9c71bc9b1aa5a38fc7d9827be0f8e1a27d0532 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Mon, 14 Jan 2019 18:41:34 +0700 Subject: [PATCH 3/3] Cleanup from review comments --- android/KMEA/app/src/main/assets/keyboard.html | 6 ++---- android/history.md | 8 +++++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/android/KMEA/app/src/main/assets/keyboard.html b/android/KMEA/app/src/main/assets/keyboard.html index 16871a39de..88cccf60d0 100644 --- a/android/KMEA/app/src/main/assets/keyboard.html +++ b/android/KMEA/app/src/main/assets/keyboard.html @@ -220,12 +220,10 @@ var kmw=window['keyman']; //window.console.log('executeHardwareKeystroke:('+code+', ' + shift + ', ' + lstates + ');'); try { - var r = kmw['executeHardwareKeystroke'](code, shift, lstates); - if (r == false) { + if (!kmw['executeHardwareKeystroke'](code, shift, lstates)) { // KMW didn't process the key, so have the Android app dispatch the key with the original event modifiers - var k = window.jsInterface.dispatchKey(code, eventModifiers); + window.jsInterface.dispatchKey(code, eventModifiers); } - //window.console.log('executeHardwareKeystroke completed with '+r); } catch(e) { window.console.log('executeHardwareKeystroke exception: '+e); } diff --git a/android/history.md b/android/history.md index 7d0a1b2bbb..c97372da44 100644 --- a/android/history.md +++ b/android/history.md @@ -1,12 +1,14 @@ # Keyman for Android -## 2019-01-11 11.0.2055 beta -* Fix keyboard version comparison that was causing "Unable to contact Keyman server" notifications (#1520) +## 2019-01-14 11.0.2055 beta +* Keyman for Android 11 requires a minimum version of Android 4.1 (Jelly Bean) (#1532) +* When KMW doesn't process external "tab" or "enter" keys, have the Android app dispatch the keys () ## 2019-01-10 11.0.2054 beta -* Fix "Get Started" default keyboard status on engineering builds (#1515) +* Fix keyboard version comparison that was causing "Unable to contact Keyman server" notifications (#1520) ## 2019-01-09 11.0.2053 beta +* Fix "Get Started" default keyboard status on engineering builds (#1515) * Fix crash involving certain fonts. Prioritize using .ttf font in keyboards (#1507) ## 2019-01-04 11.0.2052 beta