Skip to content

Commit 3f7a939

Browse files
Added: Add support for Share selected text of terminal in long hold MORE menu so that users don't have to copy and paste to move text between apps
1 parent 0c14c29 commit 3f7a939

7 files changed

Lines changed: 90 additions & 7 deletions

File tree

app/src/main/java/com/termux/app/TermuxActivity.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import com.termux.shared.activity.media.AppCompatActivityUtils;
3939
import com.termux.shared.data.IntentUtils;
4040
import com.termux.shared.android.PermissionUtils;
41+
import com.termux.shared.data.DataUtils;
4142
import com.termux.shared.termux.TermuxConstants;
4243
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY;
4344
import com.termux.app.activities.HelpActivity;
@@ -179,6 +180,7 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo
179180

180181
private static final int CONTEXT_MENU_SELECT_URL_ID = 0;
181182
private static final int CONTEXT_MENU_SHARE_TRANSCRIPT_ID = 1;
183+
private static final int CONTEXT_MENU_SHARE_SELECTED_TEXT = 10;
182184
private static final int CONTEXT_MENU_AUTOFILL_ID = 2;
183185
private static final int CONTEXT_MENU_RESET_TERMINAL_ID = 3;
184186
private static final int CONTEXT_MENU_KILL_PROCESS_ID = 4;
@@ -640,7 +642,10 @@ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuIn
640642

641643
menu.add(Menu.NONE, CONTEXT_MENU_SELECT_URL_ID, Menu.NONE, R.string.action_select_url);
642644
menu.add(Menu.NONE, CONTEXT_MENU_SHARE_TRANSCRIPT_ID, Menu.NONE, R.string.action_share_transcript);
643-
if (addAutoFillMenu) menu.add(Menu.NONE, CONTEXT_MENU_AUTOFILL_ID, Menu.NONE, R.string.action_autofill_password);
645+
if (!DataUtils.isNullOrEmpty(mTerminalView.getStoredSelectedText()))
646+
menu.add(Menu.NONE, CONTEXT_MENU_SHARE_SELECTED_TEXT, Menu.NONE, R.string.action_share_selected_text);
647+
if (addAutoFillMenu)
648+
menu.add(Menu.NONE, CONTEXT_MENU_AUTOFILL_ID, Menu.NONE, R.string.action_autofill_password);
644649
menu.add(Menu.NONE, CONTEXT_MENU_RESET_TERMINAL_ID, Menu.NONE, R.string.action_reset_terminal);
645650
menu.add(Menu.NONE, CONTEXT_MENU_KILL_PROCESS_ID, Menu.NONE, getResources().getString(R.string.action_kill_process, getCurrentSession().getPid())).setEnabled(currentSession.isRunning());
646651
menu.add(Menu.NONE, CONTEXT_MENU_STYLING_ID, Menu.NONE, R.string.action_style_terminal);
@@ -668,6 +673,9 @@ public boolean onContextItemSelected(MenuItem item) {
668673
case CONTEXT_MENU_SHARE_TRANSCRIPT_ID:
669674
mTermuxTerminalViewClient.shareSessionTranscript();
670675
return true;
676+
case CONTEXT_MENU_SHARE_SELECTED_TEXT:
677+
mTermuxTerminalViewClient.shareSelectedText();
678+
return true;
671679
case CONTEXT_MENU_AUTOFILL_ID:
672680
requestAutoFill();
673681
return true;
@@ -697,6 +705,13 @@ public boolean onContextItemSelected(MenuItem item) {
697705
}
698706
}
699707

708+
@Override
709+
public void onContextMenuClosed(Menu menu) {
710+
super.onContextMenuClosed(menu);
711+
// onContextMenuClosed() is triggered twice if back button is pressed to dismiss instead of tap for some reason
712+
mTerminalView.onContextMenuClosed(menu);
713+
}
714+
700715
private void showKillSessionDialog(TerminalSession session) {
701716
if (session == null) return;
702717

app/src/main/java/com/termux/app/terminal/TermuxTerminalSessionActivityClient.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import androidx.annotation.Nullable;
1818

1919
import com.termux.R;
20+
import com.termux.shared.interact.ShareUtils;
2021
import com.termux.shared.termux.shell.command.runner.terminal.TermuxSession;
2122
import com.termux.shared.termux.interact.TextInputDialogUtils;
2223
import com.termux.app.TermuxActivity;

app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,13 @@ public void shareSessionTranscript() {
684684
transcriptText, mActivity.getString(R.string.title_share_transcript_with));
685685
}
686686

