Implement Keybinds (#57)
This commit is contained in:
parent
3740553aba
commit
dd2beed4eb
|
@ -23,6 +23,16 @@ if(KF5Notifications_FOUND)
|
|||
add_definitions( -DKNOTIFICATIONS )
|
||||
endif()
|
||||
|
||||
find_package(KF5XmlGui)
|
||||
if(KF5XmlGui_FOUND)
|
||||
add_definitions( -DKXMLGUI )
|
||||
endif()
|
||||
|
||||
find_package(KF5GlobalAccel)
|
||||
if(KF5GlobalAccel_FOUND)
|
||||
add_definitions( -DKGLOBALACCEL )
|
||||
endif()
|
||||
|
||||
set(discord-screenaudio_SRC
|
||||
src/main.cpp
|
||||
src/mainwindow.cpp
|
||||
|
@ -62,6 +72,12 @@ if(KF5Notifications_FOUND)
|
|||
target_link_libraries(discord-screenaudio KF5::Notifications)
|
||||
install(FILES assets/discord-screenaudio.notifyrc DESTINATION ${CMAKE_INSTALL_PREFIX}/share/knotifications5)
|
||||
endif()
|
||||
if(KF5XmlGui_FOUND)
|
||||
target_link_libraries(discord-screenaudio KF5::XmlGui)
|
||||
endif()
|
||||
if(KF5GlobalAccel_FOUND)
|
||||
target_link_libraries(discord-screenaudio KF5::GlobalAccel)
|
||||
endif()
|
||||
|
||||
install(TARGETS discord-screenaudio DESTINATION bin)
|
||||
install(FILES assets/de.shorsh.discord-screenaudio.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/256x256/apps)
|
||||
|
|
|
@ -51,12 +51,14 @@ You have multiple options:
|
|||
|
||||
- Basic building tools
|
||||
- CMake
|
||||
- Qt5, QtWebEngine and Kf5Notifications
|
||||
- Qt5 and QtWebEngine
|
||||
- **PipeWire** (it currently doesn't work with PulseAudio)
|
||||
- Git
|
||||
- _Kf5Notifications (optional, for better notifications)_
|
||||
- _KXMLGui and KGlobalAccel (optional, for keybinds)_
|
||||
|
||||
On Debian:
|
||||
`apt install -y build-essential cmake qtbase5-dev qtwebengine5-dev libkf5notifications-dev pkg-config libpipewire-0.3-dev git`
|
||||
`apt install -y build-essential cmake qtbase5-dev qtwebengine5-dev libkf5notifications-dev libkf5xmlgui-dev libkf5globalaccel-dev pkg-config libpipewire-0.3-dev git`
|
||||
|
||||
### Building
|
||||
|
||||
|
|
|
@ -135,12 +135,21 @@ setInterval(() => {
|
|||
document.getElementsByClassName("dirscordScreenaudioAboutText").length == 0
|
||||
) {
|
||||
for (const el of document.getElementsByClassName("info-3pQQBb")) {
|
||||
const aboutEl = document.createElement("div");
|
||||
let aboutEl;
|
||||
if (window.discordScreenaudioKXMLGUI) {
|
||||
aboutEl = document.createElement("a");
|
||||
aboutEl.addEventListener("click", () => {
|
||||
console.log("!discord-screenaudio-about");
|
||||
});
|
||||
} else {
|
||||
aboutEl = document.createElement("div");
|
||||
}
|
||||
aboutEl.innerText = `discord-screenaudio ${window.discordScreenaudioVersion}`;
|
||||
aboutEl.style.fontSize = "12px";
|
||||
aboutEl.style.color = "var(--text-muted)";
|
||||
aboutEl.style.textTransform = "none";
|
||||
aboutEl.classList.add("dirscordScreenaudioAboutText");
|
||||
aboutEl.style.cursor = "pointer";
|
||||
el.appendChild(aboutEl);
|
||||
}
|
||||
}
|
||||
|
@ -149,6 +158,40 @@ setInterval(() => {
|
|||
document.getElementById("manage-streams-change-windows")?.remove();
|
||||
document.querySelector(`[aria-label="Stream Settings"]`)?.remove();
|
||||
|
||||
// Add event listener for keybind tab
|
||||
if (
|
||||
document
|
||||
.getElementById("keybinds-tab")
|
||||
?.getElementsByClassName(
|
||||
"container-3jbRo5 info-1hMolH fontSize16-3zr6Io browserNotice-1u-Y5o"
|
||||
).length
|
||||
) {
|
||||
const el = document
|
||||
.getElementById("keybinds-tab")
|
||||
.getElementsByClassName("children-1xdcWE")[0];
|
||||
const div = document.createElement("div");
|
||||
div.style.marginBottom = "50px";
|
||||
const button = document.createElement("button");
|
||||
button.classList =
|
||||
"button-f2h6uQ lookFilled-yCfaCM colorBrand-I6CyqQ sizeSmall-wU2dO- grow-2sR_-F";
|
||||
button.innerText = "Edit Global Keybinds";
|
||||
button.addEventListener("click", () => {
|
||||
console.log("!discord-screenaudio-keybinds");
|
||||
});
|
||||
div.appendChild(button);
|
||||
el.innerHTML = "";
|
||||
el.appendChild(div);
|
||||
}
|
||||
|
||||
const muteBtn = document.getElementsByClassName(
|
||||
"button-12Fmur enabled-9OeuTA button-f2h6uQ lookBlank-21BCro colorBrand-I6CyqQ grow-2sR_-F"
|
||||
)[0];
|
||||
window.discordScreenaudioToggleMute = () => muteBtn.click();
|
||||
const deafenBtn = document.getElementsByClassName(
|
||||
"button-12Fmur enabled-9OeuTA button-f2h6uQ lookBlank-21BCro colorBrand-I6CyqQ grow-2sR_-F"
|
||||
)[1];
|
||||
window.discordScreenaudioToggleDeafen = () => deafenBtn.click();
|
||||
|
||||
if (window.discordScreenaudioResolutionString) {
|
||||
for (const el of document.getElementsByClassName(
|
||||
"qualityIndicator-39wQDy"
|
||||
|
|
|
@ -1,10 +1,25 @@
|
|||
#include "discordpage.h"
|
||||
#include "log.h"
|
||||
#include "mainwindow.h"
|
||||
#include "virtmic.h"
|
||||
|
||||
#ifdef KXMLGUI
|
||||
#include <KAboutData>
|
||||
#include <KHelpMenu>
|
||||
#include <KShortcutsDialog>
|
||||
#include <KXmlGuiWindow>
|
||||
#include <QAction>
|
||||
|
||||
#ifdef KGLOBALACCEL
|
||||
#include <KGlobalAccel>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDesktopServices>
|
||||
#include <QFile>
|
||||
#include <QMessageBox>
|
||||
#include <QTimer>
|
||||
#include <QWebChannel>
|
||||
#include <QWebEngineScript>
|
||||
|
@ -36,16 +51,82 @@ DiscordPage::DiscordPage(QWidget *parent) : QWebEnginePage(parent) {
|
|||
|
||||
setUrl(QUrl("https://discord.com/app"));
|
||||
|
||||
injectScript(":/assets/userscript.js");
|
||||
injectVersion(QApplication::applicationVersion());
|
||||
injectScriptFile("userscript.js", ":/assets/userscript.js");
|
||||
|
||||
injectScriptText("version.js",
|
||||
QString("window.discordScreenaudioVersion = '%1';")
|
||||
.arg(QApplication::applicationVersion()));
|
||||
|
||||
#ifdef KXMLGUI
|
||||
injectScriptText("xmlgui.js", "window.discordScreenaudioKXMLGUI = true;");
|
||||
|
||||
KAboutData aboutData(
|
||||
"discord-screenaudio", "discord-screenaudio",
|
||||
QApplication::applicationVersion(),
|
||||
"Custom Discord client with the ability to stream audio on Linux",
|
||||
KAboutLicense::GPL_V3, "Copyright 2022 (C) Malte Jürgens");
|
||||
aboutData.setBugAddress("https://github.com/maltejur/discord-screenaudio");
|
||||
aboutData.addAuthor("Malte Jürgens", "Author", "maltejur@dismail.de",
|
||||
"https://github.com/maltejur");
|
||||
aboutData.addCredit("edisionnano",
|
||||
"For creating and documenting the approach for streaming "
|
||||
"audio in Discord used in this project.",
|
||||
QString(),
|
||||
"https://github.com/edisionnano/"
|
||||
"Screenshare-with-audio-on-Discord-with-Linux");
|
||||
aboutData.addCredit(
|
||||
"Curve", "For creating the Rohrkabel library used in this project.",
|
||||
QString(), "https://github.com/Curve");
|
||||
aboutData.addComponent("Rohrkabel", "A C++ RAII Pipewire-API Wrapper", "1.3",
|
||||
"https://github.com/Soundux/rohrkabel");
|
||||
m_helpMenu = new KHelpMenu(parent, aboutData);
|
||||
|
||||
#ifdef KGLOBALACCEL
|
||||
injectScriptText("kglobalaccel.js",
|
||||
"window.discordScreenaudioKGLOBALACCEL = true;");
|
||||
|
||||
auto toggleMuteAction = new QAction(this);
|
||||
toggleMuteAction->setText("Toggle Mute");
|
||||
toggleMuteAction->setIcon(QIcon::fromTheme("microphone-sensitivity-muted"));
|
||||
connect(toggleMuteAction, &QAction::triggered, this,
|
||||
&DiscordPage::toggleMute);
|
||||
|
||||
auto toggleDeafenAction = new QAction(this);
|
||||
toggleDeafenAction->setText("Toggle Deafen");
|
||||
toggleDeafenAction->setIcon(QIcon::fromTheme("audio-volume-muted"));
|
||||
connect(toggleDeafenAction, &QAction::triggered, this,
|
||||
&DiscordPage::toggleDeafen);
|
||||
|
||||
m_actionCollection = new KActionCollection(this);
|
||||
m_actionCollection->addAction("toggleMute", toggleMuteAction);
|
||||
KGlobalAccel::setGlobalShortcut(toggleMuteAction, QList<QKeySequence>{});
|
||||
m_actionCollection->addAction("toggleDeafen", toggleDeafenAction);
|
||||
KGlobalAccel::setGlobalShortcut(toggleDeafenAction, QList<QKeySequence>{});
|
||||
|
||||
m_shortcutsDialog = new KShortcutsDialog(KShortcutsEditor::GlobalAction);
|
||||
m_shortcutsDialog->addCollection(m_actionCollection);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
connect(&m_streamDialog, &StreamDialog::requestedStreamStart, this,
|
||||
&DiscordPage::startStream);
|
||||
}
|
||||
|
||||
void DiscordPage::injectScript(QString source) {
|
||||
qDebug(mainLog) << "Injecting " << source;
|
||||
void DiscordPage::injectScriptText(QString name, QString content) {
|
||||
qDebug(mainLog) << "Injecting " << name;
|
||||
|
||||
QWebEngineScript script;
|
||||
|
||||
script.setSourceCode(content);
|
||||
script.setName(name);
|
||||
script.setWorldId(QWebEngineScript::MainWorld);
|
||||
script.setInjectionPoint(QWebEngineScript::DocumentCreation);
|
||||
script.setRunsOnSubFrames(false);
|
||||
|
||||
scripts().insert(script);
|
||||
}
|
||||
|
||||
void DiscordPage::injectScriptFile(QString name, QString source) {
|
||||
QFile userscript(source);
|
||||
|
||||
if (!userscript.open(QIODevice::ReadOnly)) {
|
||||
|
@ -53,33 +134,10 @@ void DiscordPage::injectScript(QString source) {
|
|||
userscript.errorString().toLatin1().constData());
|
||||
} else {
|
||||
QByteArray userscriptJs = userscript.readAll();
|
||||
|
||||
QWebEngineScript script;
|
||||
|
||||
script.setSourceCode(userscriptJs);
|
||||
script.setName("userscript.js");
|
||||
script.setWorldId(QWebEngineScript::MainWorld);
|
||||
script.setInjectionPoint(QWebEngineScript::DocumentCreation);
|
||||
script.setRunsOnSubFrames(false);
|
||||
|
||||
scripts().insert(script);
|
||||
injectScriptText(name, userscriptJs);
|
||||
}
|
||||
}
|
||||
|
||||
void DiscordPage::injectVersion(QString version) {
|
||||
QWebEngineScript script;
|
||||
|
||||
auto code = QString("window.discordScreenaudioVersion = '%1';").arg(version);
|
||||
|
||||
script.setSourceCode(code);
|
||||
script.setName("version.js");
|
||||
script.setWorldId(QWebEngineScript::MainWorld);
|
||||
script.setInjectionPoint(QWebEngineScript::DocumentCreation);
|
||||
script.setRunsOnSubFrames(false);
|
||||
|
||||
scripts().insert(script);
|
||||
}
|
||||
|
||||
void DiscordPage::featurePermissionRequested(const QUrl &securityOrigin,
|
||||
QWebEnginePage::Feature feature) {
|
||||
// Allow every permission asked
|
||||
|
@ -144,6 +202,26 @@ void DiscordPage::javaScriptConsoleMessage(
|
|||
m_streamDialog.updateTargets();
|
||||
} else if (message == "!discord-screenaudio-stream-stopped") {
|
||||
stopVirtmic();
|
||||
} else if (message == "!discord-screenaudio-about") {
|
||||
#ifdef KXMLGUI
|
||||
m_helpMenu->aboutApplication();
|
||||
#endif
|
||||
} else if (message == "!discord-screenaudio-keybinds") {
|
||||
#ifdef KXMLGUI
|
||||
#ifdef KGLOBALACCEL
|
||||
m_shortcutsDialog->show();
|
||||
#else
|
||||
QMessageBox::information(MainWindow::instance(), "discord-screenaudio",
|
||||
"Keybinds are not supported on this platform "
|
||||
"(KGlobalAccel is not available).",
|
||||
QMessageBox::Ok);
|
||||
#endif
|
||||
#else
|
||||
QMessageBox::information(MainWindow::instance(), "discord-screenaudio",
|
||||
"Keybinds are not supported on this platform "
|
||||
"(KXmlGui and KGlobalAccel are not available).",
|
||||
QMessageBox::Ok);
|
||||
#endif
|
||||
} else if (message.startsWith("dsa: ")) {
|
||||
qDebug(userscriptLog) << message.mid(5).toUtf8().constData();
|
||||
} else {
|
||||
|
@ -163,3 +241,13 @@ void DiscordPage::startStream(QString target, uint width, uint height,
|
|||
.arg(frameRate));
|
||||
});
|
||||
}
|
||||
|
||||
void DiscordPage::toggleMute() {
|
||||
qDebug(shortcutLog) << "Toggling mute";
|
||||
runJavaScript("window.discordScreenaudioToggleMute();");
|
||||
}
|
||||
|
||||
void DiscordPage::toggleDeafen() {
|
||||
qDebug(shortcutLog) << "Toggling deafen";
|
||||
runJavaScript("window.discordScreenaudioToggleDeafen();");
|
||||
}
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
#include "streamdialog.h"
|
||||
#include "virtmic.h"
|
||||
|
||||
#ifdef KXMLGUI
|
||||
#include <KActionCollection>
|
||||
#include <KHelpMenu>
|
||||
#include <KShortcutsDialog>
|
||||
#endif
|
||||
|
||||
#include <QProcess>
|
||||
#include <QWebEngineFullScreenRequest>
|
||||
#include <QWebEnginePage>
|
||||
|
@ -16,6 +22,13 @@ public:
|
|||
private:
|
||||
StreamDialog m_streamDialog;
|
||||
QProcess m_virtmicProcess;
|
||||
#ifdef KXMLGUI
|
||||
KHelpMenu *m_helpMenu;
|
||||
#ifdef KGLOBALACCEL
|
||||
KActionCollection *m_actionCollection;
|
||||
KShortcutsDialog *m_shortcutsDialog;
|
||||
#endif
|
||||
#endif
|
||||
bool acceptNavigationRequest(const QUrl &url,
|
||||
QWebEnginePage::NavigationType type,
|
||||
bool isMainFrame) override;
|
||||
|
@ -24,10 +37,12 @@ private:
|
|||
javaScriptConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel level,
|
||||
const QString &message, int lineNumber,
|
||||
const QString &sourceID) override;
|
||||
void injectScript(QString source);
|
||||
void injectVersion(QString version);
|
||||
void injectScriptText(QString name, QString source);
|
||||
void injectScriptFile(QString name, QString content);
|
||||
void stopVirtmic();
|
||||
void startVirtmic(QString target);
|
||||
void toggleMute();
|
||||
void toggleDeafen();
|
||||
|
||||
private Q_SLOTS:
|
||||
void featurePermissionRequested(const QUrl &securityOrigin,
|
||||
|
|
|
@ -4,3 +4,4 @@ Q_LOGGING_CATEGORY(mainLog, "main");
|
|||
Q_LOGGING_CATEGORY(discordLog, "discord");
|
||||
Q_LOGGING_CATEGORY(userscriptLog, "userscript");
|
||||
Q_LOGGING_CATEGORY(virtmicLog, "virtmic");
|
||||
Q_LOGGING_CATEGORY(shortcutLog, "shortcut");
|
||||
|
|
|
@ -6,3 +6,4 @@ Q_DECLARE_LOGGING_CATEGORY(mainLog);
|
|||
Q_DECLARE_LOGGING_CATEGORY(discordLog);
|
||||
Q_DECLARE_LOGGING_CATEGORY(userscriptLog);
|
||||
Q_DECLARE_LOGGING_CATEGORY(virtmicLog);
|
||||
Q_DECLARE_LOGGING_CATEGORY(shortcutLog);
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#include "mainwindow.h"
|
||||
#include "virtmic.h"
|
||||
|
||||
#ifdef KXMLGUI
|
||||
#include <KAboutData>
|
||||
#endif
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCommandLineParser>
|
||||
#include <QLoggingCategory>
|
||||
|
@ -26,6 +30,7 @@ int main(int argc, char *argv[]) {
|
|||
QCommandLineOption degubOption("remote-debugging",
|
||||
"Open Chromium Remote Debugging on port 9222");
|
||||
parser.addOption(degubOption);
|
||||
|
||||
parser.process(app);
|
||||
|
||||
if (parser.isSet(virtmicOption)) {
|
||||
|
|
|
@ -22,7 +22,11 @@
|
|||
#include <QWebEngineSettings>
|
||||
#include <QWidget>
|
||||
|
||||
MainWindow *MainWindow::m_instance = nullptr;
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
|
||||
assert(MainWindow::m_instance == nullptr);
|
||||
MainWindow::m_instance = this;
|
||||
setupWebView();
|
||||
resize(1000, 700);
|
||||
showMaximized();
|
||||
|
@ -68,3 +72,5 @@ void MainWindow::fullScreenRequested(
|
|||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event) { QApplication::quit(); }
|
||||
|
||||
MainWindow *MainWindow::instance() { return m_instance; }
|
||||
|
|
|
@ -15,6 +15,7 @@ class MainWindow : public QMainWindow {
|
|||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
static MainWindow *instance();
|
||||
|
||||
private:
|
||||
void setupWebView();
|
||||
|
@ -23,6 +24,7 @@ private:
|
|||
DiscordPage *m_discordPage;
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
bool m_wasMaximized;
|
||||
static MainWindow *m_instance;
|
||||
|
||||
private Q_SLOTS:
|
||||
void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest);
|
||||
|
|
Loading…
Reference in New Issue