diff --git a/app/src/main/java/com/termux/app/TermuxActivity.java b/app/src/main/java/com/termux/app/TermuxActivity.java index 257ec38993..254b3bc50f 100644 --- a/app/src/main/java/com/termux/app/TermuxActivity.java +++ b/app/src/main/java/com/termux/app/TermuxActivity.java @@ -44,7 +44,7 @@ import com.termux.app.terminal.io.TerminalToolbarViewPager; import com.termux.app.terminal.TermuxTerminalSessionClient; import com.termux.app.terminal.TermuxTerminalViewClient; -import com.termux.app.terminal.io.extrakeys.ExtraKeysView; +import com.termux.shared.terminal.io.extrakeys.ExtraKeysView; import com.termux.app.settings.properties.TermuxAppSharedProperties; import com.termux.shared.interact.TextInputDialogUtils; import com.termux.shared.logger.Logger; diff --git a/app/src/main/java/com/termux/app/settings/properties/TermuxAppSharedProperties.java b/app/src/main/java/com/termux/app/settings/properties/TermuxAppSharedProperties.java index 6c2e03713a..fabe683a3c 100644 --- a/app/src/main/java/com/termux/app/settings/properties/TermuxAppSharedProperties.java +++ b/app/src/main/java/com/termux/app/settings/properties/TermuxAppSharedProperties.java @@ -3,7 +3,9 @@ import android.content.Context; import com.termux.app.terminal.io.KeyboardShortcut; -import com.termux.app.terminal.io.extrakeys.ExtraKeysInfo; +import com.termux.shared.terminal.io.extrakeys.ExtraKeysConstants; +import com.termux.shared.terminal.io.extrakeys.ExtraKeysConstants.EXTRA_KEY_DISPLAY_MAPS; +import com.termux.shared.terminal.io.extrakeys.ExtraKeysInfo; import com.termux.shared.logger.Logger; import com.termux.shared.settings.properties.TermuxPropertyConstants; import com.termux.shared.settings.properties.TermuxSharedProperties; @@ -50,13 +52,20 @@ private void setExtraKeys() { // {@link #getExtraKeysStyleInternalPropertyValueFromValue(String)} String extrakeys = (String) getInternalPropertyValue(TermuxPropertyConstants.KEY_EXTRA_KEYS, true); String extraKeysStyle = (String) getInternalPropertyValue(TermuxPropertyConstants.KEY_EXTRA_KEYS_STYLE, true); - mExtraKeysInfo = new ExtraKeysInfo(extrakeys, extraKeysStyle); + + ExtraKeysConstants.ExtraKeyDisplayMap extraKeyDisplayMap = ExtraKeysInfo.getCharDisplayMapForStyle(extraKeysStyle); + if (EXTRA_KEY_DISPLAY_MAPS.DEFAULT_CHAR_DISPLAY.equals(extraKeyDisplayMap) && !TermuxPropertyConstants.DEFAULT_IVALUE_EXTRA_KEYS_STYLE.equals(extraKeysStyle)) { + Logger.logError(TermuxSharedProperties.LOG_TAG, "The style \"" + extraKeysStyle + "\" for the key \"" + TermuxPropertyConstants.KEY_EXTRA_KEYS_STYLE + "\" is invalid. Using default style instead."); + extraKeysStyle = TermuxPropertyConstants.DEFAULT_IVALUE_EXTRA_KEYS_STYLE; + } + + mExtraKeysInfo = new ExtraKeysInfo(extrakeys, extraKeysStyle, ExtraKeysConstants.CONTROL_CHARS_ALIASES); } catch (JSONException e) { Logger.showToast(mContext, "Could not load and set the \"" + TermuxPropertyConstants.KEY_EXTRA_KEYS + "\" property from the properties file: " + e.toString(), true); Logger.logStackTraceWithMessage(LOG_TAG, "Could not load and set the \"" + TermuxPropertyConstants.KEY_EXTRA_KEYS + "\" property from the properties file: ", e); try { - mExtraKeysInfo = new ExtraKeysInfo(TermuxPropertyConstants.DEFAULT_IVALUE_EXTRA_KEYS, TermuxPropertyConstants.DEFAULT_IVALUE_EXTRA_KEYS_STYLE); + mExtraKeysInfo = new ExtraKeysInfo(TermuxPropertyConstants.DEFAULT_IVALUE_EXTRA_KEYS, TermuxPropertyConstants.DEFAULT_IVALUE_EXTRA_KEYS_STYLE, ExtraKeysConstants.CONTROL_CHARS_ALIASES); } catch (JSONException e2) { Logger.showToast(mContext, "Can't create default extra keys",true); Logger.logStackTraceWithMessage(LOG_TAG, "Could create default extra keys: ", e); 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 7e68d3ecf3..8e720444bc 100644 --- a/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java +++ b/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java @@ -27,13 +27,13 @@ import com.termux.shared.interact.MessageDialogUtils; import com.termux.shared.shell.ShellUtils; import com.termux.shared.terminal.TermuxTerminalViewClientBase; +import com.termux.shared.terminal.io.extrakeys.SpecialButton; import com.termux.shared.termux.AndroidUtils; import com.termux.shared.termux.TermuxConstants; import com.termux.shared.activities.ReportActivity; import com.termux.shared.models.ReportInfo; import com.termux.app.models.UserAction; import com.termux.app.terminal.io.KeyboardShortcut; -import com.termux.app.terminal.io.extrakeys.ExtraKeysView; import com.termux.shared.settings.properties.TermuxPropertyConstants; import com.termux.shared.data.DataUtils; import com.termux.shared.logger.Logger; @@ -289,12 +289,22 @@ private boolean handleVirtualKeys(int keyCode, KeyEvent event, boolean down) { @Override public boolean readControlKey() { - return (mActivity.getExtraKeysView() != null && mActivity.getExtraKeysView().readSpecialButton(ExtraKeysView.SpecialButton.CTRL)) || mVirtualControlKeyDown; + return readExtraKeysSpecialButton(SpecialButton.CTRL) || mVirtualControlKeyDown; } @Override public boolean readAltKey() { - return (mActivity.getExtraKeysView() != null && mActivity.getExtraKeysView().readSpecialButton(ExtraKeysView.SpecialButton.ALT)); + return readExtraKeysSpecialButton(SpecialButton.ALT); + } + + public boolean readExtraKeysSpecialButton(SpecialButton specialButton) { + if (mActivity.getExtraKeysView() == null) return false; + Boolean state = mActivity.getExtraKeysView().readSpecialButton(specialButton, true); + if (state == null) { + Logger.logError(LOG_TAG,"Failed to read an unregistered " + specialButton + " special button value from extra keys."); + return false; + } + return state; } @Override diff --git a/app/src/main/java/com/termux/app/terminal/io/TerminalToolbarViewPager.java b/app/src/main/java/com/termux/app/terminal/io/TerminalToolbarViewPager.java index dc306852b2..56f28fc0c2 100644 --- a/app/src/main/java/com/termux/app/terminal/io/TerminalToolbarViewPager.java +++ b/app/src/main/java/com/termux/app/terminal/io/TerminalToolbarViewPager.java @@ -11,7 +11,7 @@ import com.termux.R; import com.termux.app.TermuxActivity; -import com.termux.app.terminal.io.extrakeys.ExtraKeysView; +import com.termux.shared.terminal.io.extrakeys.ExtraKeysView; import com.termux.terminal.TerminalSession; public class TerminalToolbarViewPager { @@ -44,8 +44,8 @@ public Object instantiateItem(@NonNull ViewGroup collection, int position) { if (position == 0) { layout = inflater.inflate(R.layout.view_terminal_toolbar_extra_keys, collection, false); ExtraKeysView extraKeysView = (ExtraKeysView) layout; - extraKeysView.setTermuxTerminalViewClient(mActivity.getTermuxTerminalViewClient()); - extraKeysView.setTermuxTerminalSessionClient(mActivity.getTermuxTerminalSessionClient()); + extraKeysView.setExtraKeysViewClient(new TermuxTerminalExtraKeys(mActivity.getTerminalView(), + mActivity.getTermuxTerminalViewClient(), mActivity.getTermuxTerminalSessionClient())); mActivity.setExtraKeysView(extraKeysView); extraKeysView.reload(mActivity.getProperties().getExtraKeysInfo()); diff --git a/app/src/main/java/com/termux/app/terminal/io/TermuxTerminalExtraKeys.java b/app/src/main/java/com/termux/app/terminal/io/TermuxTerminalExtraKeys.java new file mode 100644 index 0000000000..483e6c0f2e --- /dev/null +++ b/app/src/main/java/com/termux/app/terminal/io/TermuxTerminalExtraKeys.java @@ -0,0 +1,47 @@ +package com.termux.app.terminal.io; + +import android.annotation.SuppressLint; +import android.view.Gravity; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.drawerlayout.widget.DrawerLayout; + +import com.termux.R; +import com.termux.app.terminal.TermuxTerminalSessionClient; +import com.termux.app.terminal.TermuxTerminalViewClient; +import com.termux.shared.terminal.io.TerminalExtraKeys; +import com.termux.view.TerminalView; + +public class TermuxTerminalExtraKeys extends TerminalExtraKeys { + + + TermuxTerminalViewClient mTermuxTerminalViewClient; + TermuxTerminalSessionClient mTermuxTerminalSessionClient; + + public TermuxTerminalExtraKeys(@NonNull TerminalView terminalView, + TermuxTerminalViewClient termuxTerminalViewClient, + TermuxTerminalSessionClient termuxTerminalSessionClient) { + super(terminalView); + mTermuxTerminalViewClient = termuxTerminalViewClient; + mTermuxTerminalSessionClient = termuxTerminalSessionClient; + } + + @SuppressLint("RtlHardcoded") + @Override + public void onTerminalExtraKeyButtonClick(View view, String key, boolean ctrlDown, boolean altDown, boolean shiftDown, boolean fnDown) { + if ("KEYBOARD".equals(key)) { + if(mTermuxTerminalViewClient != null) + mTermuxTerminalViewClient.onToggleSoftKeyboardRequest(); + } else if ("DRAWER".equals(key)) { + DrawerLayout drawer = view.findViewById(R.id.drawer_layout); + drawer.openDrawer(Gravity.LEFT); + } else if ("PASTE".equals(key)) { + if(mTermuxTerminalSessionClient != null) + mTermuxTerminalSessionClient.onPasteTextFromClipboard(null); + } else { + super.onTerminalExtraKeyButtonClick(view, key, ctrlDown, altDown, shiftDown, fnDown); + } + } + +} diff --git a/app/src/main/java/com/termux/app/terminal/io/extrakeys/ExtraKeyButton.java b/app/src/main/java/com/termux/app/terminal/io/extrakeys/ExtraKeyButton.java deleted file mode 100644 index 9454081970..0000000000 --- a/app/src/main/java/com/termux/app/terminal/io/extrakeys/ExtraKeyButton.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.termux.app.terminal.io.extrakeys; - -import android.text.TextUtils; - -import androidx.annotation.Nullable; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.Arrays; -import java.util.stream.Collectors; - -public class ExtraKeyButton { - - /** - * The key that will be sent to the terminal, either a control character - * defined in ExtraKeysView.keyCodesForString (LEFT, RIGHT, PGUP...) or - * some text. - */ - private final String key; - - /** - * If the key is a macro, i.e. a sequence of keys separated by space. - */ - private final boolean macro; - - /** - * The text that will be shown on the button. - */ - private final String display; - - /** - * The information of the popup (triggered by swipe up). - */ - @Nullable - private ExtraKeyButton popup; - - public ExtraKeyButton(ExtraKeysInfo.CharDisplayMap charDisplayMap, JSONObject config) throws JSONException { - this(charDisplayMap, config, null); - } - - public ExtraKeyButton(ExtraKeysInfo.CharDisplayMap charDisplayMap, JSONObject config, @Nullable ExtraKeyButton popup) throws JSONException { - String keyFromConfig = config.optString("key", null); - String macroFromConfig = config.optString("macro", null); - String[] keys; - if (keyFromConfig != null && macroFromConfig != null) { - throw new JSONException("Both key and macro can't be set for the same key"); - } else if (keyFromConfig != null) { - keys = new String[]{keyFromConfig}; - this.macro = false; - } else if (macroFromConfig != null) { - keys = macroFromConfig.split(" "); - this.macro = true; - } else { - throw new JSONException("All keys have to specify either key or macro"); - } - - for (int i = 0; i < keys.length; i++) { - keys[i] = ExtraKeysInfo.replaceAlias(keys[i]); - } - - this.key = TextUtils.join(" ", keys); - - String displayFromConfig = config.optString("display", null); - if (displayFromConfig != null) { - this.display = displayFromConfig; - } else { - this.display = Arrays.stream(keys) - .map(key -> charDisplayMap.get(key, key)) - .collect(Collectors.joining(" ")); - } - - this.popup = popup; - } - - public String getKey() { - return key; - } - - public boolean isMacro() { - return macro; - } - - public String getDisplay() { - return display; - } - - @Nullable - public ExtraKeyButton getPopup() { - return popup; - } -} diff --git a/app/src/main/java/com/termux/app/terminal/io/extrakeys/ExtraKeysInfo.java b/app/src/main/java/com/termux/app/terminal/io/extrakeys/ExtraKeysInfo.java deleted file mode 100644 index ceaad78739..0000000000 --- a/app/src/main/java/com/termux/app/terminal/io/extrakeys/ExtraKeysInfo.java +++ /dev/null @@ -1,260 +0,0 @@ -package com.termux.app.terminal.io.extrakeys; - -import com.termux.shared.logger.Logger; -import com.termux.shared.settings.properties.TermuxPropertyConstants; -import com.termux.shared.settings.properties.TermuxSharedProperties; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.HashMap; - -public class ExtraKeysInfo { - - /** - * Matrix of buttons displayed - */ - private final ExtraKeyButton[][] buttons; - - /** - * This corresponds to one of the CharMapDisplay below - */ - private String style; - - public ExtraKeysInfo(String propertiesInfo, String style) throws JSONException { - this.style = style; - - // Convert String propertiesInfo to Array of Arrays - JSONArray arr = new JSONArray(propertiesInfo); - Object[][] matrix = new Object[arr.length()][]; - for (int i = 0; i < arr.length(); i++) { - JSONArray line = arr.getJSONArray(i); - matrix[i] = new Object[line.length()]; - for (int j = 0; j < line.length(); j++) { - matrix[i][j] = line.get(j); - } - } - - // convert matrix to buttons - this.buttons = new ExtraKeyButton[matrix.length][]; - for (int i = 0; i < matrix.length; i++) { - this.buttons[i] = new ExtraKeyButton[matrix[i].length]; - for (int j = 0; j < matrix[i].length; j++) { - Object key = matrix[i][j]; - - JSONObject jobject = normalizeKeyConfig(key); - - ExtraKeyButton button; - - if (! jobject.has("popup")) { - // no popup - button = new ExtraKeyButton(getSelectedCharMap(), jobject); - } else { - // a popup - JSONObject popupJobject = normalizeKeyConfig(jobject.get("popup")); - ExtraKeyButton popup = new ExtraKeyButton(getSelectedCharMap(), popupJobject); - button = new ExtraKeyButton(getSelectedCharMap(), jobject, popup); - } - - this.buttons[i][j] = button; - } - } - } - - /** - * "hello" -> {"key": "hello"} - */ - private static JSONObject normalizeKeyConfig(Object key) throws JSONException { - JSONObject jobject; - if (key instanceof String) { - jobject = new JSONObject(); - jobject.put("key", key); - } else if (key instanceof JSONObject) { - jobject = (JSONObject) key; - } else { - throw new JSONException("An key in the extra-key matrix must be a string or an object"); - } - return jobject; - } - - public ExtraKeyButton[][] getMatrix() { - return buttons; - } - - /** - * HashMap that implements Python dict.get(key, default) function. - * Default java.util .get(key) is then the same as .get(key, null); - */ - static class CleverMap extends HashMap { - V get(K key, V defaultValue) { - if (containsKey(key)) - return get(key); - else - return defaultValue; - } - } - - static class CharDisplayMap extends CleverMap {} - - /** - * Keys are displayed in a natural looking way, like "→" for "RIGHT" - */ - static final CharDisplayMap classicArrowsDisplay = new CharDisplayMap() {{ - // classic arrow keys (for ◀ ▶ ▲ ▼ @see arrowVariationDisplay) - put("LEFT", "←"); // U+2190 ← LEFTWARDS ARROW - put("RIGHT", "→"); // U+2192 → RIGHTWARDS ARROW - put("UP", "↑"); // U+2191 ↑ UPWARDS ARROW - put("DOWN", "↓"); // U+2193 ↓ DOWNWARDS ARROW - }}; - - static final CharDisplayMap wellKnownCharactersDisplay = new CharDisplayMap() {{ - // well known characters // https://en.wikipedia.org/wiki/{Enter_key, Tab_key, Delete_key} - put("ENTER", "↲"); // U+21B2 ↲ DOWNWARDS ARROW WITH TIP LEFTWARDS - put("TAB", "↹"); // U+21B9 ↹ LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR - put("BKSP", "⌫"); // U+232B ⌫ ERASE TO THE LEFT sometimes seen and easy to understand - put("DEL", "⌦"); // U+2326 ⌦ ERASE TO THE RIGHT not well known but easy to understand - put("DRAWER", "☰"); // U+2630 ☰ TRIGRAM FOR HEAVEN not well known but easy to understand - put("KEYBOARD", "⌨"); // U+2328 ⌨ KEYBOARD not well known but easy to understand - put("PASTE", "⎘"); // U+2398 - }}; - - static final CharDisplayMap lessKnownCharactersDisplay = new CharDisplayMap() {{ - // https://en.wikipedia.org/wiki/{Home_key, End_key, Page_Up_and_Page_Down_keys} - // home key can mean "goto the beginning of line" or "goto first page" depending on context, hence the diagonal - put("HOME", "⇱"); // from IEC 9995 // U+21F1 ⇱ NORTH WEST ARROW TO CORNER - put("END", "⇲"); // from IEC 9995 // ⇲ // U+21F2 ⇲ SOUTH EAST ARROW TO CORNER - put("PGUP", "⇑"); // no ISO character exists, U+21D1 ⇑ UPWARDS DOUBLE ARROW will do the trick - put("PGDN", "⇓"); // no ISO character exists, U+21D3 ⇓ DOWNWARDS DOUBLE ARROW will do the trick - }}; - - static final CharDisplayMap arrowTriangleVariationDisplay = new CharDisplayMap() {{ - // alternative to classic arrow keys - put("LEFT", "◀"); // U+25C0 ◀ BLACK LEFT-POINTING TRIANGLE - put("RIGHT", "▶"); // U+25B6 ▶ BLACK RIGHT-POINTING TRIANGLE - put("UP", "▲"); // U+25B2 ▲ BLACK UP-POINTING TRIANGLE - put("DOWN", "▼"); // U+25BC ▼ BLACK DOWN-POINTING TRIANGLE - }}; - - static final CharDisplayMap notKnownIsoCharacters = new CharDisplayMap() {{ - // Control chars that are more clear as text // https://en.wikipedia.org/wiki/{Function_key, Alt_key, Control_key, Esc_key} - // put("FN", "FN"); // no ISO character exists - put("CTRL", "⎈"); // ISO character "U+2388 ⎈ HELM SYMBOL" is unknown to people and never printed on computers, however "U+25C7 ◇ WHITE DIAMOND" is a nice presentation, and "^" for terminal app and mac is often used - put("ALT", "⎇"); // ISO character "U+2387 ⎇ ALTERNATIVE KEY SYMBOL'" is unknown to people and only printed as the Option key "⌥" on Mac computer - put("ESC", "⎋"); // ISO character "U+238B ⎋ BROKEN CIRCLE WITH NORTHWEST ARROW" is unknown to people and not often printed on computers - }}; - - static final CharDisplayMap nicerLookingDisplay = new CharDisplayMap() {{ - // nicer looking for most cases - put("-", "―"); // U+2015 ― HORIZONTAL BAR - }}; - - /* - * Multiple maps are available to quickly change - * the style of the keys. - */ - - /** - * Some classic symbols everybody knows - */ - private static final CharDisplayMap defaultCharDisplay = new CharDisplayMap() {{ - putAll(classicArrowsDisplay); - putAll(wellKnownCharactersDisplay); - putAll(nicerLookingDisplay); - // all other characters are displayed as themselves - }}; - - /** - * Classic symbols and less known symbols - */ - private static final CharDisplayMap lotsOfArrowsCharDisplay = new CharDisplayMap() {{ - putAll(classicArrowsDisplay); - putAll(wellKnownCharactersDisplay); - putAll(lessKnownCharactersDisplay); // NEW - putAll(nicerLookingDisplay); - }}; - - /** - * Only arrows - */ - private static final CharDisplayMap arrowsOnlyCharDisplay = new CharDisplayMap() {{ - putAll(classicArrowsDisplay); - // putAll(wellKnownCharactersDisplay); // REMOVED - // putAll(lessKnownCharactersDisplay); // REMOVED - putAll(nicerLookingDisplay); - }}; - - /** - * Full Iso - */ - private static final CharDisplayMap fullIsoCharDisplay = new CharDisplayMap() {{ - putAll(classicArrowsDisplay); - putAll(wellKnownCharactersDisplay); - putAll(lessKnownCharactersDisplay); // NEW - putAll(nicerLookingDisplay); - putAll(notKnownIsoCharacters); // NEW - }}; - - /** - * Some people might call our keys differently - */ - static private final CharDisplayMap controlCharsAliases = new CharDisplayMap() {{ - put("ESCAPE", "ESC"); - put("CONTROL", "CTRL"); - put("RETURN", "ENTER"); // Technically different keys, but most applications won't see the difference - put("FUNCTION", "FN"); - // no alias for ALT - - // Directions are sometimes written as first and last letter for brevety - put("LT", "LEFT"); - put("RT", "RIGHT"); - put("DN", "DOWN"); - // put("UP", "UP"); well, "UP" is already two letters - - put("PAGEUP", "PGUP"); - put("PAGE_UP", "PGUP"); - put("PAGE UP", "PGUP"); - put("PAGE-UP", "PGUP"); - - // no alias for HOME - // no alias for END - - put("PAGEDOWN", "PGDN"); - put("PAGE_DOWN", "PGDN"); - put("PAGE-DOWN", "PGDN"); - - put("DELETE", "DEL"); - put("BACKSPACE", "BKSP"); - - // easier for writing in termux.properties - put("BACKSLASH", "\\"); - put("QUOTE", "\""); - put("APOSTROPHE", "'"); - }}; - - CharDisplayMap getSelectedCharMap() { - switch (style) { - case "arrows-only": - return arrowsOnlyCharDisplay; - case "arrows-all": - return lotsOfArrowsCharDisplay; - case "all": - return fullIsoCharDisplay; - case "none": - return new CharDisplayMap(); - default: - if (!TermuxPropertyConstants.DEFAULT_IVALUE_EXTRA_KEYS_STYLE.equals(style)) - Logger.logError(TermuxSharedProperties.LOG_TAG, "The style \"" + style + "\" for the key \"" + TermuxPropertyConstants.KEY_EXTRA_KEYS_STYLE + "\" is invalid. Using default style instead."); - return defaultCharDisplay; - } - } - - /** - * Applies the 'controlCharsAliases' mapping to all the strings in *buttons* - * Modifies the array, doesn't return a new one. - */ - public static String replaceAlias(String key) { - return controlCharsAliases.get(key, key); - } -} - diff --git a/app/src/main/java/com/termux/app/terminal/io/extrakeys/ExtraKeysView.java b/app/src/main/java/com/termux/app/terminal/io/extrakeys/ExtraKeysView.java deleted file mode 100644 index 79aceaa17d..0000000000 --- a/app/src/main/java/com/termux/app/terminal/io/extrakeys/ExtraKeysView.java +++ /dev/null @@ -1,401 +0,0 @@ -package com.termux.app.terminal.io.extrakeys; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.os.Build; -import android.provider.Settings; -import android.util.AttributeSet; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.ScheduledExecutorService; - -import java.util.Map; -import java.util.HashMap; -import java.util.Arrays; -import java.util.stream.Collectors; - -import android.view.Gravity; -import android.view.HapticFeedbackConstants; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.widget.Button; -import android.widget.GridLayout; -import android.widget.PopupWindow; - -import com.termux.R; -import com.termux.app.terminal.TermuxTerminalSessionClient; -import com.termux.app.terminal.TermuxTerminalViewClient; -import com.termux.view.TerminalView; - -import androidx.drawerlayout.widget.DrawerLayout; - -/** - * A view showing extra keys (such as Escape, Ctrl, Alt) not normally available on an Android soft - * keyboard. - */ -public final class ExtraKeysView extends GridLayout { - - private static final int TEXT_COLOR = 0xFFFFFFFF; - private static final int BUTTON_COLOR = 0x00000000; - private static final int INTERESTING_COLOR = 0xFF80DEEA; - private static final int BUTTON_PRESSED_COLOR = 0xFF7F7F7F; - - TermuxTerminalViewClient mTermuxTerminalViewClient; - TermuxTerminalSessionClient mTermuxTerminalSessionClient; - - public ExtraKeysView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - static final Map keyCodesForString = new HashMap() {{ - put("SPACE", KeyEvent.KEYCODE_SPACE); - put("ESC", KeyEvent.KEYCODE_ESCAPE); - put("TAB", KeyEvent.KEYCODE_TAB); - put("HOME", KeyEvent.KEYCODE_MOVE_HOME); - put("END", KeyEvent.KEYCODE_MOVE_END); - put("PGUP", KeyEvent.KEYCODE_PAGE_UP); - put("PGDN", KeyEvent.KEYCODE_PAGE_DOWN); - put("INS", KeyEvent.KEYCODE_INSERT); - put("DEL", KeyEvent.KEYCODE_FORWARD_DEL); - put("BKSP", KeyEvent.KEYCODE_DEL); - put("UP", KeyEvent.KEYCODE_DPAD_UP); - put("LEFT", KeyEvent.KEYCODE_DPAD_LEFT); - put("RIGHT", KeyEvent.KEYCODE_DPAD_RIGHT); - put("DOWN", KeyEvent.KEYCODE_DPAD_DOWN); - put("ENTER", KeyEvent.KEYCODE_ENTER); - put("F1", KeyEvent.KEYCODE_F1); - put("F2", KeyEvent.KEYCODE_F2); - put("F3", KeyEvent.KEYCODE_F3); - put("F4", KeyEvent.KEYCODE_F4); - put("F5", KeyEvent.KEYCODE_F5); - put("F6", KeyEvent.KEYCODE_F6); - put("F7", KeyEvent.KEYCODE_F7); - put("F8", KeyEvent.KEYCODE_F8); - put("F9", KeyEvent.KEYCODE_F9); - put("F10", KeyEvent.KEYCODE_F10); - put("F11", KeyEvent.KEYCODE_F11); - put("F12", KeyEvent.KEYCODE_F12); - }}; - - @SuppressLint("RtlHardcoded") - private void sendKey(View view, String keyName, boolean forceCtrlDown, boolean forceLeftAltDown) { - TerminalView terminalView = view.findViewById(R.id.terminal_view); - if ("KEYBOARD".equals(keyName)) { - if(mTermuxTerminalViewClient != null) - mTermuxTerminalViewClient.onToggleSoftKeyboardRequest(); - } else if ("DRAWER".equals(keyName)) { - DrawerLayout drawer = view.findViewById(R.id.drawer_layout); - drawer.openDrawer(Gravity.LEFT); - } else if ("PASTE".equals(keyName)) { - if(mTermuxTerminalSessionClient != null) - mTermuxTerminalSessionClient.onPasteTextFromClipboard(null); - } else if (keyCodesForString.containsKey(keyName)) { - Integer keyCode = keyCodesForString.get(keyName); - if (keyCode == null) return; - int metaState = 0; - if (forceCtrlDown) { - metaState |= KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON; - } - if (forceLeftAltDown) { - metaState |= KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON; - } - KeyEvent keyEvent = new KeyEvent(0, 0, KeyEvent.ACTION_UP, keyCode, 0, metaState); - terminalView.onKeyDown(keyCode, keyEvent); - } else { - // not a control char - keyName.codePoints().forEach(codePoint -> { - terminalView.inputCodePoint(codePoint, forceCtrlDown, forceLeftAltDown); - }); - } - } - - private void sendKey(View view, ExtraKeyButton buttonInfo) { - if (buttonInfo.isMacro()) { - String[] keys = buttonInfo.getKey().split(" "); - boolean ctrlDown = false; - boolean altDown = false; - for (String key : keys) { - if ("CTRL".equals(key)) { - ctrlDown = true; - } else if ("ALT".equals(key)) { - altDown = true; - } else { - sendKey(view, key, ctrlDown, altDown); - ctrlDown = false; - altDown = false; - } - } - } else { - sendKey(view, buttonInfo.getKey(), false, false); - } - } - - public enum SpecialButton { - CTRL, ALT, FN - } - - private static class SpecialButtonState { - boolean isOn = false; - boolean isActive = false; - List