Skip to content

Commit 2d38a1c

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 096464d commit 2d38a1c

File tree

7 files changed

+90
-7
lines changed

7 files changed

+90
-7
lines changed

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.termux.app.terminal.TermuxActivityRootView;
3737
import com.termux.shared.activities.ReportActivity;
3838
import com.termux.shared.packages.PermissionUtils;
39+
import com.termux.shared.data.DataUtils;
3940
import com.termux.shared.termux.TermuxConstants;
4041
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY;
4142
import com.termux.app.activities.HelpActivity;
@@ -162,6 +163,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
162163

163164
private static final int CONTEXT_MENU_SELECT_URL_ID = 0;
164165
private static final int CONTEXT_MENU_SHARE_TRANSCRIPT_ID = 1;
166+
private static final int CONTEXT_MENU_SHARE_SELECTED_TEXT = 10;
165167
private static final int CONTEXT_MENU_AUTOFILL_ID = 2;
166168
private static final int CONTEXT_MENU_RESET_TERMINAL_ID = 3;
167169
private static final int CONTEXT_MENU_KILL_PROCESS_ID = 4;
@@ -597,7 +599,10 @@ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuIn
597599

598600
menu.add(Menu.NONE, CONTEXT_MENU_SELECT_URL_ID, Menu.NONE, R.string.action_select_url);
599601
menu.add(Menu.NONE, CONTEXT_MENU_SHARE_TRANSCRIPT_ID, Menu.NONE, R.string.action_share_transcript);
600-
if (addAutoFillMenu) menu.add(Menu.NONE, CONTEXT_MENU_AUTOFILL_ID, Menu.NONE, R.string.action_autofill_password);
602+
if (!DataUtils.isNullOrEmpty(mTerminalView.getStoredSelectedText()))
603+
menu.add(Menu.NONE, CONTEXT_MENU_SHARE_SELECTED_TEXT, Menu.NONE, R.string.action_share_selected_text);
604+
if (addAutoFillMenu)
605+
menu.add(Menu.NONE, CONTEXT_MENU_AUTOFILL_ID, Menu.NONE, R.string.action_autofill_password);
601606
menu.add(Menu.NONE, CONTEXT_MENU_RESET_TERMINAL_ID, Menu.NONE, R.string.action_reset_terminal);
602607
menu.add(Menu.NONE, CONTEXT_MENU_KILL_PROCESS_ID, Menu.NONE, getResources().getString(R.string.action_kill_process, getCurrentSession().getPid())).setEnabled(currentSession.isRunning());
603608
menu.add(Menu.NONE, CONTEXT_MENU_STYLING_ID, Menu.NONE, R.string.action_style_terminal);
@@ -625,6 +630,9 @@ public boolean onContextItemSelected(MenuItem item) {
625630
case CONTEXT_MENU_SHARE_TRANSCRIPT_ID:
626631
mTermuxTerminalViewClient.shareSessionTranscript();
627632
return true;
633+
case CONTEXT_MENU_SHARE_SELECTED_TEXT:
634+
mTermuxTerminalViewClient.shareSelectedText();
635+
return true;
628636
case CONTEXT_MENU_AUTOFILL_ID:
629637
requestAutoFill();
630638
return true;
@@ -654,6 +662,13 @@ public boolean onContextItemSelected(MenuItem item) {
654662
}
655663
}
656664

