Neuerstellung
This commit is contained in:
17
NHotkey/NHotkey.Wpf/Extensions.cs
Normal file
17
NHotkey/NHotkey.Wpf/Extensions.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace NHotkey.Wpf
|
||||
{
|
||||
static class Extensions
|
||||
{
|
||||
public static bool HasFlag(this ModifierKeys modifiers, ModifierKeys flag)
|
||||
{
|
||||
return (modifiers & flag) == flag;
|
||||
}
|
||||
|
||||
public static bool HasFlag(this HotkeyFlags flags, HotkeyFlags flag)
|
||||
{
|
||||
return (flags & flag) == flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
NHotkey/NHotkey.Wpf/HotkeyAlreadyRegisteredEventArgs.cs
Normal file
19
NHotkey/NHotkey.Wpf/HotkeyAlreadyRegisteredEventArgs.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace NHotkey.Wpf
|
||||
{
|
||||
public class HotkeyAlreadyRegisteredEventArgs : EventArgs
|
||||
{
|
||||
private readonly string _name;
|
||||
|
||||
public HotkeyAlreadyRegisteredEventArgs(string name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
}
|
||||
}
|
||||
}
|
||||
249
NHotkey/NHotkey.Wpf/HotkeyManager.cs
Normal file
249
NHotkey/NHotkey.Wpf/HotkeyManager.cs
Normal file
@@ -0,0 +1,249 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
|
||||
namespace NHotkey.Wpf
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage(
|
||||
"Microsoft.Design",
|
||||
"CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable",
|
||||
Justification = "This is a singleton; disposing it would break it")]
|
||||
public class HotkeyManager : HotkeyManagerBase
|
||||
{
|
||||
#region Singleton implementation
|
||||
|
||||
public static HotkeyManager Current { get { return LazyInitializer.Instance; } }
|
||||
|
||||
private static class LazyInitializer
|
||||
{
|
||||
static LazyInitializer() { }
|
||||
public static readonly HotkeyManager Instance = new HotkeyManager();
|
||||
}
|
||||
|
||||
public void AddOrReplace(string v, object incrementKeys, object onIncrement)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Attached property for KeyBindings
|
||||
|
||||
[AttachedPropertyBrowsableForType(typeof(KeyBinding))]
|
||||
public static bool GetRegisterGlobalHotkey(KeyBinding binding)
|
||||
{
|
||||
return (bool)binding.GetValue(RegisterGlobalHotkeyProperty);
|
||||
}
|
||||
|
||||
public static void SetRegisterGlobalHotkey(KeyBinding binding, bool value)
|
||||
{
|
||||
binding.SetValue(RegisterGlobalHotkeyProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty RegisterGlobalHotkeyProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"RegisterGlobalHotkey",
|
||||
typeof(bool),
|
||||
typeof(HotkeyManager),
|
||||
new PropertyMetadata(
|
||||
false,
|
||||
RegisterGlobalHotkeyPropertyChanged));
|
||||
|
||||
private static void RegisterGlobalHotkeyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var keyBinding = d as KeyBinding;
|
||||
if (keyBinding == null)
|
||||
return;
|
||||
|
||||
bool oldValue = (bool) e.OldValue;
|
||||
bool newValue = (bool) e.NewValue;
|
||||
|
||||
if (DesignerProperties.GetIsInDesignMode(d))
|
||||
return;
|
||||
|
||||
if (oldValue && !newValue)
|
||||
{
|
||||
Current.RemoveKeyBinding(keyBinding);
|
||||
}
|
||||
else if (newValue && !oldValue)
|
||||
{
|
||||
Current.AddKeyBinding(keyBinding);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region HotkeyAlreadyRegistered event
|
||||
|
||||
public static event EventHandler<HotkeyAlreadyRegisteredEventArgs> HotkeyAlreadyRegistered;
|
||||
|
||||
private static void OnHotkeyAlreadyRegistered(string name)
|
||||
{
|
||||
var handler = HotkeyAlreadyRegistered;
|
||||
if (handler != null)
|
||||
handler(null, new HotkeyAlreadyRegisteredEventArgs(name));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||
private readonly HwndSource _source;
|
||||
private readonly WeakReferenceCollection<KeyBinding> _keyBindings;
|
||||
|
||||
private HotkeyManager()
|
||||
{
|
||||
_keyBindings = new WeakReferenceCollection<KeyBinding>();
|
||||
|
||||
var parameters = new HwndSourceParameters("Hotkey sink")
|
||||
{
|
||||
HwndSourceHook = HandleMessage,
|
||||
ParentWindow = HwndMessage
|
||||
};
|
||||
_source = new HwndSource(parameters);
|
||||
SetHwnd(_source.Handle);
|
||||
}
|
||||
|
||||
public void AddOrReplace(string name, KeyGesture gesture, EventHandler<HotkeyEventArgs> handler)
|
||||
{
|
||||
AddOrReplace(name, gesture, false, handler);
|
||||
}
|
||||
|
||||
public void AddOrReplace(string name, KeyGesture gesture, bool noRepeat, EventHandler<HotkeyEventArgs> handler)
|
||||
{
|
||||
AddOrReplace(name, gesture.Key, gesture.Modifiers, noRepeat, handler);
|
||||
}
|
||||
|
||||
public void AddOrReplace(string name, Key key, ModifierKeys modifiers, EventHandler<HotkeyEventArgs> handler)
|
||||
{
|
||||
AddOrReplace(name, key, modifiers, false, handler);
|
||||
}
|
||||
|
||||
public void AddOrReplace(string name, Key key, ModifierKeys modifiers, bool noRepeat, EventHandler<HotkeyEventArgs> handler)
|
||||
{
|
||||
var flags = GetFlags(modifiers, noRepeat);
|
||||
var vk = (uint)KeyInterop.VirtualKeyFromKey(key);
|
||||
AddOrReplace(name, vk, flags, handler);
|
||||
}
|
||||
|
||||
private static HotkeyFlags GetFlags(ModifierKeys modifiers, bool noRepeat)
|
||||
{
|
||||
var flags = HotkeyFlags.None;
|
||||
if (modifiers.HasFlag(ModifierKeys.Shift))
|
||||
flags |= HotkeyFlags.Shift;
|
||||
if (modifiers.HasFlag(ModifierKeys.Control))
|
||||
flags |= HotkeyFlags.Control;
|
||||
if (modifiers.HasFlag(ModifierKeys.Alt))
|
||||
flags |= HotkeyFlags.Alt;
|
||||
if (modifiers.HasFlag(ModifierKeys.Windows))
|
||||
flags |= HotkeyFlags.Windows;
|
||||
if (noRepeat)
|
||||
flags |= HotkeyFlags.NoRepeat;
|
||||
return flags;
|
||||
}
|
||||
|
||||
private static ModifierKeys GetModifiers(HotkeyFlags flags)
|
||||
{
|
||||
var modifiers = ModifierKeys.None;
|
||||
if (flags.HasFlag(HotkeyFlags.Shift))
|
||||
modifiers |= ModifierKeys.Shift;
|
||||
if (flags.HasFlag(HotkeyFlags.Control))
|
||||
modifiers |= ModifierKeys.Control;
|
||||
if (flags.HasFlag(HotkeyFlags.Alt))
|
||||
modifiers |= ModifierKeys.Alt;
|
||||
if (flags.HasFlag(HotkeyFlags.Windows))
|
||||
modifiers |= ModifierKeys.Windows;
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
private void AddKeyBinding(KeyBinding keyBinding)
|
||||
{
|
||||
var gesture = (KeyGesture)keyBinding.Gesture;
|
||||
string name = GetNameForKeyBinding(gesture);
|
||||
try
|
||||
{
|
||||
AddOrReplace(name, gesture.Key, gesture.Modifiers, null);
|
||||
_keyBindings.Add(keyBinding);
|
||||
}
|
||||
catch (HotkeyAlreadyRegisteredException)
|
||||
{
|
||||
OnHotkeyAlreadyRegistered(name);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveKeyBinding(KeyBinding keyBinding)
|
||||
{
|
||||
var gesture = (KeyGesture)keyBinding.Gesture;
|
||||
string name = GetNameForKeyBinding(gesture);
|
||||
Remove(name);
|
||||
_keyBindings.Remove(keyBinding);
|
||||
}
|
||||
|
||||
private readonly KeyGestureConverter _gestureConverter = new KeyGestureConverter();
|
||||
private string GetNameForKeyBinding(KeyGesture gesture)
|
||||
{
|
||||
string name = gesture.DisplayString;
|
||||
if (string.IsNullOrEmpty(name))
|
||||
name = _gestureConverter.ConvertToString(gesture);
|
||||
return name;
|
||||
}
|
||||
|
||||
private IntPtr HandleMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
|
||||
{
|
||||
Hotkey hotkey;
|
||||
var result = HandleHotkeyMessage(hwnd, msg, wparam, lparam, ref handled, out hotkey);
|
||||
if (handled)
|
||||
return result;
|
||||
|
||||
if (hotkey != null)
|
||||
handled = ExecuteBoundCommand(hotkey);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool ExecuteBoundCommand(Hotkey hotkey)
|
||||
{
|
||||
var key = KeyInterop.KeyFromVirtualKey((int)hotkey.VirtualKey);
|
||||
var modifiers = GetModifiers(hotkey.Flags);
|
||||
bool handled = false;
|
||||
foreach (var binding in _keyBindings)
|
||||
{
|
||||
if (binding.Key == key && binding.Modifiers == modifiers)
|
||||
{
|
||||
handled |= ExecuteCommand(binding);
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
private static bool ExecuteCommand(InputBinding binding)
|
||||
{
|
||||
var command = binding.Command;
|
||||
var parameter = binding.CommandParameter;
|
||||
var target = binding.CommandTarget;
|
||||
|
||||
if (command == null)
|
||||
return false;
|
||||
|
||||
var routedCommand = command as RoutedCommand;
|
||||
if (routedCommand != null)
|
||||
{
|
||||
if (routedCommand.CanExecute(parameter, target))
|
||||
{
|
||||
routedCommand.Execute(parameter, target);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (command.CanExecute(parameter))
|
||||
{
|
||||
command.Execute(parameter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
NHotkey/NHotkey.Wpf/NHotkey.Wpf.csproj
Normal file
12
NHotkey/NHotkey.Wpf/NHotkey.Wpf.csproj
Normal file
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net40;net45;netcoreapp3.0;net6.0-windows</TargetFrameworks>
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Package properties">
|
||||
<Description>A managed library to handle global hotkeys in WPF applications. This package contains the concrete HotkeyManager implementation for WPF.</Description>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NHotkey\NHotkey.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
7
NHotkey/NHotkey.Wpf/Properties/AssemblyInfo.cs
Normal file
7
NHotkey/NHotkey.Wpf/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using System.Windows.Markup;
|
||||
|
||||
// Mapping a custom namespace to the standard WPF namespace is usually something to avoid,
|
||||
// however in this case we're only importing one type (HotkeyManager), and it's unlikely to
|
||||
// collide with another type in a future version of WPF. So in this case, we do it for the
|
||||
// sake of simplicity, so that the user doesn't need to map the namespace manually.
|
||||
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "NHotkey.Wpf")]
|
||||
45
NHotkey/NHotkey.Wpf/WeakReferenceCollection.cs
Normal file
45
NHotkey/NHotkey.Wpf/WeakReferenceCollection.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NHotkey.Wpf
|
||||
{
|
||||
class WeakReferenceCollection<T> : IEnumerable<T>
|
||||
where T : class
|
||||
{
|
||||
private readonly List<WeakReference> _references = new List<WeakReference>();
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
var references = _references.ToList();
|
||||
foreach (var reference in references)
|
||||
{
|
||||
var target = reference.Target;
|
||||
if (target != null)
|
||||
yield return (T) target;
|
||||
}
|
||||
Trim();
|
||||
}
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
_references.Add(new WeakReference(item));
|
||||
}
|
||||
|
||||
public void Remove(T item)
|
||||
{
|
||||
_references.RemoveAll(r => (r.Target ?? item) == item);
|
||||
}
|
||||
|
||||
public void Trim()
|
||||
{
|
||||
_references.RemoveAll(r => !r.IsAlive);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user