diff --git a/src/main/constants.ts b/src/main/constants.ts index 81cfd53b..f0703a44 100644 --- a/src/main/constants.ts +++ b/src/main/constants.ts @@ -74,3 +74,6 @@ export const enum MessageBoxChoice { Default, Cancel } + +export const isWayland = + process.platform === "linux" && (process.env.XDG_SESSION_TYPE === "wayland" || !!process.env.WAYLAND_DISPLAY); diff --git a/src/main/keybinds.ts b/src/main/keybinds.ts new file mode 100644 index 00000000..f7737626 --- /dev/null +++ b/src/main/keybinds.ts @@ -0,0 +1,80 @@ +/* + * SPDX-License-Identifier: GPL-3.0 + * Vesktop, a desktop app aiming to give you a snappier Discord Experience + * Copyright (c) 2023 Vendicated and Vencord contributors + */ + +import { spawnSync } from "node:child_process"; +import { constants, existsSync, open, unlinkSync } from "node:fs"; +import { join } from "node:path"; + +import { Socket } from "net"; +import { IpcEvents } from "shared/IpcEvents"; + +import { mainWin } from "./mainWindow"; + +const xdgRuntimeDir = process.env.XDG_RUNTIME_DIR || process.env.TMP || "/tmp"; +const socketFile = join(xdgRuntimeDir, "vesktop-ipc"); + +const Actions = new Set([IpcEvents.TOGGLE_SELF_DEAF, IpcEvents.TOGGLE_SELF_MUTE]); + +function createFIFO() { + if (existsSync(socketFile)) { + try { + unlinkSync(socketFile); + } catch (err) { + console.error("Failed to remove existing mkfifo file:", err); + return false; + } + } + + try { + spawnSync("mkfifo", [socketFile]); + } catch (err) { + console.error("Failed to create mkfifo while initializing keybinds:", err); + return false; + } + return true; +} + +function openFIFO() { + try { + open(socketFile, constants.O_RDONLY | constants.O_NONBLOCK, (err, fd) => { + if (err) { + console.error("Error opening pipe while initializing keybinds:", err); + return; + } + + const pipe = new Socket({ fd }); + pipe.on("data", data => { + const action = data.toString().trim(); + if (Actions.has(action as IpcEvents)) { + mainWin.webContents.send(action); + } + }); + + pipe.on("end", () => { + pipe.destroy(); + openFIFO(); + }); + }); + } catch (err) { + console.error("Can't open socket file.", err); + } +} + +function cleanup() { + try { + unlinkSync(socketFile); + } catch (err) { + console.error("Failed to remove mkfifo file:", err); + } +} + +process.on("exit", cleanup); + +export function initKeybinds() { + if (createFIFO()) { + openFIFO(); + } +} diff --git a/src/main/mainWindow.ts b/src/main/mainWindow.ts index 1292449b..1d1b67aa 100644 --- a/src/main/mainWindow.ts +++ b/src/main/mainWindow.ts @@ -31,11 +31,13 @@ import { DATA_DIR, DEFAULT_HEIGHT, DEFAULT_WIDTH, + isWayland, MessageBoxChoice, MIN_HEIGHT, MIN_WIDTH, VENCORD_FILES_DIR } from "./constants"; +import { initKeybinds } from "./keybinds"; import { Settings, State, VencordSettings } from "./settings"; import { createSplashWindow } from "./splash"; import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally"; @@ -512,4 +514,5 @@ export async function createWindows() { }); initArRPC(); + if (isWayland) initKeybinds(); } diff --git a/src/main/screenShare.ts b/src/main/screenShare.ts index b63497bc..34d8e4ab 100644 --- a/src/main/screenShare.ts +++ b/src/main/screenShare.ts @@ -8,11 +8,9 @@ import { desktopCapturer, session, Streams } from "electron"; import type { StreamPick } from "renderer/components/ScreenSharePicker"; import { IpcEvents } from "shared/IpcEvents"; +import { isWayland } from "./constants"; import { handle } from "./utils/ipcWrappers"; -const isWayland = - process.platform === "linux" && (process.env.XDG_SESSION_TYPE === "wayland" || !!process.env.WAYLAND_DISPLAY); - export function registerScreenShareHandler() { handle(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, async (_, id: string) => { const sources = await desktopCapturer.getSources({ diff --git a/src/preload/VesktopNative.ts b/src/preload/VesktopNative.ts index 7a8b9775..50841bee 100644 --- a/src/preload/VesktopNative.ts +++ b/src/preload/VesktopNative.ts @@ -78,5 +78,13 @@ export const VesktopNative = { clipboard: { copyImage: (imageBuffer: Uint8Array, imageSrc: string) => invoke(IpcEvents.CLIPBOARD_COPY_IMAGE, imageBuffer, imageSrc) + }, + voice: { + onToggleSelfMute: (listener: (...args: any[]) => void) => { + ipcRenderer.on(IpcEvents.TOGGLE_SELF_MUTE, listener); + }, + onToggleSelfDeaf: (listener: (...args: any[]) => void) => { + ipcRenderer.on(IpcEvents.TOGGLE_SELF_DEAF, listener); + } } }; diff --git a/src/renderer/index.ts b/src/renderer/index.ts index e8ad31ca..66c7c882 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -60,6 +60,12 @@ VesktopNative.arrpc.onActivity(async data => { arRPC.handleEvent(new MessageEvent("message", { data })); }); +const VoiceActions = findByPropsLazy("toggleSelfMute"); + +VesktopNative.voice.onToggleSelfMute(() => VoiceActions.toggleSelfMute()); + +VesktopNative.voice.onToggleSelfDeaf(() => VoiceActions.toggleSelfDeaf()); + // TODO: remove soon const vencordDir = "vencordDir" as keyof typeof Settings.store; if (Settings.store[vencordDir]) { diff --git a/src/shared/IpcEvents.ts b/src/shared/IpcEvents.ts index 51d2a281..1545aeb3 100644 --- a/src/shared/IpcEvents.ts +++ b/src/shared/IpcEvents.ts @@ -50,5 +50,7 @@ export const enum IpcEvents { ARRPC_ACTIVITY = "VCD_ARRPC_ACTIVITY", - CLIPBOARD_COPY_IMAGE = "VCD_CLIPBOARD_COPY_IMAGE" + CLIPBOARD_COPY_IMAGE = "VCD_CLIPBOARD_COPY_IMAGE", + TOGGLE_SELF_MUTE = "VCD_TOGGLE_SELF_MUTE", + TOGGLE_SELF_DEAF = "VCD_TOGGLE_SELF_DEAF" }