Skip to content

feat(diagnostic): add read-only Windows idle and injection comparison - #90

Merged
ErikBjare merged 5 commits into
ActivityWatch:masterfrom
TimeToBuildBob:feat/windows-input-diagnostic
Oct 26, 2026
Merged

ErikBjare merged 5 commits into
ActivityWatch:masterfrom
TimeToBuildBob:feat/windows-input-diagnostic

Conversation

@TimeToBuildBob

@TimeToBuildBob TimeToBuildBob commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Problem

ActivityWatch/activitywatch#1487 reports a Bluetooth controller keeping Windows AFK status active while untouched. Windows uses GetLastInputInfo, not the pynput listener backend; a listener-only filter would not address it. The event source remains unknown.

Scope

Adds a standalone, opt-in, standard-library-only Windows diagnostic and comparison procedure. It samples Windows idle time and aggregate mouse/keyboard injection flags without recording keys, text, coordinates, window titles, device IDs or raw event timestamps. Hooks forward events and clean up on exit and partial failure. Ctrl+C inside observation is deferred until input has been forwarded.

No production backend/config changes, blanket injected-input filtering, or controller-causality claim. Unflagged does not prove physical input; missing counts do not prove no activity. Documentation covers coverage and correlation limits.

Verification

  • xvfb-run -a make test: 22 existing AFK tests + 14 diagnostic tests passed; package typecheck passed.
  • mypy --platform win32 misc/windows_input_diagnostic.py --ignore-missing-imports: passed.
  • ruff check and git diff --check: passed.
  • Independent native-ABI/privacy/lifecycle review; repaired callback cancellation defect with a failing-then-passing test.
  • Hook callback failures are contained, never escaping the ctypes boundary: classification exceptions, an interrupt raised on the pass-through call's return, and any other pass-through failure are all deferred and surfaced on the next state check, including after the final sample.
  • Unrestricted unittest discovery reaches an existing live-server test requiring localhost:5666; unavailable locally. No all-suite pass claimed.

Windows execution and reporter reproduction are unverified. API doubles test lifecycle control flow, not native ABI or hook delivery. The connected-idle/disconnected-idle procedure in docs/windows-input-diagnostic.md is the next evidence gate.

Related to ActivityWatch/activitywatch#1487; does not close the production issue.

@greptile-apps

greptile-apps Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Low risk] Adds a read-only Windows diagnostic tool and documentation.

The PR appears safe to merge based on the reviewed changes.

Summary

This PR adds an opt-in Windows diagnostic that compares idle time with aggregate keyboard and mouse injection flags without changing AFK behavior.

  • Documents a connected-versus-disconnected controller comparison and the limits of what hook counts can establish.
  • Adds lifecycle and event-aggregation tests to the default test target.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  W[Windows idle API] --> S[Interval sample]
  H[Keyboard and mouse hooks] --> C[Aggregate flag counts]
  C --> S
  S --> J[JSONL diagnostic output]
  J --> U[User compares idle periods]
Loading

Reviews (3) · Last reviewed commit: "test(diagnostic): drive message loop wit..."

Comment thread tests/test_windows_input_diagnostic.py
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

CI-green and mergeable — waiting only on a maintainer click.

This PR is ready to merge, but the bot has pull-only access to this repo and can't self-merge — surfacing it here so it isn't lost. The monitoring loop will stop re-flagging it now that this note is posted.

Git-Session-Id: 61f5bd6e-e4de-5673-8b22-b8816c300ba4
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

@greptileai review

@TimeToBuildBob

TimeToBuildBob commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor Author

🤖 AI code review

Adds a standalone Windows diagnostic that samples GetLastInputInfo and counts low-level mouse and keyboard events by injection flags. Includes hook lifecycle handling, JSON output, a comparison procedure, and unit tests with native API doubles. The production AFK backend is unchanged.

Safe to merge — no P0/P1 findings

Confidence 5/5

✅ No findings. The diff looks correct to me on this pass.

Files changed (5) — the diff as I read it
  • Makefile — Adds discovery of test_windows_input_diagnostic.py to the test target.
  • README.md — Adds a Windows unexpected input diagnostic section linking to the comparison documentation.
  • docs/windows-input-diagnostic.md — Documents execution, controller comparison steps, JSON fields, injection flag interpretation, and observation limits.
  • misc/windows_input_diagnostic.py — Adds flag classification, interval counters, idle sampling, Windows hook installation and cleanup, deferred callback errors, and a duration-bounded CLI.
  • tests/test_windows_input_diagnostic.py — Adds tests for classification, wraparound, interval aggregation, hook cleanup, callback failures, cancellation, and event delivery using native API doubles.
Previous review passes
commit score findings engine when
8a10896c647f 4/5 1 subscription 2026-10-03 20:23 UTC
d3f87a063a28 4/5 1 subscription 2026-10-03 21:24 UTC
a202201ab311 3/5 3 llm 2026-10-03 23:22 UTC
08305cf8d281 5/5 0 subscription 2026-10-04 00:28 UTC
08305cf8d281 5/5 0 subscription 2026-10-09 06:52 UTC
08305cf8d281 5/5 0 subscription 2026-10-09 07:27 UTC
08305cf8d281 5/5 0 subscription 2026-10-09 08:21 UTC
08305cf8d281 4/5 1 llm 2026-10-09 09:03 UTC

Reviewed 08305cf8d281 · panel: codex:gpt-6.1-sol · subscription engine · 67s · about this reviewer

Maintainer commands

@TimeToBuildBob review (own line) — fresh review · @TimeToBuildBob fix — a worker acts on the findings. Once per comment; 👀 = received.

Comment thread tests/test_windows_input_diagnostic.py
The mocked native lifecycle tests relied on the real time.monotonic()
deadline, so a scheduler pause of one second could skip GetMessageW
entirely and truncate event delivery on a loaded runner. Advance a
controlled fake clock per mocked GetMessageW call instead.

Git-Session-Id: 689bf8d3-ae0f-5bcf-b0e2-a6399b681ba5
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

@greptileai review

Comment thread misc/windows_input_diagnostic.py Outdated
CallNextHookEx sits outside the KeyboardInterrupt handler, so a pending
Ctrl+C surfacing on that call's return escaped the ctypes callback
boundary: ctypes ignored the exception, the diagnostic never set
interrupted (so it kept running with hooks installed), and the pass-through
result was lost. Wrap the call so cancellation is deferred and the callback
always returns a value.

Adds a regression test asserting the callback contains the interrupt
instead of letting it escape.

Git-Session-Id: f4b686bd-39f5-56c8-8982-8f943d7c1e8c
Comment thread misc/windows_input_diagnostic.py
Comment thread misc/windows_input_diagnostic.py
…llback errors

Git-Session-Id: 1c1575e9-20b0-5b4a-8619-10e44219442e
Comment thread misc/windows_input_diagnostic.py
@ErikBjare
ErikBjare merged commit b483926 into ActivityWatch:master Oct 26, 2026
3 checks passed
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