jiti-meet/modules/keyboardshortcut/keyboardshortcut.js

277 lines
9.1 KiB
JavaScript

/* global APP, $, JitsiMeetJS, interfaceConfig */
import { toggleDialog } from '../../react/features/base/dialog';
import { SpeakerStats } from '../../react/features/speaker-stats';
/**
* The reference to the shortcut dialogs when opened.
*/
let keyboardShortcutDialog = null;
/**
* Initialise global shortcuts.
* Global shortcuts are shortcuts for features that don't have a button or
* link associated with the action. In other words they represent actions
* triggered _only_ with a shortcut.
*/
function initGlobalShortcuts() {
KeyboardShortcut.registerShortcut("ESCAPE", null, function() {
showKeyboardShortcutsPanel(false);
});
KeyboardShortcut.registerShortcut("?", null, function() {
JitsiMeetJS.analytics.sendEvent("shortcut.shortcut.help");
showKeyboardShortcutsPanel(true);
}, "keyboardShortcuts.toggleShortcuts");
// register SPACE shortcut in two steps to insure visibility of help message
KeyboardShortcut.registerShortcut(" ", null, function() {
JitsiMeetJS.analytics.sendEvent("shortcut.talk.clicked");
APP.conference.muteAudio(true);
});
KeyboardShortcut._addShortcutToHelp("SPACE","keyboardShortcuts.pushToTalk");
if(!interfaceConfig.filmStripOnly) {
KeyboardShortcut.registerShortcut("T", null, () => {
JitsiMeetJS.analytics.sendEvent("shortcut.speakerStats.clicked");
APP.store.dispatch(toggleDialog(SpeakerStats, {
conference: APP.conference
}));
}, "keyboardShortcuts.showSpeakerStats");
}
/**
* FIXME: Currently focus keys are directly implemented below in onkeyup.
* They should be moved to the SmallVideo instead.
*/
KeyboardShortcut._addShortcutToHelp("0", "keyboardShortcuts.focusLocal");
KeyboardShortcut._addShortcutToHelp("1-9", "keyboardShortcuts.focusRemote");
}
/**
* Shows or hides the keyboard shortcuts dialog.
* @param {boolean} show whether to show or hide the dialog
*/
function showKeyboardShortcutsPanel(show) {
if (show
&& !APP.UI.messageHandler.isDialogOpened()
&& keyboardShortcutDialog === null) {
let msg = $('#keyboard-shortcuts').html();
let buttons = { Close: true };
keyboardShortcutDialog = APP.UI.messageHandler.openDialog(
'keyboardShortcuts.keyboardShortcuts', msg, true, buttons);
} else if (keyboardShortcutDialog !== null) {
keyboardShortcutDialog.close();
keyboardShortcutDialog = null;
}
}
/**
* Map of shortcuts. When a shortcut is registered it enters the mapping.
* @type {{}}
*/
let _shortcuts = {};
/**
* True if the keyboard shortcuts are enabled and false if not.
* @type {boolean}
*/
let enabled = true;
/**
* Maps keycode to character, id of popover for given function and function.
*/
var KeyboardShortcut = {
init: function () {
initGlobalShortcuts();
var self = this;
window.onkeyup = function(e) {
if(!enabled) {
return;
}
var key = self._getKeyboardKey(e).toUpperCase();
var num = parseInt(key, 10);
if(!($(":focus").is("input[type=text]") ||
$(":focus").is("input[type=password]") ||
$(":focus").is("textarea"))) {
if (_shortcuts.hasOwnProperty(key)) {
_shortcuts[key].function(e);
}
else if (!isNaN(num) && num >= 0 && num <= 9) {
APP.UI.clickOnVideo(num);
}
//esc while the smileys are visible hides them
} else if (key === "ESCAPE" &&
$('#smileysContainer').is(':visible')) {
APP.UI.toggleSmileys();
}
};
window.onkeydown = function(e) {
if(!enabled) {
return;
}
if(!($(":focus").is("input[type=text]") ||
$(":focus").is("input[type=password]") ||
$(":focus").is("textarea"))) {
var key = self._getKeyboardKey(e).toUpperCase();
if(key === " ") {
if(APP.conference.isLocalAudioMuted())
APP.conference.muteAudio(false);
}
}
};
},
/**
* Enables/Disables the keyboard shortcuts.
* @param {boolean} value - the new value.
*/
enable: function (value) {
enabled = value;
},
/**
* Registers a new shortcut.
*
* @param shortcutChar the shortcut character triggering the action
* @param shortcutAttr the "shortcut" html element attribute mappring an
* element to this shortcut and used to show the shortcut character on the
* element tooltip
* @param exec the function to be executed when the shortcut is pressed
* @param helpDescription the description of the shortcut that would appear
* in the help menu
*/
registerShortcut: function( shortcutChar,
shortcutAttr,
exec,
helpDescription) {
_shortcuts[shortcutChar] = {
character: shortcutChar,
shortcutAttr: shortcutAttr,
function: exec
};
if (helpDescription)
this._addShortcutToHelp(shortcutChar, helpDescription);
},
/**
* Unregisters a shortcut.
*
* @param shortcutChar unregisters the given shortcut, which means it will
* no longer be usable
*/
unregisterShortcut: function(shortcutChar) {
_shortcuts.remove(shortcutChar);
this._removeShortcutFromHelp(shortcutChar);
},
/**
* Returns the tooltip string for the given shortcut attribute.
*
* @param shortcutAttr indicates the popover associated with the shortcut
* @returns {string} the tooltip string to add to the given shortcut popover
* or an empty string if the shortcutAttr is null, an empty string or not
* found in the shortcut mapping
*/
getShortcutTooltip: function (shortcutAttr) {
if (typeof shortcutAttr === "string" && shortcutAttr.length > 0) {
for (var key in _shortcuts) {
if (_shortcuts.hasOwnProperty(key)
&& _shortcuts[key].shortcutAttr
&& _shortcuts[key].shortcutAttr === shortcutAttr) {
return " (" + _shortcuts[key].character + ")";
}
}
}
return "";
},
/**
* @param e a KeyboardEvent
* @returns {string} e.key or something close if not supported
*/
_getKeyboardKey: function (e) {
if (typeof e.key === "string") {
return e.key;
}
if (e.type === "keypress" && (
(e.which >= 32 && e.which <= 126) ||
(e.which >= 160 && e.which <= 255) )) {
return String.fromCharCode(e.which);
}
// try to fallback (0-9A-Za-z and QWERTY keyboard)
switch (e.which) {
case 27:
return "Escape";
case 191:
return e.shiftKey ? "?" : "/";
}
if (e.shiftKey || e.type === "keypress") {
return String.fromCharCode(e.which);
} else {
return String.fromCharCode(e.which).toLowerCase();
}
},
/**
* Adds the given shortcut to the help dialog.
*
* @param shortcutChar the shortcut character
* @param shortcutDescriptionKey the description of the shortcut
* @private
*/
_addShortcutToHelp: function (shortcutChar, shortcutDescriptionKey) {
let listElement = document.createElement("li");
let itemClass = 'shortcuts-list__item';
listElement.className = itemClass;
listElement.id = shortcutChar;
let spanElement = document.createElement("span");
spanElement.className = "item-action";
let kbdElement = document.createElement("kbd");
let classes = 'aui-label regular-key';
kbdElement.className = classes;
kbdElement.innerHTML = shortcutChar;
spanElement.appendChild(kbdElement);
let descriptionElement = document.createElement("span");
let descriptionClass = "shortcuts-list__description";
descriptionElement.className = descriptionClass;
descriptionElement.setAttribute("data-i18n", shortcutDescriptionKey);
APP.translation.translateElement($(descriptionElement));
listElement.appendChild(spanElement);
listElement.appendChild(descriptionElement);
let parentListElement
= document.getElementById("keyboard-shortcuts-list");
if (parentListElement)
parentListElement.appendChild(listElement);
},
/**
* Removes the list element corresponding to the given shortcut from the
* help dialog
* @private
*/
_removeShortcutFromHelp: function (shortcutChar) {
var parentListElement
= document.getElementById("keyboard-shortcuts-list");
var shortcutElement = document.getElementById(shortcutChar);
if (shortcutElement)
parentListElement.removeChild(shortcutElement);
}
};
module.exports = KeyboardShortcut;