hterm 1.32: Disable local select in all mouse reporting modes.

* Previously we allowed "local" selection (that which happens by default in
  Chrome) to stay enabled for mouse mode 1001 (report mouseup/down only).  This
  caused a few issues.  I didn't realize at the time that emacs used this
  mouseup/down positions to set an active region, which conflicts with the
  local selection.  You tend wind up with a confusing partial overlap of the two
  selections.  Additionally, with copy-on-select enabled, the mouseup event
  was consumed by the terminal and never sent to the host.

  This change disables local selection when we're in mode 1001.  Local selection
  was disabled in mode 1002, report mousedown/up/movement, which is preferred
  by vi.

  Our "mouse-cell-motion-trick" was all about allowing local selection in mode
  1002, so that's been removed too.  I doubt this preference was widely used.

  The change adds the ability to use alt-click to override the current mouse
  state, so that you can make a local selection even while in mode 1001/1002.
  Alt was chosen as its the only modifier key which can't be sent with a
  mouse event, though if you're depending on alt === meta, you'll lose
  the ability to send meta-mouse sequences.  If your local window manager
  already maps alt-click to something, then you can add any other modifier in
  addition to alt (say, alt-ctrl-mousedown) to defeat your existing binding.

Change-Id: If03b2c1242be84f3ce62156f9cd23ef3c7b965e5
Reviewed-on: https://chromium-review.googlesource.com/188923
Reviewed-by: Marvelous Marius <mschilder@chromium.org>
Reviewed-by: Robert Ginda <rginda@chromium.org>
Tested-by: Robert Ginda <rginda@chromium.org>
diff --git a/hterm/doc/changelog.txt b/hterm/doc/changelog.txt
index 911f7b7..f4fd9f8 100644
--- a/hterm/doc/changelog.txt
+++ b/hterm/doc/changelog.txt
@@ -1,3 +1,28 @@
+1.32, 2014-03-04, Disable local selection in all mouse reporting modes.
+
+* Previously we allowed "local" selection (that which happens by default in
+  Chrome) to stay enabled for mouse mode 1001 (report mouseup/down only).  This
+  caused a few issues.  I didn't realize at the time that emacs used this
+  mouseup/down positions to set an active region, which conflicts with the
+  local selection.  You tend wind up with a confusing partial overlap of the two
+  selections.  Additionally, with copy-on-select enabled, the mouseup event
+  was consumed by the terminal and never sent to the host.
+
+  This change disables local selection when we're in mode 1001.  Local selection
+  was disabled in mode 1002, report mousedown/up/movement, which is preferred
+  by vi.
+
+  Our "mouse-cell-motion-trick" was all about allowing local selection in mode
+  1002, so that's been removed too.  I doubt this preference was widely used.
+
+  The change adds the ability to use alt-click to override the current mouse
+  state, so that you can make a local selection even while in mode 1001/1002.
+  Alt was chosen as its the only modifier key which can't be sent with a
+  mouse event, though if you're depending on alt === meta, you'll lose
+  the ability to send meta-mouse sequences.  If your local window manager
+  already maps alt-click to something, then you can add any other modifier in
+  addition to alt (say, alt-ctrl-mousedown) to defeat your existing binding.
+
 1.31, 2014-03-04, Add svg based zoom detection.
 
 * Re-implement zoom detection in terms of the currentScale property of svg
