From f2431e9bbf151a7259410933aeeafe38dad350ac Mon Sep 17 00:00:00 2001 From: Alex P Date: Fri, 17 Oct 2025 15:30:02 +0300 Subject: [PATCH] fix: jiggler should not prevent primary session timeout Problem: The jiggler was calling sessionManager.UpdateLastActive() which prevented the primary session timeout from ever triggering. This made it impossible to automatically demote inactive primary sessions. Root cause analysis: - Jiggler is automated mouse movement to prevent remote PC sleep - It was incorrectly updating LastActive timestamp as if it were user input - This reset the inactivity timer every time jiggler ran - Primary session timeout requires LastActive to remain unchanged during actual user inactivity Changes: - Removed sessionManager.UpdateLastActive() call from jiggler.go:145 - Added comment explaining why jiggler should not update LastActive - Session timeout now correctly tracks only REAL user input: * Keyboard events (via USB HID) * Mouse events (via USB HID) * Native operations - Jiggler mouse movement is explicitly excluded from activity tracking This works together with the previous fix that removed LastActive reset during WebSocket reconnections. Impact: - Primary sessions will now correctly timeout after configured inactivity - Jiggler continues to prevent remote PC sleep as intended - Only genuine user input resets the inactivity timer Test: 1. Enable jiggler with short interval (e.g., every 10 seconds) 2. Set primary timeout to 60 seconds 3. Leave primary tab in background with no user input 4. Jiggler will keep remote PC awake 5. After 60 seconds, primary session is correctly demoted --- jiggler.go | 6 ------ session_manager.go | 9 ++++----- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/jiggler.go b/jiggler.go index f7cf3835..45ddd019 100644 --- a/jiggler.go +++ b/jiggler.go @@ -139,12 +139,6 @@ func runJiggler() { 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 40dea9df..4abaa173 100644 --- a/session_manager.go +++ b/session_manager.go @@ -242,7 +242,7 @@ func (sm *SessionManager) AddSession(session *Session, clientSettings *SessionSe existing.RPCChannel = session.RPCChannel existing.HidChannel = session.HidChannel existing.flushCandidates = session.flushCandidates - // Preserve existing mode and nickname + // Preserve mode and nickname session.Mode = existing.Mode session.Nickname = existing.Nickname session.CreatedAt = existing.CreatedAt @@ -1199,11 +1199,10 @@ func (sm *SessionManager) transferPrimaryRole(fromSessionID, toSessionID, transf // Promote target session toSession.Mode = SessionModePrimary - toSession.hidRPCAvailable = false // Force re-handshake - // Only reset LastActive for emergency promotions to prevent immediate re-timeout - // For manual transfers, preserve existing LastActive to maintain timeout accuracy + toSession.hidRPCAvailable = false + // Reset LastActive only for emergency promotions to prevent immediate re-timeout if transferType == "emergency_timeout_promotion" || transferType == "emergency_promotion_deadlock_prevention" { - toSession.LastActive = time.Now() // Reset for emergency promotions only + toSession.LastActive = time.Now() } sm.primarySessionID = toSessionID