Support Backspace for remove actions in UI lists
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run

Changed key handling and menu input gestures to allow Backspace (in addition to Delete) for removing items in server, profile, and routing rule lists. This improves usability and consistency across both Avalonia and WPF views.
This commit is contained in:
2dust 2025-11-18 16:54:42 +08:00
parent 84f812c8ee
commit 2ebd2b28a8
15 changed files with 168 additions and 129 deletions

View file

@ -152,7 +152,10 @@
<DataGrid.ContextMenu> <DataGrid.ContextMenu>
<ContextMenu> <ContextMenu>
<MenuItem x:Name="menuAddChildServer" Header="{x:Static resx:ResUI.menuAddChildServer}" /> <MenuItem x:Name="menuAddChildServer" Header="{x:Static resx:ResUI.menuAddChildServer}" />
<MenuItem x:Name="menuRemoveChildServer" Header="{x:Static resx:ResUI.menuRemoveChildServer}" /> <MenuItem
x:Name="menuRemoveChildServer"
Header="{x:Static resx:ResUI.menuRemoveChildServer}"
InputGesture="Back" />
<MenuItem <MenuItem
x:Name="menuSelectAllChild" x:Name="menuSelectAllChild"
Header="{x:Static resx:ResUI.menuSelectAll}" Header="{x:Static resx:ResUI.menuSelectAll}"

View file

@ -132,6 +132,7 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
break; break;
case Key.Delete: case Key.Delete:
case Key.Back:
ViewModel?.ChildRemoveAsync(); ViewModel?.ChildRemoveAsync();
e.Handled = true; e.Handled = true;
break; break;

View file

@ -115,7 +115,7 @@
<MenuItem <MenuItem
x:Name="menuRemoveServer" x:Name="menuRemoveServer"
Header="{x:Static resx:ResUI.menuRemoveServer}" Header="{x:Static resx:ResUI.menuRemoveServer}"
InputGesture="Delete" /> InputGesture="Back" />
<MenuItem x:Name="menuRemoveDuplicateServer" Header="{x:Static resx:ResUI.menuRemoveDuplicateServer}" /> <MenuItem x:Name="menuRemoveDuplicateServer" Header="{x:Static resx:ResUI.menuRemoveDuplicateServer}" />
<MenuItem x:Name="menuRemoveInvalidServerResult" Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" /> <MenuItem x:Name="menuRemoveInvalidServerResult" Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" />
<Separator /> <Separator />

View file

@ -313,33 +313,37 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
} }
else else
{ {
if (e.Key is Key.Enter or Key.Return) switch (e.Key)
{ {
ViewModel?.SetDefaultServer(); case Key.Enter:
} //case Key.Return:
else if (e.Key == Key.Delete) ViewModel?.SetDefaultServer();
{ break;
ViewModel?.RemoveServerAsync();
} case Key.Delete:
else if (e.Key == Key.T) case Key.Back:
{ ViewModel?.RemoveServerAsync();
ViewModel?.MoveServer(EMove.Top); break;
}
else if (e.Key == Key.U) case Key.T:
{ ViewModel?.MoveServer(EMove.Top);
ViewModel?.MoveServer(EMove.Up); break;
}
else if (e.Key == Key.D) case Key.U:
{ ViewModel?.MoveServer(EMove.Up);
ViewModel?.MoveServer(EMove.Down); break;
}
else if (e.Key == Key.B) case Key.D:
{ ViewModel?.MoveServer(EMove.Down);
ViewModel?.MoveServer(EMove.Bottom); break;
}
else if (e.Key == Key.Escape) case Key.B:
{ ViewModel?.MoveServer(EMove.Bottom);
ViewModel?.ServerSpeedtestStop(); break;
case Key.Escape:
ViewModel?.ServerSpeedtestStop();
break;
} }
} }
} }

View file

@ -187,7 +187,7 @@
<MenuItem <MenuItem
x:Name="menuRuleRemove" x:Name="menuRuleRemove"
Header="{x:Static resx:ResUI.menuRuleRemove}" Header="{x:Static resx:ResUI.menuRuleRemove}"
InputGesture="Delete" /> InputGesture="Back" />
<MenuItem <MenuItem
x:Name="menuRuleSelectAll" x:Name="menuRuleSelectAll"
Header="{x:Static resx:ResUI.menuSelectAll}" Header="{x:Static resx:ResUI.menuSelectAll}"

