1a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* 2a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * noVNC: HTML5 VNC client 31d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Copyright (C) 2012 Joel Martin 41d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Copyright (C) 2013 Samuel Mannehed for Cendio AB 51d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Licensed under MPL 2.0 or any later version (see LICENSE.txt) 6a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */ 7a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 81d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman/*jslint browser: true, white: false */ 9a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/*global window, Util */ 10a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 111d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartmanvar Keyboard, Mouse; 121d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 131d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman(function () { 141d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman "use strict"; 151d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 161d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // 171d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Keyboard event handler 181d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // 191d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 201d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Keyboard = function (defaults) { 211d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._keyDownList = []; // List of depressed keys 221d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // (even if they are happy) 231d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 241d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.set_defaults(this, defaults, { 251d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'target': document, 261d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'focused': true 271d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }); 281d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 291d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // create the keyboard handler 301d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._handler = new KeyEventDecoder(kbdUtil.ModifierSync(), 311d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman VerifyCharModifier( /* jshint newcap: false */ 321d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman TrackKeyState( 331d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman EscapeModifiers(this._handleRfbEvent.bind(this)) 341d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ) 351d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ) 361d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ); /* jshint newcap: true */ 371d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 381d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // keep these here so we can refer to them later 391d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._eventHandlers = { 401d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'keyup': this._handleKeyUp.bind(this), 411d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'keydown': this._handleKeyDown.bind(this), 421d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'keypress': this._handleKeyPress.bind(this), 431d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'blur': this._allKeysUp.bind(this) 441d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 451d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 461d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 471d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Keyboard.prototype = { 481d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // private methods 491d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 501d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman _handleRfbEvent: function (e) { 511d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this._onKeyPress) { 521d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.Debug("onKeyPress " + (e.type == 'keydown' ? "down" : "up") + 531d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ", keysym: " + e.keysym.keysym + "(" + e.keysym.keyname + ")"); 541d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._onKeyPress(e.keysym.keysym, e.type == 'keydown'); 551d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 561d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 57a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 581d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman _handleKeyDown: function (e) { 591d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (!this._focused) { return true; } 60a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 611d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this._handler.keydown(e)) { 621d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Suppress bubbling/default actions 631d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.stopEvent(e); 641d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman return false; 651d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } else { 661d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Allow the event to bubble and become a keyPress event which 671d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // will have the character code translated 681d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman return true; 691d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 701d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 71a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 721d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman _handleKeyPress: function (e) { 731d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (!this._focused) { return true; } 74a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 751d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this._handler.keypress(e)) { 761d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Suppress bubbling/default actions 771d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.stopEvent(e); 781d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman return false; 791d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } else { 801d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Allow the event to bubble and become a keyPress event which 811d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // will have the character code translated 821d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman return true; 831d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 841d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 85a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 861d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman _handleKeyUp: function (e) { 871d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (!this._focused) { return true; } 88a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 891d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this._handler.keyup(e)) { 901d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Suppress bubbling/default actions 911d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.stopEvent(e); 921d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman return false; 931d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } else { 941d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Allow the event to bubble and become a keyPress event which 951d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // will have the character code translated 961d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman return true; 971d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 981d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 99a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 1001d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman _allKeysUp: function () { 1011d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.Debug(">> Keyboard.allKeysUp"); 1021d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._handler.releaseAll(); 1031d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.Debug("<< Keyboard.allKeysUp"); 1041d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 105a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 1061d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Public methods 1071d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1081d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman grab: function () { 1091d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman //Util.Debug(">> Keyboard.grab"); 1101d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var c = this._target; 1111d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1121d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(c, 'keydown', this._eventHandlers.keydown); 1131d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(c, 'keyup', this._eventHandlers.keyup); 1141d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(c, 'keypress', this._eventHandlers.keypress); 1151d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1161d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Release (key up) if window loses focus 1171d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(window, 'blur', this._eventHandlers.blur); 1181d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1191d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman //Util.Debug("<< Keyboard.grab"); 1201d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 121a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 1221d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ungrab: function () { 1231d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman //Util.Debug(">> Keyboard.ungrab"); 1241d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var c = this._target; 1251d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1261d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(c, 'keydown', this._eventHandlers.keydown); 1271d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(c, 'keyup', this._eventHandlers.keyup); 1281d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(c, 'keypress', this._eventHandlers.keypress); 1291d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(window, 'blur', this._eventHandlers.blur); 1301d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1311d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Release (key up) all keys that are in a down state 1321d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._allKeysUp(); 1331d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1341d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman //Util.Debug(">> Keyboard.ungrab"); 1351d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 1361d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1371d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman sync: function (e) { 1381d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._handler.syncModifiers(e); 139a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 1401d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 1411d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1421d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.make_properties(Keyboard, [ 1431d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ['target', 'wo', 'dom'], // DOM element that captures keyboard input 1441d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ['focused', 'rw', 'bool'], // Capture and send key events 1451d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1461d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ['onKeyPress', 'rw', 'func'] // Handler for key press/release 1471d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ]); 1481d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1491d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // 1501d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Mouse event handler 1511d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // 1521d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1531d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Mouse = function (defaults) { 1541d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._mouseCaptured = false; 1551d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1561d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._doubleClickTimer = null; 1571d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._lastTouchPos = null; 1581d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1591d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Configuration attributes 1601d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.set_defaults(this, defaults, { 1611d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'target': document, 1621d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'focused': true, 1631d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'scale': 1.0, 1641d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'touchButton': 1 1651d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }); 1661d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1671d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._eventHandlers = { 1681d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'mousedown': this._handleMouseDown.bind(this), 1691d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'mouseup': this._handleMouseUp.bind(this), 1701d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'mousemove': this._handleMouseMove.bind(this), 1711d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'mousewheel': this._handleMouseWheel.bind(this), 1721d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 'mousedisable': this._handleMouseDisable.bind(this) 1731d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 1741d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 1751d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1761d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Mouse.prototype = { 1771d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // private methods 1781d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman _captureMouse: function () { 1791d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // capturing the mouse ensures we get the mouseup event 1801d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this._target.setCapture) { 1811d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._target.setCapture(); 182a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 1831d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1841d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // some browsers give us mouseup events regardless, 1851d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // so if we never captured the mouse, we can disregard the event 1861d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._mouseCaptured = true; 1871d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 1881d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1891d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman _releaseMouse: function () { 1901d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this._target.releaseCapture) { 1911d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._target.releaseCapture(); 192a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 1931d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._mouseCaptured = false; 1941d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 1951d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1961d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman _resetDoubleClickTimer: function () { 1971d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._doubleClickTimer = null; 1981d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 1991d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2001d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman _handleMouseButton: function (e, down) { 2011d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (!this._focused) { return true; } 2021d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2031d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this._notify) { 2041d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._notify(e); 2051d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 2061d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2071d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var evt = (e ? e : window.event); 2081d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var pos = Util.getEventPosition(e, this._target, this._scale); 2091d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2101d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var bmask; 2111d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (e.touches || e.changedTouches) { 2121d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Touch device 2131d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2141d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // When two touches occur within 500 ms of each other and are 2151d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // closer than 20 pixels together a double click is triggered. 2161d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (down == 1) { 2171d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this._doubleClickTimer === null) { 2181d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._lastTouchPos = pos; 2191d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } else { 2201d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman clearTimeout(this._doubleClickTimer); 2211d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2221d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // When the distance between the two touches is small enough 2231d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // force the position of the latter touch to the position of 2241d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // the first. 2251d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2261d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var xs = this._lastTouchPos.x - pos.x; 2271d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var ys = this._lastTouchPos.y - pos.y; 2281d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var d = Math.sqrt((xs * xs) + (ys * ys)); 2291d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2301d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // The goal is to trigger on a certain physical width, the 2311d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // devicePixelRatio brings us a bit closer but is not optimal. 2321d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (d < 20 * window.devicePixelRatio) { 2331d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman pos = this._lastTouchPos; 2341d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 2351d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 2361d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._doubleClickTimer = setTimeout(this._resetDoubleClickTimer.bind(this), 500); 2371d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 2381d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman bmask = this._touchButton; 2391d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // If bmask is set 2401d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } else if (evt.which) { 2411d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /* everything except IE */ 2421d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman bmask = 1 << evt.button; 243a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } else { 2441d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /* IE including 9 */ 2451d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman bmask = (evt.button & 0x1) + // Left 2461d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman (evt.button & 0x2) * 2 + // Right 2471d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman (evt.button & 0x4) / 2; // Middle 248a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 249a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 2501d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this._onMouseButton) { 2511d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.Debug("onMouseButton " + (down ? "down" : "up") + 2521d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ", x: " + pos.x + ", y: " + pos.y + ", bmask: " + bmask); 2531d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._onMouseButton(pos.x, pos.y, down, bmask); 2541d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 2551d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.stopEvent(e); 2561d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman return false; 2571d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 2581d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2591d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman _handleMouseDown: function (e) { 2601d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._captureMouse(); 2611d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._handleMouseButton(e, 1); 2621d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 263a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 2641d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman _handleMouseUp: function (e) { 2651d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (!this._mouseCaptured) { return; } 266a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 2671d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._handleMouseButton(e, 0); 2681d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._releaseMouse(); 2691d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 270a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 2711d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman _handleMouseWheel: function (e) { 2721d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (!this._focused) { return true; } 273a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 2741d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this._notify) { 2751d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._notify(e); 2761d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 277a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 2781d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var evt = (e ? e : window.event); 2791d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var pos = Util.getEventPosition(e, this._target, this._scale); 2801d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var wheelData = evt.detail ? evt.detail * -1 : evt.wheelDelta / 40; 2811d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var bmask; 2821d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (wheelData > 0) { 2831d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman bmask = 1 << 3; 2841d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } else { 2851d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman bmask = 1 << 4; 2861d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 287a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 2881d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this._onMouseButton) { 2891d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._onMouseButton(pos.x, pos.y, 1, bmask); 2901d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._onMouseButton(pos.x, pos.y, 0, bmask); 2911d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 2921d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.stopEvent(e); 2931d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman return false; 2941d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 295a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 2961d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman _handleMouseMove: function (e) { 2971d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (! this._focused) { return true; } 298a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 2991d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this._notify) { 3001d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._notify(e); 3011d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 302a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 3031d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var evt = (e ? e : window.event); 3041d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var pos = Util.getEventPosition(e, this._target, this._scale); 3051d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this._onMouseMove) { 3061d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._onMouseMove(pos.x, pos.y); 3071d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 3081d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.stopEvent(e); 3091d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman return false; 3101d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 3111d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 3121d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman _handleMouseDisable: function (e) { 3131d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (!this._focused) { return true; } 3141d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 3151d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var evt = (e ? e : window.event); 3161d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var pos = Util.getEventPosition(e, this._target, this._scale); 3171d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 3181d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /* Stop propagation if inside canvas area */ 3191d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if ((pos.realx >= 0) && (pos.realy >= 0) && 3201d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman (pos.realx < this._target.offsetWidth) && 3211d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman (pos.realy < this._target.offsetHeight)) { 3221d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman //Util.Debug("mouse event disabled"); 3231d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.stopEvent(e); 3241d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman return false; 3251d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 326a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 3271d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman return true; 3281d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 329a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 330a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 3311d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Public methods 3321d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman grab: function () { 3331d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var c = this._target; 334a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 3351d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if ('ontouchstart' in document.documentElement) { 3361d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(c, 'touchstart', this._eventHandlers.mousedown); 3371d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(window, 'touchend', this._eventHandlers.mouseup); 3381d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(c, 'touchend', this._eventHandlers.mouseup); 3391d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(c, 'touchmove', this._eventHandlers.mousemove); 3401d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } else { 3411d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(c, 'mousedown', this._eventHandlers.mousedown); 3421d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(window, 'mouseup', this._eventHandlers.mouseup); 3431d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(c, 'mouseup', this._eventHandlers.mouseup); 3441d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(c, 'mousemove', this._eventHandlers.mousemove); 3451d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel', 3461d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._eventHandlers.mousewheel); 3471d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 348a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 3491d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /* Work around right and middle click browser behaviors */ 3501d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(document, 'click', this._eventHandlers.mousedisable); 3511d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.addEvent(document.body, 'contextmenu', this._eventHandlers.mousedisable); 3521d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }, 353a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 3541d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ungrab: function () { 3551d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var c = this._target; 356a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 3571d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if ('ontouchstart' in document.documentElement) { 3581d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(c, 'touchstart', this._eventHandlers.mousedown); 3591d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(window, 'touchend', this._eventHandlers.mouseup); 3601d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(c, 'touchend', this._eventHandlers.mouseup); 3611d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(c, 'touchmove', this._eventHandlers.mousemove); 3621d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } else { 3631d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(c, 'mousedown', this._eventHandlers.mousedown); 3641d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(window, 'mouseup', this._eventHandlers.mouseup); 3651d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(c, 'mouseup', this._eventHandlers.mouseup); 3661d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(c, 'mousemove', this._eventHandlers.mousemove); 3671d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel', 3681d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._eventHandlers.mousewheel); 3691d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 370a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 3711d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /* Work around right and middle click browser behaviors */ 3721d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(document, 'click', this._eventHandlers.mousedisable); 3731d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.removeEvent(document.body, 'contextmenu', this._eventHandlers.mousedisable); 374a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 3751d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 3761d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 377a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 3781d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman Util.make_properties(Mouse, [ 3791d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ['target', 'ro', 'dom'], // DOM element that captures mouse input 3801d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ['notify', 'ro', 'func'], // Function to call to notify whenever a mouse event is received 3811d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ['focused', 'rw', 'bool'], // Capture and send mouse clicks/movement 3821d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ['scale', 'rw', 'float'], // Viewport scale factor 0.0 - 1.0 383a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 3841d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ['onMouseButton', 'rw', 'func'], // Handler for mouse button click/release 3851d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ['onMouseMove', 'rw', 'func'], // Handler for mouse movement 3861d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ['touchButton', 'rw', 'int'] // Button mask (1, 2, 4) for touch devices (0 means ignore clicks) 3871d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman ]); 3881d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman})(); 389