-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f808871
commit 98555a6
Showing
16 changed files
with
880 additions
and
0 deletions.
There are no files selected for viewing
143 changes: 143 additions & 0 deletions
143
OngekiFumenEditor/Kernel/KeyBinding/DefaultKeyBindingManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
using OngekiFumenEditor.Properties; | ||
using OngekiFumenEditor.Utils; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.ComponentModel.Composition; | ||
using System.Configuration; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Text.Json; | ||
using System.Text.RegularExpressions; | ||
using System.Threading.Tasks; | ||
using System.Windows.Input; | ||
|
||
namespace OngekiFumenEditor.Kernel.KeyBinding | ||
{ | ||
[Export(typeof(IKeyBindingManager))] | ||
[PartCreationPolicy(CreationPolicy.Shared)] | ||
internal class DefaultKeyBindingManager : IKeyBindingManager | ||
{ | ||
private readonly string jsonConfigFilePath; | ||
|
||
private class Config | ||
{ | ||
public Dictionary<string, string> KeyBindings { get; set; } = new(); | ||
} | ||
|
||
public IEnumerable<KeyBindingDefinition> KeyBindingDefinations => definitionMap.Values; | ||
|
||
private Dictionary<string, KeyBindingDefinition> definitionMap = new(); | ||
|
||
[ImportingConstructor] | ||
public DefaultKeyBindingManager([ImportMany] KeyBindingDefinition[] definations) | ||
{ | ||
definitionMap = definations.ToDictionary(x => x.ConfigKey, x => x); | ||
|
||
jsonConfigFilePath = Path.GetFullPath("./keybind.json"); | ||
Log.LogInfo($"jsonConfigFilePath: {jsonConfigFilePath}"); | ||
|
||
LoadConfig(); | ||
} | ||
|
||
public void SaveConfig() | ||
{ | ||
var json = JsonSerializer.Serialize(new Config() { KeyBindings = definitionMap.ToDictionary(x => x.Key, x => KeyBindingDefinition.FormatToExpression(x.Value.Key, x.Value.Modifiers)) }); | ||
File.WriteAllText(jsonConfigFilePath, json); | ||
|
||
Log.LogInfo($"Saved."); | ||
} | ||
|
||
public void LoadConfig() | ||
{ | ||
if (File.Exists(jsonConfigFilePath)) | ||
{ | ||
try | ||
{ | ||
var json = File.ReadAllText(jsonConfigFilePath); | ||
var strMap = JsonSerializer.Deserialize<Config>(json).KeyBindings; | ||
|
||
foreach (var item in strMap) | ||
{ | ||
var name = item.Key; | ||
var expr = item.Value; | ||
|
||
if (!KeyBindingDefinition.TryParseExpression(expr, out var k, out var m)) | ||
{ | ||
Log.LogError($"Can't parse {name} keybinding expr: {expr}"); | ||
continue; | ||
} | ||
|
||
if (definitionMap.TryGetValue(name, out var definition)) | ||
{ | ||
definition.Key = k; | ||
definition.Modifiers = m; | ||
} | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
Log.LogInfo($"Load failed: {e.Message}"); | ||
} | ||
} | ||
|
||
Log.LogInfo($"Loaded."); | ||
} | ||
|
||
public bool CheckKeyBinding(KeyBindingDefinition defination, KeyEventArgs e) | ||
{ | ||
var key = (e.Key == Key.System) ? e.SystemKey : e.Key; | ||
|
||
if (defination.Key == Key.None) | ||
return false; | ||
|
||
var modifier = Keyboard.Modifiers; | ||
#if DEBUG | ||
var str = $"{KeyBindingDefinition.FormatToExpression(key, modifier)} check {defination.Name}({KeyBindingDefinition.FormatToExpression(defination)})"; | ||
if (QueryKeyBinding(key, modifier) is KeyBindingDefinition query) | ||
str += $", query {query.Name}({KeyBindingDefinition.FormatToExpression(query)})"; | ||
Log.LogDebug(str); | ||
#endif | ||
return (key == defination.Key) && (modifier == GetActualModifiers(e.Key, defination.Modifiers)); | ||
} | ||
|
||
private static ModifierKeys GetActualModifiers(Key key, ModifierKeys modifiers) | ||
{ | ||
switch (key) | ||
{ | ||
case Key.LeftCtrl: | ||
case Key.RightCtrl: | ||
modifiers |= ModifierKeys.Control; | ||
return modifiers; | ||
|
||
case Key.LeftAlt: | ||
case Key.RightAlt: | ||
modifiers |= ModifierKeys.Alt; | ||
return modifiers; | ||
|
||
case Key.LeftShift: | ||
case Key.RightShift: | ||
modifiers |= ModifierKeys.Shift; | ||
break; | ||
} | ||
|
||
return modifiers; | ||
} | ||
|
||
public void ChangeKeyBinding(KeyBindingDefinition definition, Key newKey, ModifierKeys newModifier) | ||
{ | ||
Log.LogInfo($"{KeyBindingDefinition.FormatToExpression(definition.Key, definition.Modifiers)} --> {KeyBindingDefinition.FormatToExpression(newKey, newModifier)}"); | ||
|
||
definition.Key = newKey; | ||
definition.Modifiers = newModifier; | ||
} | ||
|
||
public KeyBindingDefinition QueryKeyBinding(Key key, ModifierKeys modifier) | ||
{ | ||
if (key is Key.None) | ||
return default; | ||
|
||
return KeyBindingDefinations.FirstOrDefault(x => x.Key == key && modifier == x.Modifiers); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using System.Windows.Input; | ||
|
||
namespace OngekiFumenEditor.Kernel.KeyBinding | ||
{ | ||
internal interface IKeyBindingManager | ||
{ | ||
bool CheckKeyBinding(KeyBindingDefinition defination, KeyEventArgs e); | ||
|
||
void ChangeKeyBinding(KeyBindingDefinition definition, Key newKey, ModifierKeys newModifier); | ||
|
||
void DefaultKeyBinding(KeyBindingDefinition definition) => | ||
ChangeKeyBinding(definition, definition.DefaultKey, definition.DefaultModifiers); | ||
|
||
KeyBindingDefinition QueryKeyBinding(Key key, ModifierKeys modifier); | ||
|
||
void SaveConfig(); | ||
|
||
void LoadConfig(); | ||
|
||
IEnumerable<KeyBindingDefinition> KeyBindingDefinations { get; } | ||
} | ||
} |
117 changes: 117 additions & 0 deletions
117
OngekiFumenEditor/Kernel/KeyBinding/KeyBindingDefinition.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
using Caliburn.Micro; | ||
using OngekiFumenEditor.Properties; | ||
using System.Text.RegularExpressions; | ||
using System; | ||
using System.Windows.Input; | ||
using Xceed.Wpf.Toolkit.Core.Input; | ||
|
||
namespace OngekiFumenEditor.Kernel.KeyBinding | ||
{ | ||
public class KeyBindingDefinition : PropertyChangedBase | ||
{ | ||
private readonly string resourceName; | ||
|
||
public Key DefaultKey { get; } | ||
public ModifierKeys DefaultModifiers { get; } | ||
|
||
public string ConfigKey => resourceName; | ||
|
||
public string Name => resourceName/*Resources.ResourceManager.GetString(resourceName)*/; | ||
|
||
public KeyBindingDefinition(string resourceName, Key defaultKey) : this(resourceName, ModifierKeys.None, defaultKey) | ||
{ | ||
|
||
} | ||
|
||
public KeyBindingDefinition(string resourceName, ModifierKeys defaultModifiers, Key defaultKey) | ||
{ | ||
this.resourceName = resourceName; | ||
|
||
DefaultModifiers = defaultModifiers; | ||
DefaultKey = defaultKey; | ||
} | ||
|
||
private Key? key; | ||
public Key Key | ||
{ | ||
get => key ?? DefaultKey; | ||
set | ||
{ | ||
Set(ref key, value); | ||
} | ||
} | ||
|
||
private ModifierKeys? modifiers; | ||
public ModifierKeys Modifiers | ||
{ | ||
get => modifiers ?? DefaultModifiers; | ||
set | ||
{ | ||
Set(ref modifiers, value); | ||
} | ||
} | ||
|
||
public static string FormatToExpression(Key key, ModifierKeys modifier) | ||
{ | ||
var modifierStr = modifier switch | ||
{ | ||
ModifierKeys.Alt => "Alt", | ||
ModifierKeys.Control => "Ctrl", | ||
ModifierKeys.Shift => "Shift", | ||
ModifierKeys.Windows => "Win", | ||
_ => string.Empty, | ||
}; | ||
|
||
var expr = key is Key.None ? string.Empty : key.ToString(); | ||
|
||
if (!string.IsNullOrWhiteSpace(modifierStr)) | ||
expr = modifierStr + " + " + expr; | ||
|
||
return expr; | ||
} | ||
|
||
public static string FormatToExpression(KeyBindingDefinition definition) | ||
{ | ||
return FormatToExpression(definition.Key, definition.Modifiers); | ||
} | ||
|
||
//Ctrl + A | ||
static Regex regex = new Regex(@"(\s*\w+\s*\+\s*)?(\w+)"); | ||
|
||
public static bool TryParseExpression(string keybindExpr, out Key key, out ModifierKeys modifier) | ||
{ | ||
key = Key.None; | ||
modifier = ModifierKeys.None; | ||
|
||
if (string.IsNullOrWhiteSpace(keybindExpr)) | ||
return true; | ||
|
||
var match = regex.Match(keybindExpr); | ||
if (!match.Success) | ||
return false; | ||
|
||
var modifierStr = match.Groups[1].Value.Trim().ToLower().TrimEnd('+').Trim(); | ||
if (!string.IsNullOrWhiteSpace(modifierStr)) | ||
{ | ||
modifier = modifierStr switch | ||
{ | ||
"ctrl" or "control" => ModifierKeys.Control, | ||
"win" or "windows" => ModifierKeys.Windows, | ||
"alt" => ModifierKeys.Alt, | ||
"shift" => ModifierKeys.Shift, | ||
_ => ModifierKeys.None | ||
}; | ||
|
||
if (modifier == ModifierKeys.None) | ||
return false; | ||
} | ||
|
||
var keyStr = match.Groups[2].Value.Trim(); | ||
if (!Enum.TryParse<Key>(keyStr, true, out var k)) | ||
return false; | ||
|
||
key = k; | ||
return key != Key.None; | ||
} | ||
} | ||
} |
72 changes: 72 additions & 0 deletions
72
OngekiFumenEditor/Kernel/SettingPages/KeyBinding/Dialogs/ConfigKeyBindingDialog.xaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
<mah:MetroWindow | ||
x:Class="OngekiFumenEditor.Kernel.SettingPages.KeyBinding.Dialogs.ConfigKeyBindingDialog" | ||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | ||
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" | ||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | ||
Title="设置快捷键" | ||
Width="300" | ||
Background="{DynamicResource EnvironmentWindowBackground}" | ||
SaveWindowPosition="True" | ||
ShowMaxRestoreButton="False" | ||
ShowMinButton="False" | ||
SizeToContent="WidthAndHeight" | ||
Style="{DynamicResource MainWindowStyle}" | ||
WindowStartupLocation="CenterOwner" | ||
mc:Ignorable="d"> | ||
<Window.DataContext> | ||
<Binding RelativeSource="{RelativeSource Self}"> | ||
</Binding> | ||
</Window.DataContext> | ||
<StackPanel Margin="10"> | ||
<TextBlock | ||
HorizontalAlignment="Center" | ||
FontSize="16" | ||
Text="{Binding Definition.Name, StringFormat=请为 {0} 输入合适的快捷键组合:}" /> | ||
<TextBlock | ||
Margin="0,15" | ||
HorizontalAlignment="Center" | ||
FontSize="25" | ||
FontWeight="Bold" | ||
Text="{Binding CurrentExpression}"> | ||
</TextBlock> | ||
<TextBlock | ||
HorizontalAlignment="Center" | ||
FontSize="16" | ||
FontWeight="Bold" | ||
Text="{Binding ConflictDefinition.Name, StringFormat=与 {0} 的绑定键位起冲突}" /> | ||
<Grid> | ||
<Grid.ColumnDefinitions> | ||
<ColumnDefinition Width="1*" /> | ||
<ColumnDefinition Width="1*" /> | ||
<ColumnDefinition Width="1*" /> | ||
</Grid.ColumnDefinitions> | ||
<Button | ||
Margin="5" | ||
Padding="10,5,10,5" | ||
Click="Button_Click_1" | ||
FontSize="16"> | ||
确定 | ||
</Button> | ||
|
||
<Button | ||
Grid.Column="1" | ||
Margin="5" | ||
Padding="10,5,10,5" | ||
Click="Button_Click" | ||
FontSize="16"> | ||
重置 | ||
</Button> | ||
|
||
<Button | ||
Grid.Column="2" | ||
Margin="5" | ||
Padding="10,5,10,5" | ||
Click="Button_Click_2" | ||
FontSize="16"> | ||
清空绑定 | ||
</Button> | ||
</Grid> | ||
</StackPanel> | ||
</mah:MetroWindow> |
Oops, something went wrong.