665+
@Override
666+
public void onContextMenuClosed(Menu menu) {
667+
super.onContextMenuClosed(menu);
668+
// onContextMenuClosed() is triggered twice if back button is pressed to dismiss instead of tap for some reason
669+
mTerminalView.onContextMenuClosed(menu);
670+
}
671+
657672
private void showKillSessionDialog(TerminalSession session) {
658673
if (session == null) return;
659674

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.termux.R;
1616
import com.termux.shared.shell.TermuxSession;
1717
import com.termux.shared.interact.TextInputDialogUtils;
18+
import com.termux.shared.interact.ShareUtils;
1819
import com.termux.app.TermuxActivity;
1920
import com.termux.shared.terminal.TermuxTerminalSessionClientBase;
2021
import com.termux.shared.termux.TermuxConstants;

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

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

655+
public void shareSelectedText() {
656+
String selectedText = mActivity.getTerminalView().getStoredSelectedText();
657+
if (DataUtils.isNullOrEmpty(selectedText)) return;
658+
ShareUtils.shareText(mActivity, mActivity.getString(R.string.title_share_selected_text),
659+
selectedText, mActivity.getString(R.string.title_share_selected_text_with));
660+
}
661+
655662
public void showUrlSelection() {
656663
TerminalSession session = mActivity.getCurrentSession();
657664
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
@@ -65,6 +65,10 @@
6565
<string name="title_share_transcript">Terminal transcript</string>
6666
<string name="title_share_transcript_with">Send transcript to:</string>
6767

68+
<string name="action_share_selected_text">Share selected text</string>
69+
<string name="title_share_selected_text">Terminal Text</string>
70+
<string name="title_share_selected_text_with">Send selected text to:</string>
71+
6872
<string name="action_autofill_password">Autofill password</string>
6973

7074
<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;
@@ -20,6 +21,7 @@
2021
import android.view.InputDevice;
2122
import android.view.KeyCharacterMap;
2223
import android.view.KeyEvent;
24+
import android.view.Menu;
2325
import android.view.MotionEvent;
2426
import android.view.View;
2527
import android.view.ViewConfiguration;
@@ -31,6 +33,7 @@
3133
import android.view.inputmethod.InputConnection;
3234
import android.widget.Scroller;
3335

36+
import androidx.annotation.Nullable;
3437
import androidx.annotation.RequiresApi;
3538

3639
import com.termux.terminal.KeyHandler;
@@ -441,6 +444,14 @@ public void onScreenUpdated() {
441444
if (mAccessibilityEnabled) setContentDescription(getText());
442445
}
443446

447+
/** This must be called by the hosting activity in {@link Activity#onContextMenuClosed(Menu)}
448+
* when context menu for the {@link TerminalView} is started by
449+
* {@link TextSelectionCursorController#ACTION_MORE} is closed. */
450+
public void onContextMenuClosed(Menu menu) {
451+
// Unset the stored text since it shouldn't be used anymore and should be cleared from memory
452+
unsetStoredSelectedText();
453+
}
454+
444455
/**
445456
* Sets the text size, which in turn sets the number of rows and columns.
446457
*
@@ -1211,6 +1222,25 @@ public boolean isSelectingText() {
12111222
}
12121223
}
12131224

1225+
/** Get the currently selected text if selecting. */
1226+
public String getSelectedText() {
1227+
if (isSelectingText() && mTextSelectionCursorController != null)
1228+
return mTextSelectionCursorController.getSelectedText();
1229+
else
1230+
return null;
1231+
}
1232+
1233+
/** Get the selected text stored before "MORE" button was pressed on the context menu. */
1234+
@Nullable
1235+
public String getStoredSelectedText() {
1236+
return mTextSelectionCursorController != null ? mTextSelectionCursorController.getStoredSelectedText() : null;
1237+
}
1238+
1239+
/** Unset the selected text stored before "MORE" button was pressed on the context menu. */
1240+
public void unsetStoredSelectedText() {
1241+
if (mTextSelectionCursorController != null) mTextSelectionCursorController.unsetStoredSelectedText();
1242+
}
1243+
12141244
private ActionMode getTextSelectionActionMode() {
12151245
if (mTextSelectionCursorController != null) {
12161246
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
@@ -12,6 +12,8 @@
1212
import android.view.MotionEvent;
1313
import android.view.View;
1414

15+
import androidx.annotation.Nullable;
16+
1517
import com.termux.terminal.TerminalBuffer;
1618
import com.termux.terminal.WcWidth;
1719
import com.termux.view.R;
@@ -21,16 +23,17 @@ public class TextSelectionCursorController implements CursorController {
2123

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

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

3033
private ActionMode mActionMode;
31-
private final int ACTION_COPY = 1;
32-
private final int ACTION_PASTE = 2;
33-
private final int ACTION_MORE = 3;
34+
public final int ACTION_COPY = 1;
35+
public final int ACTION_PASTE = 2;
36+
public final int ACTION_MORE = 3;
3437

3538
public TextSelectionCursorController(TerminalView terminalView) {
3639
this.terminalView = terminalView;
@@ -113,7 +116,7 @@ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
113116

114117
ClipboardManager clipboard = (ClipboardManager) terminalView.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
115118
menu.add(Menu.NONE, ACTION_COPY, Menu.NONE, R.string.copy_text).setShowAsAction(show);
116-
menu.add(Menu.NONE, ACTION_PASTE, Menu.NONE, R.string.paste_text).setEnabled(clipboard.hasPrimaryClip()).setShowAsAction(show);
119+
menu.add(Menu.NONE, ACTION_PASTE, Menu.NONE, R.string.paste_text).setEnabled(clipboard != null && clipboard.hasPrimaryClip()).setShowAsAction(show);
117120
menu.add(Menu.NONE, ACTION_MORE, Menu.NONE, R.string.text_selection_more);
118121
return true;
119122
}
@@ -132,7 +135,7 @@ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
132135

133136
switch (item.getItemId()) {
134137
case ACTION_COPY:
135-
String selectedText = terminalView.mEmulator.getSelectedText(mSelX1, mSelY1, mSelX2, mSelY2).trim();
138+
String selectedText = getSelectedText();
136139
terminalView.mTermSession.onCopyTextToClipboard(selectedText);
137140
terminalView.stopTextSelectionMode();
138141
break;
@@ -141,7 +144,13 @@ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
141144
terminalView.mTermSession.onPasteTextFromClipboard();
142145
break;
143146
case ACTION_MORE:
144-
terminalView.stopTextSelectionMode(); //we stop text selection first, otherwise handles will show above popup
147+
// We first store the selected text in case TerminalViewClient needs the
148+
// selected text before MORE button was pressed since we are going to
149+
// stop selection mode
150+
mStoredSelectedText = getSelectedText();
151+
// The text selection needs to be stopped before showing context menu,
152+
// otherwise handles will show above popup
153+
terminalView.stopTextSelectionMode();
145154
terminalView.showContextMenu();
146155
break;
147156
}
@@ -356,6 +365,22 @@ public void getSelectors(int[] sel) {
356365
sel[3] = mSelX2;
357366
}
358367

368+
/** Get the currently selected text. */
369+
public String getSelectedText() {
370+
return terminalView.mEmulator.getSelectedText(mSelX1, mSelY1, mSelX2, mSelY2);
371+
}
372+
373+
/** Get the selected text stored before "MORE" button was pressed on the context menu. */
374+
@Nullable
375+
public String getStoredSelectedText() {
376+
return mStoredSelectedText;
377+
}
378+
379+
/** Unset the selected text stored before "MORE" button was pressed on the context menu. */
380+
public void unsetStoredSelectedText() {
381+
mStoredSelectedText = null;
382+
}
383+
359384
public ActionMode getActionMode() {
360385
return mActionMode;
361386
}

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
@@ -155,6 +155,7 @@ public static CharSequence getTextFromClipboard(Context context, boolean coerceT
155155

156156

157157

158+
/**
158159
* Open a url.
159160
*
160161
* @param context The context for operations.

0 commit comments

Comments
 (0)