using Ink_Canvas.Helpers; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using Point = System.Windows.Point; namespace Ink_Canvas { public partial class MainWindow : Window { #region Multi-Touch private bool isInMultiTouchMode; private List dec = new List(); private bool isSingleFingerDragMode; private Point centerPoint = new Point(0, 0); private InkCanvasEditingMode lastInkCanvasEditingMode = InkCanvasEditingMode.Ink; /// /// 保存画布上的非笔画元素(如图片、媒体元素等) /// private List PreserveNonStrokeElements() { var preservedElements = new List(); // 遍历inkCanvas的所有子元素 for (int i = inkCanvas.Children.Count - 1; i >= 0; i--) { var child = inkCanvas.Children[i]; // 保存图片、媒体元素等非笔画相关的UI元素 if (child is Image || child is MediaElement || (child is Border border && border.Name != "AdvancedEraserOverlay")) { preservedElements.Add(child); } } return preservedElements; } /// /// 恢复之前保存的非笔画元素到画布 /// private void RestoreNonStrokeElements(List preservedElements) { if (preservedElements == null) return; foreach (var element in preservedElements) { // 确保元素没有父容器再添加到inkCanvas if (element is FrameworkElement fe && fe.Parent == null) { inkCanvas.Children.Add(element); } } } private void BorderMultiTouchMode_MouseUp(object sender, MouseButtonEventArgs e) { if (isInMultiTouchMode) { inkCanvas.StylusDown -= MainWindow_StylusDown; inkCanvas.StylusMove -= MainWindow_StylusMove; inkCanvas.StylusUp -= MainWindow_StylusUp; inkCanvas.TouchDown -= MainWindow_TouchDown; inkCanvas.TouchDown += Main_Grid_TouchDown; if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke) { inkCanvas.EditingMode = InkCanvasEditingMode.Ink; } // 保存非笔画元素(如图片) var preservedElements = PreserveNonStrokeElements(); inkCanvas.Children.Clear(); // 恢复非笔画元素 RestoreNonStrokeElements(preservedElements); isInMultiTouchMode = false; } else { inkCanvas.StylusDown += MainWindow_StylusDown; inkCanvas.StylusMove += MainWindow_StylusMove; inkCanvas.StylusUp += MainWindow_StylusUp; inkCanvas.TouchDown += MainWindow_TouchDown; inkCanvas.TouchDown -= Main_Grid_TouchDown; if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke) { inkCanvas.EditingMode = InkCanvasEditingMode.None; } // 保存非笔画元素(如图片) var preservedElements = PreserveNonStrokeElements(); inkCanvas.Children.Clear(); // 恢复非笔画元素 RestoreNonStrokeElements(preservedElements); isInMultiTouchMode = true; } } private void MainWindow_TouchDown(object sender, TouchEventArgs e) { if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint || inkCanvas.EditingMode == InkCanvasEditingMode.EraseByStroke || inkCanvas.EditingMode == InkCanvasEditingMode.Select) return; if (!isHidingSubPanelsWhenInking) { isHidingSubPanelsWhenInking = true; HideSubPanels(); // 书写时自动隐藏二级菜单 } // 修复:几何绘制模式下完全禁止触摸轨迹收集 if (drawingShapeMode != 0) { // 确保几何绘制模式下不切换到Ink模式,避免触摸轨迹被收集 inkCanvas.EditingMode = InkCanvasEditingMode.None; return; } // 只保留普通橡皮逻辑 TouchDownPointsList[e.TouchDevice.Id] = InkCanvasEditingMode.None; inkCanvas.EraserShape = new EllipseStylusShape(50, 50); if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke) { inkCanvas.EditingMode = InkCanvasEditingMode.None; } } private void MainWindow_StylusDown(object sender, StylusDownEventArgs e) { // 新增:根据是否为笔尾自动切换橡皮擦/画笔模式 if (e.StylusDevice.Inverted) { inkCanvas.EditingMode = InkCanvasEditingMode.EraseByPoint; } else { // 修复:几何绘制模式下完全禁止触摸轨迹收集 if (drawingShapeMode != 0) { // 确保几何绘制模式下不切换到Ink模式,避免触摸轨迹被收集 inkCanvas.EditingMode = InkCanvasEditingMode.None; return; } // 修复:保持当前的线擦模式,不要强制切换到Ink模式 if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke) { inkCanvas.EditingMode = InkCanvasEditingMode.Ink; } } SetCursorBasedOnEditingMode(inkCanvas); inkCanvas.CaptureStylus(); ViewboxFloatingBar.IsHitTestVisible = false; BlackboardUIGridForInkReplay.IsHitTestVisible = false; // 确保手写笔模式下显示光标 if (Settings.Canvas.IsShowCursor) { inkCanvas.ForceCursor = true; inkCanvas.UseCustomCursor = true; // 根据当前编辑模式设置不同的光标 if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint) { inkCanvas.Cursor = Cursors.Cross; } else if (inkCanvas.EditingMode == InkCanvasEditingMode.Ink) { var sri = Application.GetResourceStream(new Uri("Resources/Cursors/Pen.cur", UriKind.Relative)); if (sri != null) inkCanvas.Cursor = new Cursor(sri.Stream); } // 强制显示光标 System.Windows.Forms.Cursor.Show(); } if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint || inkCanvas.EditingMode == InkCanvasEditingMode.EraseByStroke || inkCanvas.EditingMode == InkCanvasEditingMode.Select) return; TouchDownPointsList[e.StylusDevice.Id] = InkCanvasEditingMode.None; } private async void MainWindow_StylusUp(object sender, StylusEventArgs e) { try { inkCanvas.Strokes.Add(GetStrokeVisual(e.StylusDevice.Id).Stroke); await Task.Delay(5); // 避免渲染墨迹完成前预览墨迹被删除导致墨迹闪烁 inkCanvas.Children.Remove(GetVisualCanvas(e.StylusDevice.Id)); inkCanvas_StrokeCollected(inkCanvas, new InkCanvasStrokeCollectedEventArgs(GetStrokeVisual(e.StylusDevice.Id).Stroke)); } catch (Exception ex) { Label.Content = ex.ToString(); } try { StrokeVisualList.Remove(e.StylusDevice.Id); VisualCanvasList.Remove(e.StylusDevice.Id); TouchDownPointsList.Remove(e.StylusDevice.Id); if (StrokeVisualList.Count == 0 || VisualCanvasList.Count == 0 || TouchDownPointsList.Count == 0) { // 只清除手写笔预览相关的Canvas,不清除所有子元素 foreach (var canvas in VisualCanvasList.Values.ToList()) { if (inkCanvas.Children.Contains(canvas)) { inkCanvas.Children.Remove(canvas); } } StrokeVisualList.Clear(); VisualCanvasList.Clear(); TouchDownPointsList.Clear(); } } catch { } inkCanvas.ReleaseStylusCapture(); ViewboxFloatingBar.IsHitTestVisible = true; BlackboardUIGridForInkReplay.IsHitTestVisible = true; } private void MainWindow_StylusMove(object sender, StylusEventArgs e) { try { if (GetTouchDownPointsList(e.StylusDevice.Id) != InkCanvasEditingMode.None) return; try { if (e.StylusDevice.StylusButtons[1].StylusButtonState == StylusButtonState.Down) return; } catch { } // 确保手写笔移动时光标保持可见 if (Settings.Canvas.IsShowCursor) { inkCanvas.ForceCursor = true; inkCanvas.UseCustomCursor = true; System.Windows.Forms.Cursor.Show(); } var strokeVisual = GetStrokeVisual(e.StylusDevice.Id); var stylusPointCollection = e.GetStylusPoints(this); foreach (var stylusPoint in stylusPointCollection) strokeVisual.Add(new StylusPoint(stylusPoint.X, stylusPoint.Y, stylusPoint.PressureFactor)); strokeVisual.Redraw(); } catch { } } private StrokeVisual GetStrokeVisual(int id) { if (StrokeVisualList.TryGetValue(id, out var visual)) return visual; var strokeVisual = new StrokeVisual(inkCanvas.DefaultDrawingAttributes.Clone()); StrokeVisualList[id] = strokeVisual; StrokeVisualList[id] = strokeVisual; var visualCanvas = new VisualCanvas(strokeVisual); VisualCanvasList[id] = visualCanvas; inkCanvas.Children.Add(visualCanvas); return strokeVisual; } private VisualCanvas GetVisualCanvas(int id) { return VisualCanvasList.TryGetValue(id, out var visualCanvas) ? visualCanvas : null; } private InkCanvasEditingMode GetTouchDownPointsList(int id) { return TouchDownPointsList.TryGetValue(id, out var inkCanvasEditingMode) ? inkCanvasEditingMode : inkCanvas.EditingMode; } private Dictionary TouchDownPointsList { get; } = new Dictionary(); private Dictionary StrokeVisualList { get; } = new Dictionary(); private Dictionary VisualCanvasList { get; } = new Dictionary(); #endregion private int lastTouchDownTime = 0, lastTouchUpTime = 0; private Point iniP = new Point(0, 0); private void Main_Grid_TouchDown(object sender, TouchEventArgs e) { SetCursorBasedOnEditingMode(inkCanvas); inkCanvas.CaptureTouch(e.TouchDevice); if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint) { // 橡皮状态下只return,保证橡皮状态可保持 return; } if (inkCanvas.EditingMode == InkCanvasEditingMode.Select) { // 套索选状态下只return,保证套索选可用 return; } // 修复:几何绘制模式下完全禁止触摸轨迹收集 if (drawingShapeMode != 0) { // 确保几何绘制模式下不切换到Ink模式,避免触摸轨迹被收集 inkCanvas.EditingMode = InkCanvasEditingMode.None; return; } if (inkCanvas.EditingMode == InkCanvasEditingMode.Ink) { return; } if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByStroke) { return; } if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke) { inkCanvas.EditingMode = InkCanvasEditingMode.Ink; } } // 手掌擦相关变量 private bool isPalmEraserActive; private InkCanvasEditingMode palmEraserLastEditingMode = InkCanvasEditingMode.Ink; private bool palmEraserLastIsHighlighter; private bool palmEraserWasEnabledBeforeMultiTouch; private bool palmEraserTouchDownHandled = false; // 新增:标记手掌擦触摸按下是否已处理 private DateTime palmEraserActivationTime; // 新增:记录手掌擦激活时间 private const int PALM_ERASER_TIMEOUT_MS = 5000; // 新增:手掌擦超时时间(5秒) private System.Windows.Threading.DispatcherTimer palmEraserRecoveryTimer; // 新增:手掌擦恢复定时器 private void inkCanvas_PreviewTouchDown(object sender, TouchEventArgs e) { // 橡皮状态下不做任何切换,直接return,保证橡皮可持续 if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint || inkCanvas.EditingMode == InkCanvasEditingMode.EraseByStroke) { return; } // 修复:几何绘制模式下完全禁止触摸轨迹收集 if (drawingShapeMode != 0) { // 确保几何绘制模式下不切换到Ink模式,避免触摸轨迹收集 inkCanvas.EditingMode = InkCanvasEditingMode.None; // 几何绘制模式下不记录触摸点,避免触摸轨迹被收集 SetCursorBasedOnEditingMode(inkCanvas); inkCanvas.CaptureTouch(e.TouchDevice); ViewboxFloatingBar.IsHitTestVisible = false; BlackboardUIGridForInkReplay.IsHitTestVisible = false; // 修复:几何绘制模式下,只记录几何绘制的起点,不记录触摸轨迹 if (dec.Count == 0) { var touchPoint = e.GetTouchPoint(inkCanvas); // 对于双曲线绘制,第一笔时记录起点,第二笔时不更新起点 if (drawingShapeMode == 24 || drawingShapeMode == 25) { // 双曲线绘制:第一笔记录起点,第二笔保持第一笔的起点 if (drawMultiStepShapeCurrentStep == 0) { iniP = touchPoint.Position; } // 第二笔时不更新iniP,保持第一笔的起点 } else { // 其他图形正常记录起点 iniP = touchPoint.Position; } lastTouchDownStrokeCollection = inkCanvas.Strokes.Clone(); } dec.Add(e.TouchDevice.Id); return; } // 非几何绘制模式下的正常触摸处理 SetCursorBasedOnEditingMode(inkCanvas); inkCanvas.CaptureTouch(e.TouchDevice); ViewboxFloatingBar.IsHitTestVisible = false; BlackboardUIGridForInkReplay.IsHitTestVisible = false; dec.Add(e.TouchDevice.Id); // Palm Eraser 逻辑 - 修复:只在触摸按下时处理一次,避免重复触发 if (Settings.Canvas.EnablePalmEraser && dec.Count >= 2 && !isPalmEraserActive && !palmEraserTouchDownHandled) { var bounds = e.GetTouchPoint(inkCanvas).Bounds; double palmThreshold = 40; // 触摸面积阈值,可根据实际调整 if (bounds.Width >= palmThreshold || bounds.Height >= palmThreshold) { // 记录当前编辑模式和高光状态 palmEraserLastEditingMode = inkCanvas.EditingMode; palmEraserLastIsHighlighter = drawingAttributes.IsHighlighter; // 切换为橡皮擦 EraserIcon_Click(null, null); isPalmEraserActive = true; palmEraserActivationTime = DateTime.Now; // 记录激活时间 palmEraserTouchDownHandled = true; // 标记已处理 // 启动恢复定时器,防止卡死 StartPalmEraserRecoveryTimer(); } } // 设备1个的时候,记录中心点 if (dec.Count == 1) { var touchPoint = e.GetTouchPoint(inkCanvas); centerPoint = touchPoint.Position; // 修复:只允许在此处赋值iniP,防止TouchMove等其他地方覆盖,保证几何绘制起点一致 if (drawingShapeMode != 0) { // 对于双曲线绘制,第一笔时记录起点,第二笔时不更新起点 if (drawingShapeMode == 24 || drawingShapeMode == 25) { // 双曲线绘制:第一笔记录起点,第二笔保持第一笔的起点 if (drawMultiStepShapeCurrentStep == 0) { iniP = touchPoint.Position; } // 第二笔时不更新iniP,保持第一笔的起点 } else { // 其他图形正常记录起点 iniP = touchPoint.Position; } } // 记录第一根手指点击时的 StrokeCollection lastTouchDownStrokeCollection = inkCanvas.Strokes.Clone(); } //设备两个及两个以上,将画笔功能关闭 if (dec.Count > 1 || isSingleFingerDragMode || !Settings.Gesture.IsEnableTwoFingerGesture) { if (isInMultiTouchMode || !Settings.Gesture.IsEnableTwoFingerGesture) return; if (inkCanvas.EditingMode == InkCanvasEditingMode.None || inkCanvas.EditingMode == InkCanvasEditingMode.Select) return; lastInkCanvasEditingMode = inkCanvas.EditingMode; // 修复:几何绘制模式下禁止切回Ink if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke && drawingShapeMode == 0) { inkCanvas.EditingMode = InkCanvasEditingMode.None; } } } private void inkCanvas_PreviewTouchUp(object sender, TouchEventArgs e) { // 橡皮状态下不做任何切换,直接return,保证橡皮可持续 if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint && !isPalmEraserActive) { return; } inkCanvas.ReleaseAllTouchCaptures(); ViewboxFloatingBar.IsHitTestVisible = true; BlackboardUIGridForInkReplay.IsHitTestVisible = true; // Palm Eraser 逻辑:所有点抬起后恢复原编辑模式 dec.Remove(e.TouchDevice.Id); if (isPalmEraserActive && dec.Count == 0) { // 恢复高光状态 drawingAttributes.IsHighlighter = palmEraserLastIsHighlighter; // 恢复编辑模式 - 修复:确保正确恢复状态 try { if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint) { if (palmEraserLastEditingMode == InkCanvasEditingMode.Ink) { PenIcon_Click(null, null); } else if (palmEraserLastEditingMode == InkCanvasEditingMode.Select) { SymbolIconSelect_MouseUp(null, null); } else { inkCanvas.EditingMode = palmEraserLastEditingMode; } } } catch (Exception ex) { // 如果恢复失败,强制切换到批注模式 Trace.WriteLine($"Palm eraser recovery failed: {ex.Message}, forcing to Ink mode"); inkCanvas.EditingMode = InkCanvasEditingMode.Ink; } // 重置手掌擦状态 isPalmEraserActive = false; palmEraserTouchDownHandled = false; // 停止恢复定时器 StopPalmEraserRecoveryTimer(); // 确保触摸事件能正常响应 inkCanvas.IsHitTestVisible = true; inkCanvas.IsManipulationEnabled = true; } // 新增:超时检测 - 如果手掌擦激活时间过长,强制重置状态 if (isPalmEraserActive && dec.Count == 0) { var timeSinceActivation = DateTime.Now - palmEraserActivationTime; if (timeSinceActivation.TotalMilliseconds > PALM_ERASER_TIMEOUT_MS) { Trace.WriteLine($"Palm eraser timeout detected ({timeSinceActivation.TotalMilliseconds}ms), forcing recovery"); // 强制恢复状态 try { if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint) { if (palmEraserLastEditingMode == InkCanvasEditingMode.Ink) { PenIcon_Click(null, null); } else if (palmEraserLastEditingMode == InkCanvasEditingMode.Select) { SymbolIconSelect_MouseUp(null, null); } else { inkCanvas.EditingMode = palmEraserLastEditingMode; } } } catch (Exception ex) { Trace.WriteLine($"Palm eraser timeout recovery failed: {ex.Message}, forcing to Ink mode"); inkCanvas.EditingMode = InkCanvasEditingMode.Ink; } // 重置所有手掌擦状态 isPalmEraserActive = false; palmEraserTouchDownHandled = false; inkCanvas.IsHitTestVisible = true; inkCanvas.IsManipulationEnabled = true; // 停止恢复定时器 StopPalmEraserRecoveryTimer(); } } // 修复:几何绘制模式下,触摸抬手时应该正确处理,而不是简单模拟鼠标事件 if (drawingShapeMode != 0) { // 对于双曲线等需要多步绘制的图形,触摸抬手时应该进入下一步 if (drawingShapeMode == 24 || drawingShapeMode == 25) { // 双曲线绘制:触摸抬手时进入下一步,但不自动触发鼠标抬起事件 // 让用户继续绘制第二笔 if (drawMultiStepShapeCurrentStep == 0) { // 第一笔完成,进入第二笔 drawMultiStepShapeCurrentStep = 1; } else { // 第二笔完成,完成绘制 var mouseArgs = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = MouseLeftButtonUpEvent, Source = inkCanvas }; inkCanvas_MouseUp(inkCanvas, mouseArgs); } } else { // 其他单步绘制的图形,触摸抬手时完成绘制 var mouseArgs = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = MouseLeftButtonUpEvent, Source = inkCanvas }; inkCanvas_MouseUp(inkCanvas, mouseArgs); } } // 手势完成后切回之前的状态 if (drawingShapeMode == 0) { if (dec.Count > 1) { if (inkCanvas.EditingMode == InkCanvasEditingMode.None) { if (lastInkCanvasEditingMode != InkCanvasEditingMode.EraseByPoint) { inkCanvas.EditingMode = lastInkCanvasEditingMode; } } } else if (dec.Count == 0) { // 当所有触摸点都抬起时,确保正确恢复编辑模式 // 这对于从橡皮擦切换到笔后恢复多指手势功能很重要 if (inkCanvas.EditingMode == InkCanvasEditingMode.None && lastInkCanvasEditingMode != InkCanvasEditingMode.None && lastInkCanvasEditingMode != InkCanvasEditingMode.EraseByPoint) { inkCanvas.EditingMode = lastInkCanvasEditingMode; } // 修复:确保手掌擦除后触摸事件能正常响应 if (isPalmEraserActive) { // 如果手掌擦还在激活状态但触摸点已清空,强制重置状态 isPalmEraserActive = false; palmEraserTouchDownHandled = false; inkCanvas.IsHitTestVisible = true; inkCanvas.IsManipulationEnabled = true; } } } inkCanvas.Opacity = 1; if (dec.Count == 0) if (lastTouchDownStrokeCollection.Count() != inkCanvas.Strokes.Count() && !(drawingShapeMode == 9 && !isFirstTouchCuboid)) { var whiteboardIndex = CurrentWhiteboardIndex; if (currentMode == 0) whiteboardIndex = 0; strokeCollections[whiteboardIndex] = lastTouchDownStrokeCollection; } } private void inkCanvas_ManipulationStarting(object sender, ManipulationStartingEventArgs e) { e.Mode = ManipulationModes.All; } private void inkCanvas_ManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e) { } private void Main_Grid_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { if (e.Manipulators.Count() != 0) return; // 修复:几何绘制模式下不自动切换到Ink模式,避免触摸轨迹被收集 if (drawingShapeMode == 0 && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke) { inkCanvas.EditingMode = InkCanvasEditingMode.Ink; // 修复:确保多指手势完成后正确更新lastInkCanvasEditingMode lastInkCanvasEditingMode = InkCanvasEditingMode.Ink; } } private void Main_Grid_ManipulationDelta(object sender, ManipulationDeltaEventArgs e) { // 手掌擦时禁止移动/缩放 if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint) return; // 三指及以上禁止缩放 bool disableScale = dec.Count >= 3; if (isInMultiTouchMode || !Settings.Gesture.IsEnableTwoFingerGesture) return; if ((dec.Count >= 2 && (Settings.PowerPointSettings.IsEnableTwoFingerGestureInPresentationMode || StackPanelPPTControls.Visibility != Visibility.Visible || StackPanelPPTButtons.Visibility == Visibility.Collapsed)) || isSingleFingerDragMode) { var md = e.DeltaManipulation; var trans = md.Translation; // 获得位移矢量 var m = new Matrix(); if (Settings.Gesture.IsEnableTwoFingerTranslate) m.Translate(trans.X, trans.Y); // 移动 if (Settings.Gesture.IsEnableTwoFingerGestureTranslateOrRotation) { var rotate = md.Rotation; // 获得旋转角度 var scale = md.Scale; // 获得缩放倍数 // Find center of element and then transform to get current location of center var fe = e.Source as FrameworkElement; var center = new Point(fe.ActualWidth / 2, fe.ActualHeight / 2); center = m.Transform(center); // 转换为矩阵缩放和旋转的中心点 if (Settings.Gesture.IsEnableTwoFingerRotation) m.RotateAt(rotate, center.X, center.Y); // 旋转 if (Settings.Gesture.IsEnableTwoFingerZoom && !disableScale) m.ScaleAt(scale.X, scale.Y, center.X, center.Y); // 缩放 } var strokes = inkCanvas.GetSelectedStrokes(); if (strokes.Count != 0) { foreach (var stroke in strokes) { stroke.Transform(m, false); foreach (var circle in circles) if (stroke == circle.Stroke) { circle.R = GetDistance(circle.Stroke.StylusPoints[0].ToPoint(), circle.Stroke.StylusPoints[circle.Stroke.StylusPoints.Count / 2].ToPoint()) / 2; circle.Centroid = new Point( (circle.Stroke.StylusPoints[0].X + circle.Stroke.StylusPoints[circle.Stroke.StylusPoints.Count / 2].X) / 2, (circle.Stroke.StylusPoints[0].Y + circle.Stroke.StylusPoints[circle.Stroke.StylusPoints.Count / 2].Y) / 2); break; } if (!Settings.Gesture.IsEnableTwoFingerZoom) continue; try { stroke.DrawingAttributes.Width *= md.Scale.X; stroke.DrawingAttributes.Height *= md.Scale.Y; } catch { } } } else { if (Settings.Gesture.IsEnableTwoFingerZoom) { foreach (var stroke in inkCanvas.Strokes) { stroke.Transform(m, false); try { stroke.DrawingAttributes.Width *= md.Scale.X; stroke.DrawingAttributes.Height *= md.Scale.Y; } catch { } } ; } else { foreach (var stroke in inkCanvas.Strokes) stroke.Transform(m, false); ; } foreach (var circle in circles) { circle.R = GetDistance(circle.Stroke.StylusPoints[0].ToPoint(), circle.Stroke.StylusPoints[circle.Stroke.StylusPoints.Count / 2].ToPoint()) / 2; circle.Centroid = new Point( (circle.Stroke.StylusPoints[0].X + circle.Stroke.StylusPoints[circle.Stroke.StylusPoints.Count / 2].X) / 2, (circle.Stroke.StylusPoints[0].Y + circle.Stroke.StylusPoints[circle.Stroke.StylusPoints.Count / 2].Y) / 2 ); } } } } // 退出多指书写模式,恢复InkCanvas的TouchDown事件绑定 private void ExitMultiTouchModeIfNeeded() { if (isInMultiTouchMode) { inkCanvas.StylusDown -= MainWindow_StylusDown; inkCanvas.StylusMove -= MainWindow_StylusMove; inkCanvas.StylusUp -= MainWindow_StylusUp; inkCanvas.TouchDown -= MainWindow_TouchDown; inkCanvas.TouchDown += Main_Grid_TouchDown; // 修复:几何绘制模式下不自动切换到Ink模式,避免触摸轨迹被收集 if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke && drawingShapeMode == 0) { inkCanvas.EditingMode = InkCanvasEditingMode.Ink; } // 保存非笔画元素(如图片) var preservedElements = PreserveNonStrokeElements(); inkCanvas.Children.Clear(); // 恢复非笔画元素 RestoreNonStrokeElements(preservedElements); isInMultiTouchMode = false; // 关闭多指书写时,恢复手掌擦开关 if (palmEraserWasEnabledBeforeMultiTouch) { Settings.Canvas.EnablePalmEraser = true; if (ToggleSwitchEnablePalmEraser != null) ToggleSwitchEnablePalmEraser.IsOn = true; } } } // 进入多指书写模式,绑定Main_Grid_TouchDown private void EnterMultiTouchModeIfNeeded() { if (!isInMultiTouchMode) { inkCanvas.StylusDown += MainWindow_StylusDown; inkCanvas.StylusMove += MainWindow_StylusMove; inkCanvas.StylusUp += MainWindow_StylusUp; inkCanvas.TouchDown += MainWindow_TouchDown; inkCanvas.TouchDown -= Main_Grid_TouchDown; // 修复:几何绘制模式下不自动切换到Ink模式,避免触摸轨迹被收集 if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByPoint && inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke && drawingShapeMode == 0) { inkCanvas.EditingMode = InkCanvasEditingMode.None; } // 保存非笔画元素(如图片) var preservedElements = PreserveNonStrokeElements(); inkCanvas.Children.Clear(); // 恢复非笔画元素 RestoreNonStrokeElements(preservedElements); isInMultiTouchMode = true; // 启用多指书写时,自动禁用手掌擦 palmEraserWasEnabledBeforeMultiTouch = Settings.Canvas.EnablePalmEraser; Settings.Canvas.EnablePalmEraser = false; if (ToggleSwitchEnablePalmEraser != null) ToggleSwitchEnablePalmEraser.IsOn = false; } } /// /// 启动手掌擦恢复定时器,防止卡死状态 /// private void StartPalmEraserRecoveryTimer() { if (palmEraserRecoveryTimer == null) { palmEraserRecoveryTimer = new System.Windows.Threading.DispatcherTimer(); palmEraserRecoveryTimer.Interval = TimeSpan.FromMilliseconds(1000); // 每秒检查一次 palmEraserRecoveryTimer.Tick += PalmEraserRecoveryTimer_Tick; } palmEraserRecoveryTimer.Start(); } /// /// 停止手掌擦恢复定时器 /// private void StopPalmEraserRecoveryTimer() { if (palmEraserRecoveryTimer != null) { palmEraserRecoveryTimer.Stop(); } } /// /// 手掌擦恢复定时器事件处理 /// private void PalmEraserRecoveryTimer_Tick(object sender, EventArgs e) { if (!isPalmEraserActive) return; // 检查是否超时 var timeSinceActivation = DateTime.Now - palmEraserActivationTime; if (timeSinceActivation.TotalMilliseconds > PALM_ERASER_TIMEOUT_MS) { Trace.WriteLine($"Palm eraser recovery timer triggered, forcing recovery after {timeSinceActivation.TotalMilliseconds}ms"); // 强制恢复状态 try { if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint) { if (palmEraserLastEditingMode == InkCanvasEditingMode.Ink) { PenIcon_Click(null, null); } else if (palmEraserLastEditingMode == InkCanvasEditingMode.Select) { SymbolIconSelect_MouseUp(null, null); } else { inkCanvas.EditingMode = palmEraserLastEditingMode; } } } catch (Exception ex) { Trace.WriteLine($"Palm eraser recovery timer failed: {ex.Message}, forcing to Ink mode"); inkCanvas.EditingMode = InkCanvasEditingMode.Ink; } // 重置所有手掌擦状态 isPalmEraserActive = false; palmEraserTouchDownHandled = false; inkCanvas.IsHitTestVisible = true; inkCanvas.IsManipulationEnabled = true; // 停止定时器 StopPalmEraserRecoveryTimer(); } } } }