mirror of
https://github.com/SlimeVR/SlimeVR-Server.git
synced 2026-04-06 02:01:58 +02:00
Started implementing proof of concept for keybind support on Wayland
This commit is contained in:
@@ -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 (
|
||||
<div className="flex flex-col px-5 py-5 gap-3 overflow-y-auto bg-background-70 rounded-lg h-full">
|
||||
@@ -76,12 +74,11 @@ export function SettingsSidebar() {
|
||||
id="settings-sidebar-gesture_control"
|
||||
/>
|
||||
{
|
||||
currentPlatform == 'windows' || currentPlatform == 'linux' ?
|
||||
<SettingsLink
|
||||
to="/settings/keybinds"
|
||||
scrollTo="keybinds"
|
||||
id="settings-sidebar-keybinds"
|
||||
/> : <></>
|
||||
<SettingsLink
|
||||
to="/settings/keybinds"
|
||||
scrollTo="keybinds"
|
||||
id="settings-sidebar-keybinds"
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<String, Variant<*>>): DBusPath
|
||||
|
||||
fun BindShortcuts(
|
||||
sessionHandle: DBusPath,
|
||||
shortcuts: Array<Shortcut>,
|
||||
parentWindow: String,
|
||||
options: Map<String, Variant<*>>
|
||||
): DBusPath
|
||||
|
||||
class Activated(
|
||||
path: String,
|
||||
val sessionHandle: DBusPath,
|
||||
val shortcutId: String,
|
||||
val timestamp: Long,
|
||||
val options: Map<String, Variant<*>>
|
||||
) : DBusSignal(path, sessionHandle, shortcutId, timestamp, options)
|
||||
}
|
||||
|
||||
data class Shortcut(val id: String, val properties: Map<String, Variant<*>>)
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -51,6 +51,7 @@ allprojects {
|
||||
mavenCentral()
|
||||
maven(url = "https://jitpack.io")
|
||||
maven(url = "https://oss.sonatype.org/content/repositories/snapshots")
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -14,6 +14,7 @@ pluginManagement {
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
val kotlinVersion: String by settings
|
||||
|
||||
Reference in New Issue
Block a user