This commit is contained in:
2025-08-30 14:53:50 +08:00
parent 4a86d1aa05
commit 7095a5890c
5 changed files with 135 additions and 44 deletions
+14 -1
View File
@@ -841,7 +841,20 @@
IsOn="False" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchEnablePalmEraser_Toggled" />
</ui:SimpleStackPanel>
<TextBlock Text="# 开启后,两个及以上触点且触摸面积较大时自动切换为橡皮擦,抬手后恢复原编辑模式。" TextWrapping="Wrap" Foreground="#a1a1aa" />
<TextBlock Text="# 开启后,两个及以上触点且触摸面积较大时自动切换为橡皮擦,抬手后恢复原编辑模式。" TextWrapping="Wrap" Foreground="#a1a1aa" />
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left"
Visibility="{Binding ElementName=ToggleSwitchEnablePalmEraser, Path=IsOn, Converter={StaticResource BooleanToVisibilityConverter}}">
<TextBlock Foreground="#fafafa" Text="手掌擦敏感度" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<ComboBox Name="ComboBoxPalmEraserSensitivity" Width="120" SelectionChanged="ComboBoxPalmEraserSensitivity_SelectionChanged">
<ComboBoxItem Content="低敏感度" />
<ComboBoxItem Content="中敏感度" />
<ComboBoxItem Content="高敏感度" />
</ComboBox>
</ui:SimpleStackPanel>
<TextBlock Text="# 低敏感度:需要更大的触摸面积和更多触摸点,减少误判;高敏感度:更容易触发手掌擦,但可能误判手指。"
TextWrapping="Wrap" Foreground="#a1a1aa"
Visibility="{Binding ElementName=ToggleSwitchEnablePalmEraser, Path=IsOn, Converter={StaticResource BooleanToVisibilityConverter}}" />
</ui:SimpleStackPanel>
</GroupBox>
<GroupBox Name="GroupBoxInkRecognition">
+6
View File
@@ -3034,6 +3034,12 @@ namespace Ink_Canvas
#endregion
private void ComboBoxPalmEraserSensitivity_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!isLoaded) return;
Settings.Canvas.PalmEraserSensitivity = ComboBoxPalmEraserSensitivity.SelectedIndex;
SaveSettingsToFile();
}
}
}
@@ -683,6 +683,7 @@ namespace Ink_Canvas
if (Settings.Canvas != null)
{
ToggleSwitchEnablePalmEraser.IsOn = Settings.Canvas.EnablePalmEraser;
ComboBoxPalmEraserSensitivity.SelectedIndex = Settings.Canvas.PalmEraserSensitivity;
}
// Advanced
+112 -43
View File
@@ -365,8 +365,9 @@ namespace Ink_Canvas
private bool palmEraserWasEnabledBeforeMultiTouch;
private bool palmEraserTouchDownHandled = false; // 新增:标记手掌擦触摸按下是否已处理
private DateTime palmEraserActivationTime; // 新增:记录手掌擦激活时间
private const int PALM_ERASER_TIMEOUT_MS = 5000; // 新增:手掌擦超时时间(5秒)
private const int PALM_ERASER_TIMEOUT_MS = 3000; // 修改:减少手掌擦超时时间(3秒)
private System.Windows.Threading.DispatcherTimer palmEraserRecoveryTimer; // 新增:手掌擦恢复定时器
private HashSet<int> palmEraserTouchIds = new HashSet<int>(); // 新增:记录参与手掌擦的触摸点ID
private void inkCanvas_PreviewTouchDown(object sender, TouchEventArgs e)
{
@@ -419,16 +420,57 @@ namespace Ink_Canvas
BlackboardUIGridForInkReplay.IsHitTestVisible = false;
dec.Add(e.TouchDevice.Id);
// Palm Eraser 逻辑 - 修复:只在触摸按下时处理一次,避免重复触发
// 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)
// 根据敏感度设置调整判定参数
double palmThreshold;
double aspectRatioThreshold;
int minTouchPoints;
switch (Settings.Canvas.PalmEraserSensitivity)
{
case 0: // 低敏感度 - 更严格的判定
palmThreshold = 80;
aspectRatioThreshold = 0.4;
minTouchPoints = 4;
break;
case 1: // 中敏感度 - 平衡的判定
palmThreshold = 60;
aspectRatioThreshold = 0.3;
minTouchPoints = 3;
break;
case 2: // 高敏感度 - 较宽松的判定
default:
palmThreshold = 50;
aspectRatioThreshold = 0.25;
minTouchPoints = 2;
break;
}
// 计算宽高比
double aspectRatio = Math.Min(bounds.Width, bounds.Height) / Math.Max(bounds.Width, bounds.Height);
// 更严格的手掌判定条件
bool isLargeTouch = bounds.Width >= palmThreshold && bounds.Height >= palmThreshold;
bool isPalmLikeShape = aspectRatio >= aspectRatioThreshold;
bool hasMultipleTouchPoints = dec.Count >= minTouchPoints;
if (isLargeTouch && isPalmLikeShape && hasMultipleTouchPoints)
{
// 记录当前编辑模式和高光状态
palmEraserLastEditingMode = inkCanvas.EditingMode;
palmEraserLastIsHighlighter = drawingAttributes.IsHighlighter;
// 记录参与手掌擦的触摸点ID
palmEraserTouchIds.Clear();
foreach (int touchId in dec)
{
palmEraserTouchIds.Add(touchId);
}
// 切换为橡皮擦
EraserIcon_Click(null, null);
isPalmEraserActive = true;
@@ -437,6 +479,9 @@ namespace Ink_Canvas
// 启动恢复定时器,防止卡死
StartPalmEraserRecoveryTimer();
// 记录日志
LogHelper.WriteLogToFile($"Palm eraser activated - Sensitivity: {Settings.Canvas.PalmEraserSensitivity}, Touch bounds: {bounds.Width}x{bounds.Height}, Aspect ratio: {aspectRatio:F2}, Touch points: {dec.Count}", LogHelper.LogType.Info);
}
}
@@ -497,41 +542,54 @@ namespace Ink_Canvas
ViewboxFloatingBar.IsHitTestVisible = true;
BlackboardUIGridForInkReplay.IsHitTestVisible = true;
// Palm Eraser 逻辑:所有点抬起后恢复原编辑模式
// Palm Eraser 逻辑:优化状态恢复机制
dec.Remove(e.TouchDevice.Id);
if (isPalmEraserActive && dec.Count == 0)
// 如果是手掌擦的触摸点,从记录中移除
if (palmEraserTouchIds.Contains(e.TouchDevice.Id))
{
palmEraserTouchIds.Remove(e.TouchDevice.Id);
}
// 当所有手掌擦触摸点都抬起时,恢复原编辑模式
if (isPalmEraserActive && palmEraserTouchIds.Count == 0)
{
// 恢复高光状态
drawingAttributes.IsHighlighter = palmEraserLastIsHighlighter;
// 恢复编辑模式 - 修复:确保正确恢复状态
// 恢复编辑模式 - 优化:改进状态恢复逻辑
try
{
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
{
if (palmEraserLastEditingMode == InkCanvasEditingMode.Ink)
// 根据之前的状态恢复
switch (palmEraserLastEditingMode)
{
PenIcon_Click(null, null);
}
else if (palmEraserLastEditingMode == InkCanvasEditingMode.Select)
{
SymbolIconSelect_MouseUp(null, null);
}
else
{
inkCanvas.EditingMode = palmEraserLastEditingMode;
case InkCanvasEditingMode.Ink:
PenIcon_Click(null, null);
break;
case InkCanvasEditingMode.Select:
SymbolIconSelect_MouseUp(null, null);
break;
default:
inkCanvas.EditingMode = palmEraserLastEditingMode;
break;
}
LogHelper.WriteLogToFile($"Palm eraser recovered to mode: {palmEraserLastEditingMode}", LogHelper.LogType.Info);
}
}
catch (Exception ex)
{
// 如果恢复失败,强制切换到批注模式
Trace.WriteLine($"Palm eraser recovery failed: {ex.Message}, forcing to Ink mode");
LogHelper.WriteLogToFile($"Palm eraser recovery failed: {ex.Message}, forcing to Ink mode", LogHelper.LogType.Error);
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
}
// 重置手掌擦状态
isPalmEraserActive = false;
palmEraserTouchDownHandled = false;
palmEraserTouchIds.Clear();
// 停止恢复定时器
StopPalmEraserRecoveryTimer();
@@ -542,44 +600,47 @@ namespace Ink_Canvas
ViewboxFloatingBar.IsHitTestVisible = true;
BlackboardUIGridForInkReplay.IsHitTestVisible = true;
LogHelper.WriteLogToFile("Palm eraser state reset completed", LogHelper.LogType.Info);
}
// 新增:超时检测 - 如果手掌擦激活时间过长,强制重置状态
if (isPalmEraserActive && dec.Count == 0)
if (isPalmEraserActive)
{
var timeSinceActivation = DateTime.Now - palmEraserActivationTime;
if (timeSinceActivation.TotalMilliseconds > PALM_ERASER_TIMEOUT_MS)
{
Trace.WriteLine($"Palm eraser timeout detected ({timeSinceActivation.TotalMilliseconds}ms), forcing recovery");
LogHelper.WriteLogToFile($"Palm eraser timeout detected ({timeSinceActivation.TotalMilliseconds}ms), forcing recovery", LogHelper.LogType.Warning);
// 强制恢复状态
try
{
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
{
if (palmEraserLastEditingMode == InkCanvasEditingMode.Ink)
switch (palmEraserLastEditingMode)
{
PenIcon_Click(null, null);
}
else if (palmEraserLastEditingMode == InkCanvasEditingMode.Select)
{
SymbolIconSelect_MouseUp(null, null);
}
else
{
inkCanvas.EditingMode = palmEraserLastEditingMode;
case InkCanvasEditingMode.Ink:
PenIcon_Click(null, null);
break;
case InkCanvasEditingMode.Select:
SymbolIconSelect_MouseUp(null, null);
break;
default:
inkCanvas.EditingMode = palmEraserLastEditingMode;
break;
}
}
}
catch (Exception ex)
{
Trace.WriteLine($"Palm eraser timeout recovery failed: {ex.Message}, forcing to Ink mode");
LogHelper.WriteLogToFile($"Palm eraser timeout recovery failed: {ex.Message}, forcing to Ink mode", LogHelper.LogType.Error);
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
}
// 重置所有手掌擦状态
isPalmEraserActive = false;
palmEraserTouchDownHandled = false;
palmEraserTouchIds.Clear();
inkCanvas.IsHitTestVisible = true;
inkCanvas.IsManipulationEnabled = true;
@@ -588,6 +649,8 @@ namespace Ink_Canvas
// 停止恢复定时器
StopPalmEraserRecoveryTimer();
LogHelper.WriteLogToFile("Palm eraser timeout recovery completed", LogHelper.LogType.Info);
}
}
// 修复:几何绘制模式下,触摸抬手时应该正确处理,而不是简单模拟鼠标事件
@@ -656,6 +719,7 @@ namespace Ink_Canvas
// 如果手掌擦还在激活状态但触摸点已清空,强制重置状态
isPalmEraserActive = false;
palmEraserTouchDownHandled = false;
palmEraserTouchIds.Clear(); // 确保清空触摸点ID
inkCanvas.IsHitTestVisible = true;
inkCanvas.IsManipulationEnabled = true;
@@ -902,36 +966,39 @@ namespace Ink_Canvas
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");
LogHelper.WriteLogToFile($"Palm eraser recovery timer triggered, forcing recovery after {timeSinceActivation.TotalMilliseconds}ms", LogHelper.LogType.Warning);
// 强制恢复状态
try
{
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
{
if (palmEraserLastEditingMode == InkCanvasEditingMode.Ink)
switch (palmEraserLastEditingMode)
{
PenIcon_Click(null, null);
}
else if (palmEraserLastEditingMode == InkCanvasEditingMode.Select)
{
SymbolIconSelect_MouseUp(null, null);
}
else
{
inkCanvas.EditingMode = palmEraserLastEditingMode;
case InkCanvasEditingMode.Ink:
PenIcon_Click(null, null);
break;
case InkCanvasEditingMode.Select:
SymbolIconSelect_MouseUp(null, null);
break;
default:
inkCanvas.EditingMode = palmEraserLastEditingMode;
break;
}
LogHelper.WriteLogToFile($"Palm eraser timer recovery to mode: {palmEraserLastEditingMode}", LogHelper.LogType.Info);
}
}
catch (Exception ex)
{
Trace.WriteLine($"Palm eraser recovery timer failed: {ex.Message}, forcing to Ink mode");
LogHelper.WriteLogToFile($"Palm eraser recovery timer failed: {ex.Message}, forcing to Ink mode", LogHelper.LogType.Error);
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
}
// 重置所有手掌擦状态
isPalmEraserActive = false;
palmEraserTouchDownHandled = false;
palmEraserTouchIds.Clear();
inkCanvas.IsHitTestVisible = true;
inkCanvas.IsManipulationEnabled = true;
@@ -940,6 +1007,8 @@ namespace Ink_Canvas
// 停止定时器
StopPalmEraserRecoveryTimer();
LogHelper.WriteLogToFile("Palm eraser timer recovery completed", LogHelper.LogType.Info);
}
}
}
+2
View File
@@ -88,6 +88,8 @@ namespace Ink_Canvas
public bool IsCompressPicturesUploaded { get; set; }
[JsonProperty("enablePalmEraser")]
public bool EnablePalmEraser { get; set; } = true;
[JsonProperty("palmEraserSensitivity")]
public int PalmEraserSensitivity { get; set; } = 2; // 0-低敏感度, 1-中敏感度, 2-高敏感度
[JsonProperty("clearCanvasAlsoClearImages")]
public bool ClearCanvasAlsoClearImages { get; set; } = true;
[JsonProperty("showCircleCenter")]