From c259d8d258494dbdd61595548936fcfcf62ae7aa Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 29 Jan 2018 10:33:55 +0100 Subject: [PATCH] Focus tracking support, fixes #222 --- .../main/java/org/jline/reader/LineReader.java | 2 ++ .../org/jline/reader/impl/LineReaderImpl.java | 15 +++++++++++++++ .../main/java/org/jline/terminal/Terminal.java | 17 +++++++++++++++++ .../jline/terminal/impl/AbstractTerminal.java | 16 ++++++++++++++++ 4 files changed, 50 insertions(+) diff --git a/reader/src/main/java/org/jline/reader/LineReader.java b/reader/src/main/java/org/jline/reader/LineReader.java index 94f2dd98e..86421672f 100644 --- a/reader/src/main/java/org/jline/reader/LineReader.java +++ b/reader/src/main/java/org/jline/reader/LineReader.java @@ -247,6 +247,8 @@ public interface LineReader { String YANK = "yank"; String YANK_POP = "yank-pop"; String MOUSE = "mouse"; + String FOCUS_IN = "terminal-focus-in"; + String FOCUS_OUT = "terminal-focus-out"; String BEGIN_PASTE = "begin-paste"; diff --git a/reader/src/main/java/org/jline/reader/impl/LineReaderImpl.java b/reader/src/main/java/org/jline/reader/impl/LineReaderImpl.java index 94e09dd2c..fee9de870 100644 --- a/reader/src/main/java/org/jline/reader/impl/LineReaderImpl.java +++ b/reader/src/main/java/org/jline/reader/impl/LineReaderImpl.java @@ -100,6 +100,9 @@ public class LineReaderImpl implements LineReader, Flushable public static final String BRACKETED_PASTE_BEGIN = "\033[200~"; public static final String BRACKETED_PASTE_END = "\033[201~"; + public static final String FOCUS_IN_SEQ = "\033[I"; + public static final String FOCUS_OUT_SEQ = "\033[O"; + /** * Possible states in which the current readline operation may be in. */ @@ -3338,6 +3341,8 @@ protected Map builtinWidgets() { widgets.put(YANK_POP, this::yankPop); widgets.put(MOUSE, this::mouse); widgets.put(BEGIN_PASTE, this::beginPaste); + widgets.put(FOCUS_IN, this::focusIn); + widgets.put(FOCUS_OUT, this::focusOut); return widgets; } @@ -4995,6 +5000,14 @@ public boolean beginPaste() { return true; } + public boolean focusIn() { + return false; + } + + public boolean focusOut() { + return false; + } + /** * Clean the used display */ @@ -5426,6 +5439,8 @@ private void bindArrowKeys(KeyMap map) { bind(map, OVERWRITE_MODE, key(Capability.key_ic)); bind(map, MOUSE, key(Capability.key_mouse)); bind(map, BEGIN_PASTE, BRACKETED_PASTE_BEGIN); + bind(map, FOCUS_IN, FOCUS_IN_SEQ); + bind(map, FOCUS_OUT, FOCUS_OUT_SEQ); } /** diff --git a/terminal/src/main/java/org/jline/terminal/Terminal.java b/terminal/src/main/java/org/jline/terminal/Terminal.java index 76ec1a381..95ac3bed4 100644 --- a/terminal/src/main/java/org/jline/terminal/Terminal.java +++ b/terminal/src/main/java/org/jline/terminal/Terminal.java @@ -247,4 +247,21 @@ enum MouseTracking { */ MouseEvent readMouseEvent(IntSupplier reader); + /** + * Returns true if the terminal has support for focus tracking. + * @return whether focus tracking is supported by the terminal + * @see #trackFocus(boolean) + */ + boolean hasFocusSupport(); + + /** + * Enable or disable focus tracking mode. + * When focus tracking has been activated, each time the terminal grabs the focus, + * the string "\33[I" will be sent to the input stream and each time the focus is lost, + * the string "\33[O" will be sent to the input stream. + * + * @param tracking whether the focus tracking mode should be enabled or not + * @return true if focus tracking is supported + */ + boolean trackFocus(boolean tracking); } diff --git a/terminal/src/main/java/org/jline/terminal/impl/AbstractTerminal.java b/terminal/src/main/java/org/jline/terminal/impl/AbstractTerminal.java index c88406998..7f899d601 100644 --- a/terminal/src/main/java/org/jline/terminal/impl/AbstractTerminal.java +++ b/terminal/src/main/java/org/jline/terminal/impl/AbstractTerminal.java @@ -206,6 +206,22 @@ public MouseEvent readMouseEvent(IntSupplier reader) { return lastMouseEvent = MouseSupport.readMouse(reader, lastMouseEvent); } + @Override + public boolean hasFocusSupport() { + return type != null && type.startsWith("xterm"); + } + + @Override + public boolean trackFocus(boolean tracking) { + if (hasFocusSupport()) { + writer().write(tracking ? "\033[?1004h" : "\033[?1004l"); + writer().flush(); + return true; + } else { + return false; + } + } + protected void checkInterrupted() throws InterruptedIOException { if (Thread.interrupted()) { throw new InterruptedIOException();