]> git.proxmox.com Git - mirror_xterm.js.git/commitdiff
Fix third level shifts for Mac OS and windows
authorrunarberg <runar@greenqloud.com>
Wed, 1 Jun 2016 17:06:57 +0000 (17:06 +0000)
committerrunarberg <runar@greenqloud.com>
Fri, 10 Jun 2016 16:14:31 +0000 (16:14 +0000)
ISO third level keys were not working. That prevented some inputting
important characters (like pipe `|` and caret `^`) on some keyboard
layouts.

Instead of parsing the user-agent string to find the users os, we now
look into the `platform` attribute of the `navigator` object.

Removed the hijacking of the command key `⌘` on Mac OS as the `Alt` key
on other systems.

src/xterm.js
test/test.js

index 2ba64e262d2ac9dcaac9c185ce75b1f07b221146..7f01e2a417ff0b42cbb7095d771fda7afb2a2a8a 100644 (file)
       * Parse User-Agent
       */
       if (this.context.navigator && this.context.navigator.userAgent) {
-        this.isMac = !!~this.context.navigator.userAgent.indexOf('Mac');
-        this.isIpad = !!~this.context.navigator.userAgent.indexOf('iPad');
-        this.isIphone = !!~this.context.navigator.userAgent.indexOf('iPhone');
         this.isMSIE = !!~this.context.navigator.userAgent.indexOf('MSIE');
       }
 
+      /*
+      * Find the users platform. We use this to interpret the meta key
+      * and ISO third level shifts.
+      * http://stackoverflow.com/questions/19877924/what-is-the-list-of-possible-values-for-navigator-platform-as-of-today
+      */
+      if (this.context.navigator && this.context.navigator.platform) {
+        this.isMac = contains(
+          this.context.navigator.platform,
+          ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K']
+        );
+        this.isIpad = this.context.navigator.platform === 'iPad';
+        this.isIphone = this.context.navigator.platform === 'iPhone';
+        this.isMSWindows = contains(
+          this.context.navigator.platform,
+          ['Windows', 'Win16', 'Win32', 'WinCE']
+        );
+      }
+
       /*
       * Create main element container
       */
         return this.cancel(ev);
       }
 