687+
public void shareSelectedText() {
688+
String selectedText = mActivity.getTerminalView().getStoredSelectedText();
689+
if (DataUtils.isNullOrEmpty(selectedText)) return;
690+
ShareUtils.shareText(mActivity, mActivity.getString(R.string.title_share_selected_text),
691+
selectedText, mActivity.getString(R.string.title_share_selected_text_with));
692+
}
693+
687694
public void showUrlSelection() {
688695
TerminalSession session = mActivity.getCurrentSession();
689696
if (session == null) return;

app/src/main/res/values/strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@
6969
<string name="title_share_transcript">Terminal transcript</string>
7070
<string name="title_share_transcript_with">Send transcript to:</string>
7171

72+
<string name="action_share_selected_text">Share selected text</string>
73+
<string name="title_share_selected_text">Terminal Text</string>
74+
<string name="title_share_selected_text_with">Send selected text to:</string>
75+
7276
<string name="action_autofill_password">Autofill password</string>
7377

7478
<string name="action_reset_terminal">Reset</string>

terminal-view/src/main/java/com/termux/view/TerminalView.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import android.annotation.SuppressLint;
44
import android.annotation.TargetApi;
5+
import android.app.Activity;
56
import android.content.ClipData;
67
import android.content.ClipboardManager;
78
import android.content.Context;
@@ -19,6 +20,7 @@
1920
import android.view.InputDevice;
2021
import android.view.KeyCharacterMap;
2122
import android.view.KeyEvent;
23+
import android.view.Menu;
2224
import android.view.MotionEvent;
2325
import android.view.View;
2426
import android.view.ViewConfiguration;
@@ -30,6 +32,7 @@
3032
import android.view.inputmethod.InputConnection;
3133
import android.widget.Scroller;
3234

35+
import androidx.annotation.Nullable;
3336
import androidx.annotation.RequiresApi;
3437

3538
import com.termux.terminal.KeyHandler;
@@ -456,6 +459,14 @@ public void onScreenUpdated(boolean skipScrolling) {
456459
if (mAccessibilityEnabled) setContentDescription(getText());
457460
}
458461

462+
/** This must be called by the hosting activity in {@link Activity#onContextMenuClosed(Menu)}
463+
* when context menu for the {@link TerminalView} is started by
464+
* {@link TextSelectionCursorController#ACTION_MORE} is closed. */
465+
public void onContextMenuClosed(Menu menu) {
466+
// Unset the stored text since it shouldn't be used anymore and should be cleared from memory
467+
unsetStoredSelectedText();
468+
}
469+
459470
/**
460471
* Sets the text size, which in turn sets the number of rows and columns.
461472
*
@@ -1206,6 +1217,25 @@ public boolean isSelectingText() {
12061217
}
12071218
}
12081219

1220+
/** Get the currently selected text if selecting. */
1221+
public String getSelectedText() {
1222+
if (isSelectingText() && mTextSelectionCursorController != null)
1223+
return mTextSelectionCursorController.getSelectedText();
1224+
else
1225+
return null;
1226+
}
1227+
1228+
/** Get the selected text stored before "MORE" button was pressed on the context menu. */
1229+
@Nullable
1230+
public String getStoredSelectedText() {
1231+
return mTextSelectionCursorController != null ? mTextSelectionCursorController.getStoredSelectedText() : null;
1232+
}
1233+
1234+
/** Unset the selected text stored before "MORE" button was pressed on the context menu. */
1235+
public void unsetStoredSelectedText() {
1236+
if (mTextSelectionCursorController != null) mTextSelectionCursorController.unsetStoredSelectedText();
1237+
}
1238+
12091239
private ActionMode getTextSelectionActionMode() {
12101240
if (mTextSelectionCursorController != null) {
12111241
return mTextSelectionCursorController.getActionMode();

terminal-view/src/main/java/com/termux/view/textselection/TextSelectionCursorController.java

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import android.view.MotionEvent;
1212
import android.view.View;
1313

14+
import androidx.annotation.Nullable;
15+
1416
import com.termux.terminal.TerminalBuffer;
1517
import com.termux.terminal.WcWidth;
1618
import com.termux.view.R;
@@ -20,16 +22,17 @@ public class TextSelectionCursorController implements CursorController {
2022

2123
private final TerminalView terminalView;
2224
private final TextSelectionHandleView mStartHandle, mEndHandle;
25+
private String mStoredSelectedText;
2326
private boolean mIsSelectingText = false;
2427
private long mShowStartTime = System.currentTimeMillis();
2528

2629
private final int mHandleHeight;
2730
private int mSelX1 = -1, mSelX2 = -1, mSelY1 = -1, mSelY2 = -1;
2831

2932
private ActionMode mActionMode;
30-
private final int ACTION_COPY = 1;
31-
private final int ACTION_PASTE = 2;
32-
private final int ACTION_MORE = 3;
33+
public final int ACTION_COPY = 1;
34+
public final int ACTION_PASTE = 2;
35+
public final int ACTION_MORE = 3;
3336

3437
public TextSelectionCursorController(TerminalView terminalView) {
3538
this.terminalView = terminalView;
@@ -112,7 +115,7 @@ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
112115

113116
ClipboardManager clipboard = (ClipboardManager) terminalView.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
114117
menu.add(Menu.NONE, ACTION_COPY, Menu.NONE, R.string.copy_text).setShowAsAction(show);
115-
menu.add(Menu.NONE, ACTION_PASTE, Menu.NONE, R.string.paste_text).setEnabled(clipboard.hasPrimaryClip()).setShowAsAction(show);
118+
menu.add(Menu.NONE, ACTION_PASTE, Menu.NONE, R.string.paste_text).setEnabled(clipboard != null && clipboard.hasPrimaryClip()).setShowAsAction(show);
116119
menu.add(Menu.NONE, ACTION_MORE, Menu.NONE, R.string.text_selection_more);
117120
return true;
118121
}
@@ -131,7 +134,7 @@ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
131134

132135
switch (item.getItemId()) {
133136
case ACTION_COPY:
134-
String selectedText = terminalView.mEmulator.getSelectedText(mSelX1, mSelY1, mSelX2, mSelY2).trim();
137+
String selectedText = getSelectedText();
135138
terminalView.mTermSession.onCopyTextToClipboard(selectedText);
136139
terminalView.stopTextSelectionMode();
137140
break;
@@ -140,7 +143,13 @@ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
140143
terminalView.mTermSession.onPasteTextFromClipboard();
141144
break;
142145
case ACTION_MORE:
143-
terminalView.stopTextSelectionMode(); //we stop text selection first, otherwise handles will show above popup
146+
// We first store the selected text in case TerminalViewClient needs the
147+
// selected text before MORE button was pressed since we are going to
148+
// stop selection mode
149+
mStoredSelectedText = getSelectedText();
150+
// The text selection needs to be stopped before showing context menu,
151+
// otherwise handles will show above popup
152+
terminalView.stopTextSelectionMode();
144153
terminalView.showContextMenu();
145154
break;
146155
}
@@ -361,6 +370,22 @@ public void getSelectors(int[] sel) {
361370
sel[3] = mSelX2;
362371
}
363372

373+
/** Get the currently selected text. */
374+
public String getSelectedText() {
375+
return terminalView.mEmulator.getSelectedText(mSelX1, mSelY1, mSelX2, mSelY2);
376+
}
377+
378+
/** Get the selected text stored before "MORE" button was pressed on the context menu. */
379+
@Nullable
380+
public String getStoredSelectedText() {
381+
return mStoredSelectedText;
382+
}
383+
384+
/** Unset the selected text stored before "MORE" button was pressed on the context menu. */
385+
public void unsetStoredSelectedText() {
386+
mStoredSelectedText = null;
387+
}
388+
364389
public ActionMode getActionMode() {
365390
return mActionMode;
366391
}

termux-shared/src/main/java/com/termux/shared/interact/ShareUtils.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ public static CharSequence getTextFromClipboard(Context context, boolean coerceT
156156

157157

158158

159+
/**
159160
* Open a url.
160161
*
161162
* @param context The context for operations.

0 commit comments

Comments
 (0)