| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 | 
							- /* global $, JitsiMeetJS, APP */
 - const logger = require("jitsi-meet-logger").getLogger(__filename);
 - import * as KeyCodes from "../keycode/keycode";
 - import {
 -     EVENT_TYPES,
 -     PERMISSIONS_ACTIONS,
 -     REMOTE_CONTROL_EVENT_NAME
 - } from "../../service/remotecontrol/Constants";
 - import RemoteControlParticipant from "./RemoteControlParticipant";
 - import UIEvents from "../../service/UI/UIEvents";
 - 
 - const ConferenceEvents = JitsiMeetJS.events.conference;
 - 
 - /**
 -  * Extract the keyboard key from the keyboard event.
 -  * @param event {KeyboardEvent} the event.
 -  * @returns {KEYS} the key that is pressed or undefined.
 -  */
 - function getKey(event) {
 -     return KeyCodes.keyboardEventToKey(event);
 - }
 - 
 - /**
 -  * Extract the modifiers from the keyboard event.
 -  * @param event {KeyboardEvent} the event.
 -  * @returns {Array} with possible values: "shift", "control", "alt", "command".
 -  */
 - function getModifiers(event) {
 -     let modifiers = [];
 -     if(event.shiftKey) {
 -         modifiers.push("shift");
 -     }
 - 
 -     if(event.ctrlKey) {
 -         modifiers.push("control");
 -     }
 - 
 - 
 -     if(event.altKey) {
 -         modifiers.push("alt");
 -     }
 - 
 -     if(event.metaKey) {
 -         modifiers.push("command");
 -     }
 - 
 -     return modifiers;
 - }
 - 
 - /**
 -  * This class represents the controller party for a remote controller session.
 -  * It listens for mouse and keyboard events and sends them to the receiver
 -  * party of the remote control session.
 -  */
 - export default class Controller extends RemoteControlParticipant {
 -     /**
 -      * Creates new instance.
 -      */
 -     constructor() {
 -         super();
 -         this.isCollectingEvents = false;
 -         this.controlledParticipant = null;
 -         this.requestedParticipant = null;
 -         this._stopListener = this._handleRemoteControlStoppedEvent.bind(this);
 -         this._userLeftListener = this._onUserLeft.bind(this);
 -         this._largeVideoChangedListener
 -             = this._onLargeVideoIdChanged.bind(this);
 -     }
 - 
 -     /**
 -      * Requests permissions from the remote control receiver side.
 -      * @param {string} userId the user id of the participant that will be
 -      * requested.
 -      * @param {JQuerySelector} eventCaptureArea the area that is going to be
 -      * used mouse and keyboard event capture.
 -      * @returns {Promise<boolean>} - resolve values:
 -      * true - accept
 -      * false - deny
 -      * null - the participant has left.
 -      */
 -     requestPermissions(userId, eventCaptureArea) {
 -         if(!this.enabled) {
 -             return Promise.reject(new Error("Remote control is disabled!"));
 -         }
 -         this.area = eventCaptureArea;// $("#largeVideoWrapper")
 -         logger.log("Requsting remote control permissions from: " + userId);
 -         return new Promise((resolve, reject) => {
 -             const clearRequest = () => {
 -                 this.requestedParticipant = null;
 -                 APP.conference.removeConferenceListener(
 -                     ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
 -                     permissionsReplyListener);
 -                 APP.conference.removeConferenceListener(
 -                     ConferenceEvents.USER_LEFT,
 -                     onUserLeft);
 -             };
 -             const permissionsReplyListener = (participant, event) => {
 -                 let result = null;
 -                 try {
 -                     result = this._handleReply(participant, event);
 -                 } catch (e) {
 -                     reject(e);
 -                 }
 -                 if(result !== null) {
 -                     clearRequest();
 -                     resolve(result);
 -                 }
 -             };
 -             const onUserLeft = (id) => {
 -                 if(id === this.requestedParticipant) {
 -                     clearRequest();
 -                     resolve(null);
 -                 }
 -             };
 -             APP.conference.addConferenceListener(
 -                 ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
 -                 permissionsReplyListener);
 -             APP.conference.addConferenceListener(ConferenceEvents.USER_LEFT,
 -                 onUserLeft);
 -             this.requestedParticipant = userId;
 -             this._sendRemoteControlEvent(userId, {
 -                 type: EVENT_TYPES.permissions,
 -                 action: PERMISSIONS_ACTIONS.request
 -             }, e => {
 -                 clearRequest();
 -                 reject(e);
 -             });
 -         });
 -     }
 - 
 -     /**
 -      * Handles the reply of the permissions request.
 -      * @param {JitsiParticipant} participant the participant that has sent the
 -      * reply
 -      * @param {RemoteControlEvent} event the remote control event.
 -      */
 -     _handleReply(participant, event) {
 -         const userId = participant.getId();
 -         if(this.enabled
 -                 && event.name === REMOTE_CONTROL_EVENT_NAME
 -                 && event.type === EVENT_TYPES.permissions
 -                 && userId === this.requestedParticipant) {
 -             if(event.action !== PERMISSIONS_ACTIONS.grant) {
 -                 this.area = null;
 -             }
 -             switch(event.action) {
 -                 case PERMISSIONS_ACTIONS.grant: {
 -                     this.controlledParticipant = userId;
 -                     logger.log("Remote control permissions granted to: "
 -                         + userId);
 -                     this._start();
 -                     return true;
 -                 }
 -                 case PERMISSIONS_ACTIONS.deny:
 -                     return false;
 -                 case PERMISSIONS_ACTIONS.error:
 -                     throw new Error("Error occurred on receiver side");
 -                 default:
 -                     throw new Error("Unknown reply received!");
 -             }
 -         } else {
 -             //different message type or another user -> ignoring the message
 -             return null;
 -         }
 -     }
 - 
 -     /**
 -      * Handles remote control stopped.
 -      * @param {JitsiParticipant} participant the participant that has sent the
 -      * event
 -      * @param {Object} event EndpointMessage event from the data channels.
 -      * @property {string} type property. The function process only events with
 -      * name REMOTE_CONTROL_EVENT_NAME
 -      * @property {RemoteControlEvent} event - the remote control event.
 -      */
 -     _handleRemoteControlStoppedEvent(participant, event) {
 -         if(this.enabled
 -                 && event.name === REMOTE_CONTROL_EVENT_NAME
 -                 && event.type === EVENT_TYPES.stop
 -                 && participant.getId() === this.controlledParticipant) {
 -             this._stop();
 -         }
 -     }
 - 
 -     /**
 -      * Starts processing the mouse and keyboard events. Sets conference
 -      * listeners. Disables keyboard events.
 -      */
 -     _start() {
 -         logger.log("Starting remote control controller.");
 -         APP.UI.addListener(UIEvents.LARGE_VIDEO_ID_CHANGED,
 -             this._largeVideoChangedListener);
 -         APP.conference.addConferenceListener(
 -             ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
 -             this._stopListener);
 -         APP.conference.addConferenceListener(ConferenceEvents.USER_LEFT,
 -             this._userLeftListener);
 -         this.resume();
 -     }
 - 
 -     /**
 -      * Disables the keyboatd shortcuts. Starts collecting remote control
 -      * events.
 -      *
 -      * It can be used to resume an active remote control session wchich was
 -      * paused with this.pause().
 -      */
 -     resume() {
 -         if(!this.enabled || this.isCollectingEvents) {
 -             return;
 -         }
 -         logger.log("Resuming remote control controller.");
 -         this.isCollectingEvents = true;
 -         APP.keyboardshortcut.enable(false);
 -         this.area.mousemove(event => {
 -             const position = this.area.position();
 -             this._sendRemoteControlEvent(this.controlledParticipant, {
 -                 type: EVENT_TYPES.mousemove,
 -                 x: (event.pageX - position.left)/this.area.width(),
 -                 y: (event.pageY - position.top)/this.area.height()
 -             });
 -         });
 -         this.area.mousedown(this._onMouseClickHandler.bind(this,
 -             EVENT_TYPES.mousedown));
 -         this.area.mouseup(this._onMouseClickHandler.bind(this,
 -             EVENT_TYPES.mouseup));
 -         this.area.dblclick(
 -             this._onMouseClickHandler.bind(this, EVENT_TYPES.mousedblclick));
 -         this.area.contextmenu(() => false);
 -         this.area[0].onmousewheel = event => {
 -             this._sendRemoteControlEvent(this.controlledParticipant, {
 -                 type: EVENT_TYPES.mousescroll,
 -                 x: event.deltaX,
 -                 y: event.deltaY
 -             });
 -         };
 -         $(window).keydown(this._onKeyPessHandler.bind(this,
 -             EVENT_TYPES.keydown));
 -         $(window).keyup(this._onKeyPessHandler.bind(this, EVENT_TYPES.keyup));
 -     }
 - 
 -     /**
 -      * Stops processing the mouse and keyboard events. Removes added listeners.
 -      * Enables the keyboard shortcuts. Displays dialog to notify the user that
 -      * remote control session has ended.
 -      */
 -     _stop() {
 -         if(!this.controlledParticipant) {
 -             return;
 -         }
 -         logger.log("Stopping remote control controller.");
 -         APP.UI.removeListener(UIEvents.LARGE_VIDEO_ID_CHANGED,
 -             this._largeVideoChangedListener);
 -         APP.conference.removeConferenceListener(
 -             ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
 -             this._stopListener);
 -         APP.conference.removeConferenceListener(ConferenceEvents.USER_LEFT,
 -             this._userLeftListener);
 -         this.controlledParticipant = null;
 -         this.pause();
 -         this.area = null;
 -         APP.UI.messageHandler.openMessageDialog(
 -             "dialog.remoteControlTitle",
 -             "dialog.remoteControlStopMessage"
 -         );
 -     }
 - 
 -     /**
 -      * Executes this._stop() mehtod:
 -      * Stops processing the mouse and keyboard events. Removes added listeners.
 -      * Enables the keyboard shortcuts. Displays dialog to notify the user that
 -      * remote control session has ended.
 -      *
 -      * In addition:
 -      * Sends stop message to the controlled participant.
 -      */
 -     stop() {
 -         if(!this.controlledParticipant) {
 -             return;
 -         }
 -         this._sendRemoteControlEvent(this.controlledParticipant, {
 -             type: EVENT_TYPES.stop
 -         });
 -         this._stop();
 -     }
 - 
 -     /**
 -      * Pauses the collecting of events and enables the keyboard shortcus. But
 -      * it doesn't removes any other listeners. Basically the remote control
 -      * session will be still active after this.pause(), but no events from the
 -      * controller side will be captured and sent.
 -      *
 -      * You can resume the collecting of the events with this.resume().
 -      */
 -     pause() {
 -         if(!this.controlledParticipant) {
 -             return;
 -         }
 -         logger.log("Pausing remote control controller.");
 -         this.isCollectingEvents = false;
 -         APP.keyboardshortcut.enable(true);
 -         this.area.off( "mousemove" );
 -         this.area.off( "mousedown" );
 -         this.area.off( "mouseup" );
 -         this.area.off( "contextmenu" );
 -         this.area.off( "dblclick" );
 -         $(window).off( "keydown");
 -         $(window).off( "keyup");
 -         this.area[0].onmousewheel = undefined;
 -     }
 - 
 -     /**
 -      * Handler for mouse click events.
 -      * @param {String} type the type of event ("mousedown"/"mouseup")
 -      * @param {Event} event the mouse event.
 -      */
 -     _onMouseClickHandler(type, event) {
 -         this._sendRemoteControlEvent(this.controlledParticipant, {
 -             type: type,
 -             button: event.which
 -         });
 -     }
 - 
 -     /**
 -      * Returns true if the remote control session is started.
 -      * @returns {boolean}
 -      */
 -     isStarted() {
 -         return this.controlledParticipant !== null;
 -     }
 - 
 -     /**
 -      * Returns the id of the requested participant
 -      * @returns {string} this.requestedParticipant.
 -      * NOTE: This id should be the result of JitsiParticipant.getId() call.
 -      */
 -     getRequestedParticipant() {
 -         return this.requestedParticipant;
 -     }
 - 
 -     /**
 -      * Handler for key press events.
 -      * @param {String} type the type of event ("keydown"/"keyup")
 -      * @param {Event} event the key event.
 -      */
 -     _onKeyPessHandler(type, event) {
 -         this._sendRemoteControlEvent(this.controlledParticipant, {
 -             type: type,
 -             key: getKey(event),
 -             modifiers: getModifiers(event),
 -         });
 -     }
 - 
 -     /**
 -      * Calls the stop method if the other side have left.
 -      * @param {string} id - the user id for the participant that have left
 -      */
 -     _onUserLeft(id) {
 -         if(this.controlledParticipant === id) {
 -             this._stop();
 -         }
 -     }
 - 
 -     /**
 -      * Handles changes of the participant displayed on the large video.
 -      * @param {string} id - the user id for the participant that is displayed.
 -      */
 -     _onLargeVideoIdChanged(id) {
 -         if (!this.controlledParticipant) {
 -             return;
 -         }
 -         if(this.controlledParticipant == id) {
 -             this.resume();
 -         } else {
 -             this.pause();
 -         }
 -     }
 - }
 
 
  |