| Index: remoting/webapp/crd/js/client_plugin_impl.js
|
| diff --git a/remoting/webapp/crd/js/client_plugin_impl.js b/remoting/webapp/crd/js/client_plugin_impl.js
|
| deleted file mode 100644
|
| index 6248956f79518a22aca0f80cfe5ddcd154803be6..0000000000000000000000000000000000000000
|
| --- a/remoting/webapp/crd/js/client_plugin_impl.js
|
| +++ /dev/null
|
| @@ -1,911 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -/**
|
| - * @fileoverview
|
| - * Class that wraps low-level details of interacting with the client plugin.
|
| - *
|
| - * This abstracts a <embed> element and controls the plugin which does
|
| - * the actual remoting work. It also handles differences between
|
| - * client plugins versions when it is necessary.
|
| - */
|
| -
|
| -'use strict';
|
| -
|
| -/** @suppress {duplicate} */
|
| -var remoting = remoting || {};
|
| -
|
| -/** @constructor */
|
| -remoting.ClientPluginMessage = function() {
|
| - /** @type {string} */
|
| - this.method = '';
|
| -
|
| - /** @type {Object<string,*>} */
|
| - this.data = {};
|
| -};
|
| -
|
| -/**
|
| - * @param {Element} container The container for the embed element.
|
| - * @param {Array<string>} requiredCapabilities The set of capabilties that the
|
| - * session must support for this application.
|
| - * @constructor
|
| - * @implements {remoting.ClientPlugin}
|
| - */
|
| -remoting.ClientPluginImpl = function(container,
|
| - requiredCapabilities) {
|
| - // TODO(kelvinp): Hack to remove all plugin elements as our current code does
|
| - // not handle connection cancellation properly.
|
| - container.innerText = '';
|
| - this.plugin_ = remoting.ClientPluginImpl.createPluginElement_();
|
| - this.plugin_.id = 'session-client-plugin';
|
| - container.appendChild(this.plugin_);
|
| -
|
| - /** @private {Array<string>} */
|
| - this.requiredCapabilities_ = requiredCapabilities;
|
| -
|
| - /** @private {remoting.ClientPlugin.ConnectionEventHandler} */
|
| - this.connectionEventHandler_ = null;
|
| -
|
| - /** @private {?function(string, number, number)} */
|
| - this.updateMouseCursorImage_ = base.doNothing;
|
| - /** @private {?function(string, string)} */
|
| - this.updateClipboardData_ = base.doNothing;
|
| - /** @private {?function(string)} */
|
| - this.onCastExtensionHandler_ = base.doNothing;
|
| - /** @private {?function({rects:Array<Array<number>>}):void} */
|
| - this.debugRegionHandler_ = null;
|
| -
|
| - /** @private {number} */
|
| - this.pluginApiVersion_ = -1;
|
| - /** @private {Array<string>} */
|
| - this.pluginApiFeatures_ = [];
|
| - /** @private {number} */
|
| - this.pluginApiMinVersion_ = -1;
|
| - /**
|
| - * Capabilities to be used for the next connect request.
|
| - * @private {!Array<string>}
|
| - */
|
| - this.capabilities_ = [];
|
| - /**
|
| - * Capabilities that are negotiated between the client and the host.
|
| - * @private {Array<remoting.ClientSession.Capability>}
|
| - */
|
| - this.hostCapabilities_ = null;
|
| - /** @private {boolean} */
|
| - this.helloReceived_ = false;
|
| - /** @private {function(boolean)|null} */
|
| - this.onInitializedCallback_ = null;
|
| - /** @private {function(string, string):void} */
|
| - this.onPairingComplete_ = function(clientId, sharedSecret) {};
|
| - /** @private {remoting.ClientSession.PerfStats} */
|
| - this.perfStats_ = new remoting.ClientSession.PerfStats();
|
| -
|
| - /** @type {remoting.ClientPluginImpl} */
|
| - var that = this;
|
| - this.plugin_.addEventListener('message',
|
| - /** @param {Event} event Message event from the plugin. */
|
| - function(event) {
|
| - that.handleMessage_(
|
| - /** @type {remoting.ClientPluginMessage} */ (event.data));
|
| - }, false);
|
| -
|
| - if (remoting.settings.CLIENT_PLUGIN_TYPE == 'native') {
|
| - window.setTimeout(this.showPluginForClickToPlay_.bind(this), 500);
|
| - }
|
| -
|
| - /** @private */
|
| - this.hostDesktop_ = new remoting.ClientPlugin.HostDesktopImpl(
|
| - this, this.postMessage_.bind(this));
|
| -
|
| - /** @private */
|
| - this.extensions_ = new remoting.ProtocolExtensionManager(
|
| - this.sendClientMessage_.bind(this));
|
| -
|
| - /** @private {remoting.CredentialsProvider} */
|
| - this.credentials_ = null;
|
| -
|
| - /** @private {string} */
|
| - this.keyRemappings_ = '';
|
| -};
|
| -
|
| -/**
|
| - * Creates plugin element without adding it to a container.
|
| - *
|
| - * @return {HTMLEmbedElement} Plugin element
|
| - */
|
| -remoting.ClientPluginImpl.createPluginElement_ = function() {
|
| - var plugin =
|
| - /** @type {HTMLEmbedElement} */ (document.createElement('embed'));
|
| - if (remoting.settings.CLIENT_PLUGIN_TYPE == 'pnacl') {
|
| - plugin.src = 'remoting_client_pnacl.nmf';
|
| - plugin.type = 'application/x-pnacl';
|
| - } else if (remoting.settings.CLIENT_PLUGIN_TYPE == 'nacl') {
|
| - plugin.src = 'remoting_client_nacl.nmf';
|
| - plugin.type = 'application/x-nacl';
|
| - } else {
|
| - plugin.src = 'about://none';
|
| - plugin.type = 'application/vnd.chromium.remoting-viewer';
|
| - }
|
| - plugin.width = '0';
|
| - plugin.height = '0';
|
| - plugin.tabIndex = 0; // Required, otherwise focus() doesn't work.
|
| - return plugin;
|
| -}
|
| -
|
| -/**
|
| - * Chromoting session API version (for this javascript).
|
| - * This is compared with the plugin API version to verify that they are
|
| - * compatible.
|
| - *
|
| - * @const
|
| - * @private
|
| - */
|
| -remoting.ClientPluginImpl.prototype.API_VERSION_ = 6;
|
| -
|
| -/**
|
| - * The oldest API version that we support.
|
| - * This will differ from the |API_VERSION_| if we maintain backward
|
| - * compatibility with older API versions.
|
| - *
|
| - * @const
|
| - * @private
|
| - */
|
| -remoting.ClientPluginImpl.prototype.API_MIN_VERSION_ = 5;
|
| -
|
| -/**
|
| - * @param {remoting.ClientPlugin.ConnectionEventHandler} handler
|
| - */
|
| -remoting.ClientPluginImpl.prototype.setConnectionEventHandler =
|
| - function(handler) {
|
| - this.connectionEventHandler_ = handler;
|
| -};
|
| -
|
| -/**
|
| - * @param {function(string, number, number):void} handler
|
| - */
|
| -remoting.ClientPluginImpl.prototype.setMouseCursorHandler = function(handler) {
|
| - this.updateMouseCursorImage_ = handler;
|
| -};
|
| -
|
| -/**
|
| - * @param {function(string, string):void} handler
|
| - */
|
| -remoting.ClientPluginImpl.prototype.setClipboardHandler = function(handler) {
|
| - this.updateClipboardData_ = handler;
|
| -};
|
| -
|
| -/**
|
| - * @param {?function({rects:Array<Array<number>>}):void} handler
|
| - */
|
| -remoting.ClientPluginImpl.prototype.setDebugDirtyRegionHandler =
|
| - function(handler) {
|
| - this.debugRegionHandler_ = handler;
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'enableDebugRegion', data: { enable: handler != null } }));
|
| -};
|
| -
|
| -/**
|
| - * @param {string|remoting.ClientPluginMessage}
|
| - * rawMessage Message from the plugin.
|
| - * @private
|
| - */
|
| -remoting.ClientPluginImpl.prototype.handleMessage_ = function(rawMessage) {
|
| - var message =
|
| - /** @type {remoting.ClientPluginMessage} */
|
| - ((typeof(rawMessage) == 'string') ? base.jsonParseSafe(rawMessage)
|
| - : rawMessage);
|
| - if (!message || !('method' in message) || !('data' in message)) {
|
| - console.error('Received invalid message from the plugin:', rawMessage);
|
| - return;
|
| - }
|
| -
|
| - try {
|
| - this.handleMessageMethod_(message);
|
| - } catch(/** @type {*} */ e) {
|
| - console.error(e);
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * @param {remoting.ClientPluginMessage}
|
| - * message Parsed message from the plugin.
|
| - * @private
|
| - */
|
| -remoting.ClientPluginImpl.prototype.handleMessageMethod_ = function(message) {
|
| - /**
|
| - * Splits a string into a list of words delimited by spaces.
|
| - * @param {string} str String that should be split.
|
| - * @return {!Array<string>} List of words.
|
| - */
|
| - var tokenize = function(str) {
|
| - /** @type {Array<string>} */
|
| - var tokens = str.match(/\S+/g);
|
| - return tokens ? tokens : [];
|
| - };
|
| -
|
| - if (this.connectionEventHandler_) {
|
| - var handler = this.connectionEventHandler_;
|
| -
|
| - if (message.method == 'sendOutgoingIq') {
|
| - handler.onOutgoingIq(base.getStringAttr(message.data, 'iq'));
|
| -
|
| - } else if (message.method == 'logDebugMessage') {
|
| - handler.onDebugMessage(base.getStringAttr(message.data, 'message'));
|
| -
|
| - } else if (message.method == 'onConnectionStatus') {
|
| - var stateString = base.getStringAttr(message.data, 'state');
|
| - var state = remoting.ClientSession.State.fromString(stateString);
|
| - var error = remoting.ClientSession.ConnectionError.fromString(
|
| - base.getStringAttr(message.data, 'error'));
|
| -
|
| - // Delay firing the CONNECTED event until the capabilities are negotiated,
|
| - // TODO(kelvinp): Fix the client plugin to fire capabilities and the
|
| - // connected event in the same message.
|
| - if (state === remoting.ClientSession.State.CONNECTED) {
|
| - base.debug.assert(this.hostCapabilities_ === null,
|
| - 'Capabilities should only be set after the session is connected');
|
| - return;
|
| - }
|
| - handler.onConnectionStatusUpdate(state, error);
|
| -
|
| - } else if (message.method == 'onRouteChanged') {
|
| - var channel = base.getStringAttr(message.data, 'channel');
|
| - var connectionType = base.getStringAttr(message.data, 'connectionType');
|
| - handler.onRouteChanged(channel, connectionType);
|
| -
|
| - } else if (message.method == 'onConnectionReady') {
|
| - var ready = base.getBooleanAttr(message.data, 'ready');
|
| - handler.onConnectionReady(ready);
|
| -
|
| - } else if (message.method == 'setCapabilities') {
|
| - var capabilityString = base.getStringAttr(message.data, 'capabilities');
|
| - console.log('plugin: setCapabilities: [' + capabilityString + ']');
|
| -
|
| - base.debug.assert(this.hostCapabilities_ === null,
|
| - 'setCapabilities() should only be called once');
|
| - this.hostCapabilities_ = tokenize(capabilityString);
|
| -
|
| - handler.onConnectionStatusUpdate(
|
| - remoting.ClientSession.State.CONNECTED,
|
| - remoting.ClientSession.ConnectionError.NONE);
|
| - this.extensions_.start();
|
| -
|
| - } else if (message.method == 'onFirstFrameReceived') {
|
| - handler.onFirstFrameReceived();
|
| -
|
| - }
|
| - }
|
| -
|
| - if (message.method == 'hello') {
|
| - // Resize in case we had to enlarge it to support click-to-play.
|
| - this.hidePluginForClickToPlay_();
|
| - this.pluginApiVersion_ = base.getNumberAttr(message.data, 'apiVersion');
|
| - this.pluginApiMinVersion_ =
|
| - base.getNumberAttr(message.data, 'apiMinVersion');
|
| -
|
| - if (this.pluginApiVersion_ >= 7) {
|
| - this.pluginApiFeatures_ =
|
| - tokenize(base.getStringAttr(message.data, 'apiFeatures'));
|
| -
|
| - // Negotiate capabilities.
|
| - /** @type {!Array<string>} */
|
| - var supportedCapabilities = [];
|
| - if ('supportedCapabilities' in message.data) {
|
| - supportedCapabilities =
|
| - tokenize(base.getStringAttr(message.data, 'supportedCapabilities'));
|
| - }
|
| - // At the moment the webapp does not recognize any of
|
| - // 'requestedCapabilities' capabilities (so they all should be disabled)
|
| - // and do not care about any of 'supportedCapabilities' capabilities (so
|
| - // they all can be enabled).
|
| - // All the required capabilities (specified by the app) are added to this.
|
| - this.capabilities_ = supportedCapabilities.concat(
|
| - this.requiredCapabilities_);
|
| - } else if (this.pluginApiVersion_ >= 6) {
|
| - this.pluginApiFeatures_ = ['highQualityScaling', 'injectKeyEvent'];
|
| - } else {
|
| - this.pluginApiFeatures_ = ['highQualityScaling'];
|
| - }
|
| - this.helloReceived_ = true;
|
| - if (this.onInitializedCallback_ != null) {
|
| - this.onInitializedCallback_(true);
|
| - this.onInitializedCallback_ = null;
|
| - }
|
| -
|
| - } else if (message.method == 'onDesktopSize') {
|
| - this.hostDesktop_.onSizeUpdated(message);
|
| - } else if (message.method == 'onDesktopShape') {
|
| - this.hostDesktop_.onShapeUpdated(message);
|
| - } else if (message.method == 'onPerfStats') {
|
| - // Return value is ignored. These calls will throw an error if the value
|
| - // is not a number.
|
| - base.getNumberAttr(message.data, 'videoBandwidth');
|
| - base.getNumberAttr(message.data, 'videoFrameRate');
|
| - base.getNumberAttr(message.data, 'captureLatency');
|
| - base.getNumberAttr(message.data, 'encodeLatency');
|
| - base.getNumberAttr(message.data, 'decodeLatency');
|
| - base.getNumberAttr(message.data, 'renderLatency');
|
| - base.getNumberAttr(message.data, 'roundtripLatency');
|
| - this.perfStats_ =
|
| - /** @type {remoting.ClientSession.PerfStats} */ (message.data);
|
| -
|
| - } else if (message.method == 'injectClipboardItem') {
|
| - var mimetype = base.getStringAttr(message.data, 'mimeType');
|
| - var item = base.getStringAttr(message.data, 'item');
|
| - this.updateClipboardData_(mimetype, item);
|
| -
|
| - } else if (message.method == 'fetchPin') {
|
| - // The pairingSupported value in the dictionary indicates whether both
|
| - // client and host support pairing. If the client doesn't support pairing,
|
| - // then the value won't be there at all, so give it a default of false.
|
| - var pairingSupported = base.getBooleanAttr(message.data, 'pairingSupported',
|
| - false);
|
| - this.credentials_.getPIN(pairingSupported).then(
|
| - this.onPinFetched_.bind(this)
|
| - );
|
| -
|
| - } else if (message.method == 'fetchThirdPartyToken') {
|
| - var tokenUrl = base.getStringAttr(message.data, 'tokenUrl');
|
| - var hostPublicKey = base.getStringAttr(message.data, 'hostPublicKey');
|
| - var scope = base.getStringAttr(message.data, 'scope');
|
| - this.credentials_.getThirdPartyToken(tokenUrl, hostPublicKey, scope).then(
|
| - this.onThirdPartyTokenFetched_.bind(this)
|
| - );
|
| - } else if (message.method == 'pairingResponse') {
|
| - var clientId = base.getStringAttr(message.data, 'clientId');
|
| - var sharedSecret = base.getStringAttr(message.data, 'sharedSecret');
|
| - this.onPairingComplete_(clientId, sharedSecret);
|
| -
|
| - } else if (message.method == 'unsetCursorShape') {
|
| - this.updateMouseCursorImage_('', 0, 0);
|
| -
|
| - } else if (message.method == 'setCursorShape') {
|
| - var width = base.getNumberAttr(message.data, 'width');
|
| - var height = base.getNumberAttr(message.data, 'height');
|
| - var hotspotX = base.getNumberAttr(message.data, 'hotspotX');
|
| - var hotspotY = base.getNumberAttr(message.data, 'hotspotY');
|
| - var srcArrayBuffer = base.getObjectAttr(message.data, 'data');
|
| -
|
| - var canvas =
|
| - /** @type {HTMLCanvasElement} */ (document.createElement('canvas'));
|
| - canvas.width = width;
|
| - canvas.height = height;
|
| -
|
| - var context =
|
| - /** @type {CanvasRenderingContext2D} */ (canvas.getContext('2d'));
|
| - var imageData = context.getImageData(0, 0, width, height);
|
| - base.debug.assert(srcArrayBuffer instanceof ArrayBuffer);
|
| - var src = new Uint8Array(/** @type {ArrayBuffer} */(srcArrayBuffer));
|
| - var dest = imageData.data;
|
| - for (var i = 0; i < /** @type {number} */(dest.length); i += 4) {
|
| - dest[i] = src[i + 2];
|
| - dest[i + 1] = src[i + 1];
|
| - dest[i + 2] = src[i];
|
| - dest[i + 3] = src[i + 3];
|
| - }
|
| -
|
| - context.putImageData(imageData, 0, 0);
|
| - this.updateMouseCursorImage_(canvas.toDataURL(), hotspotX, hotspotY);
|
| -
|
| - } else if (message.method == 'onDebugRegion') {
|
| - if (this.debugRegionHandler_) {
|
| - this.debugRegionHandler_(
|
| - /** @type {{rects: Array<(Array<number>)>}} **/(message.data));
|
| - }
|
| - } else if (message.method == 'extensionMessage') {
|
| - var extMsgType = base.getStringAttr(message.data, 'type');
|
| - var extMsgData = base.getStringAttr(message.data, 'data');
|
| - this.extensions_.onProtocolExtensionMessage(extMsgType, extMsgData);
|
| -
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Deletes the plugin.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.dispose = function() {
|
| - if (this.plugin_) {
|
| - this.plugin_.parentNode.removeChild(this.plugin_);
|
| - this.plugin_ = null;
|
| - }
|
| -
|
| - base.dispose(this.extensions_);
|
| - this.extensions_ = null;
|
| -};
|
| -
|
| -/**
|
| - * @return {HTMLEmbedElement} HTML element that corresponds to the plugin.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.element = function() {
|
| - return this.plugin_;
|
| -};
|
| -
|
| -/**
|
| - * @param {function(boolean): void} onDone
|
| - */
|
| -remoting.ClientPluginImpl.prototype.initialize = function(onDone) {
|
| - if (this.helloReceived_) {
|
| - onDone(true);
|
| - } else {
|
| - this.onInitializedCallback_ = onDone;
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * @return {boolean} True if the plugin and web-app versions are compatible.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.isSupportedVersion = function() {
|
| - if (!this.helloReceived_) {
|
| - console.error(
|
| - "isSupportedVersion() is called before the plugin is initialized.");
|
| - return false;
|
| - }
|
| - return this.API_VERSION_ >= this.pluginApiMinVersion_ &&
|
| - this.pluginApiVersion_ >= this.API_MIN_VERSION_;
|
| -};
|
| -
|
| -/**
|
| - * @param {remoting.ClientPlugin.Feature} feature The feature to test for.
|
| - * @return {boolean} True if the plugin supports the named feature.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.hasFeature = function(feature) {
|
| - if (!this.helloReceived_) {
|
| - console.error(
|
| - "hasFeature() is called before the plugin is initialized.");
|
| - return false;
|
| - }
|
| - return this.pluginApiFeatures_.indexOf(feature) > -1;
|
| -};
|
| -
|
| -
|
| -/**
|
| - * @param {remoting.ClientSession.Capability} capability The capability to test
|
| - * for.
|
| - * @return {boolean} True if the capability has been negotiated between
|
| - * the client and host.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.hasCapability = function(capability) {
|
| - return this.hostCapabilities_ !== null &&
|
| - this.hostCapabilities_.indexOf(capability) > -1;
|
| -};
|
| -
|
| -/**
|
| - * @return {boolean} True if the plugin supports the injectKeyEvent API.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.isInjectKeyEventSupported = function() {
|
| - return this.pluginApiVersion_ >= 6;
|
| -};
|
| -
|
| -/**
|
| - * @param {string} iq Incoming IQ stanza.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.onIncomingIq = function(iq) {
|
| - if (this.plugin_ && this.plugin_.postMessage) {
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'incomingIq', data: { iq: iq } }));
|
| - } else {
|
| - // plugin.onIq may not be set after the plugin has been shut
|
| - // down. Particularly this happens when we receive response to
|
| - // session-terminate stanza.
|
| - console.warn('plugin.onIq is not set so dropping incoming message.');
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * @param {remoting.Host} host The host to connect to.
|
| - * @param {string} localJid Local jid.
|
| - * @param {remoting.CredentialsProvider} credentialsProvider
|
| - */
|
| -remoting.ClientPluginImpl.prototype.connect =
|
| - function(host, localJid, credentialsProvider) {
|
| - var keyFilter = '';
|
| - if (remoting.platformIsMac()) {
|
| - keyFilter = 'mac';
|
| - } else if (remoting.platformIsChromeOS()) {
|
| - keyFilter = 'cros';
|
| - }
|
| -
|
| - // Use PPB_VideoDecoder API only in Chrome 43 and above. It is broken in
|
| - // previous versions of Chrome, see crbug.com/459103 and crbug.com/463577 .
|
| - var enableVideoDecodeRenderer =
|
| - parseInt((remoting.getChromeVersion() || '0').split('.')[0], 10) >= 43;
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'delegateLargeCursors', data: {} }));
|
| - var methods = 'third_party,spake2_pair,spake2_hmac,spake2_plain';
|
| - this.credentials_ = credentialsProvider;
|
| - this.useAsyncPinDialog_();
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'connect', data: {
|
| - hostJid: host.jabberId,
|
| - hostPublicKey: host.publicKey,
|
| - localJid: localJid,
|
| - sharedSecret: '',
|
| - authenticationMethods: methods,
|
| - authenticationTag: host.hostId,
|
| - capabilities: this.capabilities_.join(" "),
|
| - clientPairingId: credentialsProvider.getPairingInfo().clientId,
|
| - clientPairedSecret: credentialsProvider.getPairingInfo().sharedSecret,
|
| - keyFilter: keyFilter,
|
| - enableVideoDecodeRenderer: enableVideoDecodeRenderer
|
| - }
|
| - }));
|
| -};
|
| -
|
| -/**
|
| - * Release all currently pressed keys.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.releaseAllKeys = function() {
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'releaseAllKeys', data: {} }));
|
| -};
|
| -
|
| -/**
|
| - * Sets and stores the key remapping setting for the current host.
|
| - *
|
| - * @param {string} remappings Comma separated list of key remappings.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.setRemapKeys =
|
| - function(remappings) {
|
| - // Cancel any existing remappings and apply the new ones.
|
| - this.applyRemapKeys_(this.keyRemappings_, false);
|
| - this.applyRemapKeys_(remappings, true);
|
| - this.keyRemappings_ = remappings;
|
| -};
|
| -
|
| -/**
|
| - * Applies the configured key remappings to the session, or resets them.
|
| - *
|
| - * @param {string} remapKeys
|
| - * @param {boolean} apply True to apply remappings, false to cancel them.
|
| - * @private
|
| - */
|
| -remoting.ClientPluginImpl.prototype.applyRemapKeys_ =
|
| - function(remapKeys, apply) {
|
| - if (remapKeys == '') {
|
| - return;
|
| - }
|
| -
|
| - var remappings = remapKeys.split(',');
|
| - for (var i = 0; i < remappings.length; ++i) {
|
| - var keyCodes = remappings[i].split('>');
|
| - if (keyCodes.length != 2) {
|
| - console.log('bad remapKey: ' + remappings[i]);
|
| - continue;
|
| - }
|
| - var fromKey = parseInt(keyCodes[0], 0);
|
| - var toKey = parseInt(keyCodes[1], 0);
|
| - if (!fromKey || !toKey) {
|
| - console.log('bad remapKey code: ' + remappings[i]);
|
| - continue;
|
| - }
|
| - if (apply) {
|
| - console.log('remapKey 0x' + fromKey.toString(16) +
|
| - '>0x' + toKey.toString(16));
|
| - this.remapKey(fromKey, toKey);
|
| - } else {
|
| - console.log('cancel remapKey 0x' + fromKey.toString(16));
|
| - this.remapKey(fromKey, fromKey);
|
| - }
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Sends a key combination to the remoting host, by sending down events for
|
| - * the given keys, followed by up events in reverse order.
|
| - *
|
| - * @param {Array<number>} keys Key codes to be sent.
|
| - * @return {void} Nothing.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.injectKeyCombination =
|
| - function(keys) {
|
| - for (var i = 0; i < keys.length; i++) {
|
| - this.injectKeyEvent(keys[i], true);
|
| - }
|
| - for (var i = 0; i < keys.length; i++) {
|
| - this.injectKeyEvent(keys[i], false);
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Send a key event to the host.
|
| - *
|
| - * @param {number} usbKeycode The USB-style code of the key to inject.
|
| - * @param {boolean} pressed True to inject a key press, False for a release.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.injectKeyEvent =
|
| - function(usbKeycode, pressed) {
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'injectKeyEvent', data: {
|
| - 'usbKeycode': usbKeycode,
|
| - 'pressed': pressed}
|
| - }));
|
| -};
|
| -
|
| -/**
|
| - * Remap one USB keycode to another in all subsequent key events.
|
| - *
|
| - * @param {number} fromKeycode The USB-style code of the key to remap.
|
| - * @param {number} toKeycode The USB-style code to remap the key to.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.remapKey =
|
| - function(fromKeycode, toKeycode) {
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'remapKey', data: {
|
| - 'fromKeycode': fromKeycode,
|
| - 'toKeycode': toKeycode}
|
| - }));
|
| -};
|
| -
|
| -/**
|
| - * Enable/disable redirection of the specified key to the web-app.
|
| - *
|
| - * @param {number} keycode The USB-style code of the key.
|
| - * @param {Boolean} trap True to enable trapping, False to disable.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.trapKey = function(keycode, trap) {
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'trapKey', data: {
|
| - 'keycode': keycode,
|
| - 'trap': trap}
|
| - }));
|
| -};
|
| -
|
| -/**
|
| - * Returns an associative array with a set of stats for this connecton.
|
| - *
|
| - * @return {remoting.ClientSession.PerfStats} The connection statistics.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.getPerfStats = function() {
|
| - return this.perfStats_;
|
| -};
|
| -
|
| -/**
|
| - * Sends a clipboard item to the host.
|
| - *
|
| - * @param {string} mimeType The MIME type of the clipboard item.
|
| - * @param {string} item The clipboard item.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.sendClipboardItem =
|
| - function(mimeType, item) {
|
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.SEND_CLIPBOARD_ITEM))
|
| - return;
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'sendClipboardItem',
|
| - data: { mimeType: mimeType, item: item }}));
|
| -};
|
| -
|
| -/**
|
| - * Notifies the host that the client has the specified size and pixel density.
|
| - *
|
| - * @param {number} width The available client width in DIPs.
|
| - * @param {number} height The available client height in DIPs.
|
| - * @param {number} device_scale The number of device pixels per DIP.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.notifyClientResolution =
|
| - function(width, height, device_scale) {
|
| - this.hostDesktop_.resize(width, height, device_scale);
|
| -};
|
| -
|
| -/**
|
| - * Requests that the host pause or resume sending video updates.
|
| - *
|
| - * @param {boolean} pause True to suspend video updates, false otherwise.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.pauseVideo =
|
| - function(pause) {
|
| - if (this.hasFeature(remoting.ClientPlugin.Feature.VIDEO_CONTROL)) {
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'videoControl', data: { pause: pause }}));
|
| - } else if (this.hasFeature(remoting.ClientPlugin.Feature.PAUSE_VIDEO)) {
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'pauseVideo', data: { pause: pause }}));
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Requests that the host pause or resume sending audio updates.
|
| - *
|
| - * @param {boolean} pause True to suspend audio updates, false otherwise.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.pauseAudio =
|
| - function(pause) {
|
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.PAUSE_AUDIO)) {
|
| - return;
|
| - }
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'pauseAudio', data: { pause: pause }}));
|
| -};
|
| -
|
| -/**
|
| - * Requests that the host configure the video codec for lossless encode.
|
| - *
|
| - * @param {boolean} wantLossless True to request lossless encoding.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.setLosslessEncode =
|
| - function(wantLossless) {
|
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.VIDEO_CONTROL)) {
|
| - return;
|
| - }
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'videoControl', data: { losslessEncode: wantLossless }}));
|
| -};
|
| -
|
| -/**
|
| - * Requests that the host configure the video codec for lossless color.
|
| - *
|
| - * @param {boolean} wantLossless True to request lossless color.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.setLosslessColor =
|
| - function(wantLossless) {
|
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.VIDEO_CONTROL)) {
|
| - return;
|
| - }
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'videoControl', data: { losslessColor: wantLossless }}));
|
| -};
|
| -
|
| -/**
|
| - * Called when a PIN is obtained from the user.
|
| - *
|
| - * @param {string} pin The PIN.
|
| - * @private
|
| - */
|
| -remoting.ClientPluginImpl.prototype.onPinFetched_ =
|
| - function(pin) {
|
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.ASYNC_PIN)) {
|
| - return;
|
| - }
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'onPinFetched', data: { pin: pin }}));
|
| -};
|
| -
|
| -/**
|
| - * Tells the plugin to ask for the PIN asynchronously.
|
| - * @private
|
| - */
|
| -remoting.ClientPluginImpl.prototype.useAsyncPinDialog_ =
|
| - function() {
|
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.ASYNC_PIN)) {
|
| - return;
|
| - }
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'useAsyncPinDialog', data: {} }));
|
| -};
|
| -
|
| -/**
|
| - * Allows automatic mouse-lock.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.allowMouseLock = function() {
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'allowMouseLock', data: {} }));
|
| -};
|
| -
|
| -/**
|
| - * Sets the third party authentication token and shared secret.
|
| - *
|
| - * @param {remoting.ThirdPartyToken} token
|
| - * @private
|
| - */
|
| -remoting.ClientPluginImpl.prototype.onThirdPartyTokenFetched_ = function(
|
| - token) {
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'onThirdPartyTokenFetched',
|
| - data: { token: token.token, sharedSecret: token.secret}}));
|
| -};
|
| -
|
| -/**
|
| - * Request pairing with the host for PIN-less authentication.
|
| - *
|
| - * @param {string} clientName The human-readable name of the client.
|
| - * @param {function(string, string):void} onDone, Callback to receive the
|
| - * client id and shared secret when they are available.
|
| - */
|
| -remoting.ClientPluginImpl.prototype.requestPairing =
|
| - function(clientName, onDone) {
|
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.PINLESS_AUTH)) {
|
| - return;
|
| - }
|
| - this.onPairingComplete_ = onDone;
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'requestPairing', data: { clientName: clientName } }));
|
| -};
|
| -
|
| -/**
|
| - * Send an extension message to the host.
|
| - *
|
| - * @param {string} type The message type.
|
| - * @param {string} message The message payload.
|
| - * @private
|
| - */
|
| -remoting.ClientPluginImpl.prototype.sendClientMessage_ =
|
| - function(type, message) {
|
| - if (!this.hasFeature(remoting.ClientPlugin.Feature.EXTENSION_MESSAGE)) {
|
| - return;
|
| - }
|
| - this.plugin_.postMessage(JSON.stringify(
|
| - { method: 'extensionMessage',
|
| - data: { type: type, data: message } }));
|
| -
|
| -};
|
| -
|
| -remoting.ClientPluginImpl.prototype.hostDesktop = function() {
|
| - return this.hostDesktop_;
|
| -};
|
| -
|
| -remoting.ClientPluginImpl.prototype.extensions = function() {
|
| - return this.extensions_;
|
| -};
|
| -
|
| -/**
|
| - * If we haven't yet received a "hello" message from the plugin, change its
|
| - * size so that the user can confirm it if click-to-play is enabled, or can
|
| - * see the "this plugin is disabled" message if it is actually disabled.
|
| - * @private
|
| - */
|
| -remoting.ClientPluginImpl.prototype.showPluginForClickToPlay_ = function() {
|
| - if (!this.helloReceived_) {
|
| - var width = 200;
|
| - var height = 200;
|
| - this.plugin_.style.width = width + 'px';
|
| - this.plugin_.style.height = height + 'px';
|
| - // Center the plugin just underneath the "Connnecting..." dialog.
|
| - var dialog = document.getElementById('client-dialog');
|
| - var dialogRect = dialog.getBoundingClientRect();
|
| - this.plugin_.style.top = (dialogRect.bottom + 16) + 'px';
|
| - this.plugin_.style.left = (window.innerWidth - width) / 2 + 'px';
|
| - this.plugin_.style.position = 'fixed';
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Undo the CSS rules needed to make the plugin clickable for click-to-play.
|
| - * @private
|
| - */
|
| -remoting.ClientPluginImpl.prototype.hidePluginForClickToPlay_ = function() {
|
| - this.plugin_.style.width = '';
|
| - this.plugin_.style.height = '';
|
| - this.plugin_.style.top = '';
|
| - this.plugin_.style.left = '';
|
| - this.plugin_.style.position = '';
|
| -};
|
| -
|
| -/**
|
| - * Callback passed to submodules to post a message to the plugin.
|
| - *
|
| - * @param {Object} message
|
| - * @private
|
| - */
|
| -remoting.ClientPluginImpl.prototype.postMessage_ = function(message) {
|
| - if (this.plugin_ && this.plugin_.postMessage) {
|
| - this.plugin_.postMessage(JSON.stringify(message));
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * @constructor
|
| - * @implements {remoting.ClientPluginFactory}
|
| - */
|
| -remoting.DefaultClientPluginFactory = function() {};
|
| -
|
| -/**
|
| - * @param {Element} container
|
| - * @param {Array<string>} requiredCapabilities
|
| - * @return {remoting.ClientPlugin}
|
| - */
|
| -remoting.DefaultClientPluginFactory.prototype.createPlugin =
|
| - function(container, requiredCapabilities) {
|
| - return new remoting.ClientPluginImpl(container,
|
| - requiredCapabilities);
|
| -};
|
| -
|
| -remoting.DefaultClientPluginFactory.prototype.preloadPlugin = function() {
|
| - if (remoting.settings.CLIENT_PLUGIN_TYPE != 'pnacl') {
|
| - return;
|
| - }
|
| -
|
| - var plugin = remoting.ClientPluginImpl.createPluginElement_();
|
| - plugin.addEventListener(
|
| - 'loadend', function() { document.body.removeChild(plugin); }, false);
|
| - document.body.appendChild(plugin);
|
| -};
|
|
|