您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

keyboardshortcut.js 9.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /* global APP, $, JitsiMeetJS */
  2. import {
  3. toggleDialog
  4. } from '../../react/features/base/dialog';
  5. import { SpeakerStats } from '../../react/features/speaker-stats';
  6. /**
  7. * The reference to the shortcut dialogs when opened.
  8. */
  9. let keyboardShortcutDialog = null;
  10. /**
  11. * Initialise global shortcuts.
  12. * Global shortcuts are shortcuts for features that don't have a button or
  13. * link associated with the action. In other words they represent actions
  14. * triggered _only_ with a shortcut.
  15. */
  16. function initGlobalShortcuts() {
  17. KeyboardShortcut.registerShortcut("ESCAPE", null, function() {
  18. showKeyboardShortcutsPanel(false);
  19. });
  20. KeyboardShortcut.registerShortcut("?", null, function() {
  21. JitsiMeetJS.analytics.sendEvent("shortcut.shortcut.help");
  22. showKeyboardShortcutsPanel(true);
  23. }, "keyboardShortcuts.toggleShortcuts");
  24. // register SPACE shortcut in two steps to insure visibility of help message
  25. KeyboardShortcut.registerShortcut(" ", null, function() {
  26. JitsiMeetJS.analytics.sendEvent("shortcut.talk.clicked");
  27. APP.conference.muteAudio(true);
  28. });
  29. KeyboardShortcut._addShortcutToHelp("SPACE","keyboardShortcuts.pushToTalk");
  30. KeyboardShortcut.registerShortcut("T", null, () => {
  31. APP.store.dispatch(toggleDialog(SpeakerStats, {
  32. conference: APP.conference
  33. }));
  34. }, "keyboardShortcuts.showSpeakerStats");
  35. /**
  36. * FIXME: Currently focus keys are directly implemented below in onkeyup.
  37. * They should be moved to the SmallVideo instead.
  38. */
  39. KeyboardShortcut._addShortcutToHelp("0", "keyboardShortcuts.focusLocal");
  40. KeyboardShortcut._addShortcutToHelp("1-9", "keyboardShortcuts.focusRemote");
  41. }
  42. /**
  43. * Shows or hides the keyboard shortcuts dialog.
  44. * @param {boolean} show whether to show or hide the dialog
  45. */
  46. function showKeyboardShortcutsPanel(show) {
  47. if (show
  48. && !APP.UI.messageHandler.isDialogOpened()
  49. && keyboardShortcutDialog === null) {
  50. let msg = $('#keyboard-shortcuts').html();
  51. let buttons = { Close: true };
  52. keyboardShortcutDialog = APP.UI.messageHandler.openDialog(
  53. 'keyboardShortcuts.keyboardShortcuts', msg, true, buttons);
  54. } else {
  55. if (keyboardShortcutDialog !== null) {
  56. keyboardShortcutDialog.close();
  57. keyboardShortcutDialog = null;
  58. }
  59. }
  60. }
  61. /**
  62. * Map of shortcuts. When a shortcut is registered it enters the mapping.
  63. * @type {{}}
  64. */
  65. let _shortcuts = {};
  66. /**
  67. * True if the keyboard shortcuts are enabled and false if not.
  68. * @type {boolean}
  69. */
  70. let enabled = true;
  71. /**
  72. * Maps keycode to character, id of popover for given function and function.
  73. */
  74. var KeyboardShortcut = {
  75. init: function () {
  76. initGlobalShortcuts();
  77. var self = this;
  78. window.onkeyup = function(e) {
  79. if(!enabled) {
  80. return;
  81. }
  82. var key = self._getKeyboardKey(e).toUpperCase();
  83. var num = parseInt(key, 10);
  84. if(!($(":focus").is("input[type=text]") ||
  85. $(":focus").is("input[type=password]") ||
  86. $(":focus").is("textarea"))) {
  87. if (_shortcuts.hasOwnProperty(key)) {
  88. _shortcuts[key].function(e);
  89. }
  90. else if (!isNaN(num) && num >= 0 && num <= 9) {
  91. APP.UI.clickOnVideo(num);
  92. }
  93. //esc while the smileys are visible hides them
  94. } else if (key === "ESCAPE" &&
  95. $('#smileysContainer').is(':visible')) {
  96. APP.UI.toggleSmileys();
  97. }
  98. };
  99. window.onkeydown = function(e) {
  100. if(!enabled) {
  101. return;
  102. }
  103. if(!($(":focus").is("input[type=text]") ||
  104. $(":focus").is("input[type=password]") ||
  105. $(":focus").is("textarea"))) {
  106. var key = self._getKeyboardKey(e).toUpperCase();
  107. if(key === " ") {
  108. if(APP.conference.isLocalAudioMuted())
  109. APP.conference.muteAudio(false);
  110. }
  111. }
  112. };
  113. },
  114. /**
  115. * Enables/Disables the keyboard shortcuts.
  116. * @param {boolean} value - the new value.
  117. */
  118. enable: function (value) {
  119. enabled = value;
  120. },
  121. /**
  122. * Registers a new shortcut.
  123. *
  124. * @param shortcutChar the shortcut character triggering the action
  125. * @param shortcutAttr the "shortcut" html element attribute mappring an
  126. * element to this shortcut and used to show the shortcut character on the
  127. * element tooltip
  128. * @param exec the function to be executed when the shortcut is pressed
  129. * @param helpDescription the description of the shortcut that would appear
  130. * in the help menu
  131. */
  132. registerShortcut: function( shortcutChar,
  133. shortcutAttr,
  134. exec,
  135. helpDescription) {
  136. _shortcuts[shortcutChar] = {
  137. character: shortcutChar,
  138. shortcutAttr: shortcutAttr,
  139. function: exec
  140. };
  141. if (helpDescription)
  142. this._addShortcutToHelp(shortcutChar, helpDescription);
  143. },
  144. /**
  145. * Unregisters a shortcut.
  146. *
  147. * @param shortcutChar unregisters the given shortcut, which means it will
  148. * no longer be usable
  149. */
  150. unregisterShortcut: function(shortcutChar) {
  151. _shortcuts.remove(shortcutChar);
  152. this._removeShortcutFromHelp(shortcutChar);
  153. },
  154. /**
  155. * Returns the tooltip string for the given shortcut attribute.
  156. *
  157. * @param shortcutAttr indicates the popover associated with the shortcut
  158. * @returns {string} the tooltip string to add to the given shortcut popover
  159. * or an empty string if the shortcutAttr is null, an empty string or not
  160. * found in the shortcut mapping
  161. */
  162. getShortcutTooltip: function (shortcutAttr) {
  163. if (typeof shortcutAttr === "string" && shortcutAttr.length > 0) {
  164. for (var key in _shortcuts) {
  165. if (_shortcuts.hasOwnProperty(key)
  166. && _shortcuts[key].shortcutAttr
  167. && _shortcuts[key].shortcutAttr === shortcutAttr) {
  168. return " (" + _shortcuts[key].character + ")";
  169. }
  170. }
  171. }
  172. return "";
  173. },
  174. /**
  175. * @param e a KeyboardEvent
  176. * @returns {string} e.key or something close if not supported
  177. */
  178. _getKeyboardKey: function (e) {
  179. if (typeof e.key === "string") {
  180. return e.key;
  181. }
  182. if (e.type === "keypress" && (
  183. (e.which >= 32 && e.which <= 126) ||
  184. (e.which >= 160 && e.which <= 255) )) {
  185. return String.fromCharCode(e.which);
  186. }
  187. // try to fallback (0-9A-Za-z and QWERTY keyboard)
  188. switch (e.which) {
  189. case 27:
  190. return "Escape";
  191. case 191:
  192. return e.shiftKey ? "?" : "/";
  193. }
  194. if (e.shiftKey || e.type === "keypress") {
  195. return String.fromCharCode(e.which);
  196. } else {
  197. return String.fromCharCode(e.which).toLowerCase();
  198. }
  199. },
  200. /**
  201. * Adds the given shortcut to the help dialog.
  202. *
  203. * @param shortcutChar the shortcut character
  204. * @param shortcutDescriptionKey the description of the shortcut
  205. * @private
  206. */
  207. _addShortcutToHelp: function (shortcutChar, shortcutDescriptionKey) {
  208. let listElement = document.createElement("li");
  209. let itemClass = 'shortcuts-list__item';
  210. listElement.className = itemClass;
  211. listElement.id = shortcutChar;
  212. let spanElement = document.createElement("span");
  213. spanElement.className = "item-action";
  214. let kbdElement = document.createElement("kbd");
  215. let classes = 'aui-label regular-key';
  216. kbdElement.className = classes;
  217. kbdElement.innerHTML = shortcutChar;
  218. spanElement.appendChild(kbdElement);
  219. let descriptionElement = document.createElement("span");
  220. let descriptionClass = "shortcuts-list__description";
  221. descriptionElement.className = descriptionClass;
  222. descriptionElement.setAttribute("data-i18n", shortcutDescriptionKey);
  223. APP.translation.translateElement($(descriptionElement));
  224. listElement.appendChild(spanElement);
  225. listElement.appendChild(descriptionElement);
  226. let parentListElement
  227. = document.getElementById("keyboard-shortcuts-list");
  228. if (parentListElement)
  229. parentListElement.appendChild(listElement);
  230. },
  231. /**
  232. * Removes the list element corresponding to the given shortcut from the
  233. * help dialog
  234. * @private
  235. */
  236. _removeShortcutFromHelp: function (shortcutChar) {
  237. var parentListElement
  238. = document.getElementById("keyboard-shortcuts-list");
  239. var shortcutElement = document.getElementById(shortcutChar);
  240. if (shortcutElement)
  241. parentListElement.removeChild(shortcutElement);
  242. }
  243. };
  244. module.exports = KeyboardShortcut;