Skip to content

fix(windows): recover tray and hooks after system sleep/hibernate#94

Merged
debugtheworldbot merged 7 commits intomainfrom
fix/windows-resume-recovery
Apr 3, 2026
Merged

fix(windows): recover tray and hooks after system sleep/hibernate#94
debugtheworldbot merged 7 commits intomainfrom
fix/windows-resume-recovery

Conversation

@debugtheworldbot
Copy link
Copy Markdown
Owner

Summary

  • Windows version becomes unresponsive after system hibernate/sleep: tray icon frozen, input monitoring stopped, no data recorded for the day
  • Add power event listener (SystemEvents.PowerModeChanged) and session switch listener to proactively recover hooks and tray
  • Handle Explorer taskbar recreation (TaskbarCreated message) to prevent orphaned tray icons

Changes

System event handling (App.xaml.cs)

  • Register PowerModeChanged / SessionSwitch event handlers
  • Flush pending stats before suspend, trigger full recovery after resume
  • HandleSystemResume() runs on background thread to avoid blocking UI
  • Add TaskbarCreatedWatcher (NativeWindow) to listen for Explorer taskbar recreation
  • Extract tray rebuild logic into RecreateTrayIntegration(), use named methods for event handlers

Input monitor recovery (InputMonitorService.cs)

  • Add HandleSystemResume() with retry logic (3 attempts × 750ms interval)
  • Refactor hook thread management: StartHookThread() / TryStopHookThread() / ResetTransientState()
  • Add 5s timeout to readyEvent.Wait, clean up thread state on failure
  • Watchdog now detects keyboard activity too (HasRecentKeyboardActivity), not just mouse movement
  • Rename _lastMouseHookTick_lastHookCallbackTick, update in both keyboard and mouse callbacks
  • Add lock protection for _pressedKeys to fix race condition with ResetTransientState

Date synchronization (StatsManager.cs)

  • Add HandleSystemResume() calling SynchronizeCurrentDay() + reschedule midnight timer
  • No longer depends on input events to trigger date switch
  • Add _midnightTimerLock to prevent race between resume recovery and midnight timer callback
  • Remove redundant SaveStats / SaveHistorySnapshot calls

Native API (NativeInterop.cs)

  • Add RegisterWindowMessage / GetAsyncKeyState P/Invoke declarations

Test plan

  • Short sleep (~1 min) then wake: tray responsive, data continues recording
  • Long hibernate (across days) then wake: date switches correctly, new day starts recording
  • Lock/unlock screen: hooks recover normally
  • Restart Explorer via Task Manager: tray icon auto-recreates
  • Normal exit: data saved completely

🤖 Generated with Claude Code

- Rename _lastMouseHookTick → _lastHookCallbackTick, update in keyboard hook callback too (prevents false watchdog reinstalls during keyboard-only use)
- Move StatsManager.HandleSystemResume to Task.Run (avoids blocking UI thread with sync file I/O)
- Remove redundant SaveStats/SaveHistorySnapshot calls in HandleSystemResume and SynchronizeCurrentDay
- Fix constructor double-save: only call UpdateNotificationBaselines+SaveStats when date hasn't changed
- Add _midnightTimerLock to prevent race between resume recovery and midnight timer callback
- Clean up hook thread on StartHookThread failure, use 'using' for ManualResetEventSlim
Copilot AI review requested due to automatic review settings April 3, 2026 07:39
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves Windows reliability after sleep/hibernate/lock/unlock by proactively recovering input hooks, resynchronizing daily stats, and rebuilding tray integration when Explorer restarts.

Changes:

  • Add Windows system event handlers (power/session) and a TaskbarCreated watcher to recreate tray integration after resume or Explorer restarts.
  • Add hook-thread restart/retry logic and broaden watchdog detection to include keyboard activity, plus additional transient-state resets for input monitoring.
  • Add stats “current day” synchronization on midnight and system resume, with a lock around midnight timer rescheduling.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