diff --git a/hterm/js/hterm_preference_manager.js b/hterm/js/hterm_preference_manager.js
index b7ecfa8..734568a 100644
--- a/hterm/js/hterm_preference_manager.js
+++ b/hterm/js/hterm_preference_manager.js
@@ -198,15 +198,6 @@
     ['meta-sends-escape', true],
 
     /**
-     * Set whether we should treat DEC mode 1002 (mouse cell motion tracking)
-     * as if it were 1000 (mouse click tracking).
-     *
-     * This makes it possible to use vi's ":set mouse=a" mode without losing
-     * access to the system text selection mechanism.
-     */
-    ['mouse-cell-motion-trick', false],
-
-    /**
      * Mouse paste button, or null to autodetect.
      *
      * For autodetect, we'll try to enable middle button paste for non-X11
diff --git a/hterm/js/hterm_scrollport.js b/hterm/js/hterm_scrollport.js
index f5b7dc2..a3296c0 100644
--- a/hterm/js/hterm_scrollport.js
+++ b/hterm/js/hterm_scrollport.js
@@ -313,7 +313,6 @@
   this.screen_.addEventListener('mousewheel', this.onScrollWheel_.bind(this));
   this.screen_.addEventListener('copy', this.onCopy_.bind(this));
   this.screen_.addEventListener('paste', this.onPaste_.bind(this));
-  this.screen_.addEventListener('mousedown', this.onMouseDown_.bind(this));
 
   // We send focus to this element just before a paste happens, so we can
   // capture the pasted text and forward it on to someone who cares.
@@ -380,18 +379,10 @@
       'left: 0;' +
       'visibility: hidden');
 
-  this.setSelectionEnabled(true);
   this.resize();
 };
 
 /**
- * Enable or disable mouse based text selection in the scrollport.
- */
-hterm.ScrollPort.prototype.setSelectionEnabled = function(state) {
-  this.selectionEnabled_ = state;
-};
-
-/**
  * Select the font-family and font-smoothing for this scrollport.
  *
  * @param {string} fontFamily Value of the CSS 'font-family' to use for this
@@ -1329,15 +1320,6 @@
 };
 
 /**
- * Handle mouse down events on the ScrollPort's screen element.
- */
-hterm.ScrollPort.prototype.onMouseDown_ = function(e) {
-  if (e.which == 1 && !this.selectionEnabled_) {
-    e.preventDefault();
-  }
-};
-
-/**
  * Set the vertical scrollbar mode of the ScrollPort.
  */
 hterm.ScrollPort.prototype.setScrollbarVisible = function(state) {
diff --git a/hterm/js/hterm_terminal.js b/hterm/js/hterm_terminal.js
index 334ef62..9be742a 100644
--- a/hterm/js/hterm_terminal.js
+++ b/hterm/js/hterm_terminal.js
@@ -91,6 +91,10 @@
   this.scrollOnOutput_ = null;
   this.scrollOnKeystroke_ = null;
 
+  // True if we should send mouse events to the vt, false if we want them
+  // to manage the local text selection.
+  this.reportMouseEvents_ = false;
+
   // Terminal bell sound.
   this.bellAudio_ = this.document_.createElement('audio');
   this.bellAudio_.setAttribute('preload', 'auto');
@@ -309,10 +313,6 @@
       terminal.keyboard.metaSendsEscape = v;
     },
 
-    'mouse-cell-motion-trick': function(v) {
-      terminal.vt.setMouseCellMotionTrick(v);
-    },
-
     'mouse-paste-button': function(v) {
       terminal.syncMousePasteButton();
     },
