























public interface IInputSignal
{
bool IsMatch(InputEventArgs args);
}
public class KeyDownSignal : KeySignal
{
public KeyDownSignal(Key key) : base(key)
{
}
public override bool IsMatch(InputEventArgs args)
{
return Keyboard.IsKeyDown(Key);
}
}
public class KeySignal : IInputSignal
{
public Key Key { get; set; }
public KeySignal(Key key)
{
Key = key;
}
public virtual bool IsMatch(InputEventArgs args)
{
return args is KeyEventArgs e && e.Key == Key;
}
}
public class KeyRepeatSignal : KeySignal
{
public KeyRepeatSignal(Key key) : base(key)
{
}
public override bool IsMatch(InputEventArgs args)
{
return args is KeyEventArgs e && Key == e.Key && e.IsRepeat;
}
}
public class MouseSignal : IInputSignal
{
public MouseButton MouseButton { get; set; }
public MouseButtonState MouseButtonState { get; set; }
public MouseSignal(MouseButton mouseButton, MouseButtonState state)
{
MouseButton = mouseButton;
MouseButtonState = state;
}
public virtual bool IsMatch(InputEventArgs args)
{
MouseButtonEventArgs e = (MouseButtonEventArgs)args;
return e != null && e.ChangedButton == MouseButton && e.ButtonState == MouseButtonState;
}
}
public class MouseWheelSignal : IInputSignal
{
public bool IsMatch(InputEventArgs args)
{
MouseWheelEventArgs e = (MouseWheelEventArgs)args;
return e != null;
}
}
public class CommandMethod
{
public Action<CommandMethodEventArgs?>? Execute { get; set; }
public Predicate<CommandMethodEventArgs?>? CanExecute { get; set; }
public CommandMethod(Action<CommandMethodEventArgs?>? execute, Predicate<CommandMethodEventArgs?>? canExecute = null)
{
Execute = execute;
CanExecute = canExecute;
}
}
public class CommandMethodEventArgs : EventArgs
{
public bool Handled { get; set; }
public object Data { get; set; }
public InputCommand Command { get; set; }
public CommandMethodEventArgs(object data, InputCommand command)
{
Data = data;
Command = command;
}
}
public enum MatchModel { Step, All }
public class InputCommand : ICommand
{
int _index = 0;
DateTime? _dateTime;
public List<CommandMethod> CommandMethods { get; set; }
public List<IInputSignal> InputSignals { get; set; }
public string Name { get; set; }
/// <summary>
/// Step按顺序按,All所有信号同时存在
/// </summary>
public MatchModel MatchModel { get; set; }
public Window Owner { get; set; }
public event EventHandler? CanExecuteChanged;
public InputCommand(string name, IEnumerable<IInputSignal> inputSignals, MatchModel matchModel, Window owner)
: this(name, inputSignals, matchModel, owner, null)
{
}
public InputCommand(string name, IEnumerable<IInputSignal> inputSignals, MatchModel matchModel, Window owner, IEnumerable<CommandMethod>? commandMethods)
{
this.Name = name;
MatchModel = matchModel;
InputSignals = new List<IInputSignal>();
if (inputSignals != null)
InputSignals.AddRange(inputSignals);
CommandMethods = new List<CommandMethod>();
if (commandMethods != null)
CommandMethods.AddRange(commandMethods);
Owner = owner;
if(Owner != null)
Owner.CommandBindings.Add(new CommandBinding(this));
}
/// <summary>
/// MatchModel.All时args可以为null
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
public virtual bool IsMatch(InputEventArgs args)
{
if (InputSignals == null || InputSignals.Count <= 0) return false;
if (MatchModel == MatchModel.Step)
{
if (InputSignals[_index].IsMatch(args))
{
if (_dateTime == null)
{
_dateTime = DateTime.Now;
_index++;
}
else if ((DateTime.Now - _dateTime) <= TimeSpan.FromMilliseconds(200))
{
_index++;
_dateTime = DateTime.Now;
}
else
{
_index = 0;
_dateTime = null;
return false;
}
if (_index >= InputSignals.Count)
{
_index = 0;
_dateTime = null;
return true;
}
}
}
else
{
foreach (var k in InputSignals)
if (!k.IsMatch(null))
return false;
return true;
}
return false;
}
bool ICommand.CanExecute(object? parameter)
{
CommandMethodEventArgs arg = new CommandMethodEventArgs(parameter, this);
return CanExecute(arg);
}
void ICommand.Execute(object? parameter)
{
CommandMethodEventArgs arg = new CommandMethodEventArgs(parameter, this);
Execute(arg);
}
public bool CanExecute(CommandMethodEventArgs arg)
{
foreach (var method in CommandMethods)
{
if (method.CanExecute != null)
{
bool can = method.CanExecute.Invoke(arg);
if (arg.Handled) return can;
}
}
return true;
}
public void Execute(CommandMethodEventArgs arg)
{
foreach (var method in CommandMethods)
{
method.Execute?.Invoke(arg);
if (arg.Handled) return;
}
}
public void RaiseCmd()
{
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
public static void TryExecute(Window window, InputEventArgs e)
{
foreach (CommandBinding cmd in window.CommandBindings)
{
if (cmd.Command is InputCommand command)
{
if (command.IsMatch(e))
{
CommandMethodEventArgs arg = new CommandMethodEventArgs(e, command);
command.Execute(arg);
if (arg.Handled) break;
}
}
}
}
public static void RegistPreview(Window window)
{
RegistPreviewKeyDown(window);
RegistPreviewKeyUp(window);
RegistPreviewMouseDown(window);
RegistPreviewKeyUp(window);
}
public static void RegistPreviewKeyDown(Window window)
{
window.PreviewKeyDown += (s, e) => TryExecute(window, e);
}
public static void RegistPreviewKeyUp(Window window)
{
window.PreviewKeyUp += (s, e) => TryExecute(window, e);
}
public static void RegistPreviewMouseDown(Window window)
{
window.PreviewMouseDown += (s, e) => TryExecute(window, e);
}
public static void RegistPreviewMouseUp(Window window)
{
window.PreviewMouseUp += (s, e) => TryExecute(window, e);
}
public static void RegistPreviewMouseWheel(Window window)
{
window.PreviewMouseWheel += (s, e) => TryExecute(window, e);
}
}
使用方式:
public class KeyBindingVM : ITemplateView
{
public ObservableCollection<InputCommand> InputCommands { get; set; }
public string Title { get; set; } = "按键设置";
public List<IInputSignal> OldKeys { get; set; }
public SimpleCommand<KeyEventArgs> AddKeyCmd { get; set; }
public SimpleCommand<RoutedEventArgs> ClearKeyCmd { get; set; }
public SimpleCommand SaveCmd { get; set; }
public KeyBindingVM()
{
OldKeys = new List<IInputSignal>();
AddKeyCmd = new SimpleCommand<KeyEventArgs>(AddKey);
ClearKeyCmd = new SimpleCommand<RoutedEventArgs>(ClearKey);
SaveCmd = new SimpleCommand(() => { });
InputCommands = new ObservableCollection<InputCommand>
{
new InputCommand("背包", new KeyDownSignal[]{ new KeyDownSignal(Key.B) }, MatchModel.All, App.Current.MainWindow, new List<CommandMethod>{ new CommandMethod(Alert) }),
new InputCommand("技能", new KeyDownSignal[]{ new KeyDownSignal(Key.K) }, MatchModel.All, App.Current.MainWindow, new List<CommandMethod>{ new CommandMethod(Alert) }),
new InputCommand("任务", new KeyDownSignal[]{ new KeyDownSignal(Key.O) }, MatchModel.All, App.Current.MainWindow, new List<CommandMethod>{ new CommandMethod(Alert) }),
new InputCommand("地图", new KeyDownSignal[]{ new KeyDownSignal(Key.M) }, MatchModel.All, App.Current.MainWindow, new List<CommandMethod>{ new CommandMethod(Alert) }),
};
}
void Alert(CommandMethodEventArgs? e)
{
MessageBox.Show(e.Command.Name);
}
private void ClearKey(RoutedEventArgs e)
{
var inputcmd = (e.OriginalSource as FrameworkElement).DataContext as InputCommand;
OldKeys.Clear();
OldKeys.AddRange(inputcmd.InputSignals);
inputcmd.InputSignals.Clear();
}
private void AddKey(KeyEventArgs e)
{
e.Handled = true;
if (e.IsRepeat) return;
var control = (e.OriginalSource as TextBox);
var inputcmd = control.DataContext as InputCommand;
if (inputcmd.InputSignals.Exists(f => (f as KeySignal).Key == e.Key)) return;
inputcmd.InputSignals.Add(new KeyDownSignal(e.Key));
control.SetBinding(TextBox.TextProperty, new Binding { Source = inputcmd, Path = new PropertyPath(nameof(inputcmd.InputSignals)), Converter = new Converters.KeyStringConverter() });
}
}
public class KeyStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return value;
var keys = value as List<IInputSignal>;
if (keys == null || keys.Count <= 0) return null;
return string.Join("+", keys.Select(f => (f as KeySignal).Key));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
<StackPanel>
<ItemsControl ItemsSource="{Binding InputCommands}" VerticalAlignment="Top">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="2"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type input:InputCommand}">
<UniformGrid Columns="2">
<TextBlock Text="{Binding Name}"/>
<TextBox Text="{Binding Path=InputSignals, Converter={StaticResource KeyStringConverter}}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewKeyDown">
<i:InvokeCommandAction Command="{Binding DataContext.AddKeyCmd, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ItemsControl}}}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding DataContext.ClearKeyCmd, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ItemsControl}}}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</UniformGrid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="保存" Command="{Binding SaveCmd}"/>
</StackPanel>
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。