@@ -297,6 +297,9 @@ private void GoosePublisherRow_PreviewMouseLeftButtonDown(object sender, MouseBu
297297 sender is not ListViewItem { DataContext : ProcessBus . Core . Presentation . GoosePublisherRow row } )
298298 return ;
299299
300+ // This click ACKs exactly this physical publisher's decoded signal changes.
301+ // Modifier/range selection never ACKs any other source in the set.
302+ vm . AcknowledgeGooseSource ( row . Key ) ;
300303 var next = vm . SelectedGooseSourceKeys . ToHashSet ( ) ;
301304 var modifiers = Keyboard . Modifiers ;
302305 var shift = modifiers . HasFlag ( ModifierKeys . Shift ) ;
@@ -347,10 +350,12 @@ private void GooseSourceList_SelectionChanged(object sender, SelectionChangedEve
347350
348351 private void GooseSourceList_PreviewKeyDown ( object sender , KeyEventArgs e )
349352 {
350- if ( e . Key != Key . Space || DataContext is not MainWindowViewModel vm ||
351- GooseSourceList . ItemContainerGenerator . ContainerFromItem ( GooseSourceList . SelectedItem ) is not ListViewItem ||
353+ if ( e . Key is not ( Key . Space or Key . Enter ) || DataContext is not MainWindowViewModel vm ||
352354 GooseSourceList . SelectedItem is not ProcessBus . Core . Presentation . GoosePublisherRow row )
353355 return ;
356+ // Space toggles membership and ACKs; Enter ACKs the focused source only.
357+ vm . AcknowledgeGooseSource ( row . Key ) ;
358+ if ( e . Key == Key . Enter ) { e . Handled = true ; return ; }
354359 var next = vm . SelectedGooseSourceKeys . ToHashSet ( ) ;
355360 if ( ! next . Add ( row . Key ) ) next . Remove ( row . Key ) ;
356361 vm . SetGooseSourceSelection ( next ) ;
@@ -381,6 +386,21 @@ private void GooseTraffic_ClickInteraction(object sender, MouseButtonEventArgs e
381386 {
382387 SuspendGooseFollowFromOperator ( ) ;
383388 DeferGooseTrafficFlush ( ) ;
389+ if ( e . ChangedButton != MouseButton . Left ) return ;
390+
391+ // ACK only the row that was actually clicked, not the selected item in
392+ // the VM: that item may still reference an earlier pinned history event.
393+ // Never ACK all rows, nor ACK on passive streaming/virtualized recycling.
394+ for ( var node = e . OriginalSource as DependencyObject ;
395+ node is not null && ! ReferenceEquals ( node , GooseMessageGrid ) ;
396+ node = VisualTreeHelper . GetParent ( node ) )
397+ {
398+ if ( node is DataGridRow { DataContext : GooseTrafficRow history } )
399+ {
400+ history . Acknowledge ( ) ;
401+ return ;
402+ }
403+ }
384404 }
385405
386406 private bool _gooseFollowScrollScheduled ;
@@ -406,8 +426,17 @@ private void GooseMessageGrid_PreviewTouchDown(object sender, TouchEventArgs e)
406426 private void GooseMessageGrid_PreviewKeyDown ( object sender , KeyEventArgs e )
407427 {
408428 if ( e . Key is Key . Up or Key . Down or Key . Home or Key . End or
409- Key . PageUp or Key . PageDown or Key . Space or Key . Left or Key . Right )
429+ Key . PageUp or Key . PageDown or Key . Space or Key . Left or Key . Right or Key . Enter )
410430 SuspendGooseFollowFromOperator ( ) ;
431+
432+ // Accessible keyboard acknowledgement of the explicitly focused event.
433+ // Directional navigation suspends follow but does not ACK history.
434+ if ( e . Key is Key . Enter or Key . Space &&
435+ GooseMessageGrid . SelectedItem is GooseTrafficRow selected )
436+ {
437+ selected . Acknowledge ( ) ;
438+ e . Handled = true ;
439+ }
411440 }
412441
413442 private static T ? FindGooseVisualChild < T > ( DependencyObject root ) where T : DependencyObject
0 commit comments