@@ -424,7 +424,6 @@
  */
 hterm.Terminal.prototype.setSelectionEnabled = function(state) {
   this.enableMouseDragScroll = state;
-  this.scrollPort_.setSelectionEnabled(state);
 };
 
 /**
@@ -2547,22 +2546,33 @@
   e.terminalColumn = parseInt(e.clientX /
                               this.scrollPort_.characterSize.width) + 1;
 
-  if (this.enableMouseDragScroll) {
+  if (e.type == 'mousedown') {
+    if (e.altKey || this.vt.mouseReport == this.vt.MOUSE_REPORT_DISABLED) {
+      // If VT mouse reporting is disabled, or has been defeated with
+      // alt-mousedown, then the mouse will act on the local selection.
+      this.reportMouseEvents_ = false;
+      this.setSelectionEnabled(true);
+    } else {
+      // Otherwise we defer ownership of the mouse to the VT.
+      this.reportMouseEvents_ = true;
+      this.document_.getSelection().collapse();
+      this.setSelectionEnabled(false);
+      e.preventDefault();
+    }
+  }
+
+  if (!this.reportMouseEvents_) {
     if (e.type == 'dblclick') {
       this.screen_.expandSelection(this.document_.getSelection());
       hterm.copySelectionToClipboard(this.document_);
-      return;
     }
 
-    if (e.type == 'mousedown' && e.which == this.mousePasteButton) {
+    if (e.type == 'mousedown' && e.which == this.mousePasteButton)
       this.paste();
-      return;
-    }
 
     if (e.type == 'mouseup' && e.which == 1 && this.copyOnSelect &&
         !this.document_.getSelection().isCollapsed) {
       hterm.copySelectionToClipboard(this.document_);
-      return;
     }
 
     if ((e.type == 'mousemove' || e.type == 'mouseup') &&
@@ -2572,7 +2582,7 @@
       this.scrollBlockerNode_.style.top = '-99px';
     }
 
-  } else /* if (!this.enableMouseDragScroll) */ {
+  } else /* if (this.reportMouseEvents) */ {
     if (!this.scrollBlockerNode_.engaged) {
       if (e.type == 'mousedown') {
         // Move the scroll-blocker into place if we want to keep the scrollport
@@ -2587,9 +2597,17 @@
         e.preventDefault();
       }
     }
+
+    this.onMouse(e);
   }
 
