Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support clicking directly on a URL to open it #2146

Merged
merged 2 commits into from
Oct 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.termux.shared.data.UrlUtils;
import com.termux.shared.file.FileUtils;
import com.termux.shared.interact.MessageDialogUtils;
import com.termux.shared.interact.ShareUtils;
import com.termux.shared.shell.ShellUtils;
import com.termux.shared.terminal.TermuxTerminalViewClientBase;
import com.termux.shared.terminal.io.extrakeys.SpecialButton;
Expand All @@ -42,6 +43,7 @@
import com.termux.shared.view.KeyboardUtils;
import com.termux.shared.view.ViewUtils;
import com.termux.terminal.KeyHandler;
import com.termux.terminal.TerminalBuffer;
import com.termux.terminal.TerminalEmulator;
import com.termux.terminal.TerminalSession;

Expand Down Expand Up @@ -172,10 +174,26 @@ public float onScale(float scale) {

@Override
public void onSingleTapUp(MotionEvent e) {
if (!KeyboardUtils.areDisableSoftKeyboardFlagsSet(mActivity))
KeyboardUtils.showSoftKeyboard(mActivity, mActivity.getTerminalView());
else
Logger.logVerbose(LOG_TAG, "Not showing soft keyboard onSingleTapUp since its disabled");
TerminalEmulator term = mActivity.getCurrentSession().getEmulator();

if (mActivity.getProperties().shouldOpenTerminalTranscriptURLOnClick()) {
int[] columnAndRow = mActivity.getTerminalView().getColumnAndRow(e, true);
String wordAtTap = term.getScreen().getWordAtLocation(columnAndRow[0], columnAndRow[1]);
LinkedHashSet<CharSequence> urlSet = UrlUtils.extractUrls(wordAtTap);

if (!urlSet.isEmpty()) {
String url = (String) urlSet.iterator().next();
ShareUtils.openURL(mActivity, url);
return;
}
}

if (!term.isMouseTrackingActive() && !e.isFromSource(InputDevice.SOURCE_MOUSE)) {
if (!KeyboardUtils.areDisableSoftKeyboardFlagsSet(mActivity))
KeyboardUtils.showSoftKeyboard(mActivity, mActivity.getTerminalView());
else
Logger.logVerbose(LOG_TAG, "Not showing soft keyboard onSingleTapUp since its disabled");
}
}

@Override
Expand Down Expand Up @@ -670,13 +688,7 @@ public void showUrlSelection() {
lv.setOnItemLongClickListener((parent, view, position, id) -> {
dialog.dismiss();
String url = (String) urls[position];
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
try {
mActivity.startActivity(i, null);
} catch (ActivityNotFoundException e) {
// If no applications match, Android displays a system message.
mActivity.startActivity(Intent.createChooser(i, null));
}
ShareUtils.openURL(mActivity, url);
return true;
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,45 @@ public String getSelectedText(int selX1, int selY1, int selX2, int selY2, boolea
return builder.toString();
}

public String getWordAtLocation(int x, int y) {
// Set y1 and y2 to the lines where the wrapped line starts and ends.
// I.e. if a line that is wrapped to 3 lines starts at line 4, and this
// is called with y=5, then y1 would be set to 4 and y2 would be set to 6.
int y1 = y;
int y2 = y;
while (y1 > 0 && !getSelectedText(0, y1 - 1, mColumns, y, true, true).contains("\n")) {
y1--;
}
while (y2 < mScreenRows && !getSelectedText(0, y, mColumns, y2 + 1, true, true).contains("\n")) {
y2++;
}

// Get the text for the whole wrapped line
String text = getSelectedText(0, y1, mColumns, y2, true, true);
// The index of x in text
int textOffset = (y - y1) * mColumns + x;

if (textOffset >= text.length()) {
// The click was to the right of the last word on the line, so
// there's no word to return
return "";
}

// Set x1 and x2 to the indices of the last space before x and the
// first space after x in text respectively
int x1 = text.lastIndexOf(' ', textOffset);
int x2 = text.indexOf(' ', textOffset);
if (x2 == -1) {
x2 = text.length();
}

if (x1 == x2) {
// The click was on a space, so there's no word to return
return "";
}
return text.substring(x1 + 1, x2);
}

public int getActiveTranscriptRows() {
return mActiveTranscriptRows;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,21 @@ public void testGetSelectedTextJoinFullLines() {
withTerminalSized(5, 3).enterString("ABC\r\nFG");
assertEquals("ABC\nFG", mTerminal.getScreen().getSelectedText(0, 0, 1, 1, true, true));
}

public void testGetWordAtLocation() {
withTerminalSized(5, 3).enterString("ABCDEFGHIJ\r\nKLMNO");
assertEquals("ABCDEFGHIJKLMNO", mTerminal.getScreen().getWordAtLocation(0, 0));
assertEquals("ABCDEFGHIJKLMNO", mTerminal.getScreen().getWordAtLocation(4, 1));
assertEquals("ABCDEFGHIJKLMNO", mTerminal.getScreen().getWordAtLocation(4, 2));

withTerminalSized(5, 3).enterString("ABC DEF GHI ");
assertEquals("ABC", mTerminal.getScreen().getWordAtLocation(0, 0));
assertEquals("", mTerminal.getScreen().getWordAtLocation(3, 0));
assertEquals("DEF", mTerminal.getScreen().getWordAtLocation(4, 0));
assertEquals("DEF", mTerminal.getScreen().getWordAtLocation(0, 1));
assertEquals("DEF", mTerminal.getScreen().getWordAtLocation(1, 1));
assertEquals("GHI", mTerminal.getScreen().getWordAtLocation(0, 2));
assertEquals("", mTerminal.getScreen().getWordAtLocation(1, 2));
assertEquals("", mTerminal.getScreen().getWordAtLocation(2, 2));
}
}
37 changes: 26 additions & 11 deletions terminal-view/src/main/java/com/termux/view/TerminalView.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public TerminalView(Context context, AttributeSet attributes) { // NO_UCD (unuse
@Override
public boolean onUp(MotionEvent event) {
mScrollRemainder = 0.0f;
if (mEmulator != null && mEmulator.isMouseTrackingActive() && !isSelectingText() && !scrolledWithFinger) {
if (mEmulator != null && mEmulator.isMouseTrackingActive() && !event.isFromSource(InputDevice.SOURCE_MOUSE) && !isSelectingText() && !scrolledWithFinger) {
// Quick event processing when mouse tracking is active - do not wait for check of double tapping
// for zooming.
sendMouseEventCode(event, TerminalEmulator.MOUSE_LEFT_BUTTON, true);
Expand All @@ -114,13 +114,8 @@ public boolean onSingleTapUp(MotionEvent event) {
return true;
}
requestFocus();
if (!mEmulator.isMouseTrackingActive()) {
if (!event.isFromSource(InputDevice.SOURCE_MOUSE)) {
mClient.onSingleTapUp(event);
return true;
}
}
return false;
mClient.onSingleTapUp(event);
return true;
}

@Override
Expand Down Expand Up @@ -471,10 +466,31 @@ public boolean isOpaque() {
return true;
}

/**
* Get the zero indexed column and row of the terminal view for the
* position of the event.
*
* @param event The event with the position to get the column and row for.
* @param relativeToScroll If true the column number will take the scroll
* position into account. E.g. if scrolled 3 lines up and the event
* position is in the top left, column will be -3 if relativeToScroll is
* true and 0 if relativeToScroll is false.
* @return Array with the column and row.
*/
public int[] getColumnAndRow(MotionEvent event, boolean relativeToScroll) {
int column = (int) (event.getX() / mRenderer.mFontWidth);
int row = (int) ((event.getY() - mRenderer.mFontLineSpacingAndAscent) / mRenderer.mFontLineSpacing);
if (relativeToScroll) {
row += mTopRow;
}
return new int[] { column, row };
}

/** Send a single mouse event code to the terminal. */
void sendMouseEventCode(MotionEvent e, int button, boolean pressed) {
int x = (int) (e.getX() / mRenderer.mFontWidth) + 1;
int y = (int) ((e.getY() - mRenderer.mFontLineSpacingAndAscent) / mRenderer.mFontLineSpacing) + 1;
int[] columnAndRow = getColumnAndRow(e, false);
int x = columnAndRow[0] + 1;
int y = columnAndRow[1] + 1;
if (pressed && (button == TerminalEmulator.MOUSE_WHEELDOWN_BUTTON || button == TerminalEmulator.MOUSE_WHEELUP_BUTTON)) {
if (mMouseStartDownTime == e.getDownTime()) {
x = mMouseScrollStartX;
Expand Down Expand Up @@ -550,7 +566,6 @@ public boolean onTouchEvent(MotionEvent event) {
sendMouseEventCode(event, TerminalEmulator.MOUSE_LEFT_BUTTON_MOVED, true);
break;
}
return true;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,9 @@ public void render() {
}

public void setInitialTextSelectionPosition(MotionEvent event) {
int cx = (int) (event.getX() / terminalView.mRenderer.getFontWidth());
final boolean eventFromMouse = event.isFromSource(InputDevice.SOURCE_MOUSE);
// Offset for finger:
final int SELECT_TEXT_OFFSET_Y = eventFromMouse ? 0 : -40;
int cy = (int) ((event.getY() + SELECT_TEXT_OFFSET_Y) / terminalView.mRenderer.getFontLineSpacing()) + terminalView.getTopRow();

mSelX1 = mSelX2 = cx;
mSelY1 = mSelY2 = cy;
int[] columnAndRow = terminalView.getColumnAndRow(event, true);
mSelX1 = mSelX2 = columnAndRow[0];
mSelY1 = mSelY2 = columnAndRow[1];

TerminalBuffer screen = terminalView.mEmulator.getScreen();
if (!" ".equals(screen.getSelectedText(mSelX1, mSelY1, mSelX1, mSelY1))) {
Expand Down