From 03dd26597b56ef50fab70066aae0aabdb1fe5d97 Mon Sep 17 00:00:00 2001
From: hristoterezov <hristo@jitsi.org>
Date: Thu, 6 Jul 2017 21:48:03 -0500
Subject: [PATCH] ref: Extract remote control and SS to
 jitsi-meet-electron-utils

---
 README.md                                     |   4 -
 modules/remotecontrol/constants.js            |  28 --
 modules/remotecontrol/index.js                | 241 ------------------
 modules/screensharing/index.js                |  33 ---
 node_addons/sourceId2Coordinates/binding.gyp  |  27 --
 node_addons/sourceId2Coordinates/index.js     |  22 --
 node_addons/sourceId2Coordinates/package.json |  17 --
 node_addons/sourceId2Coordinates/src/index.cc |  37 ---
 .../src/sourceId2Coordinates.cc               |  45 ----
 .../src/sourceId2Coordinates.h                |   7 -
 package.json                                  |   4 +-
 windows/jitsi-meet/render.js                  |  21 +-
 12 files changed, 7 insertions(+), 479 deletions(-)
 delete mode 100644 modules/remotecontrol/constants.js
 delete mode 100644 modules/remotecontrol/index.js
 delete mode 100644 modules/screensharing/index.js
 delete mode 100644 node_addons/sourceId2Coordinates/binding.gyp
 delete mode 100644 node_addons/sourceId2Coordinates/index.js
 delete mode 100644 node_addons/sourceId2Coordinates/package.json
 delete mode 100644 node_addons/sourceId2Coordinates/src/index.cc
 delete mode 100644 node_addons/sourceId2Coordinates/src/sourceId2Coordinates.cc
 delete mode 100644 node_addons/sourceId2Coordinates/src/sourceId2Coordinates.h

diff --git a/README.md b/README.md
index 430f630..b20f0f1 100644
--- a/README.md
+++ b/README.md
@@ -10,10 +10,6 @@ from config.js
 ```bash
 npm install
 ```