-      if (result.cancel) {
+      if (isThirdLevelShift(this, ev)) {
+        return true;
+      }
+
+      if (result.cancel ) {
         // The event is canceled at the end already, is this necessary?
         this.cancel(ev, true);
       }
 
-      if (!result.key || (this.isMac && ev.metaKey)) {
+      if (!result.key) {
         return true;
       }
 
               // ^] - group sep
               result.key = String.fromCharCode(29);
             }
-          } else if ((!this.isMac && ev.altKey) || (this.isMac && ev.metaKey)) {
+          } else if (!this.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) {
+            // On Mac this is a third level shift. Use <Esc> instead.
             if (ev.keyCode >= 65 && ev.keyCode <= 90) {
               result.key = '\x1b' + String.fromCharCode(ev.keyCode + 32);
             } else if (ev.keyCode === 192) {
         return false;
       }
 
-      if (!key || ev.ctrlKey || ev.altKey || ev.metaKey) {
+      if (!key || (
+        (ev.altKey || ev.ctrlKey || ev.metaKey) && !isThirdLevelShift(this, ev)
+      )) {
         return false;
       }
 
      * Helpers
      */
 
+    function contains(el, arr) {
+      for (var i = 0; i < arr.length; i += 1) {
+        if (el === arr[i]) {
+          return true;
+        }
+      }
+      return false;
+    }
+
     function on(el, type, handler, capture) {
       if (!Array.isArray(el)) {
         el = [el];
       return -1;
     }
 
+  function isThirdLevelShift(term, ev) {
+      var thirdLevelKey =
+          (term.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) ||
+          (term.isMSWindows && ev.altKey && ev.ctrlKey && !ev.metaKey);
+
+      // Don't invoke for arrows, pageDown, home, backspace, etc.
+      return thirdLevelKey && (!ev.keyCode || ev.keyCode > 47);
+    }
+
     function isWide(ch) {
       if (ch <= '\uff00') return false;
       return (ch >= '\uff01' && ch <= '\uffbe')
index ffbc285f73473376d6666348b197d611180f42aa..6f7a07914d8bc6b85899cdbf2cfc496ac48d8d95 100644 (file)
@@ -68,4 +68,126 @@ describe('xterm.js', function() {
       assert.equal(processedText.indexOf(nonBreakingSpace), -1);
     });
   });
+
+  describe('Third level shift', function() {
+    var ev = {
+      preventDefault: function() {},
+      stopPropagation: function() {}
+    };
+
+    beforeEach(function() {
+      xterm.handler = function() {};
+      xterm.showCursor = function() {};
+      xterm.clearSelection = function() {};
+    })
+
+    describe('On Mac OS', function() {
+      beforeEach(function() {
+        xterm.isMac = true;
+      });
+
+      it('should not interfere with the alt key on keyDown', function() {
+        assert.equal(
+          xterm.keyDown(Object.assign({}, ev, { altKey: true, keyCode: 81 })),
+          true
+        );
+        assert.equal(
+          xterm.keyDown(Object.assign({}, ev, { altKey: true, keyCode: 192 })),
+          true
+        );
+      });
+
+      it('should interefere with the alt + arrow keys', function() {
+        assert.equal(
+          xterm.keyDown(Object.assign({}, ev, { altKey: true, keyCode: 37 })),
+          false
+        );
+        assert.equal(
+          xterm.keyDown(Object.assign({}, ev, { altKey: true, keyCode: 39 })),
+          false
+        );
+      });
+
+      it('should emit key with alt + key on keyPress', function(done) {
+        var keys = ['@', '@', '\\', '\\', '|', '|'];
+
+        xterm.on('keypress', function(key) {
+          if (key) {
+            var index = keys.indexOf(key);
+            assert(index !== -1, "Emitted wrong key: " + key);
+            keys.splice(index, 1);
+          }
+          if (keys.length === 0) done();
+        });
+
+        xterm.keyPress(Object.assign({}, ev, { altKey: true, keyCode: 64 })); // @
+        // Firefox
+        xterm.keyPress(Object.assign({}, ev, { altKey: true, charCode: 64, keyCode: 0 }));
+        xterm.keyPress(Object.assign({}, ev, { altKey: true, keyCode: 92 })); // \
+        xterm.keyPress(Object.assign({}, ev, { altKey: true, charCode: 92, keyCode: 0 }));
+        xterm.keyPress(Object.assign({}, ev, { altKey: true, keyCode: 124 })); // |
+        xterm.keyPress(Object.assign({}, ev, { altKey: true, charCode: 124, keyCode: 0 }));
+      });
+    });
+
+    describe('On MS Windows', function() {
+      beforeEach(function() {
+        xterm.isMSWindows = true;
+      });
+
+      it('should not interfere with the alt + ctrl key on keyDown', function() {
+        assert.equal(
+          xterm.keyDown(Object.assign({}, ev, { altKey: true, ctrlKey: true, keyCode: 81 })),
+          true
+        );
+        assert.equal(
+          xterm.keyDown(Object.assign({}, ev, { altKey: true, ctrlKey: true, keyCode: 192 })),
+          true
+        );
+      });
+
+      it('should interefere with the alt + ctrl + arrow keys', function() {
+        assert.equal(
+          xterm.keyDown(Object.assign({}, ev, { altKey: true, ctrlKey: true, keyCode: 37 })),
+          false
+        );
+        assert.equal(
+          xterm.keyDown(Object.assign({}, ev, { altKey: true, ctrlKey: true, keyCode: 39 })),
+          false
+        );
+      });
+
+      it('should emit key with alt + ctrl + key on keyPress', function(done) {
+        var keys = ['@', '@', '\\', '\\', '|', '|'];
+
+        xterm.on('keypress', function(key) {
+          if (key) {
+            var index = keys.indexOf(key);
+            assert(index !== -1, "Emitted wrong key: " + key);
+            keys.splice(index, 1);
+          }
+          if (keys.length === 0) done();
+        });
+
+        xterm.keyPress(
+          Object.assign({}, ev, { altKey: true, ctrlKey: true, keyCode: 64 })
+        ); // @
+        xterm.keyPress(
+          Object.assign({}, ev, { altKey: true, ctrlKey: true, charCode: 64, keyCode: 0 })
+        );
+        xterm.keyPress(
+          Object.assign({}, ev, { altKey: true, ctrlKey: true, keyCode: 92 })
+        ); // \
+        xterm.keyPress(
+          Object.assign({}, ev, { altKey: true, ctrlKey: true, charCode: 92, keyCode: 0 })
+        );
+        xterm.keyPress(
+          Object.assign({}, ev, { altKey: true, ctrlKey: true, keyCode: 124 })
+        ); // |
+        xterm.keyPress(
+          Object.assign({}, ev, { altKey: true, ctrlKey: true, charCode: 124, keyCode: 0 })
+        );
+      });
+    });
+  });
 });