diff --git a/jiggler.go b/jiggler.go index 3323d0bb..f7cf3835 100644 --- a/jiggler.go +++ b/jiggler.go @@ -129,19 +129,22 @@ func runJiggler() { } inactivitySeconds := config.JigglerConfig.InactivityLimitSeconds timeSinceLastInput := time.Since(gadget.GetLastUserInputTime()) - logger.Debug().Msgf("Time since last user input %v", timeSinceLastInput) if timeSinceLastInput > time.Duration(inactivitySeconds)*time.Second { - logger.Debug().Msg("Jiggling mouse...") - //TODO: change to rel mouse - // Use direct hardware calls for jiggler - bypass session permissions - err := gadget.AbsMouseReport(1, 1, 0) + err := gadget.RelMouseReport(1, 0, 0) if err != nil { logger.Warn().Msgf("Failed to jiggle mouse: %v", err) } - err = gadget.AbsMouseReport(0, 0, 0) + time.Sleep(50 * time.Millisecond) + err = gadget.RelMouseReport(-1, 0, 0) if err != nil { logger.Warn().Msgf("Failed to reset mouse position: %v", err) } + + if sessionManager != nil { + if primarySession := sessionManager.GetPrimarySession(); primarySession != nil { + sessionManager.UpdateLastActive(primarySession.ID) + } + } } } } diff --git a/session_manager.go b/session_manager.go index ed619ed0..80646413 100644 --- a/session_manager.go +++ b/session_manager.go @@ -1087,6 +1087,7 @@ func (sm *SessionManager) transferPrimaryRole(fromSessionID, toSessionID, transf // Promote target session toSession.Mode = SessionModePrimary toSession.hidRPCAvailable = false // Force re-handshake + toSession.LastActive = time.Now() // Reset activity timestamp to prevent immediate timeout sm.primarySessionID = toSessionID // ALWAYS set lastPrimaryID to the new primary to support WebRTC reconnections diff --git a/ui/src/routes/devices.$id.tsx b/ui/src/routes/devices.$id.tsx index 2ad16bbe..c5ba7149 100644 --- a/ui/src/routes/devices.$id.tsx +++ b/ui/src/routes/devices.$id.tsx @@ -400,18 +400,29 @@ export default function KvmIdRoute() { const { newMode, action } = parsedMessage.data; if (action === "reconnect_required" && newMode) { - console.log(`[Websocket] Mode changed to ${newMode}, reconnecting...`); - + // Update session state immediately if (currentSessionId) { setCurrentSession(currentSessionId, newMode); } + // Trigger RPC event handler handleRpcEvent("connectionModeChanged", parsedMessage.data); - setTimeout(() => { - peerConnection?.close(); - setupPeerConnection(); - }, 500); + // Only reconnect if the peer connection is actually stale + // If already connected, the mode change via RPC is sufficient + const isConnectionHealthy = + peerConnection?.connectionState === "connected" && + peerConnection?.iceConnectionState === "connected"; + + if (!isConnectionHealthy) { + console.log(`[Websocket] Mode changed to ${newMode}, connection unhealthy, reconnecting...`); + setTimeout(() => { + peerConnection?.close(); + setupPeerConnection(); + }, 500); + } else { + console.log(`[Websocket] Mode changed to ${newMode}, connection healthy, skipping reconnect`); + } } } },