[mirotalksfu] - add keyboard shortcuts

هذا الالتزام موجود في:
Miroslav Pejic
2025-01-09 01:50:11 +01:00
الأصل 9b4e5651b3
التزام a2db7eb9cc
8 ملفات معدلة مع 304 إضافات و8 حذوفات

عرض الملف

@@ -469,6 +469,36 @@ th {
width: 180px;
}
/*--------------------------------------------------------------
# Shortcut Table
--------------------------------------------------------------*/
#shortcutsTable {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
font-size: 16px;
text-align: left;
color: #fff;
border-radius: 10px;
background: var(--body-bg);
}
#shortcutsTable th,
#shortcutsTable td {
border: var(--border);
padding: 5px;
}
#shortcutsTable th {
background: var(--body-bg);
font-weight: bold;
}
#shortcutsTable td i {
color: #007bff;
}
#shortcutsTable tr:nth-child(even) {
background: var(--body-bg);
}
/*--------------------------------------------------------------
# RTMP settings
--------------------------------------------------------------*/
@@ -640,7 +670,7 @@ th {
width: 65%;
background-color: var(--body-bg);
min-height: 480px;
max-height: 680px;
max-height: 768px;
overflow-x: hidden;
overflow-y: auto;
}

عرض الملف

@@ -45,6 +45,7 @@ class LocalStorage {
pitch_bar: true, // volume indicator
sounds: true, // room notify sounds
keep_buttons_visible: false, // Keep buttons always visible
keyboard_shortcuts: false, // keyboard shortcuts
host_only_recording: false, // presenter
rec_prioritize_h264: false, // Prioritize h.264 with AAC or h.264 with Opus codecs over VP8 with Opus or VP9 with Opus codecs
rec_server: false, // The recording will be stored on the server rather than locally

عرض الملف

@@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.6.89
* @version 1.6.90
*
*/
@@ -215,6 +215,7 @@ let isSpaceDown = false;
let isPitchBarEnabled = true;
let isSoundEnabled = true;
let isKeepButtonsVisible = false;
let isShortcutsEnabled = false;
let isBroadcastingEnabled = false;
let isLobbyEnabled = false;
let isLobbyOpen = false;
@@ -236,6 +237,11 @@ let isSpeechSynthesisSupported = 'speechSynthesis' in window;
let joinRoomWithoutAudioVideo = true;
let joinRoomWithScreen = false;
let audio = false;
let video = false;
let screen = false;
let hand = false;
let recTimer = null;
let recElapsedTime = null;
@@ -1551,6 +1557,10 @@ function setColor(elem, color) {
elem.style.color = color;
}
function getColor(elem) {
return elem.style.color;
}
// ####################################################
// SESSION TIMER
// ####################################################
@@ -1687,6 +1697,9 @@ function handleButtons() {
tabProfileBtn.onclick = (e) => {
rc.openTab(e, 'tabProfile');
};
tabShortcutsBtn.onclick = (e) => {
rc.openTab(e, 'tabShortcuts');
};
tabStylingBtn.onclick = (e) => {
rc.openTab(e, 'tabStyling');
};
@@ -2746,6 +2759,148 @@ function handleSelects() {
lS.setSettings(localStorageSettings);
e.target.blur();
};
// handle Shortcuts
if (!isDesktopDevice) {
elemDisplay('tabShortcutsBtn', false);
} else {
switchShortcuts.onchange = (e) => {
isShortcutsEnabled = e.currentTarget.checked;
localStorageSettings.keyboard_shortcuts = isShortcutsEnabled;
lS.setSettings(localStorageSettings);
const status = isShortcutsEnabled ? 'enabled' : 'disabled';
userLog('info', `Keyboard shortcuts ${status}`, 'top-end');
e.target.blur();
};
document.addEventListener('keydown', (event) => {
if (
!isShortcutsEnabled ||
rc.isChatOpen ||
wbIsOpen ||
rc.isEditorOpen ||
(!isPresenter && isBroadcastingEnabled)
)
return;
const key = event.key.toLowerCase(); // Convert to lowercase for simplicity
console.log(`Detected shortcut: ${key}`);
const { audio_cant_unmute, video_cant_unhide, screen_cant_share } = rc._moderator;
const notPresenter = isRulesActive && !isPresenter;
switch (key) {
case 'a':
if (notPresenter && !audio && (audio_cant_unmute || !BUTTONS.main.startAudioButton)) {
userLog('warning', 'The presenter has disabled your ability to enable audio', 'top-end');
break;
}
audio ? stopAudioButton.click() : startAudioButton.click();
break;
case 'v':
if (notPresenter && !video && (video_cant_unhide || !BUTTONS.main.startVideoButton)) {
userLog('warning', 'The presenter has disabled your ability to enable video', 'top-end');
break;
}
video ? stopVideoButton.click() : startVideoButton.click();
break;
case 's':
if (notPresenter && !screen && (screen_cant_share || !BUTTONS.main.startScreenButton)) {
userLog('warning', 'The presenter has disabled your ability to share the screen', 'top-end');
break;
}
screen ? stopScreenButton.click() : startScreenButton.click();
break;
case 'r':
if (notPresenter && (hostOnlyRecording || !BUTTONS.settings.tabRecording)) {
userLog('warning', 'The presenter has disabled your ability to start recording', 'top-end');
break;
}
isRecording ? stopRecButton.click() : startRecButton.click();
break;
case 'h':
if (notPresenter && !BUTTONS.main.raiseHandButton) {
userLog('warning', 'The presenter has disabled your ability to raise your hand', 'top-end');
break;
}
hand ? lowerHandButton.click() : raiseHandButton.click();
break;
case 'c':
if (notPresenter && !BUTTONS.main.chatButton) {
userLog('warning', 'The presenter has disabled your ability to open the chat', 'top-end');
break;
}
chatButton.click();
break;
case 'o':
if (notPresenter && !BUTTONS.main.settingsButton) {
userLog('warning', 'The presenter has disabled your ability to open the settings', 'top-end');
break;
}
settingsButton.click();
break;
case 'x':
if (notPresenter && !BUTTONS.main.hideMeButton) {
userLog('warning', 'The presenter has disabled your ability to hide yourself', 'top-end');
break;
}
hideMeButton.click();
break;
case 'k':
if (notPresenter && !BUTTONS.main.transcriptionButton) {
userLog('warning', 'The presenter has disabled your ability to start transcription', 'top-end');
break;
}
transcriptionButton.click();
break;
case 'p':
if (notPresenter && !BUTTONS.main.pollButton) {
userLog('warning', 'The presenter has disabled your ability to start a poll', 'top-end');
break;
}
pollButton.click();
break;
case 'e':
if (notPresenter && !BUTTONS.main.editorButton) {
userLog('warning', 'The presenter has disabled your ability to open the editor', 'top-end');
break;
}
editorButton.click();
break;
case 'w':
if (notPresenter && !BUTTONS.main.whiteboardButton) {
userLog('warning', 'The presenter has disabled your ability to open the whiteboard', 'top-end');
break;
}
whiteboardButton.click();
break;
case 'j':
if (notPresenter && !BUTTONS.main.emojiRoomButton) {
userLog('warning', 'The presenter has disabled your ability to open the room emoji', 'top-end');
break;
}
emojiRoomButton.click();
break;
case 't':
if (notPresenter && !BUTTONS.main.snapshotRoomButton) {
userLog('warning', 'The presenter has disabled your ability to take a snapshot', 'top-end');
break;
}
snapshotRoomButton.click();
break;
case 'f':
if (notPresenter && !BUTTONS.settings.fileSharing) {
userLog('warning', 'The presenter has disabled your ability to share files', 'top-end');
break;
}
fileShareButton.click();
break;
//...
default:
console.log(`Unhandled shortcut key: ${key}`);
}
});
}
}
// ####################################################
@@ -2963,6 +3118,7 @@ function loadSettingsFromLocalStorage() {
isPitchBarEnabled = localStorageSettings.pitch_bar;
isSoundEnabled = localStorageSettings.sounds;
isKeepButtonsVisible = localStorageSettings.keep_buttons_visible;
isShortcutsEnabled = localStorageSettings.keyboard_shortcuts;
showChatOnMsg.checked = rc.showChatOnMessage;
transcriptShowOnMsg.checked = transcription.showOnMessage;
speechIncomingMsg.checked = rc.speechInMessages;
@@ -2970,6 +3126,7 @@ function loadSettingsFromLocalStorage() {
switchSounds.checked = isSoundEnabled;
switchShare.checked = notify;
switchKeepButtonsVisible.checked = isKeepButtonsVisible;
switchShortcuts.checked = isShortcutsEnabled;
recPrioritizeH264 = localStorageSettings.rec_prioritize_h264;
switchH264Recording.checked = recPrioritizeH264;
@@ -3047,12 +3204,14 @@ function handleRoomClientEvents() {
hide(raiseHandButton);
show(lowerHandButton);
setColor(lowerHandIcon, 'lime');
hand = true;
});
rc.on(RoomClient.EVENTS.lowerHand, () => {
console.log('Room event: Client lower hand');
hide(lowerHandButton);
show(raiseHandButton);
setColor(lowerHandIcon, 'white');
hand = false;
});
rc.on(RoomClient.EVENTS.startAudio, () => {
console.log('Room event: Client start audio');
@@ -3060,6 +3219,7 @@ function handleRoomClientEvents() {
show(stopAudioButton);
setColor(startAudioButton, 'red');
setAudioButtonsDisabled(false);
audio = true;
});
rc.on(RoomClient.EVENTS.pauseAudio, () => {
console.log('Room event: Client pause audio');
@@ -3067,12 +3227,14 @@ function handleRoomClientEvents() {
show(startAudioButton);
setColor(startAudioButton, 'red');
setAudioButtonsDisabled(false);
audio = false;
});
rc.on(RoomClient.EVENTS.resumeAudio, () => {
console.log('Room event: Client resume audio');
hide(startAudioButton);
show(stopAudioButton);
setAudioButtonsDisabled(false);
audio = true;
});
rc.on(RoomClient.EVENTS.stopAudio, () => {
console.log('Room event: Client stop audio');
@@ -3080,6 +3242,7 @@ function handleRoomClientEvents() {
show(startAudioButton);
setAudioButtonsDisabled(false);
stopMicrophoneProcessing();
audio = false;
});
rc.on(RoomClient.EVENTS.startVideo, () => {
console.log('Room event: Client start video');
@@ -3089,6 +3252,7 @@ function handleRoomClientEvents() {
setVideoButtonsDisabled(false);
hideClassElements('videoMenuBar');
// if (isParticipantsListOpen) getRoomParticipants();
video = true;
});
rc.on(RoomClient.EVENTS.pauseVideo, () => {
console.log('Room event: Client pause video');
@@ -3097,6 +3261,7 @@ function handleRoomClientEvents() {
setColor(startVideoButton, 'red');
setVideoButtonsDisabled(false);
hideClassElements('videoMenuBar');
video = false;
});
rc.on(RoomClient.EVENTS.resumeVideo, () => {
console.log('Room event: Client resume video');
@@ -3105,6 +3270,7 @@ function handleRoomClientEvents() {
setVideoButtonsDisabled(false);
isVideoPrivacyActive = false;
hideClassElements('videoMenuBar');
video = true;
});
rc.on(RoomClient.EVENTS.stopVideo, () => {
console.log('Room event: Client stop video');
@@ -3114,6 +3280,7 @@ function handleRoomClientEvents() {
isVideoPrivacyActive = false;
hideClassElements('videoMenuBar');
// if (isParticipantsListOpen) getRoomParticipants();
video = false;
});
rc.on(RoomClient.EVENTS.startScreen, () => {
console.log('Room event: Client start screen');
@@ -3121,18 +3288,21 @@ function handleRoomClientEvents() {
show(stopScreenButton);
hideClassElements('videoMenuBar');
// if (isParticipantsListOpen) getRoomParticipants();
screen = true;
});
rc.on(RoomClient.EVENTS.pauseScreen, () => {
console.log('Room event: Client pause screen');
hide(startScreenButton);
show(stopScreenButton);
hideClassElements('videoMenuBar');
screen = false;
});
rc.on(RoomClient.EVENTS.resumeScreen, () => {
console.log('Room event: Client resume screen');
hide(stopScreenButton);
show(startScreenButton);
hideClassElements('videoMenuBar');
screen = true;
});
rc.on(RoomClient.EVENTS.stopScreen, () => {
console.log('Room event: Client stop screen');
@@ -3140,6 +3310,7 @@ function handleRoomClientEvents() {
show(startScreenButton);
hideClassElements('videoMenuBar');
// if (isParticipantsListOpen) getRoomParticipants();
screen = false;
});
rc.on(RoomClient.EVENTS.roomLock, () => {
console.log('Room event: Client lock room');
@@ -4697,7 +4868,7 @@ function showAbout() {
imageUrl: image.about,
customClass: { image: 'img-about' },
position: 'center',
title: 'WebRTC SFU v1.6.89',
title: 'WebRTC SFU v1.6.90',
html: `
<br />
<div id="about">

عرض الملف

@@ -9,7 +9,7 @@
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.6.89
* @version 1.6.90
*
*/

عرض الملف

@@ -26,6 +26,7 @@ let BUTTONS = {
raiseHandButton: true,
transcriptionButton: true,
whiteboardButton: true,
editorButton: true,
snapshotRoomButton: true,
emojiRoomButton: true,
settingsButton: true,

عرض الملف

@@ -253,6 +253,9 @@ access to use this app.
<button id="tabProfileBtn" class="fas fa-user tablinks">
<p class="tabButtonText">Profile</p>
</button>
<button id="tabShortcutsBtn" class="fas fa-keyboard tablinks">
<p class="tabButtonText">Shortcuts</p>
</button>
<button id="tabAspectBtn" class="fas fa-screwdriver-wrench tablinks">
<p class="tabButtonText">Aspect</p>
</button>
@@ -964,7 +967,7 @@ access to use this app.
<hr />
<table class="settingsTable">
<tr id="avatars">
<td class=".width-180">
<td class="width-180">
<div class="title">
<i class="fa-solid fa-users-line"></i>
<p>Show free avatars</p>
@@ -1123,6 +1126,96 @@ access to use this app.
</table>
</div>
<div id="tabShortcuts" class="tabcontent">
<table class="settingsTable">
<tr>
<td class="width-180">
<div class="title">
<i class="fa-solid fa-keyboard"></i>
<p>Shortcuts</p>
</div>
</td>
<td>
<div class="form-check form-switch form-switch-md">
<input id="switchShortcuts" class="form-check-input" type="checkbox" />
</div>
</td>
</tr>
</table>
<div>
<table id="shortcutsTable">
<thead>
<tr>
<th>Shortcut</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td><i class="fa-solid fa-a"></i></td>
<td><strong>Mute/Unmute</strong> your microphone</td>
</tr>
<tr>
<td><i class="fa-solid fa-v"></i></td>
<td><strong>Start/Stop</strong> your camera</td>
</tr>
<tr>
<td><i class="fa-solid fa-s"></i></td>
<td><strong>Start/Stop</strong> your screen</td>
</tr>
<tr>
<td><i class="fa-solid fa-r"></i></td>
<td><strong>Start/Stop</strong> the recording</td>
</tr>
<tr>
<td><i class="fa-solid fa-h"></i></td>
<td><strong>Raise/Lower</strong> your hand</td>
</tr>
<tr>
<td><i class="fa-solid fa-c"></i></td>
<td><strong>Open/Close</strong> the chat</td>
</tr>
<tr>
<td><i class="fa-solid fa-o"></i></td>
<td><strong>Open/Close</strong> the settings</td>
</tr>
<tr>
<td><i class="fa-solid fa-x"></i></td>
<td><strong>Hide/Show</strong> myself</td>
</tr>
<tr>
<td><i class="fa-solid fa-k"></i></td>
<td><strong>Open/Close</strong> the captions</td>
</tr>
<tr>
<td><i class="fa-solid fa-p"></i></td>
<td><strong>Open/Close</strong> the polls</td>
</tr>
<tr>
<td><i class="fa-solid fa-w"></i></td>
<td><strong>Open/Close</strong> the whiteboard</td>
</tr>
<tr>
<td><i class="fa-solid fa-e"></i></td>
<td><strong>Open/Close</strong> the editor</td>
</tr>
<tr>
<td><i class="fa-solid fa-j"></i></td>
<td><strong>Open/Close</strong> the emoji</td>
</tr>
<tr>
<td><i class="fa-solid fa-t"></i></td>
<td><strong>Snapshot</strong> screen/window or tab</td>
</tr>
<tr>
<td><i class="fa-solid fa-f"></i></td>
<td><strong>Share</strong> the file</td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="tabAspect" class="tabcontent">
<br />
<div class="title">