[WIP] Partway through swap to NHotkey

Also trying to port Willy-Kimura's HKL
HotkeySelector code over as well cause
it is ace!
This commit is contained in:
Terry MacDonald 2021-04-27 22:19:44 +12:00
parent 92c0678e79
commit 209e3f0338
4 changed files with 553 additions and 10 deletions

View File

@ -108,6 +108,9 @@
<Compile Include="GameLibraries\UplayLibrary.cs" />
<Compile Include="GameLibraries\SteamLibrary.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="HotkeySelector.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="IconFromFile.cs" />
<Compile Include="IconUtils.cs" />
<Compile Include="ImageUtils.cs" />
@ -262,9 +265,6 @@
<PackageReference Include="EDIDParser">
<Version>1.2.0.1</Version>
</PackageReference>
<PackageReference Include="HotkeyListener">
<Version>1.9.0</Version>
</PackageReference>
<PackageReference Include="HtmlAgilityPack">
<Version>1.11.33</Version>
</PackageReference>
@ -292,6 +292,12 @@
<PackageReference Include="Newtonsoft.Json">
<Version>13.0.1</Version>
</PackageReference>
<PackageReference Include="NHotkey">
<Version>2.1.0</Version>
</PackageReference>
<PackageReference Include="NHotkey.WindowsForms">
<Version>2.1.0</Version>
</PackageReference>
<PackageReference Include="NLog">
<Version>4.7.9</Version>
</PackageReference>

View File