-  this.onMouse(e);
+  if (e.type == 'mouseup' && this.document_.getSelection().isCollapsed) {
+    // Restore this on mouseup in case it was temporarily defeated with a
+    // alt-mousedown.  Only do this when the selection is empty so that
+    // we don't immediately kill the users selection.
+    this.reportMouseEvents_ = (this.vt.mouseReport !=
+                               this.vt.MOUSE_REPORT_DISABLED);
+  }
 };
 
 /**
diff --git a/hterm/js/hterm_vt.js b/hterm/js/hterm_vt.js
index e80c981..9812556 100644
--- a/hterm/js/hterm_vt.js
+++ b/hterm/js/hterm_vt.js
@@ -44,7 +44,7 @@
   this.terminal = terminal;
 
   terminal.onMouse = this.onTerminalMouse_.bind(this);
-  this.mouseReport_ = this.MOUSE_REPORT_DISABLED;
+  this.mouseReport = this.MOUSE_REPORT_DISABLED;
 
   // Parse state left over from the last parse.  You should use the parseState
   // instance passed into your parse routine, rather than reading
@@ -62,9 +62,6 @@
   // Whether or not to respect the escape codes for setting terminal width.
   this.allowColumnWidthChanges_ = false;
 
-  // True if we should fake-out mouse "cell motion" reporting (DECSET 1002)
-  this.mouseCellMotionTrick_ = false;
-
   // The amount of time we're willing to wait for the end of an OSC sequence.
   this.oscTimeLimit_ = 20000;
 
@@ -169,25 +166,6 @@
 hterm.VT.prototype.MOUSE_REPORT_CLICK = 1;
 
 /**
- * Report only mouse down events.
- *
- * This is an hterm specific mode that tricks vi's ':set mouse=a' mode into
- * working more like emacs xterm-mouse-mode.  Clicks will reposition the
- * cursor, and the scroll wheel will scroll the buffer.  Selection, however,
- * will be browser-native, rather than the custom vi selection you usually get
- * with ':set mouse=a'.
- *
- * When the 'mouse-cell-motion-trick' pref is enabled, we'll use this mode
- * in place of MOUSE_REPORT_DRAG.
- *
- * It is distinct from the normal MOUSE_REPORT_CLICK so that we can switch it
- * off if the user changes their 'mouse-cell-motion-trick' pref while this
- * is enabled.  (If it weren't distinct, we wouldn't be sure how we got into
- * MOUSE_REPORT_CLICK mode.)
- */
-hterm.VT.prototype.MOUSE_REPORT_CLICK_1002 = 2;
-
-/**
  * DECSET mode 1002.
  *
  * Report mouse down/up and movement while a button is down.
@@ -355,17 +333,7 @@
 
   this.savedState_ = new hterm.VT.CursorState(this);
 
-  this.mouseReport_ = this.MOUSE_REPORT_DISABLED;
-  this.terminal.setSelectionEnabled(true);
-};
-
-hterm.VT.prototype.setMouseCellMotionTrick = function(state) {
-  this.mouseCellMotionTrick_ = state;
-
-  if ((state && this.mouseReport_ == this.MOUSE_REPORT_DRAG) ||
-      (!state && this.mouseReport_ == this.MOUSE_REPORT_CLICK_1002)) {
-    this.setDECMode('1002', true);
-  }
+  this.mouseReport = this.MOUSE_REPORT_DISABLED;
 };
 
 /**
@@ -374,7 +342,7 @@
  * See the "Mouse Tracking" section of [xterm].
  */
 hterm.VT.prototype.onTerminalMouse_ = function(e) {
-  if (this.mouseReport_ == this.MOUSE_REPORT_DISABLED)
+  if (this.mouseReport == this.MOUSE_REPORT_DISABLED)
     return;
 
   // Temporary storage for our response.
@@ -422,7 +390,7 @@
       break;
 
     case 'mousemove':
-      if (this.mouseReport_ == this.MOUSE_REPORT_DRAG && e.which) {
+      if (this.mouseReport == this.MOUSE_REPORT_DRAG && e.which) {
         // Standard button bits.
         b = 32 + Math.min(e.which - 1, 2);
 
@@ -847,24 +815,13 @@
       break;
 
     case '1000':  // Report on mouse clicks only.
-      this.mouseReport_ = (
+      this.mouseReport = (
           state ? this.MOUSE_REPORT_CLICK : this.MOUSE_REPORT_DISABLED);
-      this.terminal.setSelectionEnabled(true);
       break;
 
     case '1002':  // Report on mouse clicks and drags
-      if (!state) {
-        this.mouseReport_ = this.MOUSE_REPORT_DISABLED;
-        this.terminal.setSelectionEnabled(true);
-
-      } else if (this.mouseCellMotionTrick_) {
-        this.mouseReport_ = this.MOUSE_REPORT_CLICK_1002;
-        this.terminal.setSelectionEnabled(true);
-
-      } else {
-        this.mouseReport_ = this.MOUSE_REPORT_DRAG;
-        this.terminal.setSelectionEnabled(false);
-      }
+      this.mouseReport = (
+          state ? this.MOUSE_REPORT_DRAG : this.MOUSE_REPORT_DISABLED);
       break;
 
     case '1010':  // rxvt
diff --git a/nassh/doc/faq.txt b/nassh/doc/faq.txt
index 69c40cc..1071a8d 100644
--- a/nassh/doc/faq.txt
+++ b/nassh/doc/faq.txt
@@ -572,19 +572,7 @@
   allow you to position the cursor with a mouse click, and use the wheel
   (or two-finger scroll) to scroll the buffer.
 
-  In vi, use ":set mouse=a" to enable mouse mode.  Vi's mouse mode is slightly
-  different from emacs in that it manages your text selection.  Some people
-  prefer this, others may go crazy.
-
-  A quick way to get your native selection back is to set the
-  'mouse-cell-motion-trick' to true.  This will make vi's mouse support
-  essentially the same as emacs.
-
-  With the cell motion trick enabled, you lose the ability to select more
-  than one screenful of text with the mouse.  Instead of using this trick,
-  you may want to script vi so that it sends the current selection to
-  Secure Shell to be copied to the system clipboard.  See the next question
-  for some more information on this.
+  In vi, use ":set mouse=a" to enable mouse mode.
 
 
 > Does hterm support the "OSC 52", aka "clipboard operations" sequence?