-Since node_addons/sourceId2Coordinates add-on is local dependency, every code change requires increasing the version in its package.json. To rebuild the add-on if it is already installed execute:
-```bash
-npm update
-```
 
 ## Statring the application
 ```bash
diff --git a/modules/remotecontrol/constants.js b/modules/remotecontrol/constants.js
deleted file mode 100644
index edd2e6b..0000000
--- a/modules/remotecontrol/constants.js
+++ /dev/null
@@ -1,28 +0,0 @@
-module.exports = {
-    /**
-     * Types of remote-control events.
-     */
-    EVENTS: {
-        mousemove: "mousemove",
-        mousedown: "mousedown",
-        mouseup: "mouseup",
-        mousedblclick: "mousedblclick",
-        mousescroll: "mousescroll",
-        keydown: "keydown",
-        keyup: "keyup",
-        stop: "stop",
-        supported: "supported"
-    },
-
-    /**
-     * Types of remote-control requests.
-     */
-    REQUESTS: {
-        start: "start"
-    },
-
-    /**
-     * The name of remote control messages.
-     */
-    REMOTE_CONTROL_MESSAGE_NAME: "remote-control"
-};
diff --git a/modules/remotecontrol/index.js b/modules/remotecontrol/index.js
deleted file mode 100644
index 4efcdad..0000000
--- a/modules/remotecontrol/index.js
+++ /dev/null
@@ -1,241 +0,0 @@
-let robot = require("robotjs");
-const sourceId2Coordinates = require("sourceId2Coordinates");
-const electron = require("electron");
-const constants = require("../../modules/remotecontrol/constants");
-const { EVENTS, REQUESTS, REMOTE_CONTROL_MESSAGE_NAME } = constants;
-
-/**
- * Attaching to the window for debug purposes.
- * We should remove this in production.
- */
-window.robot = robot;
-
-/**
- * Mouse button mapping between the values in remote control mouse event and
- * robotjs methods.
- */
-const MOUSE_BUTTONS = {
-    1: "left",
-    2: "middle",
-    3: "right"
-};
-
-/**
- * Mouse actions mapping between the values in remote control mouse event and
- * robotjs methods.
- */
-const MOUSE_ACTIONS_FROM_EVENT_TYPE = {
-    "mousedown": "down",
-    "mouseup": "up"
-};
-
-/**
- * Key actions mapping between the values in remote control key event and
- * robotjs methods.
- */
-const KEY_ACTIONS_FROM_EVENT_TYPE = {
-    "keydown": "down",
-    "keyup": "up"
-};
-
-/**
- * The status ("up"/"down") of the mouse button.
- * FIXME: Assuming that one button at a time can be pressed. Haven't noticed
- * any issues but maybe we should store the status for every mouse button
- * that we are processing.
- */
-let mouseButtonStatus = "up";
-
-/**
- * Parses the remote control events and executes them via robotjs.
- */
-class RemoteControl {
-    /**
-     * Constructs new instance and initializes the remote control functionality.
-     *
-     * @param {Postis} channel the postis channel.
-     */
-    constructor(channel) {
-        // TODO: if no channel is passed, create one.
-        this.channel = channel;
-        this.channel.ready(() => {
-            this.channel.listen('message', message => {
-                const { name } = message.data;
-                if(name === REMOTE_CONTROL_MESSAGE_NAME) {
-                    this.onRemoteControlMessage(message);
-                }
-            });
-            this.sendEvent({ type: EVENTS.supported });
-        });
-    }
-
-    /**
-     * Disposes the remote control functionality.
-     */
-    dispose() {
-        this.channel = null;
-        this.stop();
-    }
-
-    /**
-     * Handles remote control start messages.
-     *
-     * @param {number} id - the id of the request that will be used for the
-     * response.
-     * @param {string} sourceId - The source id of the desktop sharing stream.
-     */
-    start(id, sourceId) {
-        const displays = electron.screen.getAllDisplays();
-
-        switch(displays.length) {
-            case 0:
-                this.display = undefined;
-            break;
-            case 1:
-                // On Linux probably we'll end up here even if there are
-                // multiple monitors.
-                this.display = displays[0];
-            break;
-            // eslint-disable-next-line no-case-declarations
-            default: // > 1 display
-                const coordinates = sourceId2Coordinates(sourceId);
-                if(coordinates) {
-                    // Currently sourceId2Coordinates will return undefined for
-                    // any OS except Windows. This code will be executed only on
-                    // Windows.
-                    const { x, y } = coordinates;
-                    this.display = electron.screen.getDisplayNearestPoint({
-                        x: x + 1,
-                        y: y + 1
-                    });
-                } else {
-                    // On Mac OS the sourceId = 'screen' + displayId.
-                    // Try to match displayId with sourceId.
-                    const displayId = Number(sourceId.replace('screen:', ''));
-                    this.display
-                        = displays.find(display => display.id === displayId);
-                }
-        }
-
-        const response = {
-            id,
-            type: 'response'
-        };
-
-        if(this.display) {
-            response.result = true;
-        } else {
-            response.error
-                = 'Error: Can\'t detect the display that is currently shared';
-        }
-
-        this.sendMessage(response);
-    }
-
-    /**
-     * Stops processing the events.
-     */
-    stop() {
-        this.display = undefined;
-    }
-
-    /**
-     * Executes the passed message.
-     * @param {Object} message the remote control message.
-     */
-    onRemoteControlMessage(message) {
-        const { id, data } = message;
-
-        // If we haven't set the display prop. We haven't received the remote
-        // control start message or there was an error associating a display.
-        if(!this.display
-            && data.type != REQUESTS.start) {
-            return;
-        }
-        switch(data.type) {
-            case EVENTS.mousemove: {
-                const { width, height, x, y } = this.display.workArea;
-                const destX = data.x * width + x;
-                const destY = data.y * height + y;
-                if(mouseButtonStatus === "down") {
-                    robot.dragMouse(destX, destY);
-                } else {
-                    robot.moveMouse(destX, destY);
-                }
-                break;
-            }
-            case EVENTS.mousedown:
-            case EVENTS.mouseup: {
-                mouseButtonStatus
-                    = MOUSE_ACTIONS_FROM_EVENT_TYPE[data.type];
-                robot.mouseToggle(
-                    mouseButtonStatus,
-                    (data.button
-                            ? MOUSE_BUTTONS[data.button] : undefined));
-                break;
-            }
-            case EVENTS.mousedblclick: {
-                robot.mouseClick(
-                    (data.button
-                        ? MOUSE_BUTTONS[data.button] : undefined),
-                    true);
-                break;
-            }
-            case EVENTS.mousescroll:{
-                //FIXME: implement horizontal scrolling
-                if(data.y !== 0) {
-                    robot.scrollMouse(
-                        Math.abs(data.y),
-                        data.y > 0 ? "down" : "up"
-                    );
-                }
-                break;
-            }
-            case EVENTS.keydown:
-            case EVENTS.keyup: {
-                robot.keyToggle(
-                    data.key,
-                    KEY_ACTIONS_FROM_EVENT_TYPE[data.type],
-                    data.modifiers);
-                break;
-            }
-            case REQUESTS.start: {
-                this.start(id, data.sourceId);
-                break;
-            }
-            case EVENTS.stop: {
-                this.stop();
-                break;
-            }
-            default:
-                console.error("Unknown event type!");
-        }
-    }
-
-    /**
-     * Sends remote control event to the controlled participant.
-     *
-     * @param {Object} event the remote control event.
-     */
-    sendEvent(event) {
-        const remoteControlEvent = Object.assign(
-            { name: REMOTE_CONTROL_MESSAGE_NAME },
-            event
-        );
-        this.sendMessage({ data: remoteControlEvent });
-    }
-
-    /**
-     * Sends a message to Jitsi Meet.
-     *
-     * @param {Object} message the message to be sent.
-     */
-    sendMessage(message) {
-        this.channel.send({
-            method: 'message',
-            params: message
-        });
-    }
-}
-
-module.exports = RemoteControl;
diff --git a/modules/screensharing/index.js b/modules/screensharing/index.js
deleted file mode 100644
index e1be677..0000000
--- a/modules/screensharing/index.js
+++ /dev/null
@@ -1,33 +0,0 @@
-const electron = require("electron");
-
-/**
- * Get sources available for screensharing. The callback is invoked
- * with an array of DesktopCapturerSources.
- *
- * @param {Function} callback - The success callback.
- * @param {Function} errorCallback - The callback for errors.
- * @param {Object} options - Configuration for getting sources.
- * @param {Array} options.types - Specify the desktop source types to get,
- * with valid sources being "window" and "screen".
- * @param {Object} options.thumbnailSize - Specify how big the preview
- * images for the sources should be. The valid keys are height and width,
- * e.g. { height: number, width: number}. By default electron will return
- * images with height and width of 150px.
- */
-function obtainDesktopStreams(callback, errorCallback, options = {}) {
-    electron.desktopCapturer.getSources(options,
-        (error, sources) => {
-            if (error) {
-                errorCallback(error);
-                return;
-            }
-
-            callback(sources);
-        });
-}
-
-module.exports = function setupScreenSharingForWindow(pWindow) {
-    pWindow.JitsiMeetElectron = {
-        obtainDesktopStreams
-    };
-};
diff --git a/node_addons/sourceId2Coordinates/binding.gyp b/node_addons/sourceId2Coordinates/binding.gyp
deleted file mode 100644
index 4f3d0f6..0000000
--- a/node_addons/sourceId2Coordinates/binding.gyp
+++ /dev/null
@@ -1,27 +0,0 @@
-{
-    'targets': [{
-        'target_name': 'sourceId2Coordinates',
-        'include_dirs': [
-            "<!(node -e \"require('nan')\")"
-        ],
-
-        'cflags': [
-            '-Wall',
-            '-Wparentheses',
-            '-Winline',
-            '-Wbad-function-cast',
-            '-Wdisabled-optimization'
-        ],
-
-        'conditions': [
-            ["OS=='win'", {
-                'defines': ['IS_WINDOWS']
-            }]
-        ],
-
-        'sources': [
-            'src/index.cc',
-            'src/sourceId2Coordinates.cc'
-        ]
-    }]
-}
diff --git a/node_addons/sourceId2Coordinates/index.js b/node_addons/sourceId2Coordinates/index.js
deleted file mode 100644
index 9220e52..0000000
--- a/node_addons/sourceId2Coordinates/index.js
+++ /dev/null
@@ -1,22 +0,0 @@
-const sourceId2Coordinates
-    = require('./build/Release/sourceId2Coordinates.node').sourceId2Coordinates;
-
-/**
- * Returns the coordinates of a desktop using the passed desktop sharing source
- * id.
- *
- * @param {string} sourceId - The desktop sharing source id.
- * @returns {Object.<string, number>|undefined} - The x and y coordinates of the
- * top left corner of the desktop. Currently works only for windows. Returns
- * undefined for Mac OS, Linux.
- */
-module.exports = function(sourceID) {
-    // On windows the source id will have the following format "0:desktop_id".
-    // we need the "desktop_id" only to get the coordinates.
-    const idArr = sourceID.split(":");
-    const id = Number(idArr.length > 1 ? idArr[1] : sourceID);
-    if(id) {
-        return sourceId2Coordinates(id);
-    }
-    return undefined;
-};
diff --git a/node_addons/sourceId2Coordinates/package.json b/node_addons/sourceId2Coordinates/package.json
deleted file mode 100644
index fce1579..0000000
--- a/node_addons/sourceId2Coordinates/package.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "name": "sourceId2Coordinates",
-  "version": "0.0.3",
-  "description": "Native addon that returns the coordinates of desktop using the passed source id",
-  "main": "index.js",
-  "scripts": {
-    "install": "node-gyp rebuild"
-  },
-  "keywords": [
-    "Util",
-    "WebRTC"
-  ],
-  "gypfile": true,
-  "dependencies": {
-    "nan": "^2.2.1"
-  }
-}
diff --git a/node_addons/sourceId2Coordinates/src/index.cc b/node_addons/sourceId2Coordinates/src/index.cc
deleted file mode 100644
index 5820d4c..0000000
--- a/node_addons/sourceId2Coordinates/src/index.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-#include <node.h>
-#include <nan.h>
-#include <v8.h>
-#include <stdio.h>
-#include "sourceId2Coordinates.h"
-
-using namespace v8;
-
-NAN_METHOD(sourceId2Coordinates)
-{
-	const int sourceID = info[0]->Int32Value();
-	Local<Object> obj = Nan::New<Object>();
-	Point coordinates;
-	if(!sourceId2Coordinates(sourceID, &coordinates))
-	{ // return undefined if sourceId2Coordinates function fail.
-		info.GetReturnValue().Set(Nan::Undefined());
-	}
-	else
-	{ // return the coordinates if sourceId2Coordinates function succeed.
-		Nan::Set(obj, Nan::New("x").ToLocalChecked(), Nan::New(coordinates.x));
-		Nan::Set(obj, Nan::New("y").ToLocalChecked(), Nan::New(coordinates.y));
-		info.GetReturnValue().Set(obj);
-	}
-}
-
-NAN_MODULE_INIT(Init)
-{
-	Nan::Set(
-		target,
-		Nan::New("sourceId2Coordinates").ToLocalChecked(),
-		Nan::GetFunction(Nan::New<FunctionTemplate>(sourceId2Coordinates))
-			.ToLocalChecked()
-	);
-	NAN_EXPORT(target, sourceId2Coordinates);
-}
-
-NODE_MODULE(sourceId2CoordinatesModule, Init)
diff --git a/node_addons/sourceId2Coordinates/src/sourceId2Coordinates.cc b/node_addons/sourceId2Coordinates/src/sourceId2Coordinates.cc
deleted file mode 100644
index 8f2d1f3..0000000
--- a/node_addons/sourceId2Coordinates/src/sourceId2Coordinates.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-#if defined(IS_WINDOWS)
-#include <windows.h>
-#endif
-
-#include "sourceId2Coordinates.h"
-
-/**
- * Tries to get the coordinates of a desktop from passed sourceId
- * (which identifies a desktop sharing source). Used to match the source id to a
- * screen in Electron.
- *
- * Returns true on success and false on failure.
- *
- * NOTE: Works on windows only because on the other platforms there is an easier
- * way to match the source id and the screen.
- */
-bool sourceId2Coordinates(int sourceId, Point* res)
-{
-#if defined(IS_WINDOWS)
-    DISPLAY_DEVICE device;
-    device.cb = sizeof(device);
-
-    if (!EnumDisplayDevices(NULL, sourceId, &device, 0) // device not found
-        || !(device.StateFlags & DISPLAY_DEVICE_ACTIVE))// device is not active
-    {
-        return false;
-    }
-
-    DEVMODE deviceSettings;
-    deviceSettings.dmSize = sizeof(deviceSettings);
-    deviceSettings.dmDriverExtra = 0;
-    if(!EnumDisplaySettingsEx(device.DeviceName, ENUM_CURRENT_SETTINGS,
-        &deviceSettings, 0))
-    {
-        return false;
-    }
-
-    res->x = deviceSettings.dmPosition.x;
-    res->y = deviceSettings.dmPosition.y;
-
-    return true;
-#else
-    return false;
-#endif
-}
diff --git a/node_addons/sourceId2Coordinates/src/sourceId2Coordinates.h b/node_addons/sourceId2Coordinates/src/sourceId2Coordinates.h
deleted file mode 100644
index 5425b75..0000000
--- a/node_addons/sourceId2Coordinates/src/sourceId2Coordinates.h
+++ /dev/null
@@ -1,7 +0,0 @@
-struct Point {
-    int x;
-    int y;
-    Point(): x(0), y(0) {};
-};
-
-bool sourceId2Coordinates(int sourceId, Point* res);
diff --git a/package.json b/package.json
index 0d1085c..992aea1 100644
--- a/package.json
+++ b/package.json
@@ -30,9 +30,7 @@
   "readmeFilename": "README.md",
   "license": "Apache-2.0",
   "dependencies": {
-    "sourceId2Coordinates": "file:./node_addons/sourceId2Coordinates",
-    "robotjs": "jitsi/robotjs#jitsi",
-    "postis": "^2.2.0"
+    "jitsi-meet-electron-utils": "jitsi/jitsi-meet-electron-utils"
   },
   "devDependencies": {
     "electron": "1.4.13",
diff --git a/windows/jitsi-meet/render.js b/windows/jitsi-meet/render.js
index 9b67aa2..0a5284c 100644
--- a/windows/jitsi-meet/render.js
+++ b/windows/jitsi-meet/render.js
@@ -1,14 +1,11 @@
 /* global process */
-const RemoteControl = require("../../modules/remotecontrol");
-let postis = require("postis");
-const setupScreenSharingForWindow = require("../../modules/screensharing");
+const utils = require("jitsi-meet-electron-utils");
+const {
+    RemoteControl,
+    setupScreenSharingForWindow
+} = utils;
 const config = require("../../config.js");
 
-/**
- * The postis channel.
- */
-let channel;
-
 /**
  * The remote control instance.
  */
@@ -32,18 +29,12 @@ document.body.appendChild(iframe);
 function onload() {
     setupScreenSharingForWindow(iframe.contentWindow);
     iframe.contentWindow.onunload = onunload;
-    channel = postis({
-        window: iframe.contentWindow,
-        windowForEventListening: window
-    });
-    remoteControl = new RemoteControl(channel);
+    remoteControl = new RemoteControl(iframe);
 }
 
 /**
  * Clears the postis objects and remoteControl.
  */
 function onunload() {
-    channel.destroy();
-    channel = null;
     remoteControl.dispose();
 }
-- 
GitLab