diff --git a/gui/src/components/settings/SettingsSidebar.tsx b/gui/src/components/settings/SettingsSidebar.tsx index fd6e582b6..aa97bc620 100644 --- a/gui/src/components/settings/SettingsSidebar.tsx +++ b/gui/src/components/settings/SettingsSidebar.tsx @@ -3,7 +3,6 @@ import { useMemo } from 'react'; import { NavLink, useLocation, useMatch } from 'react-router-dom'; import { Typography } from '@/components/commons/Typography'; import { useVRCConfig } from '@/hooks/vrc-config'; -import { platform } from '@tauri-apps/plugin-os'; export function SettingsLink({ to, @@ -42,7 +41,6 @@ export function SettingsLink({ export function SettingsSidebar() { const { state: vrcConfigState } = useVRCConfig(); - const currentPlatform = platform(); return (
@@ -76,12 +74,11 @@ export function SettingsSidebar() { id="settings-sidebar-gesture_control" /> { - currentPlatform == 'windows' || currentPlatform == 'linux' ? - : <> + }
diff --git a/server/core/build.gradle.kts b/server/core/build.gradle.kts index 4b62c2df7..f9a9071dc 100644 --- a/server/core/build.gradle.kts +++ b/server/core/build.gradle.kts @@ -54,6 +54,7 @@ allprojects { // You can declare any Maven/Ivy/file repository here. mavenCentral() maven(url = "https://jitpack.io") + mavenLocal() } } @@ -79,6 +80,8 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") implementation("com.mayakapps.kache:kache:2.1.1") + implementation("dev.hannahpadd:dbusglobalshortcutskotlin:0.1.0") + api("com.github.loucass003:EspflashKotlin:v0.11.0") // Allow the use of reflection diff --git a/server/core/src/main/java/dev/slimevr/Keybinding.kt b/server/core/src/main/java/dev/slimevr/Keybinding.kt index 54e169f72..8703c36ca 100644 --- a/server/core/src/main/java/dev/slimevr/Keybinding.kt +++ b/server/core/src/main/java/dev/slimevr/Keybinding.kt @@ -2,23 +2,21 @@ package dev.slimevr import com.melloware.jintellitype.HotkeyListener import com.melloware.jintellitype.JIntellitype +import dev.hannah.portals.PortalManager +import dev.hannah.portals.globalShortcuts.ShortcutTuple import dev.slimevr.config.KeybindingsConfig import dev.slimevr.tracking.trackers.TrackerUtils import io.eiren.util.OperatingSystem import io.eiren.util.OperatingSystem.Companion.currentPlatform import io.eiren.util.ann.AWTThread import io.eiren.util.logging.LogManager +import org.freedesktop.dbus.types.Variant class Keybinding @AWTThread constructor(val server: VRServer) : HotkeyListener { val config: KeybindingsConfig = server.configManager.vrConfig.keybindings init { - if (currentPlatform != OperatingSystem.WINDOWS) { - LogManager - .info( - "[Keybinding] Currently only supported on Windows. Keybindings will be disabled.", - ) - } else { + if (currentPlatform == OperatingSystem.WINDOWS) { try { if (JIntellitype.getInstance() != null) { JIntellitype.getInstance().addHotKeyListener(this) @@ -55,6 +53,55 @@ class Keybinding @AWTThread constructor(val server: VRServer) : HotkeyListener { ) } } + if (currentPlatform == OperatingSystem.LINUX) { + val portalManager = PortalManager(SLIMEVR_IDENTIFIER) + val shortcutsList = mutableListOf( + ShortcutTuple("FULL_RESET", mapOf("description" to Variant("Full Reset"), "trigger_description" to Variant("CTRL+ALT+SHIFT+Y"))), + ShortcutTuple("YAW_RESET", mapOf("description" to Variant("Yaw Reset"), "trigger_description" to Variant("CTRL+ALT+SHIFT+U"))), + ShortcutTuple("MOUNTING_RESET", mapOf("description" to Variant("Mounting Reset"), "trigger_description" to Variant("CTRL+ALT+SHIFT+I"))), + ShortcutTuple("FEET_MOUNTING_RESET", mapOf("description" to Variant("Feet Mounting Reset"), "trigger_description" to Variant("CTRL+ALT+SHIFT+P"))), + ShortcutTuple("PAUSE_TRACKING", mapOf("description" to Variant("Pause Tracking"), "trigger_description" to Variant("CTRL+ALT+SHIFT+O")))) + val globalShortcutsHandler = portalManager.globalShortcutsRequest(shortcutsList) + Runtime.getRuntime().addShutdownHook(Thread { + println("Closing connection") + globalShortcutsHandler.close() + }) + + globalShortcutsHandler.onShortcutActivated = { shortcutId -> + when (shortcutId) { + "FULL_RESET" -> { + println("Full reset triggered") + server.scheduleResetTrackersFull(RESET_SOURCE_NAME, config.fullResetDelay.toLong()) + } + "YAW_RESET" -> { + println("Yaw reset triggered") + server.scheduleResetTrackersYaw(RESET_SOURCE_NAME, config.yawResetDelay.toLong()) + } + "MOUNTING_RESET" -> { + println("Mounting reset triggered") + server.scheduleResetTrackersMounting( + RESET_SOURCE_NAME, + config.mountingResetDelay.toLong(), + ) + } + "FEET_MOUNTING_RESET" -> { + println("Feet mounting reset triggered") + server.scheduleResetTrackersMounting( + RESET_SOURCE_NAME, + config.feetMountingResetDelay.toLong(), + TrackerUtils.feetsBodyParts, + ) + } + "PAUSE_TRACKING" -> { + println("Pause tracking triggered") + server.scheduleTogglePauseTracking( + RESET_SOURCE_NAME, + config.pauseTrackingDelay.toLong(), + ) + } + } + } + } } @AWTThread diff --git a/server/core/src/main/java/dev/slimevr/keybinding/GlobalKeybinds.kt b/server/core/src/main/java/dev/slimevr/keybinding/GlobalKeybinds.kt deleted file mode 100644 index ba91a756a..000000000 --- a/server/core/src/main/java/dev/slimevr/keybinding/GlobalKeybinds.kt +++ /dev/null @@ -1,31 +0,0 @@ -package dev.slimevr.keybinding - -import org.freedesktop.dbus.DBusPath -import org.freedesktop.dbus.annotations.DBusInterfaceName -import org.freedesktop.dbus.interfaces.DBusInterface -import org.freedesktop.dbus.messages.DBusSignal -import org.freedesktop.dbus.types.Variant - -@DBusInterfaceName("org.freedesktop.portal.GlobalKeybinds") -interface GlobalKeybinds : DBusInterface { - - // Creates a session for the shortcuts - fun CreateSession(options: Map>): DBusPath - - fun BindShortcuts( - sessionHandle: DBusPath, - shortcuts: Array, - parentWindow: String, - options: Map> - ): DBusPath - - class Activated( - path: String, - val sessionHandle: DBusPath, - val shortcutId: String, - val timestamp: Long, - val options: Map> - ) : DBusSignal(path, sessionHandle, shortcutId, timestamp, options) -} - -data class Shortcut(val id: String, val properties: Map>) diff --git a/server/core/src/main/java/dev/slimevr/keybinding/Keybinding.kt b/server/core/src/main/java/dev/slimevr/keybinding/Keybinding.kt deleted file mode 100644 index 49ffcaead..000000000 --- a/server/core/src/main/java/dev/slimevr/keybinding/Keybinding.kt +++ /dev/null @@ -1,148 +0,0 @@ -package dev.slimevr.keybinding - -import com.melloware.jintellitype.HotkeyListener -import com.melloware.jintellitype.JIntellitype -import dev.slimevr.VRServer -import dev.slimevr.config.KeybindingsConfig -import dev.slimevr.tracking.trackers.TrackerUtils -import io.eiren.util.OperatingSystem -import io.eiren.util.ann.AWTThread -import io.eiren.util.logging.LogManager - -class Keybinding @AWTThread constructor(val server: VRServer) : HotkeyListener { - val config: KeybindingsConfig = server.configManager.vrConfig.keybindings - - init { - - if (OperatingSystem.Companion.currentPlatform != OperatingSystem.WINDOWS) { - LogManager - .info( - "[Keybinding] Currently only supported on Windows. Keybindings will be disabled.", - ) - - /* - try { - val connection = DBusConnectionBuilder.forSessionBus().build() - - // 1. Get the Portal object - val portal = connection.getRemoteObject( - "org.freedesktop.portal.Desktop", - "/org/freedesktop/portal/desktop", - GlobalKeybinds::class.java - ) - - // 2. Setup the Signal Listener - connection.addSigHandler(GlobalKeybinds.Activated::class.java) { signal -> - when (signal.shortcutId) { - "my_cool_action" -> println("🚀 Hotkey Triggered!") - } - } - - // 3. Create Session & Bind (Simplified) - // Note: In a real app, you'd handle the ObjectPath callbacks - // for CreateSession before calling BindShortcuts. - val shortcuts = arrayOf( - Shortcut( - "my_cool_action", - mapOf("description" to Variant("Open My App")) - ) - ) - - - // This triggers the OS permissions popup - portal.BindShortcuts(, shortcuts, "", emptyMap()) - } catch (e: Error) { - println("Dbus error: ${e}") - } - - */ - } else { - try { - if (JIntellitype.getInstance() != null) { - JIntellitype.getInstance().addHotKeyListener(this) - - val fullResetBinding = config.fullResetBinding - JIntellitype.getInstance() - .registerHotKey(FULL_RESET, fullResetBinding) - LogManager.info("[Keybinding] Bound full reset to $fullResetBinding") - - val yawResetBinding = config.yawResetBinding - JIntellitype.getInstance() - .registerHotKey(YAW_RESET, yawResetBinding) - LogManager.info("[Keybinding] Bound yaw reset to $yawResetBinding") - - val mountingResetBinding = config.mountingResetBinding - JIntellitype.getInstance() - .registerHotKey(MOUNTING_RESET, mountingResetBinding) - LogManager.info("[Keybinding] Bound reset mounting to $mountingResetBinding") - - val feetMountingResetBinding = config.feetMountingResetBinding - JIntellitype.getInstance() - .registerHotKey(FEET_MOUNTING_RESET, feetMountingResetBinding) - LogManager.info("[Keybinding] Bound feet reset mounting to $feetMountingResetBinding") - - val pauseTrackingBinding = config.pauseTrackingBinding - JIntellitype.getInstance() - .registerHotKey(PAUSE_TRACKING, pauseTrackingBinding) - LogManager.info("[Keybinding] Bound pause tracking to $pauseTrackingBinding") - } - } catch (e: Throwable) { - LogManager - .warning( - "[Keybinding] JIntellitype initialization failed. Keybindings will be disabled. Try restarting your computer.", - ) - } - } - } - - @AWTThread - override fun onHotKey(identifier: Int) { - when (identifier) { - FULL_RESET -> server.scheduleResetTrackersFull( - RESET_SOURCE_NAME, - (config.fullResetDelay * 1000).toLong() - ) - - YAW_RESET -> server.scheduleResetTrackersYaw( - RESET_SOURCE_NAME, - (config.yawResetDelay * 1000).toLong() - ) - - MOUNTING_RESET -> server.scheduleResetTrackersMounting( - RESET_SOURCE_NAME, - (config.mountingResetDelay * 1000).toLong() - ) - - FEET_MOUNTING_RESET -> server.scheduleResetTrackersMounting( - RESET_SOURCE_NAME, - (config.feetMountingResetDelay * 1000).toLong(), - TrackerUtils.feetsBodyParts, - ) - - PAUSE_TRACKING -> - server - .scheduleTogglePauseTracking( - RESET_SOURCE_NAME, - (config.pauseTrackingDelay * 1000).toLong(), - ) - } - } - - enum class KeybindName { - FULL_RESET, - YAW_RESET, - MOUNTING_RESET, - PAUSE_TRACKING - } - - companion object { - private const val RESET_SOURCE_NAME = "Keybinding" - - private const val FULL_RESET = 1 - private const val YAW_RESET = 2 - private const val MOUNTING_RESET = 3 - private const val FEET_MOUNTING_RESET = 4 - private const val PAUSE_TRACKING = 5 - } - -} diff --git a/server/core/src/main/java/dev/slimevr/protocol/rpc/keybinds/RPCKeybindHandler.kt b/server/core/src/main/java/dev/slimevr/protocol/rpc/keybinds/RPCKeybindHandler.kt index 88c336e16..6c377101d 100644 --- a/server/core/src/main/java/dev/slimevr/protocol/rpc/keybinds/RPCKeybindHandler.kt +++ b/server/core/src/main/java/dev/slimevr/protocol/rpc/keybinds/RPCKeybindHandler.kt @@ -1,7 +1,6 @@ package dev.slimevr.protocol.rpc.keybinds import com.google.flatbuffers.FlatBufferBuilder -import dev.slimevr.keybinding.Keybinding import dev.slimevr.keybind.KeybindListener import dev.slimevr.protocol.GenericConnection import dev.slimevr.protocol.rpc.RPCHandler diff --git a/server/desktop/build.gradle.kts b/server/desktop/build.gradle.kts index 1950bdbcc..5bb69923c 100644 --- a/server/desktop/build.gradle.kts +++ b/server/desktop/build.gradle.kts @@ -51,6 +51,7 @@ allprojects { mavenCentral() maven(url = "https://jitpack.io") maven(url = "https://oss.sonatype.org/content/repositories/snapshots") + mavenLocal() } } diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt b/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt index ea4645a95..22267c260 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt +++ b/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt @@ -2,7 +2,7 @@ package dev.slimevr.desktop -import dev.slimevr.keybinding.Keybinding +import dev.slimevr.Keybinding import dev.slimevr.SLIMEVR_IDENTIFIER import dev.slimevr.VRServer import dev.slimevr.bridge.Bridge diff --git a/settings.gradle.kts b/settings.gradle.kts index e2691d0b8..372916c5c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,6 +14,7 @@ pluginManagement { gradlePluginPortal() google() mavenCentral() + mavenLocal() } val kotlinVersion: String by settings