Merge pull request #9368 from jitsi/tavram/mousemove

feat(api) expose event for mouse movements inside the iframe
This commit is contained in:
Avram Tudor 2021-06-14 11:22:22 +03:00 committed by GitHub
commit 9d22da823e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 149 additions and 2 deletions

View File

@ -794,6 +794,11 @@ var config = {
websocketKeepAliveUrl websocketKeepAliveUrl
*/ */
/**
* Default interval (milliseconds) for triggering mouseMoved iframe API event
*/
mouseMoveCallbackInterval: 1000,
/** /**
Use this array to configure which notifications will be shown to the user Use this array to configure which notifications will be shown to the user
The items correspond to the title or description key of that notification The items correspond to the title or description key of that notification

View File

@ -572,6 +572,44 @@ function toggleScreenSharing(enable) {
} }
} }
/**
* Removes sensitive data from a mouse event.
*
* @param {MouseEvent} event - The mouse event to sanitize.
* @returns {Object}
*/
function sanitizeMouseEvent(event: MouseEvent) {
const {
clientX,
clientY,
movementX,
movementY,
offsetX,
offsetY,
pageX,
pageY,
x,
y,
screenX,
screenY
} = event;
return {
clientX,
clientY,
movementX,
movementY,
offsetX,
offsetY,
pageX,
pageY,
x,
y,
screenX,
screenY
};
}
/** /**
* Implements API class that communicates with external API class and provides * Implements API class that communicates with external API class and provides
* interface to access Jitsi Meet features by external applications that embed * interface to access Jitsi Meet features by external applications that embed
@ -675,6 +713,45 @@ class API {
}); });
} }
/**
* Notify external application (if API is enabled) that the mouse has entered inside the iframe.
*
* @param {MouseEvent} event - The mousemove event.
* @returns {void}
*/
notifyMouseEnter(event: MouseEvent) {
this._sendEvent({
name: 'mouse-enter',
event: sanitizeMouseEvent(event)
});
}
/**
* Notify external application (if API is enabled) that the mouse has entered inside the iframe.
*
* @param {MouseEvent} event - The mousemove event.
* @returns {void}
*/
notifyMouseLeave(event: MouseEvent) {
this._sendEvent({
name: 'mouse-leave',
event: sanitizeMouseEvent(event)
});
}
/**
* Notify external application (if API is enabled) that the mouse has moved inside the iframe.
*
* @param {MouseEvent} event - The mousemove event.
* @returns {void}
*/
notifyMouseMove(event: MouseEvent) {
this._sendEvent({
name: 'mouse-move',
event: sanitizeMouseEvent(event)
});
}
/** /**
* Notify external application that the video quality setting has changed. * Notify external application that the video quality setting has changed.
* *

View File

@ -84,6 +84,9 @@ const events = {
'incoming-message': 'incomingMessage', 'incoming-message': 'incomingMessage',
'log': 'log', 'log': 'log',
'mic-error': 'micError', 'mic-error': 'micError',
'mouse-enter': 'mouseEnter',
'mouse-leave': 'mouseLeave',
'mouse-move': 'mouseMove',
'outgoing-message': 'outgoingMessage', 'outgoing-message': 'outgoingMessage',
'participant-joined': 'participantJoined', 'participant-joined': 'participantJoined',
'participant-kicked-out': 'participantKickedOut', 'participant-kicked-out': 'participantKickedOut',

View File

@ -141,6 +141,7 @@ export default [
'liveStreamingEnabled', 'liveStreamingEnabled',
'localRecording', 'localRecording',
'maxFullResolutionParticipants', 'maxFullResolutionParticipants',
'mouseMoveCallbackInterval',
'notifications', 'notifications',
'openSharedDocumentOnJoin', 'openSharedDocumentOnJoin',
'opusMaxAverageBitrate', 'opusMaxAverageBitrate',

View File

@ -85,6 +85,11 @@ type Props = AbstractProps & {
*/ */
_layoutClassName: string, _layoutClassName: string,
/**
* The config specified interval for triggering mouseMoved iframe api events
*/
_mouseMoveCallbackInterval: number,
/** /**
* Name for this conference room. * Name for this conference room.
*/ */
@ -104,7 +109,11 @@ type Props = AbstractProps & {
*/ */
class Conference extends AbstractConference<Props, *> { class Conference extends AbstractConference<Props, *> {
_onFullScreenChange: Function; _onFullScreenChange: Function;
_onMouseEnter: Function;
_onMouseLeave: Function;
_onMouseMove: Function;
_onShowToolbar: Function; _onShowToolbar: Function;
_originalOnMouseMove: Function;
_originalOnShowToolbar: Function; _originalOnShowToolbar: Function;
_setBackground: Function; _setBackground: Function;
@ -117,9 +126,13 @@ class Conference extends AbstractConference<Props, *> {
constructor(props) { constructor(props) {
super(props); super(props);
const { _mouseMoveCallbackInterval } = props;
// Throttle and bind this component's mousemove handler to prevent it // Throttle and bind this component's mousemove handler to prevent it
// from firing too often. // from firing too often.
this._originalOnShowToolbar = this._onShowToolbar; this._originalOnShowToolbar = this._onShowToolbar;
this._originalOnMouseMove = this._onMouseMove;
this._onShowToolbar = _.throttle( this._onShowToolbar = _.throttle(
() => this._originalOnShowToolbar(), () => this._originalOnShowToolbar(),
100, 100,
@ -128,6 +141,14 @@ class Conference extends AbstractConference<Props, *> {
trailing: false trailing: false
}); });
this._onMouseMove = _.throttle(
event => this._originalOnMouseMove(event),
_mouseMoveCallbackInterval,
{
leading: true,
trailing: false
});
// Bind event handler so it is only bound once for every instance. // Bind event handler so it is only bound once for every instance.
this._onFullScreenChange = this._onFullScreenChange.bind(this); this._onFullScreenChange = this._onFullScreenChange.bind(this);
this._setBackground = this._setBackground.bind(this); this._setBackground = this._setBackground.bind(this);
@ -192,7 +213,11 @@ class Conference extends AbstractConference<Props, *> {
} = this.props; } = this.props;
return ( return (
<div id = 'layout_wrapper'> <div
id = 'layout_wrapper'
onMouseEnter = { this._onMouseEnter }
onMouseLeave = { this._onMouseLeave }
onMouseMove = { this._onMouseMove } >
<div <div
className = { _layoutClassName } className = { _layoutClassName }
id = 'videoconference_page' id = 'videoconference_page'
@ -262,6 +287,39 @@ class Conference extends AbstractConference<Props, *> {
this.props.dispatch(fullScreenChanged(APP.UI.isFullScreen())); this.props.dispatch(fullScreenChanged(APP.UI.isFullScreen()));
} }
/**
* Triggers iframe API mouseEnter event.
*
* @param {MouseEvent} event - The mouse event.
* @private
* @returns {void}
*/
_onMouseEnter(event) {
APP.API.notifyMouseEnter(event);
}
/**
* Triggers iframe API mouseLeave event.
*
* @param {MouseEvent} event - The mouse event.
* @private
* @returns {void}
*/
_onMouseLeave(event) {
APP.API.notifyMouseLeave(event);
}
/**
* Triggers iframe API mouseMove event.
*
* @param {MouseEvent} event - The mouse event.
* @private
* @returns {void}
*/
_onMouseMove(event) {
APP.API.notifyMouseMove(event);
}
/** /**
* Displays the toolbar. * Displays the toolbar.
* *
@ -305,12 +363,15 @@ class Conference extends AbstractConference<Props, *> {
* @returns {Props} * @returns {Props}
*/ */
function _mapStateToProps(state) { function _mapStateToProps(state) {
const { backgroundAlpha, mouseMoveCallbackInterval } = state['features/base/config'];
return { return {
...abstractMapStateToProps(state), ...abstractMapStateToProps(state),
_backgroundAlpha: state['features/base/config'].backgroundAlpha, _backgroundAlpha: backgroundAlpha,
_isLobbyScreenVisible: state['features/base/dialog']?.component === LobbyScreen, _isLobbyScreenVisible: state['features/base/dialog']?.component === LobbyScreen,
_isParticipantsPaneVisible: getParticipantsPaneOpen(state), _isParticipantsPaneVisible: getParticipantsPaneOpen(state),
_layoutClassName: LAYOUT_CLASSNAMES[getCurrentLayout(state)], _layoutClassName: LAYOUT_CLASSNAMES[getCurrentLayout(state)],
_mouseMoveCallbackInterval: mouseMoveCallbackInterval,
_roomName: getConferenceNameForTitle(state), _roomName: getConferenceNameForTitle(state),
_showPrejoin: isPrejoinPageVisible(state) _showPrejoin: isPrejoinPageVisible(state)
}; };