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