From 978a5d8f650488c8840d54ccc3032599ca50a084 Mon Sep 17 00:00:00 2001 From: Kevin Lamonte Date: Mon, 11 Feb 2019 20:57:31 -0600 Subject: [PATCH] hidden mouse pointer support --- src/jexer/TApplication.java | 19 ++++++++ src/jexer/TTerminalWindow.java | 3 +- src/jexer/TWidget.java | 2 +- src/jexer/TWindow.java | 31 +++++++++++++ src/jexer/backend/ECMA48Terminal.java | 9 +++- src/jexer/menu/TMenu.java | 2 +- src/jexer/tterminal/ECMA48.java | 65 ++++++++++++++++++++++++++- 7 files changed, 125 insertions(+), 6 deletions(-) diff --git a/src/jexer/TApplication.java b/src/jexer/TApplication.java index 41981da..161e161 100644 --- a/src/jexer/TApplication.java +++ b/src/jexer/TApplication.java @@ -1522,7 +1522,26 @@ public class TApplication implements Runnable { if (debugThreads) { System.err.printf("%d %s invertCell() %d %d\n", System.currentTimeMillis(), Thread.currentThread(), x, y); + + if (activeWindow != null) { + System.err.println("activeWindow.hasHiddenMouse() " + + activeWindow.hasHiddenMouse()); + } } + + // If this cell is on top of a visible window that has requested a + // hidden mouse, bail out. + if ((activeWindow != null) && (activeMenu == null)) { + if ((activeWindow.hasHiddenMouse() == true) + && (x > activeWindow.getX()) + && (x < activeWindow.getX() + activeWindow.getWidth() - 1) + && (y > activeWindow.getY()) + && (y < activeWindow.getY() + activeWindow.getHeight() - 1) + ) { + return; + } + } + Cell cell = getScreen().getCharXY(x, y); if (cell.isImage()) { cell.invertImage(); diff --git a/src/jexer/TTerminalWindow.java b/src/jexer/TTerminalWindow.java index a624e6c..ec4fd07 100644 --- a/src/jexer/TTerminalWindow.java +++ b/src/jexer/TTerminalWindow.java @@ -788,7 +788,8 @@ public class TTerminalWindow extends TScrollableWindow // Synchronize against the emulator so we don't stomp on its reader // thread. synchronized (emulator) { - + setHiddenMouse(emulator.hasHiddenMousePointer()); + setCursorX(emulator.getCursorX() + 1); setCursorY(emulator.getCursorY() + 1 + (getHeight() - 2 - emulator.getHeight()) diff --git a/src/jexer/TWidget.java b/src/jexer/TWidget.java index e8cd1a0..aa4cef8 100644 --- a/src/jexer/TWidget.java +++ b/src/jexer/TWidget.java @@ -1160,7 +1160,7 @@ public abstract class TWidget implements Comparable { public final void switchWidget(final boolean forward) { // No children: do nothing. - if (children.size() == 0) { + if ((children.size() == 0) || (activeChild == null)) { return; } diff --git a/src/jexer/TWindow.java b/src/jexer/TWindow.java index a4a9c23..e50e16f 100644 --- a/src/jexer/TWindow.java +++ b/src/jexer/TWindow.java @@ -185,6 +185,15 @@ public class TWindow extends TWidget { */ protected TStatusBar statusBar = null; + /** + * A window may request that TApplication NOT draw the mouse cursor over + * it by setting this to true. This is currently only used within Jexer + * by TTerminalWindow so that only the bottom-most instance of nested + * Jexer's draws the mouse within its application window. But perhaps + * other applications can use it, so public getter/setter is provided. + */ + private boolean hideMouse = false; + // ------------------------------------------------------------------------ // Constructors ----------------------------------------------------------- // ------------------------------------------------------------------------ @@ -1346,4 +1355,26 @@ public class TWindow extends TWidget { } } + /** + * Returns true if this window does not want the application-wide mouse + * cursor drawn over it. + * + * @return true if this window does not want the application-wide mouse + * cursor drawn over it + */ + public final boolean hasHiddenMouse() { + return hideMouse; + } + + /** + * Set request to prevent the application-wide mouse cursor from being + * drawn over this window. + * + * @param hideMouse if true, this window does not want the + * application-wide mouse cursor drawn over it + */ + public final void setHiddenMouse(final boolean hideMouse) { + this.hideMouse = hideMouse; + } + } diff --git a/src/jexer/backend/ECMA48Terminal.java b/src/jexer/backend/ECMA48Terminal.java index 2afa81a..7416819 100644 --- a/src/jexer/backend/ECMA48Terminal.java +++ b/src/jexer/backend/ECMA48Terminal.java @@ -3385,6 +3385,11 @@ public class ECMA48Terminal extends LogicalScreen * * Note that this also sets the alternate/primary screen buffer. * + * Finally, also emit a Privacy Message sequence that Jexer recognizes to + * mean "hide the mouse pointer." We have to use our own sequence to do + * this because there is no standard in xterm for unilaterally hiding the + * pointer all the time (regardless of typing). + * * @param on If true, enable mouse report and use the alternate screen * buffer. If false disable mouse reporting and use the primary screen * buffer. @@ -3392,9 +3397,9 @@ public class ECMA48Terminal extends LogicalScreen */ private String mouse(final boolean on) { if (on) { - return "\033[?1002;1003;1005;1006h\033[?1049h"; + return "\033[?1002;1003;1005;1006h\033[?1049h\033^hideMousePointer\033\\"; } - return "\033[?1002;1003;1006;1005l\033[?1049l"; + return "\033[?1002;1003;1006;1005l\033[?1049l\033^showMousePointer\033\\"; } } diff --git a/src/jexer/menu/TMenu.java b/src/jexer/menu/TMenu.java index dbbea82..7c31212 100644 --- a/src/jexer/menu/TMenu.java +++ b/src/jexer/menu/TMenu.java @@ -566,10 +566,10 @@ public class TMenu extends TWindow { break; case MID_SEARCH_AGAIN: label = i18n.getString("menuSearchAgain"); + key = kbCtrlL; break; case MID_GOTO_LINE: label = i18n.getString("menuGotoLine"); - key = kbCtrlL; break; case MID_TILE: diff --git a/src/jexer/tterminal/ECMA48.java b/src/jexer/tterminal/ECMA48.java index b08a18d..ce3570b 100644 --- a/src/jexer/tterminal/ECMA48.java +++ b/src/jexer/tterminal/ECMA48.java @@ -302,6 +302,15 @@ public class ECMA48 implements Runnable { */ private MouseEncoding mouseEncoding = MouseEncoding.X10; + /** + * A terminal may request that the mouse pointer be hidden using a + * Privacy Message containing either "hideMousePointer" or + * "showMousePointer". This is currently only used within Jexer by + * TTerminalWindow so that only the bottom-most instance of nested + * Jexer's draws the mouse within its application window. + */ + private boolean hideMousePointer = false; + /** * Physical display width. We start at 80x24, but the user can resize us * bigger/smaller. @@ -4559,6 +4568,38 @@ public class ECMA48 implements Runnable { } } + /** + * Handle the SCAN_SOSPMAPC_STRING state. This is currently only used by + * Jexer ECMA48Terminal to talk to ECMA48. + * + * @param pmChar the character received from the remote side + */ + private void pmPut(final char pmChar) { + // System.err.println("pmPut: " + pmChar); + + // Collect first + collectBuffer.append(pmChar); + + // Xterm cases... + if (collectBuffer.toString().endsWith("\033\\")) { + String arg = null; + arg = collectBuffer.substring(0, collectBuffer.length() - 2); + + // System.err.println("arg: '" + arg + "'"); + + if (arg.equals("hideMousePointer")) { + hideMousePointer = true; + } + if (arg.equals("showMousePointer")) { + hideMousePointer = false; + } + + // Go to SCAN_GROUND state + toGround(); + return; + } + } + /** * Run this input character through the ECMA48 state machine. * @@ -4588,9 +4629,11 @@ public class ECMA48 implements Runnable { // 0x1B == ESCAPE if (ch == 0x1B) { if ((type == DeviceType.XTERM) - && (scanState == ScanState.OSC_STRING) + && ((scanState == ScanState.OSC_STRING) + || (scanState == ScanState.SOSPMAPC_STRING)) ) { // Xterm can pass ESCAPE to its OSC sequence. + // Jexer can pass ESCAPE to its PM sequence. } else if ((scanState != ScanState.DCS_ENTRY) && (scanState != ScanState.DCS_INTERMEDIATE) && (scanState != ScanState.DCS_IGNORE) @@ -6446,6 +6489,15 @@ public class ECMA48 implements Runnable { case SOSPMAPC_STRING: // 00-17, 19, 1C-1F, 20-7F --> ignore + // Special case for Jexer: PM can pass one control character + if (ch == 0x1B) { + pmPut(ch); + } + + if ((ch >= 0x20) && (ch <= 0x7F)) { + pmPut(ch); + } + // 0x9C goes to GROUND if (ch == 0x9C) { toGround(); @@ -6509,4 +6561,15 @@ public class ECMA48 implements Runnable { return currentState.cursorY; } + /** + * Returns true if this terminal has requested the mouse pointer be + * hidden. + * + * @return true if this terminal has requested the mouse pointer be + * hidden + */ + public final boolean hasHiddenMousePointer() { + return hideMousePointer; + } + } -- 2.27.0