KeyStats.Windows/KeyStats/App.xaml.cs Register power/session handlers and TaskbarCreated watcher; rebuild tray integration on resume/Explorer restart.
KeyStats.Windows/KeyStats/Services/InputMonitorService.cs Add resume handling + hook recovery retries/timeouts; refactor hook thread lifecycle; expand watchdog signal sources.
KeyStats.Windows/KeyStats/Services/StatsManager.cs Centralize “current day” sync; reschedule midnight timer safely; add resume entry point.
KeyStats.Windows/KeyStats/Helpers/NativeInterop.cs Add RegisterWindowMessage P/Invoke for TaskbarCreated detection.
.agents/skills/posthog-cli-queries/SKILL.md Add agent “skill” documentation for querying PostHog via CLI/scripts.
.agents/skills/posthog-cli-queries/scripts/dashboard_list.sh Script to list PostHog dashboards using local credentials.
.agents/skills/posthog-cli-queries/scripts/dashboard_fetch.sh Script to fetch a PostHog dashboard JSON or a summary view.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread KeyStats.Windows/KeyStats/Services/StatsManager.cs
Comment thread KeyStats.Windows/KeyStats/Services/StatsManager.cs
Comment thread KeyStats.Windows/KeyStats/Services/InputMonitorService.cs
Comment thread KeyStats.Windows/KeyStats/Services/InputMonitorService.cs Outdated
Comment thread KeyStats.Windows/KeyStats/App.xaml.cs
Comment thread .agents/skills/posthog-cli-queries/SKILL.md
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new PostHog CLI skill for querying project data and enhances the Windows application's resilience to system events. Key improvements include handling power state changes (suspend/resume), session locks, and taskbar restarts to ensure the tray icon and input hooks remain functional. The InputMonitorService and StatsManager were refactored to support these recovery flows. Review feedback highlights opportunities to improve the robustness of JSON parsing in the dashboard script and to optimize performance by removing an unused, expensive history cloning operation.

Comment thread .agents/skills/posthog-cli-queries/scripts/dashboard_fetch.sh Outdated
Comment thread KeyStats.Windows/KeyStats/Services/StatsManager.cs Outdated
- Remove dead historySnapshot variable from SynchronizeCurrentDay
- Use TryStopHookThread in ReinstallHooks for consistent thread cleanup
- Narrow _pressedKeys lock scope: only guard HashSet.Add/Remove, keep GetKeyName and P/Invoke outside
- Replace DateTime _lastResumeRecoveryUtc with long ticks + Interlocked for thread-safe debounce
- Add null safety to jq result length in dashboard_fetch.sh
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread KeyStats.Windows/KeyStats/Services/InputMonitorService.cs
Comment thread KeyStats.Windows/KeyStats/Services/InputMonitorService.cs
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread KeyStats.Windows/KeyStats/Services/InputMonitorService.cs Outdated
Comment on lines +20 to +21
curl -fsS \
-H "Authorization: Bearer ${token}" \
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script passes the PostHog API token directly on the curl command line via -H "Authorization: Bearer ...", which can be exposed to other local users via process listings. Consider supplying headers via a temporary config/header file (e.g., curl --config / -H @file) or another mechanism that doesn’t put the token in argv.

Suggested change
curl -fsS \
-H "Authorization: Bearer ${token}" \
header_file="$(mktemp)"
trap 'rm -f "${header_file}"' EXIT
chmod 600 "${header_file}"
printf 'Authorization: Bearer %s\n' "${token}" > "${header_file}"
curl -fsS \
-H @"${header_file}" \

Copilot uses AI. Check for mistakes.
Comment on lines +26 to +28
response="$(
curl -fsS \
-H "Authorization: Bearer ${token}" \
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script passes the PostHog API token directly on the curl command line via -H "Authorization: Bearer ...", which can be exposed to other local users via process listings. Consider supplying headers via a temporary config/header file (e.g., curl --config / -H @file) or another mechanism that doesn’t put the token in argv.

Suggested change
response="$(
curl -fsS \
-H "Authorization: Bearer ${token}" \
header_file="$(mktemp)"
chmod 600 "${header_file}"
trap 'rm -f "${header_file}"' EXIT
printf 'Authorization: Bearer %s\n' "${token}" > "${header_file}"
response="$(
curl -fsS \
-H @"${header_file}" \

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@debugtheworldbot debugtheworldbot merged commit 3111af6 into main Apr 3, 2026
@debugtheworldbot debugtheworldbot deleted the fix/windows-resume-recovery branch April 3, 2026 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants