Neuerstellung

This commit is contained in:
maier_S
2022-03-11 14:59:36 +01:00
parent 072072202a
commit cc720e6421
128 changed files with 16224 additions and 0 deletions

400
NHotkey/.gitignore vendored Normal file
View File

@@ -0,0 +1,400 @@
# ---> VisualStudio
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml

View File

@@ -0,0 +1,22 @@
<Project>
<PropertyGroup>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)NHotkey.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup Label="Package properties">
<Authors>Thomas Levesque</Authors>
<PackageProjectUrl>https://github.com/thomaslevesque/NHotkey</PackageProjectUrl>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageTags>global;hotkey;windows</PackageTags>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MinVer" Version="2.3.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,10 @@
// ReSharper disable once CheckNamespace
namespace System.Runtime.CompilerServices
{
// Enables extension methods in assembly that targets .NET 2.0
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Method)]
internal sealed class ExtensionAttribute : Attribute
{
}
}

View File

@@ -0,0 +1,12 @@
using System.Windows.Forms;
namespace NHotkey.WindowsForms
{
static class Extensions
{
public static bool HasFlag(this Keys keys, Keys flag)
{
return (keys & flag) == flag;
}
}
}

View File

@@ -0,0 +1,91 @@
using System;
using System.Windows.Forms;
namespace NHotkey.WindowsForms
{
[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();
}
#endregion
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
private readonly MessageWindow _messageWindow;
private HotkeyManager()
{
_messageWindow = new MessageWindow(this);
SetHwnd(_messageWindow.Handle);
}
public void AddOrReplace(string name, Keys keys, bool noRepeat, EventHandler<HotkeyEventArgs> handler)
{
var flags = GetFlags(keys, noRepeat);
var vk = unchecked((uint)(keys & ~Keys.Modifiers));
AddOrReplace(name, vk, flags, handler);
}
public void AddOrReplace(string name, Keys keys, EventHandler<HotkeyEventArgs> handler)
{
AddOrReplace(name, keys, false, handler);
}
private static HotkeyFlags GetFlags(Keys hotkey, bool noRepeat)
{
var noMod = hotkey & ~Keys.Modifiers;
var flags = HotkeyFlags.None;
if (hotkey.HasFlag(Keys.Alt))
flags |= HotkeyFlags.Alt;
if (hotkey.HasFlag(Keys.Control))
flags |= HotkeyFlags.Control;
if (hotkey.HasFlag(Keys.Shift))
flags |= HotkeyFlags.Shift;
if (noMod == Keys.LWin || noMod == Keys.RWin)
flags |= HotkeyFlags.Windows;
if (noRepeat)
flags |= HotkeyFlags.NoRepeat;
return flags;
}
class MessageWindow : ContainerControl
{
private readonly HotkeyManager _hotkeyManager;
public MessageWindow(HotkeyManager hotkeyManager)
{
_hotkeyManager = hotkeyManager;
}
protected override CreateParams CreateParams
{
get
{
var parameters = base.CreateParams;
parameters.Parent = HwndMessage;
return parameters;
}
}
protected override void WndProc(ref Message m)
{
bool handled = false;
Hotkey hotkey;
m.Result = _hotkeyManager.HandleHotkeyMessage(Handle, m.Msg, m.WParam, m.LParam, ref handled, out hotkey);
if (!handled)
base.WndProc(ref m);
}
}
}
}

View File

@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFrameworks>net40;net45;netcoreapp3.0</TargetFrameworks>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<PropertyGroup Label="Package properties">
<Description>A managed library to handle global hotkeys in Windows Forms applications. This package contains the concrete HotkeyManager implementation for Windows Forms.</Description>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\NHotkey\NHotkey.csproj" />
</ItemGroup>
</Project>

View 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;
}
}
}

View 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; }
}
}
}

View 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;
}
}
}

View 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>

View 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")]

View 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();
}
}
}

37
NHotkey/NHotkey.sln Normal file
View File

