Feature: Changeable ExtraKeysView
This commit is contained in:
@ -15,6 +15,7 @@ import io.neoterm.backend.EmulatorDebug
|
|||||||
import io.neoterm.backend.TerminalSession
|
import io.neoterm.backend.TerminalSession
|
||||||
import io.neoterm.preference.NeoTermPreference
|
import io.neoterm.preference.NeoTermPreference
|
||||||
import io.neoterm.ui.NeoTermActivity
|
import io.neoterm.ui.NeoTermActivity
|
||||||
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,7 +78,14 @@ class NeoTermService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (executablePath == null) {
|
if (executablePath == null) {
|
||||||
executablePath = if (systemShell) "/system/bin/sh" else NeoTermPreference.USR_PATH + "/bin/sh"
|
executablePath = if (systemShell)
|
||||||
|
"/system/bin/sh"
|
||||||
|
else
|
||||||
|
NeoTermPreference.USR_PATH + "/bin/" + NeoTermPreference.loadString(R.string.key_general_shell, "sh")
|
||||||
|
|
||||||
|
if (!File(executablePath).exists()) {
|
||||||
|
NeoTermPreference.USR_PATH + "/bin/sh"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arguments == null) {
|
if (arguments == null) {
|
||||||
|
@ -10,6 +10,9 @@ import android.widget.Button;
|
|||||||
import android.widget.GridLayout;
|
import android.widget.GridLayout;
|
||||||
import android.widget.ToggleButton;
|
import android.widget.ToggleButton;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import io.neoterm.R;
|
import io.neoterm.R;
|
||||||
import io.neoterm.backend.TerminalSession;
|
import io.neoterm.backend.TerminalSession;
|
||||||
|
|
||||||
@ -18,16 +21,88 @@ import io.neoterm.backend.TerminalSession;
|
|||||||
* keyboard.
|
* keyboard.
|
||||||
*/
|
*/
|
||||||
public final class ExtraKeysView extends GridLayout {
|
public final class ExtraKeysView extends GridLayout {
|
||||||
|
public static abstract class ExtraButton implements OnClickListener {
|
||||||
|
public String buttonText;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract void onClick(View view);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ControlButton extends ExtraButton {
|
||||||
|
public ControlButton(String text) {
|
||||||
|
buttonText = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
ExtraKeysView.sendKey(view, buttonText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TextButton extends ExtraButton {
|
||||||
|
public TextButton(String text) {
|
||||||
|
buttonText = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
ExtraKeysView.sendKey(view, buttonText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StatedControlButton extends ControlButton {
|
||||||
|
public ToggleButton toggleButton;
|
||||||
|
|
||||||
|
public StatedControlButton(String text) {
|
||||||
|
super(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
toggleButton.setChecked(toggleButton.isChecked());
|
||||||
|
toggleButton.setTextColor(toggleButton.isChecked() ? 0xFF80DEEA : TEXT_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean readState() {
|
||||||
|
if (toggleButton.isPressed()) return true;
|
||||||
|
boolean result = toggleButton.isChecked();
|
||||||
|
if (result) {
|
||||||
|
toggleButton.setChecked(false);
|
||||||
|
toggleButton.setTextColor(TEXT_COLOR);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final ControlButton ESC = new ControlButton("ESC");
|
||||||
|
public static final ControlButton TAB = new ControlButton("TAB");
|
||||||
|
public static final StatedControlButton CTRL = new StatedControlButton("CTRL");
|
||||||
|
public static final StatedControlButton ALT = new StatedControlButton("ALT");
|
||||||
|
public static final StatedControlButton FN = new StatedControlButton("FN");
|
||||||
|
|
||||||
|
public static final ControlButton ARROW_UP = new ControlButton("▲");
|
||||||
|
public static final ControlButton ARROW_DOWN = new ControlButton("▼");
|
||||||
|
public static final ControlButton ARROW_LEFT = new ControlButton("◀");
|
||||||
|
public static final ControlButton ARROW_RIGHT = new ControlButton("▶");
|
||||||
|
|
||||||
|
public static final TextButton HORIZONTAL = new TextButton("-");
|
||||||
|
public static final TextButton SLASH = new TextButton("/");
|
||||||
|
public static final TextButton PIPE = new TextButton("|");
|
||||||
|
|
||||||
private static final int TEXT_COLOR = 0xFFFFFFFF;
|
private static final int TEXT_COLOR = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
private List<ExtraButton> extraButtons;
|
||||||
|
private List<ExtraButton> externalButtons;
|
||||||
|
|
||||||
public ExtraKeysView(Context context, AttributeSet attrs) {
|
public ExtraKeysView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
externalButtons = new ArrayList<>(3);
|
||||||
|
extraButtons = new ArrayList<>();
|
||||||
|
resetExternalButtons();
|
||||||
reload();
|
reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sendKey(View view, String keyName) {
|
public static void sendKey(View view, String keyName) {
|
||||||
int keyCode = 0;
|
int keyCode = 0;
|
||||||
String chars = null;
|
String chars = null;
|
||||||
switch (keyName) {
|
switch (keyName) {
|
||||||
@ -66,78 +141,72 @@ public final class ExtraKeysView extends GridLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ToggleButton controlButton;
|
|
||||||
private ToggleButton altButton;
|
|
||||||
private ToggleButton fnButton;
|
|
||||||
|
|
||||||
public boolean readControlButton() {
|
public boolean readControlButton() {
|
||||||
if (controlButton.isPressed()) return true;
|
return CTRL.readState();
|
||||||
boolean result = controlButton.isChecked();
|
|
||||||
if (result) {
|
|
||||||
controlButton.setChecked(false);
|
|
||||||
controlButton.setTextColor(TEXT_COLOR);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean readAltButton() {
|
public boolean readAltButton() {
|
||||||
if (altButton.isPressed()) return true;
|
return ALT.readState();
|
||||||
boolean result = altButton.isChecked();
|
|
||||||
if (result) {
|
|
||||||
altButton.setChecked(false);
|
|
||||||
altButton.setTextColor(TEXT_COLOR);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean readFnButton() {
|
public boolean readFnButton() {
|
||||||
if (fnButton.isPressed()) return true;
|
return FN.readState();
|
||||||
boolean result = fnButton.isChecked();
|
|
||||||
if (result) {
|
|
||||||
fnButton.setChecked(false);
|
|
||||||
fnButton.setTextColor(TEXT_COLOR);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void reload() {
|
public void addExternalButton(ExtraButton button) {
|
||||||
altButton = controlButton = null;
|
externalButtons.add(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeExternalButton(ExtraButton button) {
|
||||||
|
externalButtons.remove(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearExternalButton() {
|
||||||
|
externalButtons.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetExternalButtons() {
|
||||||
|
clearExternalButton();
|
||||||
|
externalButtons.add(HORIZONTAL);
|
||||||
|
externalButtons.add(SLASH);
|
||||||
|
externalButtons.add(PIPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadDefaultButtons(List<ExtraButton> buttons) {
|
||||||
|
buttons.add(ESC);
|
||||||
|
buttons.add(CTRL);
|
||||||
|
buttons.add(ALT);
|
||||||
|
buttons.add(TAB);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadExternalButtons(List<ExtraButton> buttons) {
|
||||||
|
buttons.addAll(externalButtons);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reload() {
|
||||||
|
ALT.toggleButton = CTRL.toggleButton = null;
|
||||||
removeAllViews();
|
removeAllViews();
|
||||||
|
|
||||||
String[][] buttons = {
|
extraButtons.clear();
|
||||||
{"ESC", "CTRL", "ALT", "TAB", "―", "/", "|"}
|
loadDefaultButtons(extraButtons);
|
||||||
};
|
loadExternalButtons(extraButtons);
|
||||||
|
|
||||||
final int rows = buttons.length;
|
setRowCount(1);
|
||||||
final int cols = buttons[0].length;
|
setColumnCount(extraButtons.size());
|
||||||
|
|
||||||
setRowCount(rows);
|
for (int col = 0; col < extraButtons.size(); col++) {
|
||||||
setColumnCount(cols);
|
final ExtraButton extraButton = extraButtons.get(col);
|
||||||
|
|
||||||
for (int row = 0; row < rows; row++) {
|
|
||||||
for (int col = 0; col < cols; col++) {
|
|
||||||
final String buttonText = buttons[row][col];
|
|
||||||
|
|
||||||
Button button;
|
Button button;
|
||||||
switch (buttonText) {
|
if (extraButton instanceof StatedControlButton) {
|
||||||
case "CTRL":
|
StatedControlButton btn = ((StatedControlButton) extraButton);
|
||||||
button = controlButton = new ToggleButton(getContext(), null, android.R.attr.buttonBarButtonStyle);
|
button = btn.toggleButton = new ToggleButton(getContext(), null, android.R.attr.buttonBarButtonStyle);
|
||||||
button.setClickable(true);
|
button.setClickable(true);
|
||||||
break;
|
} else {
|
||||||
case "ALT":
|
|
||||||
button = altButton = new ToggleButton(getContext(), null, android.R.attr.buttonBarButtonStyle);
|
|
||||||
button.setClickable(true);
|
|
||||||
break;
|
|
||||||
case "FN":
|
|
||||||
button = fnButton = new ToggleButton(getContext(), null, android.R.attr.buttonBarButtonStyle);
|
|
||||||
button.setClickable(true);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
button = new Button(getContext(), null, android.R.attr.buttonBarButtonStyle);
|
button = new Button(getContext(), null, android.R.attr.buttonBarButtonStyle);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button.setText(buttonText);
|
button.setText(extraButton.buttonText);
|
||||||
button.setTextColor(TEXT_COLOR);
|
button.setTextColor(TEXT_COLOR);
|
||||||
|
|
||||||
final Button finalButton = button;
|
final Button finalButton = button;
|
||||||
@ -146,33 +215,21 @@ public final class ExtraKeysView extends GridLayout {
|
|||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
finalButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
finalButton.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||||
View root = getRootView();
|
View root = getRootView();
|
||||||
switch (buttonText) {
|
extraButton.onClick(root);
|
||||||
case "CTRL":
|
|
||||||
case "ALT":
|
|
||||||
case "FN":
|
|
||||||
ToggleButton self = (ToggleButton) finalButton;
|
|
||||||
self.setChecked(self.isChecked());
|
|
||||||
self.setTextColor(self.isChecked() ? 0xFF80DEEA : TEXT_COLOR);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sendKey(root, buttonText);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
LayoutParams param = new LayoutParams();
|
LayoutParams param = new LayoutParams();
|
||||||
param.height = param.width = 0;
|
param.height = param.width = 0;
|
||||||
param.rightMargin = param.topMargin = 0;
|
param.rightMargin = param.topMargin = 0;
|
||||||
param.setGravity(Gravity.LEFT);
|
param.setGravity(Gravity.START);
|
||||||
float weight = "▲▼◀▶".contains(buttonText) ? 0.7f : 1.f;
|
float weight = "▲▼◀▶".contains(extraButton.buttonText) ? 0.7f : 1.f;
|
||||||
param.columnSpec = GridLayout.spec(col, GridLayout.FILL, weight);
|
param.columnSpec = GridLayout.spec(col, GridLayout.FILL, weight);
|
||||||
param.rowSpec = GridLayout.spec(row, GridLayout.FILL, 1.f);
|
param.rowSpec = GridLayout.spec(0, GridLayout.FILL, 1.f);
|
||||||
button.setLayoutParams(param);
|
button.setLayoutParams(param);
|
||||||
|
|
||||||
addView(button);
|
addView(button);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import android.os.Vibrator
|
|||||||
import io.neoterm.R
|
import io.neoterm.R
|
||||||
import io.neoterm.backend.TerminalSession
|
import io.neoterm.backend.TerminalSession
|
||||||
import io.neoterm.preference.NeoTermPreference
|
import io.neoterm.preference.NeoTermPreference
|
||||||
|
import io.neoterm.view.ExtraKeysView
|
||||||
import io.neoterm.view.TerminalView
|
import io.neoterm.view.TerminalView
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -15,6 +16,7 @@ import io.neoterm.view.TerminalView
|
|||||||
*/
|
*/
|
||||||
class TermSessionChangedCallback : TerminalSession.SessionChangedCallback {
|
class TermSessionChangedCallback : TerminalSession.SessionChangedCallback {
|
||||||
var termView: TerminalView? = null
|
var termView: TerminalView? = null
|
||||||
|
var extraKeysView: ExtraKeysView? = null
|
||||||
var termTab: TermTab? = null
|
var termTab: TermTab? = null
|
||||||
|
|
||||||
var bellId: Int = 0
|
var bellId: Int = 0
|
||||||
|
@ -29,6 +29,7 @@ class TermTab(title: CharSequence) : Tab(title) {
|
|||||||
viewClient?.extraKeysView = null
|
viewClient?.extraKeysView = null
|
||||||
sessionCallback?.termView = null
|
sessionCallback?.termView = null
|
||||||
sessionCallback?.termTab = null
|
sessionCallback?.termTab = null
|
||||||
|
sessionCallback?.extraKeysView = null
|
||||||
closeTabProvider = null
|
closeTabProvider = null
|
||||||
toolbar = null
|
toolbar = null
|
||||||
termSession = null
|
termSession = null
|
||||||
|
@ -68,6 +68,7 @@ class TermTabDecorator(val context: NeoTermActivity) : TabSwitcherDecorator() {
|
|||||||
// 复用前一次的 TermSession
|
// 复用前一次的 TermSession
|
||||||
termTab.sessionCallback?.termView = view
|
termTab.sessionCallback?.termView = view
|
||||||
termTab.sessionCallback?.termTab = termTab
|
termTab.sessionCallback?.termTab = termTab
|
||||||
|
termTab.sessionCallback?.extraKeysView = extraKeysView
|
||||||
|
|
||||||
// 复用上一次的 TermViewClient
|
// 复用上一次的 TermViewClient
|
||||||
termTab.viewClient?.termTab = termTab
|
termTab.viewClient?.termTab = termTab
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<string name="key_general_bell" translatable="false">neoterm_general_bell</string>
|
<string name="key_general_bell" translatable="false">neoterm_general_bell</string>
|
||||||
<string name="key_general_vibrate" translatable="false">neoterm_general_vibrate</string>
|
<string name="key_general_vibrate" translatable="false">neoterm_general_vibrate</string>
|
||||||
<string name="key_generaL_backspace_map_to_esc">neoterm_general_backspace_map_to_esc</string>
|
<string name="key_generaL_backspace_map_to_esc">neoterm_general_backspace_map_to_esc</string>
|
||||||
|
<string name="key_general_shell">neoterm_general_shell</string>
|
||||||
|
|
||||||
<string name="key_ui_fullscreen" translatable="false">neoterm_ui_fullscreen</string>
|
<string name="key_ui_fullscreen" translatable="false">neoterm_ui_fullscreen</string>
|
||||||
<string name="key_ui_font" translatable="false">neoterm_ui_font</string>
|
<string name="key_ui_font" translatable="false">neoterm_ui_font</string>
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
<string name="pref_general_vibrate_desc">Vibrate when receiving \'\\a\'</string>
|
<string name="pref_general_vibrate_desc">Vibrate when receiving \'\\a\'</string>
|
||||||
<string name="pref_general_backspace_map_to_esc">BackSpace Mapped to Esc</string>
|
<string name="pref_general_backspace_map_to_esc">BackSpace Mapped to Esc</string>
|
||||||
<string name="pref_general_backspace_map_to_esc_desc">Send esc when backspace is pressed</string>
|
<string name="pref_general_backspace_map_to_esc_desc">Send esc when backspace is pressed</string>
|
||||||
|
<string name="pref_general_shell">Shell</string>
|
||||||
|
<string name="pref_general_shell_desc">Which shell should we use when login</string>
|
||||||
<string name="pref_ui_fullscreen">Full Screen</string>
|
<string name="pref_ui_fullscreen">Full Screen</string>
|
||||||
<string name="pref_ui_font">Font</string>
|
<string name="pref_ui_font">Font</string>
|
||||||
<string name="pref_ui_color_scheme">Color Scheme</string>
|
<string name="pref_ui_color_scheme">Color Scheme</string>
|
||||||
@ -28,8 +30,15 @@
|
|||||||
<string name="pref_ui_close_tab_anim_next_tab_desc">Switch to next tab instead of previous tab when closing tab</string>
|
<string name="pref_ui_close_tab_anim_next_tab_desc">Switch to next tab instead of previous tab when closing tab</string>
|
||||||
<string name="pref_package_source">Source</string>
|
<string name="pref_package_source">Source</string>
|
||||||
|
|
||||||
<string-array name="pref_ui_color_scheme_entries">
|
<string-array name="pref_ui_color_scheme_entries" translatable="false">
|
||||||
<item>Default</item>
|
<item>Default</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="pref_general_shell_entries" translatable="false">
|
||||||
|
<item>sh</item>
|
||||||
|
<item>zsh</item>
|
||||||
|
<item>bash</item>
|
||||||
|
<item>fish</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -18,4 +18,12 @@
|
|||||||
android:summary="@string/pref_general_backspace_map_to_esc_desc"
|
android:summary="@string/pref_general_backspace_map_to_esc_desc"
|
||||||
android:title="@string/pref_general_backspace_map_to_esc" />
|
android:title="@string/pref_general_backspace_map_to_esc" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="0"
|
||||||
|
android:entries="@array/pref_general_shell_entries"
|
||||||
|
android:entryValues="@array/pref_general_shell_entries"
|
||||||
|
android:key="@string/key_general_shell"
|
||||||
|
android:summary="@string/pref_general_shell_desc"
|
||||||
|
android:title="@string/pref_general_shell" />
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
Reference in New Issue
Block a user