diff --git a/src/resources/js/meet/app.js b/src/resources/js/meet/app.js --- a/src/resources/js/meet/app.js +++ b/src/resources/js/meet/app.js @@ -1284,6 +1284,10 @@ editableUpdate() return false } + + // Do not propagate the event, so it does not interfere with our + // keyboard shortcuts + e.stopPropagation() }) } else { element.find('.action-nickname').remove() diff --git a/src/resources/vue/Meet/Room.vue b/src/resources/vue/Meet/Room.vue --- a/src/resources/vue/Meet/Room.vue +++ b/src/resources/vue/Meet/Room.vue @@ -290,6 +290,8 @@ } delete axios.defaults.headers.common[authHeader] + + $(document.body).off('keydown.meet') }, methods: { authSuccess() { @@ -523,6 +525,22 @@ this.session.onMediaSetup = () => { this.setupMedia() } this.meet.joinRoom(this.session) + + this.keyboardShortcuts() + }, + keyboardShortcuts() { + $(document.body).on('keydown.meet', e => { + if ($(e.target).is('select,input,textarea')) { + return + } + + // Self-Mute with 'm' key + if (e.key == 'm' || e.key == 'M') { + if ($('#meet-session-menu').find('.link-audio:not(:disabled)').length) { + this.switchSound() + } + } + }) }, logout() { const logout = () => { diff --git a/src/tests/Browser/Meet/RoomControlsTest.php b/src/tests/Browser/Meet/RoomControlsTest.php --- a/src/tests/Browser/Meet/RoomControlsTest.php +++ b/src/tests/Browser/Meet/RoomControlsTest.php @@ -180,6 +180,22 @@ $guest->waitUntilMissing('div.meet-video:not(.self) .status .status-audio'); + // Test muting audio with a keyboard shortcut (key 'm') + $owner->driver->getKeyboard()->sendKeys('m'); + $owner->assertToolbarButtonState('audio', RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_ENABLED) + ->assertVisible('div.meet-video.self .status .status-audio'); + + $guest->waitFor('div.meet-video:not(.self) .status .status-audio') + ->assertAudioMuted('div.meet-video:not(.self) video', true); + + // Test unmuting audio with a keyboard shortcut (key 'm') + $owner->driver->getKeyboard()->sendKeys('m'); + $owner->assertToolbarButtonState('audio', RoomPage::BUTTON_ACTIVE | RoomPage::BUTTON_ENABLED) + ->assertMissing('div.meet-video.self .status .status-audio'); + + $guest->waitUntilMissing('div.meet-video:not(.self) .status .status-audio') + ->assertAudioMuted('div.meet-video:not(.self) video', false); + // Test muting video $owner->click('@menu button.link-video') ->assertToolbarButtonState('video', RoomPage::BUTTON_INACTIVE | RoomPage::BUTTON_ENABLED)