From e1194be3c26a188c6e67090a3cd1b9e40271fa5d Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Tue, 2 Jun 2026 12:21:58 -0400 Subject: [PATCH] Add emit-on-change tracker for the Windows polling sensor --- internal/evidence/foreground_tracker.go | 21 ++++++++++++++ internal/evidence/foreground_tracker_test.go | 29 ++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 internal/evidence/foreground_tracker.go create mode 100644 internal/evidence/foreground_tracker_test.go diff --git a/internal/evidence/foreground_tracker.go b/internal/evidence/foreground_tracker.go new file mode 100644 index 0000000..7afcbdb --- /dev/null +++ b/internal/evidence/foreground_tracker.go @@ -0,0 +1,21 @@ +package evidence + +// foregroundTracker remembers the last observed foreground window so the +// Windows polling Source emits only on change. hwnd is held as uintptr so this +// file stays platform-neutral (it must build and test on Linux). +type foregroundTracker struct { + primed bool + available bool + hwnd uintptr + title string +} + +// changed reports whether (available, hwnd, title) differs from the last +// observation and records the new values. The first call always returns true. +func (t *foregroundTracker) changed(available bool, hwnd uintptr, title string) bool { + if t.primed && available == t.available && hwnd == t.hwnd && title == t.title { + return false + } + t.primed, t.available, t.hwnd, t.title = true, available, hwnd, title + return true +} diff --git a/internal/evidence/foreground_tracker_test.go b/internal/evidence/foreground_tracker_test.go new file mode 100644 index 0000000..b664238 --- /dev/null +++ b/internal/evidence/foreground_tracker_test.go @@ -0,0 +1,29 @@ +package evidence + +import "testing" + +func TestForegroundTrackerChanged(t *testing.T) { + var tr foregroundTracker + + if !tr.changed(true, 100, "A") { + t.Fatal("first observation should always report changed") + } + if tr.changed(true, 100, "A") { + t.Error("identical observation should not report changed") + } + if !tr.changed(true, 100, "B") { + t.Error("title change on same hwnd should report changed") + } + if !tr.changed(true, 200, "B") { + t.Error("hwnd change should report changed") + } + if !tr.changed(false, 0, "") { + t.Error("transition to unavailable should report changed") + } + if tr.changed(false, 0, "") { + t.Error("repeated unavailable should not report changed") + } + if !tr.changed(true, 200, "B") { + t.Error("transition back to available should report changed") + } +}