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 62c09ed1..0a565a9a 100644 --- a/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java +++ b/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java @@ -25,6 +25,7 @@ import com.termux.app.TermuxActivity; 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; @@ -42,6 +43,7 @@ import com.termux.shared.termux.TermuxUtils; 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; @@ -172,10 +174,26 @@ public class TermuxTerminalViewClient extends TermuxTerminalViewClientBase { @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 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 @@ -670,13 +688,7 @@ public class TermuxTerminalViewClient extends TermuxTerminalViewClientBase { 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; }); }); diff --git a/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java b/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java index 1e3af9de..8b898434 100644 --- a/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java +++ b/terminal-emulator/src/main/java/com/termux/terminal/TerminalBuffer.java @@ -102,6 +102,45 @@ public final class TerminalBuffer { 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; } diff --git a/terminal-emulator/src/test/java/com/termux/terminal/ScreenBufferTest.java b/terminal-emulator/src/test/java/com/termux/terminal/ScreenBufferTest.java index 23942bf5..9a8f115e 100644 --- a/terminal-emulator/src/test/java/com/termux/terminal/ScreenBufferTest.java +++ b/terminal-emulator/src/test/java/com/termux/terminal/ScreenBufferTest.java @@ -45,4 +45,21 @@ public class ScreenBufferTest extends TerminalTestCase { 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)); + } } diff --git a/terminal-view/src/main/java/com/termux/view/TerminalView.java b/terminal-view/src/main/java/com/termux/view/TerminalView.java index a6ef7106..2b56d66e 100644 --- a/terminal-view/src/main/java/com/termux/view/TerminalView.java +++ b/terminal-view/src/main/java/com/termux/view/TerminalView.java @@ -94,7 +94,7 @@ public final class TerminalView extends View { @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); @@ -114,13 +114,8 @@ public final class TerminalView extends View { 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 @@ -471,10 +466,31 @@ public final class TerminalView extends View { 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; @@ -550,7 +566,6 @@ public final class TerminalView extends View { sendMouseEventCode(event, TerminalEmulator.MOUSE_LEFT_BUTTON_MOVED, true); break; } - return true; } } diff --git a/terminal-view/src/main/java/com/termux/view/textselection/TextSelectionCursorController.java b/terminal-view/src/main/java/com/termux/view/textselection/TextSelectionCursorController.java index 954bf84c..253e8dea 100644 --- a/terminal-view/src/main/java/com/termux/view/textselection/TextSelectionCursorController.java +++ b/terminal-view/src/main/java/com/termux/view/textselection/TextSelectionCursorController.java @@ -89,14 +89,9 @@ public class TextSelectionCursorController implements CursorController { } 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))) {