@ -0,0 +1,537 @@
#region Copyright
/*
* Developer : Willy Kimura (WK).
* Library : HotkeySelector.
* License : MIT.
*
* Copied and repurposed to help with DisplayMagician by Terry MacDonald
*/
#endregion
using System;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
using System.Windows.Forms;
using System.ComponentModel;
namespace DisplayMagician
{
/// <summary>
/// Provides support for enabling standard Windows controls
/// and User controls to select hotkeys at runtime.
/// Combined with the <see cref="HotkeyListener"/> class,
/// you can easily enable the selection and registering of
/// hotkeys for a seamless end-user experience.
/// </summary>
[DebuggerStepThrough]
[Description("Provides support for enabling standard Windows controls " +
"and User controls to select hotkeys at runtime.")]
public partial class HotkeySelector : Component
{
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="HotkeySelector"/> class.
/// </summary>
public HotkeySelector() { }
/// <summary>
/// Initializes a new instance of the <see cref="HotkeySelector"/> class.
/// </summary>
public HotkeySelector(IContainer container)
{
container.Add(this);
//InitializeComponent();
}
#endregion
#region Fields
// These variables store the selected hotkey and modifier key(s).
private Keys _hotkey = Keys.None;
//private Keys _modifiers = Keys.None;
// ArrayLists used to enforce the use of proper modifiers.
// Shift+A isn't a valid hotkey, for instance.
private ArrayList _needNonShiftModifier = null;
private ArrayList _needNonAltGrModifier = null;
// Stores the list of enabled hotkey selection controls.
private List<Control> _controls = new List<Control>();
#endregion
#region Properties
#region Public
/// <summary>
/// Gets or sets the text to be displayed in a
/// control when no hotkey has been set.
/// (Preferred default text is "None")
/// </summary>
public string EmptyHotkeyText { get; set; } = "None";
/// <summary>
/// Gets or sets the text to be displayed in a control
/// when an invalid or unsupported hotkey is pressed.
/// (Preferred default text is "(Unsupported)")
/// </summary>
public string InvalidHotkeyText { get; set; } = "Unsupported";
#endregion
#endregion
#region Methods
#region Public
/// <summary>
/// Enables a control for hotkey selection and previewing.
/// This will make use of the control's Text property to
/// preview the current hotkey selected.
/// </summary>
/// <param name="control">The control to enable.</param>
public bool Enable(Control control)
{
try
{
control.Text = EmptyHotkeyText;
control.KeyPress += new KeyPressEventHandler(OnKeyPress);
control.KeyDown += new KeyEventHandler(OnKeyDown);
control.KeyUp += new KeyEventHandler(OnKeyUp);
ResetModifiers();
try
{
_controls.Add(control);
}
catch (Exception) { }
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Enables a control for hotkey selection and previewing.
/// This will make use of the control's Text property to
/// preview the current hotkey selected.
/// </summary>
/// <param name="control">The control to enable.</param>
/// <param name="hotkey">Assign the default Keys to be previewed in the control.</param>
public bool Enable(Control control, Keys hotkey)
{
try
{
Enable(control);
_hotkey = hotkey;
Refresh(control);
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Disables a control for hotkey selection and previewing.
/// </summary>
/// <param name="control">The control to disable.</param>
/// <param name="clearKeys">Clear the control's previewed keys?</param>
public bool Disable(Control control, bool clearKeys = true)
{
try
{
control.KeyPress -= OnKeyPress;
control.KeyDown -= OnKeyDown;
control.KeyUp -= OnKeyUp;
if (clearKeys)
control.Text = string.Empty;
try
{
if (_controls.Contains(control))
_controls.Remove(control);
}
catch (Exception) { }
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Gets a value indicating whether a specific
/// control is enabled for hotkey selection.
/// </summary>
/// <param name="control">The control to determine.</param>
public bool IsEnabled(Control control)
{
if (_controls.Contains(control))
return true;
else
return false;
}
/// <summary>
/// Sets a hotkey selection to be previewed in a control.
/// Thsi does not automatically enable the control for
/// hotkey selection. For this, please use the <see cref="Enable(Control)"/> method.
/// </summary>
/// <param name="control">The control to set.</param>
/// <param name="key">Provide a standard key selection.</param>
/// <param name="modifiers">Provide a modifier key selection.</param>
public bool Set(Control control, Keys hotkey)
{
try
{
_hotkey = hotkey;
Refresh(control);
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Clears the currently previewed hotkey
/// selection displayed in a control.
/// </summary>
public void Clear(Control control)
{
this._hotkey = Keys.None;
Refresh(control);
}
/// <summary>
/// (Variant of the <see cref="Clear(Control)"/> method)
/// Clears the currently previewed hotkey
/// selection displayed in a control.
/// </summary>
public void Reset(Control control)
{
this._hotkey = Keys.None;
Refresh(control);
}
/// <summary>
/// [Helper] Converts keys or key combinations to their string types.
/// </summary>
/// <param name="hotkey">The hotkey to convert.</param>
public string Convert(Keys hotkey)
{
try
{
_hotkey = hotkey;
string parsedHotkey = string.Empty;
// No modifier or shift only, and a hotkey that needs another modifier.
if ((_hotkey == Keys.Shift || _hotkey == Keys.None))
{
if (_needNonShiftModifier != null && _needNonShiftModifier.Contains((int)this._hotkey))
{
if (this._hotkey == Keys.None)
{
// Set Ctrl+Alt as the modifier unless Ctrl+Alt+<key> won't work.
if (_needNonAltGrModifier.Contains((int)this._hotkey) == false)
{
this._hotkey = Keys.Alt | Keys.Control;
}
else
{
// ...In that case, use Shift+Alt instead.
this._hotkey = Keys.Alt | Keys.Shift;
}
}
else
{
// User pressed Shift and an invalid key (e.g. a letter or a number),
// that needs another set of modifier keys.
this._hotkey = Keys.None;
}
}
}
// Without this code, pressing only Ctrl
// will show up as "Control + ControlKey", etc.
if (this._hotkey == Keys.Menu || /* Alt */
this._hotkey == Keys.ShiftKey ||
this._hotkey == Keys.ControlKey)
{
this._hotkey = Keys.None;
}
if (this._hotkey == Keys.None)
{
// LWin/RWin don't work as hotkeys...
// (neither do they work as modifier keys in .NET 2.0).
if (_hotkey == Keys.None || _hotkey == Keys.LWin || _hotkey == Keys.RWin)
{
parsedHotkey = string.Empty;
}
else
{
parsedHotkey = this._hotkey.ToString();
}
}
else
{
parsedHotkey = this._hotkey.ToString();
}
return parsedHotkey;
}
catch (Exception)
{
return string.Empty;
}
}
#endregion
#region Private
/// <summary>
/// Resets the hotkey modifiers to their defaults.
/// </summary>
private void ResetModifiers()
{
// Fill the ArrayLists that contain
// all invalid hotkey combinations.
_needNonShiftModifier = new ArrayList();
_needNonAltGrModifier = new ArrayList();
PopulateModifierLists();
}
/// <summary>
/// Populates the ArrayLists specifying disallowed Hotkeys
/// such as Shift+A, Ctrl+Alt+4 (produces 'dollar' sign).
/// </summary>
private void PopulateModifierLists()
{
// Shift + 0 - 9, A - Z.
for (Keys k = Keys.D0; k <= Keys.Z; k++)
_needNonShiftModifier.Add((int)k);
// Shift + Numpad keys.
for (Keys k = Keys.NumPad0; k <= Keys.NumPad9; k++)
_needNonShiftModifier.Add((int)k);
// Shift + Misc (,;<./ etc).
for (Keys k = Keys.Oem1; k <= Keys.OemBackslash; k++)
_needNonShiftModifier.Add((int)k);
// Shift + Space, PgUp, PgDn, End, Home.
for (Keys k = Keys.Space; k <= Keys.Home; k++)
_needNonShiftModifier.Add((int)k);
// Misc keys that we can't loop through.
_needNonShiftModifier.Add((int)Keys.Insert);
_needNonShiftModifier.Add((int)Keys.Help);
_needNonShiftModifier.Add((int)Keys.Multiply);
_needNonShiftModifier.Add((int)Keys.Add);
_needNonShiftModifier.Add((int)Keys.Subtract);
_needNonShiftModifier.Add((int)Keys.Divide);
_needNonShiftModifier.Add((int)Keys.Decimal);
_needNonShiftModifier.Add((int)Keys.Return);
_needNonShiftModifier.Add((int)Keys.Escape);
_needNonShiftModifier.Add((int)Keys.NumLock);
_needNonShiftModifier.Add((int)Keys.Scroll);
_needNonShiftModifier.Add((int)Keys.Pause);
// Ctrl+Alt + 0 - 9.
for (Keys k = Keys.D0; k <= Keys.D9; k++)
_needNonAltGrModifier.Add((int)k);
}
/// <summary>
/// Refreshes the previewed hotkey combination displayed in a control.
/// </summary>
/// <param name="control">
/// The control providing hotkey selection.
/// </param>
private void Refresh(Control control)
{
Refresh(control, false);
}
/// <summary>
/// Refreshes the previewed hotkey combination displayed in a control.
/// </summary>
/// <param name="control">
/// The control providing hotkey selection.
/// </param>
/// <param name="internalCall">
/// Specifies whether this function is
/// called internally or by the user.
/// </param>
private void Refresh(Control control, bool internalCall)
{
try
{
string parsedHotkey = string.Empty;
// No hotkey set.
if (this._hotkey == Keys.None)
{
control.Text = EmptyHotkeyText;
return;
}
// LWin/RWin don't work as hotkeys...
// (neither do they work as modifier keys in .NET 2.0).
if (this._hotkey == Keys.LWin || this._hotkey == Keys.RWin)
{
control.Text = InvalidHotkeyText;
return;
}
// Only validate input if it comes from the user.
if (internalCall == false)
{
// No modifier or shift only, and a hotkey that needs another modifier.
if ((this._hotkey == Keys.Shift || this._hotkey == Keys.None) &&
this._needNonShiftModifier.Contains((int)this._hotkey))
{
if (this._hotkey == Keys.None)
{
// Set Ctrl+Alt as the modifier unless Ctrl+Alt+<key> won't work.
if (_needNonAltGrModifier.Contains((int)this._hotkey) == false)
{
this._hotkey |= Keys.Alt | Keys.Control;
}
else
{
// ...In that case, use Shift+Alt instead.
this._hotkey |= Keys.Alt | Keys.Shift;
}
}
else
{
// User pressed Shift and an invalid key (e.g. a letter or a number),
// that needs another set of modifier keys.
this._hotkey = Keys.None;
control.Text = this._hotkey.ToString() + $" + {InvalidHotkeyText}";
return;
}
}
}
// Without this code, pressing only Ctrl
// will show up as "Control + ControlKey", etc.
if (this._hotkey == Keys.Menu || /* Alt */
this._hotkey == Keys.ShiftKey ||
this._hotkey == Keys.ControlKey)
{
this._hotkey = Keys.None;
}
// A final compilation of the processed keys in string format.
parsedHotkey = this._hotkey.ToString();
control.Text = parsedHotkey;
return;
}
catch (Exception) { }
}
#endregion
#endregion
#region Events
#region Private
/// <summary>
/// Fires when a key is pressed down. Here, we'll want to update the Text
/// property to notify the user what key combination is currently pressed.
/// </summary>
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.KeyData == Keys.Delete || e.KeyData == (Keys.Control | Keys.Delete))
Reset((Control)sender);
if (e.KeyData == (Keys.Shift | Keys.Insert))
{
this._hotkey = Keys.Shift;
e.Handled = true;
}
// Clear the current hotkey.
if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete)
{
Reset((Control)sender);
return;
}
else
{
this._hotkey = e.KeyCode;
Refresh((Control)sender);
}
}
/// <summary>
/// Fires when all keys are released. If the current hotkey isn't valid, reset it.
/// Otherwise, do nothing and keep the Text and hotkey as it was.
/// </summary>
private void OnKeyUp(object sender, KeyEventArgs e)
{
if (this._hotkey == Keys.None && Control.ModifierKeys == Keys.None)
{
Reset((Control)sender);
return;
}
}
/// <summary>
/// Prevents anything entered in Input controls from being displayed.
/// Without this, a "A" key press would appear as "aControl, Alt + A".
/// </summary>
private void OnKeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
#endregion
#endregion
}
}

View File

@ -17,7 +17,7 @@ using DesktopNotifications;
using System.Runtime.Serialization;
using NLog.Config;
using System.Collections.Generic;
using WK.Libraries.HotkeyListenerNS;
using NHotkey.WindowsForms;
namespace DisplayMagician {
@ -45,7 +45,6 @@ namespace DisplayMagician {
public static bool WaitingForGameToExit = false;
public static ProgramSettings AppProgramSettings;
public static MainForm AppMainForm;
public static HotkeyListener HotkeyListener;
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private static SharedLogger sharedLogger;
@ -206,8 +205,6 @@ namespace DisplayMagician {
Application.SetCompatibleTextRenderingDefault(false);
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// Create a program-wide HotKeyListener
HotkeyListener = new HotkeyListener();
logger.Debug($"Setting up commandline processing configuration");
var app = new CommandLineApplication

View File

@ -104,9 +104,6 @@
<PackageReference Include="EDIDParser">
<Version>1.2.0.1</Version>
</PackageReference>
<PackageReference Include="HotkeyListener">
<Version>1.9.0</Version>
</PackageReference>
<PackageReference Include="IconExtractor.dll">
<Version>1.0.2.1-beta</Version>
</PackageReference>
@ -121,6 +118,12 @@
<PackageReference Include="Newtonsoft.Json">
<Version>12.0.3</Version>
</PackageReference>
<PackageReference Include="NHotkey">
<Version>2.1.0</Version>
</PackageReference>
<PackageReference Include="NHotkey.WindowsForms">
<Version>2.1.0</Version>
</PackageReference>
<PackageReference Include="NLog">
<Version>4.7.8</Version>
</PackageReference>