View file

@ -140,25 +140,28 @@ public partial class RoutingRuleSettingWindow : WindowBase<RoutingRuleSettingVie
} }
else else
{ {
if (e.Key == Key.T) switch (e.Key)
{ {
ViewModel?.MoveRule(EMove.Top); case Key.T:
} ViewModel?.MoveRule(EMove.Top);
else if (e.Key == Key.U) break;
{
ViewModel?.MoveRule(EMove.Up); case Key.U:
} ViewModel?.MoveRule(EMove.Up);
else if (e.Key == Key.D) break;
{
ViewModel?.MoveRule(EMove.Down); case Key.D:
} ViewModel?.MoveRule(EMove.Down);
else if (e.Key == Key.B) break;
{
ViewModel?.MoveRule(EMove.Bottom); case Key.B:
} ViewModel?.MoveRule(EMove.Bottom);
else if (e.Key == Key.Delete) break;
{
ViewModel?.RuleRemoveAsync(); case Key.Delete:
case Key.Back:
ViewModel?.RuleRemoveAsync();
break;
} }
} }
} }

View file

@ -102,7 +102,7 @@
<MenuItem <MenuItem
x:Name="menuRoutingAdvancedRemove" x:Name="menuRoutingAdvancedRemove"
Header="{x:Static resx:ResUI.menuRoutingAdvancedRemove}" Header="{x:Static resx:ResUI.menuRoutingAdvancedRemove}"
InputGesture="Delete" /> InputGesture="Back" />
<MenuItem <MenuItem
x:Name="menuRoutingAdvancedSelectAll" x:Name="menuRoutingAdvancedSelectAll"
Header="{x:Static resx:ResUI.menuSelectAll}" Header="{x:Static resx:ResUI.menuSelectAll}"

View file

@ -73,18 +73,27 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
{ {
if (e.KeyModifiers is KeyModifiers.Control or KeyModifiers.Meta) if (e.KeyModifiers is KeyModifiers.Control or KeyModifiers.Meta)
{ {
if (e.Key == Key.A) switch (e.Key)
{ {
lstRoutings.SelectAll(); case Key.A:
lstRoutings.SelectAll();
break;
} }
} }
else if (e.Key is Key.Enter or Key.Return) else
{ {
ViewModel?.RoutingAdvancedSetDefault(); switch (e.Key)
} {
else if (e.Key == Key.Delete) case Key.Enter:
{ //case Key.Return:
ViewModel?.RoutingAdvancedRemoveAsync(); ViewModel?.RoutingAdvancedSetDefault();
break;
case Key.Delete:
case Key.Back:
ViewModel?.RoutingAdvancedRemoveAsync();
break;
}
} }
} }

View file

@ -91,25 +91,28 @@ public partial class AddGroupServerWindow
} }
else else
{ {
if (e.Key == Key.T) switch (e.Key)
{ {
ViewModel?.MoveServer(EMove.Top); case Key.T:
} ViewModel?.MoveServer(EMove.Top);
else if (e.Key == Key.U) break;
{
ViewModel?.MoveServer(EMove.Up); case Key.U:
} ViewModel?.MoveServer(EMove.Up);
else if (e.Key == Key.D) break;
{
ViewModel?.MoveServer(EMove.Down); case Key.D:
} ViewModel?.MoveServer(EMove.Down);
else if (e.Key == Key.B) break;
{
ViewModel?.MoveServer(EMove.Bottom); case Key.B:
} ViewModel?.MoveServer(EMove.Bottom);
else if (e.Key == Key.Delete) break;
{
ViewModel?.ChildRemoveAsync(); case Key.Delete:
case Key.Back:
ViewModel?.ChildRemoveAsync();
break;
} }
} }
} }

View file

@ -138,7 +138,7 @@
x:Name="menuRemoveServer" x:Name="menuRemoveServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRemoveServer}" Header="{x:Static resx:ResUI.menuRemoveServer}"
InputGestureText="Delete" /> InputGestureText="Back" />
<MenuItem <MenuItem
x:Name="menuRemoveDuplicateServer" x:Name="menuRemoveDuplicateServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"

