From 4d1851e6beb5afb9c8de952797364fb4ff14faf2 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Sat, 8 May 2021 04:16:51 +0500 Subject: [PATCH] Fix issues where soft keyboard was not shown in some cases when hardware keyboard was attached For Termux app to be able to show a soft keyboard while a hardware keyboard is attached requires either of 2 cases: 1. User has enabled "Show on-screen keyboard while hardware keyboard is attached" toggle in Android "Language and Input" settings. 2. The toggle is disabled, but the soft keyboard app overrides the default implementation of `InputMethodService.onEvaluateInputViewShown()` and returns `true`. Some keyboard apps have a setting for this, like HackerKeyboard, but its not supported by all keyboard apps. https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:frameworks/base/core/java/android/inputmethodservice/InputMethodService.java;l=1751 Termux previously didn't forcefully show a keyboard when the drawer "KEYBOARD" toggle button was pressed and only did that for the "KEYBOARD" extra keys toggle button. This prevented the keyboard to be shown for case 2 even when the user attempted to show the keyboard with the drawer "KEYBOARD" toggle. Now both buttons will forcefully show the keyboard. Moreover, previously at app startup for case 2, the keyboard wasn't being shown. Now it will automatically be shown without requiring a manual press of a "KEYBOARD" toggle button. This may also solve the issue where the soft keyboard wouldn't show even when the toggle of case 1 was enabled. --- .../java/com/termux/app/TermuxActivity.java | 19 +----- .../terminal/TermuxTerminalViewClient.java | 60 ++++++++++++++++++- 2 files changed, 61 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/termux/app/TermuxActivity.java b/app/src/main/java/com/termux/app/TermuxActivity.java index f323d0fe22..003dec958d 100644 --- a/app/src/main/java/com/termux/app/TermuxActivity.java +++ b/app/src/main/java/com/termux/app/TermuxActivity.java @@ -237,7 +237,7 @@ public void onStart() { public void onResume() { super.onResume(); - setSoftKeyboardState(); + mTermuxTerminalViewClient.setSoftKeyboardState(); } /** @@ -418,8 +418,7 @@ private void setNewSessionButtonView() { private void setToggleKeyboardView() { findViewById(R.id.toggle_keyboard_button).setOnClickListener(v -> { - InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0); + TermuxTerminalViewClient.toggleSoftKeyboard(this); getDrawer().closeDrawers(); }); @@ -429,19 +428,7 @@ private void setToggleKeyboardView() { }); } - private void setSoftKeyboardState() { - // If soft keyboard is to disabled - if (!mPreferences.getSoftKeyboardEnabled()) { - getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - } else { - getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - } - // If soft keyboard is to be hidden on startup - if (mProperties.shouldSoftKeyboardBeHiddenOnStartup()) { - getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); - } - } @@ -780,7 +767,7 @@ private void reloadTermuxActivityStyling() { setTerminalToolbarHeight(); - setSoftKeyboardState(); + mTermuxTerminalViewClient.setSoftKeyboardState(); // To change the activity and drawer theme, activity needs to be recreated. // But this will destroy the activity, and will call the onCreate() again. diff --git a/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java b/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java index e906b01cca..400db111e3 100644 --- a/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java +++ b/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java @@ -7,6 +7,7 @@ import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; +import android.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.net.Uri; import android.text.TextUtils; @@ -14,6 +15,7 @@ import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.ListView; import android.widget.Toast; @@ -36,6 +38,7 @@ import com.termux.terminal.KeyHandler; import com.termux.terminal.TerminalEmulator; import com.termux.terminal.TerminalSession; +import com.termux.view.TerminalView; import java.util.Arrays; import java.util.Collections; @@ -122,8 +125,7 @@ public boolean onKeyDown(int keyCode, KeyEvent e, TerminalSession currentSession } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) { mActivity.getDrawer().closeDrawers(); } else if (unicodeChar == 'k'/* keyboard */) { - InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE); - imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + toggleSoftKeyboard(mActivity); } else if (unicodeChar == 'm'/* menu */) { mActivity.getTerminalView().showContextMenu(); } else if (unicodeChar == 'r'/* rename */) { @@ -151,6 +153,8 @@ public boolean onKeyDown(int keyCode, KeyEvent e, TerminalSession currentSession } + + @Override public boolean onKeyUp(int keyCode, KeyEvent e) { return handleVirtualKeys(keyCode, e, false); @@ -337,6 +341,58 @@ public void changeFontSize(boolean increase) { } + /** + * Toggle the soft keyboard. The {@link InputMethodManager#SHOW_FORCED} is passed as + * {@code showFlags} so that keyboard is forcefully shown if it needs to be enabled. + * + * This is also important for soft keyboard to be shown when a hardware keyboard is attached, and + * user has disabled the {@code Show on-screen keyboard while hardware keyboard is attached} toggle + * in Android "Language and Input" settings but the current soft keyboard app overrides the + * default implementation of {@link InputMethodService#onEvaluateInputViewShown()} and returns + * {@code true}. + */ + public static void toggleSoftKeyboard(Context context) { + InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + } + + /** + * Show the soft keyboard. The {@code 0} value is passed as {@code flags} so that keyboard is + * forcefully shown. + * + * This is also important for soft keyboard to be shown on app startup when a hardware keyboard + * is attached, and user has disabled the {@code Show on-screen keyboard while hardware keyboard + * is attached} toggle in Android "Language and Input" settings but the current soft keyboard app + * overrides the default implementation of {@link InputMethodService#onEvaluateInputViewShown()} + * and returns {@code true}. + * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:frameworks/base/core/java/android/inputmethodservice/InputMethodService.java;l=1751 + * + * Also check {@link InputMethodService#onShowInputRequested(int, boolean)} which must return + * {@code true}, which can be done by failing its {@code ((flags&InputMethod.SHOW_EXPLICIT) == 0)} + * check by passing {@code 0} as {@code flags}. + * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:frameworks/base/core/java/android/inputmethodservice/InputMethodService.java;l=2022 + */ + public static void showSoftKeyboard(Context context, TerminalView terminalView) { + InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + inputMethodManager.showSoftInput(terminalView, 0); + } + + public void setSoftKeyboardState() { + // If soft keyboard is to disabled + if (!mActivity.getPreferences().getSoftKeyboardEnabled()) { + mActivity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + } else { + mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + showSoftKeyboard(mActivity, mActivity.getTerminalView()); + } + + // If soft keyboard is to be hidden on startup + if (mActivity.getProperties().shouldSoftKeyboardBeHiddenOnStartup()) { + mActivity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); + } + } + + public void shareSessionTranscript() { TerminalSession session = mActivity.getCurrentSession();