@@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHotkey", "NHotkey\NHotkey.csproj", "{6CAB99C4-6F21-4508-9160-CE4DBF540840}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHotkey.WindowsForms", "NHotkey.WindowsForms\NHotkey.WindowsForms.csproj", "{F0D5CDB4-B74A-419B-9AD6-2A438A268837}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHotkey.Wpf", "NHotkey.Wpf\NHotkey.Wpf.csproj", "{FC92233F-6F08-45B7-B3EE-7C557582236B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6CAB99C4-6F21-4508-9160-CE4DBF540840}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6CAB99C4-6F21-4508-9160-CE4DBF540840}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6CAB99C4-6F21-4508-9160-CE4DBF540840}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6CAB99C4-6F21-4508-9160-CE4DBF540840}.Release|Any CPU.Build.0 = Release|Any CPU
{F0D5CDB4-B74A-419B-9AD6-2A438A268837}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F0D5CDB4-B74A-419B-9AD6-2A438A268837}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F0D5CDB4-B74A-419B-9AD6-2A438A268837}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F0D5CDB4-B74A-419B-9AD6-2A438A268837}.Release|Any CPU.Build.0 = Release|Any CPU
{FC92233F-6F08-45B7-B3EE-7C557582236B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC92233F-6F08-45B7-B3EE-7C557582236B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC92233F-6F08-45B7-B3EE-7C557582236B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC92233F-6F08-45B7-B3EE-7C557582236B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {67220BE9-A1D5-41B9-9D16-177606E9D4D5}
EndGlobalSection
EndGlobal

BIN
NHotkey/NHotkey.snk Normal file

Binary file not shown.

Binary file not shown.

71
NHotkey/NHotkey/Hotkey.cs Normal file
View File

@@ -0,0 +1,71 @@
using System;
using System.Runtime.InteropServices;
namespace NHotkey
{
internal class Hotkey
{
private static int _nextId;
private readonly int _id;
private readonly uint _virtualKey;
private readonly HotkeyFlags _flags;
private readonly EventHandler<HotkeyEventArgs> _handler;
public Hotkey(uint virtualKey, HotkeyFlags flags, EventHandler<HotkeyEventArgs> handler)
{
_id = ++_nextId;
_virtualKey = virtualKey;
_flags = flags;
_handler = handler;
}
public int Id
{
get { return _id; }
}
public uint VirtualKey
{
get { return _virtualKey; }
}
public HotkeyFlags Flags
{
get { return _flags; }
}
public EventHandler<HotkeyEventArgs> Handler
{
get { return _handler; }
}
private IntPtr _hwnd;
public void Register(IntPtr hwnd, string name)
{
if (!NativeMethods.RegisterHotKey(hwnd, _id, _flags, _virtualKey))
{
var hr = Marshal.GetHRForLastWin32Error();
var ex = Marshal.GetExceptionForHR(hr);
if ((uint) hr == 0x80070581)
throw new HotkeyAlreadyRegisteredException(name, ex);
throw ex;
}
_hwnd = hwnd;
}
public void Unregister()
{
if (_hwnd != IntPtr.Zero)
{
if (!NativeMethods.UnregisterHotKey(_hwnd, _id))
{
var hr = Marshal.GetHRForLastWin32Error();
throw Marshal.GetExceptionForHR(hr);
}
_hwnd = IntPtr.Zero;
}
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
namespace NHotkey
{
[Serializable]
public class HotkeyAlreadyRegisteredException : Exception
{
private readonly string _name;
public HotkeyAlreadyRegisteredException(string name, Exception inner) : base(inner.Message, inner)
{
_name = name;
HResult = Marshal.GetHRForException(inner);
}
protected HotkeyAlreadyRegisteredException(
SerializationInfo info,
StreamingContext context) : base(info, context)
{
_name = (string) info.GetValue("_name", typeof (string));
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("_name", _name);
}
public string Name
{
get { return _name; }
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
namespace NHotkey
{
public class HotkeyEventArgs : EventArgs
{
private readonly string _name;
internal HotkeyEventArgs(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
}
public bool Handled { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
using System;
namespace NHotkey
{
[Flags]
internal enum HotkeyFlags : uint
{
None = 0x0000,
Alt = 0x0001,
Control = 0x0002,
Shift = 0x0004,
Windows = 0x0008,
NoRepeat = 0x4000
}
}

View File

@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
namespace NHotkey
{
public abstract class HotkeyManagerBase
{
private readonly Dictionary<int, string> _hotkeyNames = new Dictionary<int, string>();
private readonly Dictionary<string, Hotkey> _hotkeys = new Dictionary<string, Hotkey>();
private IntPtr _hwnd;
internal static readonly IntPtr HwndMessage = (IntPtr)(-3);
internal HotkeyManagerBase()
{
}
internal void AddOrReplace(string name, uint virtualKey, HotkeyFlags flags, EventHandler<HotkeyEventArgs> handler)
{
var hotkey = new Hotkey(virtualKey, flags, handler);
lock (_hotkeys)
{
Remove(name);
_hotkeys.Add(name, hotkey);
_hotkeyNames.Add(hotkey.Id, name);
if (_hwnd != IntPtr.Zero)
hotkey.Register(_hwnd, name);
}
}
public void Remove(string name)
{
lock (_hotkeys)
{
Hotkey hotkey;
if (_hotkeys.TryGetValue(name, out hotkey))
{
_hotkeys.Remove(name);
_hotkeyNames.Remove(hotkey.Id);
if (_hwnd != IntPtr.Zero)
hotkey.Unregister();
}
}
}
public bool IsEnabled { get; set; } = true;
internal void SetHwnd(IntPtr hwnd)
{
_hwnd = hwnd;
}
private const int WmHotkey = 0x0312;
internal IntPtr HandleHotkeyMessage(
IntPtr hwnd,
int msg,
IntPtr wParam,
IntPtr lParam,
ref bool handled,
out Hotkey hotkey)
{
hotkey = null;
if (IsEnabled && msg == WmHotkey)
{
int id = wParam.ToInt32();
string name;
if (_hotkeyNames.TryGetValue(id, out name))
{
hotkey = _hotkeys[name];
var handler = hotkey.Handler;
if (handler != null)
{
var e = new HotkeyEventArgs(name);
handler(this, e);
handled = e.Handled;
}
}
}
return IntPtr.Zero;
}
}
}

View File

@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net40;net45;netcoreapp3.0;net6.0-windows</TargetFrameworks>
</PropertyGroup>
<PropertyGroup Label="Package properties">
<Description>A managed library to handle global hotkeys in Windows Forms and WPF applications. NOTE: this package doesn't contain a concrete HotkeyManager implementation; you should add either the NHotkey.Wpf or NHotkey.WindowsForms package to get one.</Description>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,14 @@
using System;
using System.Runtime.InteropServices;
namespace NHotkey
{
static class NativeMethods
{
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool RegisterHotKey(IntPtr hWnd, int id, HotkeyFlags fsModifiers, uint vk);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool UnregisterHotKey(IntPtr hWnd, int id);
}
}

View File

@@ -0,0 +1,4 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("NHotkey.WindowsForms, PublicKey=00240000048000009400000006020000002400005253413100040000010001000d37f28dea0d86462d702c5ff882a20c5701fc1421107b336430c0af082910e58ff42c9030dcfe5739ab99f74b91b11dd4de06bfcd30bc9402beb15f023becb0c6b92ad9496e8e5474f3f5684ed32bf9fb69da84593b8be9bebd86542bd452c5bb77e071bbb2f0024a501ebfa897a62798fe2f2a4e72f250fc9c8277e17db1d5")]
[assembly: InternalsVisibleTo("NHotkey.Wpf, PublicKey=00240000048000009400000006020000002400005253413100040000010001000d37f28dea0d86462d702c5ff882a20c5701fc1421107b336430c0af082910e58ff42c9030dcfe5739ab99f74b91b11dd4de06bfcd30bc9402beb15f023becb0c6b92ad9496e8e5474f3f5684ed32bf9fb69da84593b8be9bebd86542bd452c5bb77e071bbb2f0024a501ebfa897a62798fe2f2a4e72f250fc9c8277e17db1d5")]

2
NHotkey/README.md Normal file
View File

@@ -0,0 +1,2 @@
# NHotkey.Wpf