feat(diag): full input logging + read barrel from pointerFlags; focal-jump reject
All checks were successful
CI / Windows build (push) Successful in 12m44s
All checks were successful
CI / Windows build (push) Successful in 12m44s
Buttons (likely fix + ground truth): device diag showed ptr=12577 pen=10056 — WM_POINTER reaches the observer and GetPointerPenInfo succeeds, so the buttons were just read from the wrong field. Native now resolves the barrel from BOTH penFlags(PEN_FLAG_BARREL) AND pointerInfo.pointerFlags(POINTER_FLAG_SECONDBUTTON) — many pens use the latter. It also emits the full raw set (pointerFlags, penFlags, penMask, ButtonChangeType, tilt) plus OR-accumulated flags so a single session reveals exactly which field each button sets. Comprehensive logging (per user request "用好用的log库 / 我手动开启日志再记录"): new DiagnosticLogger emits through dart:developer log(name 'badnote.input') — capturable via `flutter run` / DevTools / `flutter logs` — AND mirrors to a file (path shown in the overlay) for the packaged GUI build that has no console. Manually enabled by the toolbar diagnostic toggle; off by default. PEN lines log on raw-field change; ZOOM lines log every scale frame + rebaselines. Zoom: scale-only glitch rejection didn't stop the jumping, so add focal/position glitch rejection — drop a 2-finger frame whose focal jumps >250px (a touch misread). The full per-frame trace (raw scale, pointerCount, applied change, focal jump, drops) is now logged so the residual cause is unambiguous. InputDiagnostics singleton accumulates the stats; the overlay shows summary + last trace lines + log path + reset. Removed the ad-hoc inline zoom min/max. Dart: analyze clean, 66/66 tests, linux build green. Native compiles on CI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,8 @@ import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/physics.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'input_diagnostics.dart';
|
||||
|
||||
/// Devices allowed to pan/zoom. Stylus + invertedStylus are excluded so the pen
|
||||
/// is owned exclusively by the drawing `Listener`.
|
||||
const Set<PointerDeviceKind> _kPanZoomDevices = <PointerDeviceKind>{
|
||||
@@ -46,6 +48,11 @@ const Set<PointerDeviceKind> _kPanZoomDevices = <PointerDeviceKind>{
|
||||
const double _kScaleGlitchHi = 1.4;
|
||||
const double _kScaleGlitchLo = 1 / _kScaleGlitchHi;
|
||||
|
||||
/// During a 2-finger gesture the focal point (finger midpoint) should move
|
||||
/// smoothly. A single-frame local jump beyond this is a Windows touch misread,
|
||||
/// and the frame is dropped (position-jump guard).
|
||||
const double _kFocalGlitchPx = 250.0;
|
||||
|
||||
const double _kDrag = 0.0000135;
|
||||
|
||||
enum _GestureType { pan, scale }
|
||||
@@ -162,9 +169,11 @@ class _PenInteractiveViewerState extends State<PenInteractiveViewer>
|
||||
_lastPointerCount = details.pointerCount;
|
||||
_scaleStart = _transformer.value.getMaxScaleOnAxis();
|
||||
_referenceFocalPoint = _transformer.toScene(details.localFocalPoint);
|
||||
InputDiagnostics.instance.recordRebaseline();
|
||||
return;
|
||||
}
|
||||
|
||||
final double focalJumpPx = details.focalPointDelta.distance;
|
||||
final Offset focalPointScene = _transformer.toScene(details.localFocalPoint);
|
||||
|
||||
if (_gestureType == _GestureType.pan) {
|
||||
@@ -175,16 +184,36 @@ class _PenInteractiveViewerState extends State<PenInteractiveViewer>
|
||||
}
|
||||
if (!_gestureIsSupported(_gestureType)) return;
|
||||
|
||||
// Position-jump guard: during a pinch the focal midpoint should move
|
||||
// smoothly; a big single-frame jump is a touch misread → drop the frame.
|
||||
final bool focalDrop =
|
||||
details.pointerCount >= 2 && focalJumpPx > _kFocalGlitchPx;
|
||||
|
||||
void record(double appliedChange, bool scaleDrop, bool focalDropped) {
|
||||
InputDiagnostics.instance.recordScaleFrame(
|
||||
rawScale: details.scale,
|
||||
pointerCount: details.pointerCount,
|
||||
currentScale: scale,
|
||||
appliedChange: appliedChange,
|
||||
focalJumpPx: focalJumpPx,
|
||||
scaleDrop: scaleDrop,
|
||||
focalDrop: focalDropped,
|
||||
);
|
||||
}
|
||||
|
||||
switch (_gestureType!) {
|
||||
case _GestureType.scale:
|
||||
assert(_scaleStart != null);
|
||||
final double desiredScale = _scaleStart! * details.scale;
|
||||
final double scaleChange = desiredScale / scale;
|
||||
// Glitch rejection: drop a frame that demands an implausible per-frame
|
||||
// scale jump (a Windows multi-touch position glitch). The next good
|
||||
// frame resumes from the true finger positions, so the spike never
|
||||
// shows — unlike clamping, which still applied a visible partial jump.
|
||||
if (scaleChange > _kScaleGlitchHi || scaleChange < _kScaleGlitchLo) {
|
||||
// Drop a frame demanding an implausible per-frame scale jump (Windows
|
||||
// multi-touch glitch) OR an implausible focal jump. Absolute tracking
|
||||
// means the next good frame resumes from the true finger positions, so
|
||||
// the spike never shows.
|
||||
final bool scaleDrop =
|
||||
scaleChange > _kScaleGlitchHi || scaleChange < _kScaleGlitchLo;
|
||||
if (scaleDrop || focalDrop) {
|
||||
record(1.0, scaleDrop, focalDrop);
|
||||
return;
|
||||
}
|
||||
_transformer.value = _matrixScale(_transformer.value, scaleChange);
|
||||
@@ -203,16 +232,23 @@ class _PenInteractiveViewerState extends State<PenInteractiveViewer>
|
||||
if (_round(_referenceFocalPoint!) != _round(focalPointSceneCheck)) {
|
||||
_referenceFocalPoint = focalPointSceneCheck;
|
||||
}
|
||||
record(scaleChange, false, false);
|
||||
|
||||
case _GestureType.pan:
|
||||
assert(_referenceFocalPoint != null);
|
||||
// Throw away near-scale frames so a stale reference can't jump the pan.
|
||||
if (details.scale != 1.0) return;
|
||||
if (focalDrop) {
|
||||
_referenceFocalPoint = _transformer.toScene(details.localFocalPoint);
|
||||
record(1.0, false, true);
|
||||
return;
|
||||
}
|
||||
final Offset translationChange =
|
||||
focalPointScene - _referenceFocalPoint!;
|
||||
_transformer.value =
|
||||
_matrixTranslate(_transformer.value, translationChange);
|
||||
_referenceFocalPoint = _transformer.toScene(details.localFocalPoint);
|
||||
record(1.0, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user