View file

@ -292,33 +292,37 @@ public partial class ProfilesView
} }
else else
{ {
if (e.Key is Key.Enter or Key.Return) switch (e.Key)
{ {
ViewModel?.SetDefaultServer(); case Key.Enter:
} //case Key.Return:
else if (e.Key == Key.Delete) ViewModel?.SetDefaultServer();
{ break;
ViewModel?.RemoveServerAsync();
} case Key.Delete:
else if (e.Key == Key.T) case Key.Back:
{ ViewModel?.RemoveServerAsync();
ViewModel?.MoveServer(EMove.Top); break;
}
else if (e.Key == Key.U) case Key.T:
{ ViewModel?.MoveServer(EMove.Top);
ViewModel?.MoveServer(EMove.Up); break;
}
else if (e.Key == Key.D) case Key.U:
{ ViewModel?.MoveServer(EMove.Up);
ViewModel?.MoveServer(EMove.Down); break;
}
else if (e.Key == Key.B) case Key.D:
{ ViewModel?.MoveServer(EMove.Down);
ViewModel?.MoveServer(EMove.Bottom); break;
}
else if (e.Key == Key.Escape) case Key.B:
{ ViewModel?.MoveServer(EMove.Bottom);
ViewModel?.ServerSpeedtestStop(); break;
case Key.Escape:
ViewModel?.ServerSpeedtestStop();
break;
} }
} }
} }

View file

@ -264,7 +264,7 @@
x:Name="menuRuleRemove" x:Name="menuRuleRemove"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRuleRemove}" Header="{x:Static resx:ResUI.menuRuleRemove}"
InputGestureText="Delete" /> InputGestureText="Back" />
<MenuItem <MenuItem
x:Name="menuRuleSelectAll" x:Name="menuRuleSelectAll"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"

View file

@ -140,25 +140,28 @@ public partial class RoutingRuleSettingWindow
} }
else else
{ {
if (e.Key == Key.T) switch (e.Key)
{ {
ViewModel?.MoveRule(EMove.Top); case Key.T:
} ViewModel?.MoveRule(EMove.Top);
else if (e.Key == Key.U) break;
{
ViewModel?.MoveRule(EMove.Up); case Key.U:
} ViewModel?.MoveRule(EMove.Up);
else if (e.Key == Key.D) break;
{
ViewModel?.MoveRule(EMove.Down); case Key.D:
} ViewModel?.MoveRule(EMove.Down);
else if (e.Key == Key.B) break;
{
ViewModel?.MoveRule(EMove.Bottom); case Key.B:
} ViewModel?.MoveRule(EMove.Bottom);
else if (e.Key == Key.Delete) break;
{
ViewModel?.RuleRemoveAsync(); case Key.Delete:
case Key.Back:
ViewModel?.RuleRemoveAsync();
break;
} }
} }
} }

View file

@ -145,7 +145,7 @@
x:Name="menuRoutingAdvancedRemove" x:Name="menuRoutingAdvancedRemove"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRoutingAdvancedRemove}" Header="{x:Static resx:ResUI.menuRoutingAdvancedRemove}"
InputGestureText="Delete" /> InputGestureText="Back" />
<MenuItem <MenuItem
x:Name="menuRoutingAdvancedSelectAll" x:Name="menuRoutingAdvancedSelectAll"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"

View file

@ -78,18 +78,27 @@ public partial class RoutingSettingWindow
{ {
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{ {
if (e.Key == Key.A) switch (e.Key)
{ {
lstRoutings.SelectAll(); case Key.A:
lstRoutings.SelectAll();
break;
} }
} }
else if (e.Key is Key.Enter or Key.Return) else
{ {
ViewModel?.RoutingAdvancedSetDefault(); switch (e.Key)
} {
else if (e.Key == Key.Delete) case Key.Enter:
{ //case Key.Return:
ViewModel?.RoutingAdvancedRemoveAsync(); ViewModel?.RoutingAdvancedSetDefault();
break;
case Key.Delete:
case Key.Back:
ViewModel?.RoutingAdvancedRemoveAsync();
break;
}
} }
} }