Merge pull request #8541 from keymanapp/chore/master-to-kmcompx-merge-a17s9

chore: merge master into feature-kmcompx A17S9
This commit is contained in:
Marc Durdin 2023-03-31 14:30:46 +11:00 committed by GitHub
commit eeaea2c839
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 183 additions and 150 deletions

View file

@ -1,5 +1,29 @@
# Keyman Version History
## 17.0.79 alpha 2023-03-28
* chore(linux): Revert "Run and ignore autopkgtests on s390x" (#8506)
* docs(linux): Update minimum required Ubuntu version (#8526)
* docs(linux): Update common questions (#8532)
## 17.0.78 alpha 2023-03-27
* chore(linux): Remove python3-raven dependency (#8507)
* refactor(android/engine): Make KMKeyboardJSHandler a normal class (#8494)
## 17.0.77 alpha 2023-03-25
* chore(common): use mac /usr/bin/stat rather than homebrew version (#8498)
## 17.0.76 alpha 2023-03-24
* chore(linux): Run and ignore autopkgtests on s390x (#8492)
* refactor(android/engine): Consolidate dispatchKey (#8483)
## 17.0.75 alpha 2023-03-23
* chore(common): define BUILDER_CONFIGURATION env var (#8496)
## 17.0.74 alpha 2023-03-22
* chore(windows): update sentry-native to 0.6.0 (#8464)

View file

@ -1 +1 @@
17.0.75
17.0.80

View file

@ -23,7 +23,7 @@ import com.keyman.engine.KMManager.KeyboardType;
import com.keyman.engine.util.CharSequenceUtil;
import com.keyman.engine.util.KMLog;
public abstract class KMKeyboardJSHandler {
public class KMKeyboardJSHandler {
private Context context;
private KMKeyboard k = null;
private static int KM_VIBRATE_DURATION = 100; // milliseconds
@ -96,21 +96,13 @@ public abstract class KMKeyboardJSHandler {
return;
}
if (k.keyboardType == KeyboardType.KEYBOARD_TYPE_INAPP &&
(KMTextView.activeView == null || KMTextView.activeView.getClass() != KMTextView.class)) {
if (KMTextView.activeView == null && KMManager.isDebugMode()) {
Log.w(TAG, "insertText failed: activeView is null");
}
if (!isInappKMTextViewValid(k.keyboardType)) {
return;
}
InputConnection ic = (k.keyboardType == KeyboardType.KEYBOARD_TYPE_INAPP) ?
KMTextView.activeView.onCreateInputConnection(new EditorInfo()) :
KMManager.getInputMethodService().getCurrentInputConnection();
InputConnection ic = KMManager.getInputConnection(k.keyboardType);
if (ic == null) {
if (KMManager.isDebugMode()) {
Log.w(TAG, "insertText failed: InputConnection is null");
}
KMLog.LogError(TAG, "insertText failed: InputConnection is null");
return;
}
@ -150,7 +142,7 @@ public abstract class KMKeyboardJSHandler {
}
if (s.length() > 0 && s.charAt(0) == '\n') {
keyDownUp(KeyEvent.KEYCODE_ENTER);
keyDownUp(KeyEvent.KEYCODE_ENTER, 0);
ic.endBatchEdit();
return;
}
@ -205,15 +197,59 @@ public abstract class KMKeyboardJSHandler {
}
@JavascriptInterface
public abstract boolean dispatchKey(final int code, final int eventModifiers);
public boolean dispatchKey(final int code, final int eventModifiers) {
Handler mainLoop = new Handler(Looper.getMainLooper());
mainLoop.post(new Runnable() {
public void run() {
if (k == null) {
KMLog.LogError(TAG, "dispatchKey failed: Keyboard is null");
return;
}
private void keyDownUp(int keyEventCode) {
if (k.subKeysWindow != null) {
return;
}
if (!isInappKMTextViewValid(k.keyboardType)) {
return;
}
InputConnection ic = KMManager.getInputConnection(k.keyboardType);
if (ic == null) {
KMLog.LogError(TAG, "dispatchKey failed: InputConnection is null");
return;
}
k.dismissHelpBubble();
k.setShouldShowHelpBubble(false);
// Handle tab or enter since KMW didn't process it
if (KMManager.isDebugMode()) {
Log.d(TAG, "dispatchKey called with code: " + code + ", eventModifiers: " + eventModifiers);
}
if (code == KMScanCodeMap.scanCodeMap[KMScanCodeMap.KEY_TAB]) {
keyDownUp(KeyEvent.KEYCODE_TAB, eventModifiers);
} else if (code == KMScanCodeMap.scanCodeMap[KMScanCodeMap.KEY_ENTER]) {
keyDownUp(KeyEvent.KEYCODE_ENTER, eventModifiers);
}
}
});
return true;
}
private void keyDownUp(int keyEventCode, int eventModifiers) {
if (k.keyboardType == KeyboardType.KEYBOARD_TYPE_INAPP) {
KMTextView textView = (KMTextView)KMTextView.activeView;
textView.keyDownUp(KeyEvent.KEYCODE_ENTER);
if (keyEventCode == KeyEvent.KEYCODE_TAB) {
KeyEvent event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_TAB, 0, eventModifiers, 0, 0, 0);
textView.dispatchKeyEvent(event);
} else {
textView.keyDownUp(keyEventCode);
}
} else if (k.keyboardType == KeyboardType.KEYBOARD_TYPE_SYSTEM) {
KMManager.getInputMethodService().getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode));
KMManager.getInputMethodService().getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyEventCode));
InputConnection ic = KMManager.getInputConnection(KeyboardType.KEYBOARD_TYPE_SYSTEM);
ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode));
ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyEventCode));
}
}
@ -291,4 +327,25 @@ public abstract class KMKeyboardJSHandler {
return sequence;
}
/**
* If the keyboard type is KEYBOARD_TYPE_INAPP, check if the KMTextView is valid.
* For KEYBOARD_TYPE_SYSTEM, returns true.
* @param keyboardType
* @return boolean - false if keyboard type is INAPP and KMTextView is invalid. Otherwise true
*/
private static boolean isInappKMTextViewValid(KeyboardType keyboardType) {
if (keyboardType == KeyboardType.KEYBOARD_TYPE_INAPP) {
if (KMTextView.activeView == null) {
if (KMManager.isDebugMode()) {
Log.w(TAG, "activeView is null");
}
return false;
}
if (KMTextView.activeView.getClass() != KMTextView.class) {
return false;
}
}
return true;
}
}

View file

@ -158,6 +158,8 @@ public final class KMManager {
};
protected static InputMethodService IMService;
protected static InputConnection inappInputConnection; // Input Connection for InApp Keyboard
private static boolean debugMode = false;
private static boolean shouldAllowSetKeyboard = true;
private static boolean didCopyAssets = false;
@ -421,13 +423,11 @@ public final class KMManager {
didCopyAssets = true;
}
if (keyboardType == KeyboardType.KEYBOARD_TYPE_INAPP) {
initInAppKeyboard(appContext);
} else if (keyboardType == KeyboardType.KEYBOARD_TYPE_SYSTEM) {
initSystemKeyboard(appContext);
} else {
if (keyboardType == KeyboardType.KEYBOARD_TYPE_UNDEFINED) {
String msg = "Cannot initialize: Invalid keyboard type";
KMLog.LogError(TAG, msg);
} else {
initKeyboard(appContext, keyboardType);
}
JSONUtils.initialize(new File(getPackagesDir()));
@ -459,6 +459,26 @@ public final class KMManager {
}
public static InputMethodService getInputMethodService() { return IMService; }
/**
* Get the input connection based on the keyboard type.
* For InApp keyboard, save the connection to inappInputConnection
* @param {KeyboardType} keyboard
* @return InputConnection
*/
protected static InputConnection getInputConnection(KeyboardType keyboard) {
if (keyboard == KeyboardType.KEYBOARD_TYPE_INAPP) {
if (inappInputConnection == null) {
inappInputConnection = KMTextView.activeView.onCreateInputConnection(new EditorInfo());
}
return inappInputConnection;
} else if (keyboard == KeyboardType.KEYBOARD_TYPE_SYSTEM && IMService != null) {
return IMService.getCurrentInputConnection();
}
KMLog.LogError(TAG, "Unable to determine input connection");
return null;
}
public static boolean executeHardwareKeystroke(int code, int shift, int lstates, int eventModifiers) {
if (SystemKeyboard != null) {
return executeHardwareKeystroke(code, shift, KeyboardType.KEYBOARD_TYPE_SYSTEM, lstates, eventModifiers);
@ -609,36 +629,35 @@ public final class KMManager {
return params;
}
private static void initInAppKeyboard(Context appContext) {
if (InAppKeyboard == null) {
private static void initKeyboard(Context appContext, KeyboardType keyboardType) {
KMKeyboard keyboard = null;
KMKeyboardWebViewClient webViewClient = null;
if (keyboardType == KeyboardType.KEYBOARD_TYPE_INAPP && InAppKeyboard == null) {
InAppKeyboard = new KMKeyboard(appContext, KeyboardType.KEYBOARD_TYPE_INAPP);
RelativeLayout.LayoutParams params = getKeyboardLayoutParams();
InAppKeyboard.setLayoutParams(params);
InAppKeyboard.setVerticalScrollBarEnabled(false);
InAppKeyboard.setHorizontalScrollBarEnabled(false);
InAppKeyboardWebViewClient = new KMKeyboardWebViewClient(appContext, KeyboardType.KEYBOARD_TYPE_INAPP);
InAppKeyboard.setWebViewClient(InAppKeyboardWebViewClient);
InAppKeyboard.addJavascriptInterface(new KMInAppKeyboardJSHandler(appContext, InAppKeyboard), "jsInterface");
InAppKeyboard.loadKeyboard();
setEngineWebViewVersionStatus(appContext, InAppKeyboard);
}
}
private static void initSystemKeyboard(Context appContext) {
if (SystemKeyboard == null) {
InAppKeyboardWebViewClient = new KMKeyboardWebViewClient(appContext, keyboardType);
keyboard = InAppKeyboard;
webViewClient = InAppKeyboardWebViewClient;
} else if (keyboardType == KeyboardType.KEYBOARD_TYPE_SYSTEM && SystemKeyboard == null) {
SystemKeyboard = new KMKeyboard(appContext, KeyboardType.KEYBOARD_TYPE_SYSTEM);
RelativeLayout.LayoutParams params = getKeyboardLayoutParams();
SystemKeyboard.setLayoutParams(params);
SystemKeyboard.setVerticalScrollBarEnabled(false);
SystemKeyboard.setHorizontalScrollBarEnabled(false);
SystemKeyboardWebViewClient = new KMKeyboardWebViewClient(appContext, KeyboardType.KEYBOARD_TYPE_SYSTEM);
SystemKeyboard.setWebViewClient(SystemKeyboardWebViewClient);
SystemKeyboard.addJavascriptInterface(new KMSystemKeyboardJSHandler(appContext, SystemKeyboard), "jsInterface");
SystemKeyboard.loadKeyboard();
setEngineWebViewVersionStatus(appContext, SystemKeyboard);
SystemKeyboardWebViewClient = new KMKeyboardWebViewClient(appContext, keyboardType);
keyboard = SystemKeyboard;
webViewClient = SystemKeyboardWebViewClient;
}
if (keyboard == null) {
return;
}
RelativeLayout.LayoutParams params = getKeyboardLayoutParams();
keyboard.setLayoutParams(params);
keyboard.setVerticalScrollBarEnabled(false);
keyboard.setHorizontalScrollBarEnabled(false);
keyboard.setWebViewClient(webViewClient);
keyboard.addJavascriptInterface(new KMKeyboardJSHandler(appContext, keyboard), "jsInterface");
keyboard.loadKeyboard();
setEngineWebViewVersionStatus(appContext, keyboard);
}
public static String getLanguagePredictionPreferenceKey(String langID) {
@ -1981,7 +2000,7 @@ public final class KMManager {
InAppKeyboardShouldIgnoreSelectionChange = false;
} else if (kbType == KeyboardType.KEYBOARD_TYPE_SYSTEM) {
if (SystemKeyboard != null && SystemKeyboardWebViewClient.getKeyboardLoaded() && !SystemKeyboardShouldIgnoreSelectionChange) {
InputConnection ic = (IMService != null ? IMService.getCurrentInputConnection() : null);
InputConnection ic = getInputConnection(KeyboardType.KEYBOARD_TYPE_SYSTEM);
if (ic != null) {
ExtractedText icText = ic.getExtractedText(new ExtractedTextRequest(), 0);
if (icText != null) {
@ -2226,89 +2245,4 @@ public final class KMManager {
globeKeyState = GlobeKeyState.GLOBE_KEY_STATE_UP;
}
}
private static final class KMInAppKeyboardJSHandler extends KMKeyboardJSHandler {
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 eventModifiers) {
Handler mainLoop = new Handler(Looper.getMainLooper());
mainLoop.post(new Runnable() {
public void run() {
if (InAppKeyboard == null) {
KMLog.LogError(TAG, "dispatchKey failed: InAppKeyboard is null");
return;
}
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
KMTextView textView = (KMTextView) KMTextView.activeView;
if (code == KMScanCodeMap.scanCodeMap[KMScanCodeMap.KEY_TAB]) {
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]) {
KeyEvent event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_ENTER, 0, eventModifiers, 0, 0, 0);
textView.dispatchKeyEvent(event);
}
}
});
return true;
}
}
private static final class KMSystemKeyboardJSHandler extends KMKeyboardJSHandler {
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 eventModifiers) {
Handler mainLoop = new Handler(Looper.getMainLooper());
mainLoop.post(new Runnable() {
public void run() {
if (SystemKeyboard == null) {
KMLog.LogError(TAG, "dispatchKey failed: SystemKeyboard is null");
return;
}
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();
SystemKeyboard.setShouldShowHelpBubble(false);
// Handle tab or enter since KMW didn't process it
Log.d(HANDLER_TAG, "dispatchKey called with code: " + code + ", eventModifiers: " + eventModifiers);
if (code == KMScanCodeMap.scanCodeMap[KMScanCodeMap.KEY_TAB]) {
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]) {
KeyEvent event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_ENTER, 0, eventModifiers, 0, 0, 0);
ic.sendKeyEvent(event);
}
}
});
return true;
}
}
}

View file

@ -21,7 +21,7 @@ The following projects **cannot** be built on Linux:
## System Requirements
* Minimum Ubuntu version: Ubuntu 18.04
* Minimum Ubuntu version: Ubuntu 20.04
Other Linux distributions will also work if appropriate dependencies are installed.

View file

@ -1,7 +1,19 @@
keyman (16.0.139-4) unstable; urgency=medium
* debian/tests: Revert previous change and ignore s390x from autopkgtests
-- Eberhard Beilharz <eb1@sil.org> Fri, 24 Mar 2023 16:05:07 +0100
keyman (16.0.139-3) unstable; urgency=medium
* debian/tests: Run autopkgtests on s390x but immediately return
-- Eberhard Beilharz <eb1@sil.org> Wed, 22 Mar 2023 19:25:02 +0100
keyman (16.0.139-2) unstable; urgency=medium
* Don't build on s390x because Keyman doesn't work on big-endian architectures
(upstream bug https://github.com/keymanapp/keyman/issues/5111)
(upstream bug https://github.com/keymanapp/keyman/issues/5111)
-- Eberhard Beilharz <eb1@sil.org> Mon, 20 Mar 2023 19:54:44 +0100

View file

@ -22,7 +22,7 @@ Build-Depends:
python3-pil,
python3-pip,
python3-qrcode,
python3-sentry-sdk (>= 1.1) | python3-raven,
python3-sentry-sdk (>= 1.1),
python3-requests,
python3-requests-cache,
python3-setuptools,
@ -85,7 +85,7 @@ Depends:
keyman-engine,
python3-bs4,
python3-gi,
python3-sentry-sdk (>= 1.1) | python3-raven,
python3-sentry-sdk (>= 1.1),
dbus-x11,
${misc:Depends},
${python3:Depends},

View file

@ -57,22 +57,28 @@ sudo dpkg --purge ibus-kmfl libkmfl
## Q. What Linux distros will Keyman work with?
**A.** Keyman runs on Debian, Ubuntu, Wasta Linux and can be compiled to run from source in most distributions.
**A.** Keyman runs on Debian, Ubuntu, Wasta Linux and can be compiled to run
from source in most distributions.
**Note:** Keyman for Linux no longer supports Ubuntu 16.04 LTS (Xenial Xerus).
Keyman 16 was the last version that supports Ubuntu 18.04 LTS (Bionic Beaver).
## Q. Will my existing Windows Keyman keyboard work with Keyman for Linux?
**A.** Most keyboards will work without change. A small subset of keyboards require features which
are not yet available in Keyman for Linux. These features will be progressively implemented.
**A.** Most keyboards will work without change. A small subset of keyboards
require features which are not yet available in Keyman for Linux. These
features will be progressively implemented.
## Q. How can I disable automatically reporting errors?
**A.** If Keyman crashes, it will automatically send a report to the development team. This report
is anonymous and contains only technical details relating to the crash. It does not include keystroke
data or personally identifying data. If you don't want these automatic error reports to be sent you
can set the environment variable `KEYMAN_NOSENTRY`:
**A.** If Keyman crashes, it will automatically send a report to the development
team. This report is anonymous and contains only technical details relating to
the crash. It does not include keystroke data or personally identifying data. If
you don't want these automatic error reports to be sent you can set the
environment variable `KEYMAN_NOSENTRY` and start `km-config` from
the command line:
```bash
export KEYMAN_NOSENTRY=1
km-config
```

View file

@ -81,7 +81,7 @@ DOWNLOAD_INFO_FILEPATH="${DMG_FILEPATH}.download_info"
if [[ ! -f "$DMG_FILEPATH" ]]; then
builder_die "Cannot compute file size or MD5 for non-existent DMG file: $DMG_FILEPATH"
fi
DMG_FILE_SIZE=$(stat -f"%z" "$DMG_FILEPATH")
DMG_FILE_SIZE=$(/usr/bin/stat -f"%z" "$DMG_FILEPATH")
DMG_MD5=$(md5 -q "$DMG_FILEPATH")
if [[ -f "$DOWNLOAD_INFO_FILEPATH" ]]; then

View file

@ -126,7 +126,7 @@ write_download_info() {
FILE_EXTENSION="${BASE_FILE##*.}"
FILE_SIZE=$(stat -f"%z" "${BASE_PATH}/${BASE_FILE}")
FILE_SIZE=$(/usr/bin/stat -f"%z" "${BASE_PATH}/${BASE_FILE}")
MD5_HASH=$(md5 -q "${BASE_PATH}/${BASE_FILE}")
if [[ -f "$DOWNLOAD_INFO_FILEPATH" ]]; then