Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

keyboardshortcut.js 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /* global APP, $, interfaceConfig */
  2. import { toggleDialog } from '../../react/features/base/dialog';
  3. import {
  4. SHORTCUT_HELP,
  5. SHORTCUT_SPEAKER_STATS_CLICKED,
  6. SHORTCUT_TALK_CLICKED,
  7. SHORTCUT_TALK_RELEASED,
  8. sendAnalyticsEvent
  9. } from '../../react/features/analytics';
  10. import { KeyboardShortcutsDialog }
  11. from '../../react/features/keyboard-shortcuts';
  12. import { SpeakerStats } from '../../react/features/speaker-stats';
  13. const logger = require('jitsi-meet-logger').getLogger(__filename);
  14. /**
  15. * Map of shortcuts. When a shortcut is registered it enters the mapping.
  16. * @type {{}}
  17. */
  18. const _shortcuts = {};
  19. /**
  20. * Map of registered keyboard keys and translation keys describing the
  21. * action performed by the key.
  22. * @type {Map}
  23. */
  24. const _shortcutsHelp = new Map();
  25. /**
  26. * True if the keyboard shortcuts are enabled and false if not.
  27. * @type {boolean}
  28. */
  29. let enabled = true;
  30. /**
  31. * Maps keycode to character, id of popover for given function and function.
  32. */
  33. const KeyboardShortcut = {
  34. init() {
  35. this._initGlobalShortcuts();
  36. window.onkeyup = e => {
  37. if (!enabled) {
  38. return;
  39. }
  40. const key = this._getKeyboardKey(e).toUpperCase();
  41. const num = parseInt(key, 10);
  42. if (!($(':focus').is('input[type=text]')
  43. || $(':focus').is('input[type=password]')
  44. || $(':focus').is('textarea'))) {
  45. if (_shortcuts.hasOwnProperty(key)) {
  46. _shortcuts[key].function(e);
  47. } else if (!isNaN(num) && num >= 0 && num <= 9) {
  48. APP.UI.clickOnVideo(num);
  49. }
  50. // esc while the smileys are visible hides them
  51. } else if (key === 'ESCAPE'
  52. && $('#smileysContainer').is(':visible')) {
  53. APP.UI.toggleSmileys();
  54. }
  55. };
  56. window.onkeydown = e => {
  57. if (!enabled) {
  58. return;
  59. }
  60. if (!($(':focus').is('input[type=text]')
  61. || $(':focus').is('input[type=password]')
  62. || $(':focus').is('textarea'))) {
  63. if (this._getKeyboardKey(e).toUpperCase() === ' ') {
  64. if (APP.conference.isLocalAudioMuted()) {
  65. sendAnalyticsEvent(SHORTCUT_TALK_RELEASED);
  66. logger.log('Talk shortcut released');
  67. APP.conference.muteAudio(false);
  68. }
  69. }
  70. }
  71. };
  72. },
  73. /**
  74. * Enables/Disables the keyboard shortcuts.
  75. * @param {boolean} value - the new value.
  76. */
  77. enable(value) {
  78. enabled = value;
  79. },
  80. /**
  81. * Registers a new shortcut.
  82. *
  83. * @param shortcutChar the shortcut character triggering the action
  84. * @param shortcutAttr the "shortcut" html element attribute mappring an
  85. * element to this shortcut and used to show the shortcut character on the
  86. * element tooltip
  87. * @param exec the function to be executed when the shortcut is pressed
  88. * @param helpDescription the description of the shortcut that would appear
  89. * in the help menu
  90. */
  91. registerShortcut(// eslint-disable-line max-params
  92. shortcutChar,
  93. shortcutAttr,
  94. exec,
  95. helpDescription) {
  96. _shortcuts[shortcutChar] = {
  97. character: shortcutChar,
  98. shortcutAttr,
  99. function: exec
  100. };
  101. if (helpDescription) {
  102. this._addShortcutToHelp(shortcutChar, helpDescription);
  103. }
  104. },
  105. /**
  106. * Unregisters a shortcut.
  107. *
  108. * @param shortcutChar unregisters the given shortcut, which means it will
  109. * no longer be usable
  110. */
  111. unregisterShortcut(shortcutChar) {
  112. _shortcuts.remove(shortcutChar);
  113. _shortcutsHelp.delete(shortcutChar);
  114. },
  115. /**
  116. * @param e a KeyboardEvent
  117. * @returns {string} e.key or something close if not supported
  118. */
  119. _getKeyboardKey(e) {
  120. if (typeof e.key === 'string') {
  121. return e.key;
  122. }
  123. if (e.type === 'keypress'
  124. && ((e.which >= 32 && e.which <= 126)
  125. || (e.which >= 160 && e.which <= 255))) {
  126. return String.fromCharCode(e.which);
  127. }
  128. // try to fallback (0-9A-Za-z and QWERTY keyboard)
  129. switch (e.which) {
  130. case 27:
  131. return 'Escape';
  132. case 191:
  133. return e.shiftKey ? '?' : '/';
  134. }
  135. if (e.shiftKey || e.type === 'keypress') {
  136. return String.fromCharCode(e.which);
  137. }
  138. return String.fromCharCode(e.which).toLowerCase();
  139. },
  140. /**
  141. * Adds the given shortcut to the help dialog.
  142. *
  143. * @param shortcutChar the shortcut character
  144. * @param shortcutDescriptionKey the description of the shortcut
  145. * @private
  146. */
  147. _addShortcutToHelp(shortcutChar, shortcutDescriptionKey) {
  148. _shortcutsHelp.set(shortcutChar, shortcutDescriptionKey);
  149. },
  150. /**
  151. * Initialise global shortcuts.
  152. * Global shortcuts are shortcuts for features that don't have a button or
  153. * link associated with the action. In other words they represent actions
  154. * triggered _only_ with a shortcut.
  155. */
  156. _initGlobalShortcuts() {
  157. this.registerShortcut('?', null, () => {
  158. sendAnalyticsEvent(SHORTCUT_HELP);
  159. APP.store.dispatch(toggleDialog(KeyboardShortcutsDialog, {
  160. shortcutDescriptions: _shortcutsHelp
  161. }));
  162. }, 'keyboardShortcuts.toggleShortcuts');
  163. // register SPACE shortcut in two steps to insure visibility of help
  164. // message
  165. this.registerShortcut(' ', null, () => {
  166. sendAnalyticsEvent(SHORTCUT_TALK_CLICKED);
  167. logger.log('Talk shortcut pressed');
  168. APP.conference.muteAudio(true);
  169. });
  170. this._addShortcutToHelp('SPACE', 'keyboardShortcuts.pushToTalk');
  171. if (!interfaceConfig.filmStripOnly) {
  172. this.registerShortcut('T', null, () => {
  173. sendAnalyticsEvent(SHORTCUT_SPEAKER_STATS_CLICKED);
  174. APP.store.dispatch(toggleDialog(SpeakerStats, {
  175. conference: APP.conference
  176. }));
  177. }, 'keyboardShortcuts.showSpeakerStats');
  178. }
  179. /**
  180. * FIXME: Currently focus keys are directly implemented below in
  181. * onkeyup. They should be moved to the SmallVideo instead.
  182. */
  183. this._addShortcutToHelp('0', 'keyboardShortcuts.focusLocal');
  184. this._addShortcutToHelp('1-9', 'keyboardShortcuts.focusRemote');
  185. }
  186. };
  187. export default KeyboardShortcut;