From ec9268b43eec80e8e5cb15a89db1995e93cf264d Mon Sep 17 00:00:00 2001
From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com>
Date: Sat, 24 Jan 2026 12:34:04 +0100
Subject: [PATCH 01/13] Fix: launch parameters ignored for LaunchUrlCommand
(#417)
---
src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs | 4 ++--
.../Commands/InternalCommands/LaunchUrlCommand.cs | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs b/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs
index 5f604d43..72fbb27f 100644
--- a/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs
+++ b/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs
@@ -371,9 +371,9 @@ internal static void OpenLocalFolder(string path)
///
///
///
- internal static void LaunchUrl(string url, bool incognito = false)
+ internal static void LaunchUrl(string url, bool incognito = false, bool explicitUrl = false)
{
- var targetUrl = StorageManager.GetElementUrl(url);
+ var targetUrl = explicitUrl ? url : StorageManager.GetElementUrl(url);
// did the user provide a browser?
if (string.IsNullOrEmpty(Variables.AppSettings.BrowserBinary))
diff --git a/src/HASS.Agent/HASS.Agent/HomeAssistant/Commands/InternalCommands/LaunchUrlCommand.cs b/src/HASS.Agent/HASS.Agent/HomeAssistant/Commands/InternalCommands/LaunchUrlCommand.cs
index b20b53d2..b8884225 100644
--- a/src/HASS.Agent/HASS.Agent/HomeAssistant/Commands/InternalCommands/LaunchUrlCommand.cs
+++ b/src/HASS.Agent/HASS.Agent/HomeAssistant/Commands/InternalCommands/LaunchUrlCommand.cs
@@ -39,7 +39,7 @@ public override void TurnOn()
return;
}
- HelperFunctions.LaunchUrl(_url, _incognito);
+ HelperFunctions.LaunchUrl(_url, _incognito, true);
State = "OFF";
}
@@ -59,7 +59,7 @@ public override void TurnOnWithAction(string action)
// prepare command
var command = string.IsNullOrWhiteSpace(_url) ? action : $"{_url} {action}";
- HelperFunctions.LaunchUrl(command, _incognito);
+ HelperFunctions.LaunchUrl(command, _incognito, true);
State = "OFF";
}
From efcb0e224e4f3dafd638d84092e9fca51b0260b4 Mon Sep 17 00:00:00 2001
From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com>
Date: Sat, 24 Jan 2026 12:40:54 +0100
Subject: [PATCH 02/13] Release: 2.2.1 (#418)
---
src/HASS.Agent.Installer/InstallerScript-Service-x86.iss | 2 +-
src/HASS.Agent.Installer/InstallerScript-Service.iss | 2 +-
src/HASS.Agent.Installer/InstallerScript-x86.iss | 2 +-
src/HASS.Agent.Installer/InstallerScript.iss | 2 +-
.../HASS.Agent.Satellite.Service.csproj | 6 +++---
src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj | 6 +++---
src/HASS.Agent/HASS.Agent/HASS.Agent.csproj | 6 +++---
7 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss b/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss
index 9b632fc5..d34a5ec6 100644
--- a/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss
+++ b/src/HASS.Agent.Installer/InstallerScript-Service-x86.iss
@@ -9,7 +9,7 @@
; Standard installation constants
#define MyAppName "HASS.Agent Satellite Service"
-#define MyAppVersion "2.2.0"
+#define MyAppVersion "2.2.1"
#define MyAppPublisher "HASS.Agent Team"
#define MyAppURL "https://hass-agent.io"
#define MyAppExeName "HASS.Agent.Satellite.Service.exe"
diff --git a/src/HASS.Agent.Installer/InstallerScript-Service.iss b/src/HASS.Agent.Installer/InstallerScript-Service.iss
index f2825143..f9c44adb 100644
--- a/src/HASS.Agent.Installer/InstallerScript-Service.iss
+++ b/src/HASS.Agent.Installer/InstallerScript-Service.iss
@@ -9,7 +9,7 @@
; Standard installation constants
#define MyAppName "HASS.Agent Satellite Service"
-#define MyAppVersion "2.2.0"
+#define MyAppVersion "2.2.1"
#define MyAppPublisher "HASS.Agent Team"
#define MyAppURL "https://hass-agent.io"
#define MyAppExeName "HASS.Agent.Satellite.Service.exe"
diff --git a/src/HASS.Agent.Installer/InstallerScript-x86.iss b/src/HASS.Agent.Installer/InstallerScript-x86.iss
index 62f11d9e..75927faa 100644
--- a/src/HASS.Agent.Installer/InstallerScript-x86.iss
+++ b/src/HASS.Agent.Installer/InstallerScript-x86.iss
@@ -9,7 +9,7 @@
; Standard installation constants
#define MyAppName "HASS.Agent"
-#define MyAppVersion "2.2.0"
+#define MyAppVersion "2.2.1"
#define MyAppPublisher "HASS.Agent Team"
#define MyAppURL "https://hass-agent.io"
#define MyAppExeName "HASS.Agent.exe"
diff --git a/src/HASS.Agent.Installer/InstallerScript.iss b/src/HASS.Agent.Installer/InstallerScript.iss
index 4519dba4..335f0338 100644
--- a/src/HASS.Agent.Installer/InstallerScript.iss
+++ b/src/HASS.Agent.Installer/InstallerScript.iss
@@ -9,7 +9,7 @@
; Standard installation constants
#define MyAppName "HASS.Agent"
-#define MyAppVersion "2.2.0"
+#define MyAppVersion "2.2.1"
#define MyAppPublisher "HASS.Agent Team"
#define MyAppURL "https://hass-agent.io"
#define MyAppExeName "HASS.Agent.exe"
diff --git a/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj b/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj
index 1e3dfd54..4464d5b6 100644
--- a/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj
+++ b/src/HASS.Agent/HASS.Agent.Satellite.Service/HASS.Agent.Satellite.Service.csproj
@@ -8,7 +8,7 @@
dotnet-HASSAgentSatelliteService-6E4FA50A-3AC9-4E66-8671-9FAB92372154
anycpu
x64;x86;AnyCPU
- 2.2.0
+ 2.2.1
HASS.Agent Team
HASS.Agent Satellite Service
HASS.Agent.Satellite.Service
@@ -17,9 +17,9 @@
https://github.com/hass-agent/HASS.Agent
https://github.com/hass-agent/HASS.Agent
hass.png
- 2.2.0
+ 2.2.1
hass.ico
- 2.2.0
+ 2.2.1
10.0.17763.0
false
diff --git a/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj b/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj
index 0fae9b41..31336c84 100644
--- a/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj
+++ b/src/HASS.Agent/HASS.Agent.Shared/HASS.Agent.Shared.csproj
@@ -10,9 +10,9 @@
Shared functions and models for the HASS.Agent platform.
https://github.com/hass-agent/HASS.Agent
https://github.com/hass-agent/HASS.Agent
- 2.2.0
- 2.2.0
- 2.2.0
+ 2.2.1
+ 2.2.1
+ 2.2.1
logo_128.png
True
hassagent.ico
diff --git a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj
index 0ce5be7e..42f43703 100644
--- a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj
+++ b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj
@@ -17,7 +17,7 @@
anycpu
x64;x86;AnyCPU
full
- 2.2.0
+ 2.2.1
HASS.Agent Team
HASS.Agent Team
Windows-based client for Home Assistant. Provides notifications, quick actions, commands, sensors and more.
@@ -27,8 +27,8 @@
https://github.com/hass-agent/HASS.Agent
MIT
app.manifest
- 2.2.0
- 2.2.0
+ 2.2.1
+ 2.2.1
HASS.Agent
None
true
From c5540318a68b79a3b13c5ebd813c62cff0dc8985 Mon Sep 17 00:00:00 2001
From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com>
Date: Sat, 7 Feb 2026 19:51:39 +0100
Subject: [PATCH 03/13] Fix: launch parameters for LaunchURLCommand not treated
explicitly (#428)
From 7a55068c40eec5728ffd636a2eb6cd42852319bd Mon Sep 17 00:00:00 2001
From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com>
Date: Sat, 7 Feb 2026 20:09:38 +0100
Subject: [PATCH 04/13] Fix: MQTT connection test using proper username &
password (#429)
This PR fixes issue reported via #396 by @jwidess where MQTT connection test during initial onboarding would check "configured" username rather than the provided one.
---
src/HASS.Agent/HASS.Agent/MQTT/MqttManager.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/HASS.Agent/HASS.Agent/MQTT/MqttManager.cs b/src/HASS.Agent/HASS.Agent/MQTT/MqttManager.cs
index 67cfb13b..43eae3a5 100644
--- a/src/HASS.Agent/HASS.Agent/MQTT/MqttManager.cs
+++ b/src/HASS.Agent/HASS.Agent/MQTT/MqttManager.cs
@@ -917,7 +917,7 @@ internal static async Task TestConnection(string address, int port, bool u
clientOptionsBuilder.WithTcpServer(address, port);
}
- if (!string.IsNullOrEmpty(Variables.AppSettings.MqttUsername))
+ if (!string.IsNullOrEmpty(username))
{
clientOptionsBuilder.WithCredentials(username, password);
}
From dcab412d8133f14693971a2e269f670f40c26d9c Mon Sep 17 00:00:00 2001
From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com>
Date: Sat, 7 Feb 2026 20:41:25 +0100
Subject: [PATCH 05/13] Fix: "ESCAPE" key as KeyCommand parameter (#431)
This PR fixes issue reported via #423 by @arklev where "ESCAPE" key couldn't be provided as a parameter to KeyCommand - configuration window would close.
Now closing the window requires pressing "ESCAPE" key twice.
---
.../HASS.Agent/Forms/Commands/CommandsMod.cs | 22 ++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandsMod.cs b/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandsMod.cs
index a14d80bc..de248bda 100644
--- a/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandsMod.cs
+++ b/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandsMod.cs
@@ -28,7 +28,9 @@ public partial class CommandsMod : MetroForm
private bool _interfaceLockedWrongType;
private bool _loading = true;
- private readonly Dictionary _commandEntityTypes = new();
+ private bool _escapeLock = true;
+
+ private readonly Dictionary _commandEntityTypes = new();
private readonly Dictionary _radioDevices = new();
public CommandsMod(ConfiguredCommand command, bool serviceMode = false, string serviceDeviceName = "")
@@ -977,11 +979,21 @@ private void LblIntegrityInfo_Click(object sender, EventArgs e)
private void CommandsMod_KeyUp(object sender, KeyEventArgs e)
{
- if (e.KeyCode != Keys.Escape)
- return;
+ if (e.KeyCode != Keys.Escape)
+ {
+ _escapeLock = true;
+ return;
+ }
- Close();
- }
+ if (_escapeLock)
+ {
+ _escapeLock = false;
+ }
+ else
+ {
+ Close();
+ }
+ }
private void CommandsMod_Layout(object sender, LayoutEventArgs e)
{
From 30c21ffa8ef044b4abd6e41a35e6b5dd8546525d Mon Sep 17 00:00:00 2001
From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com>
Date: Sat, 7 Feb 2026 21:52:42 +0100
Subject: [PATCH 06/13] Fix: WebViewCommand position not working properly with
negative values (#432)
This PR fixes an issue reported via #427 by @DyadicOne where moving WebViewCommand configuration window to screen with negative location values, would cause HASS.Agent to crash/save last positive value.
---
.../CommandConfig/WebViewCommandConfig.Designer.cs | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandConfig/WebViewCommandConfig.Designer.cs b/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandConfig/WebViewCommandConfig.Designer.cs
index 718b80ee..cba67b64 100644
--- a/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandConfig/WebViewCommandConfig.Designer.cs
+++ b/src/HASS.Agent/HASS.Agent/Forms/Commands/CommandConfig/WebViewCommandConfig.Designer.cs
@@ -243,11 +243,8 @@ private void InitializeComponent()
this.NumLocationX.Font = new System.Drawing.Font("Segoe UI", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.NumLocationX.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(241)))), ((int)(((byte)(241)))), ((int)(((byte)(241)))));
this.NumLocationX.Location = new System.Drawing.Point(34, 160);
- this.NumLocationX.Maximum = new decimal(new int[] {
- 65535,
- 0,
- 0,
- 0});
+ this.NumLocationX.Maximum = new decimal(Int32.MaxValue);
+ this.NumLocationX.Minimum = new decimal(Int32.MinValue);
this.NumLocationX.MaxLength = 10;
this.NumLocationX.MetroColor = System.Drawing.SystemColors.WindowFrame;
this.NumLocationX.Name = "NumLocationX";
@@ -269,11 +266,8 @@ private void InitializeComponent()
this.NumLocationY.Font = new System.Drawing.Font("Segoe UI", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.NumLocationY.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(241)))), ((int)(((byte)(241)))), ((int)(((byte)(241)))));
this.NumLocationY.Location = new System.Drawing.Point(149, 160);
- this.NumLocationY.Maximum = new decimal(new int[] {
- 65535,
- 0,
- 0,
- 0});
+ this.NumLocationY.Maximum = new decimal(Int32.MaxValue);
+ this.NumLocationY.Minimum = new decimal(Int32.MinValue);
this.NumLocationY.MaxLength = 10;
this.NumLocationY.MetroColor = System.Drawing.SystemColors.WindowFrame;
this.NumLocationY.Name = "NumLocationY";
From 493f22f73cf9ebd4ea94dce096b0ce372e9fd549 Mon Sep 17 00:00:00 2001
From: Serge Baranov
Date: Sun, 22 Mar 2026 03:18:45 -0700
Subject: [PATCH 07/13] Fix LastActiveSensor reporting wrong time after ~25
days (#440)
Thanks to @CrazyCoder!
```
Replace Environment.TickCount with Environment.TickCount64 (Int64). This returns the same millisecond count but won't overflow for about 292 million years.
Also changed Convert.ToDouble(lastInputInfo.dwTime) to (long)lastInputInfo.dwTime so the arithmetic stays in integer types instead of going through floating point for no reason.
```
---
.../Sensors/GeneralSensors/SingleValue/LastActiveSensor.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/HASS.Agent/HASS.Agent.Shared/HomeAssistant/Sensors/GeneralSensors/SingleValue/LastActiveSensor.cs b/src/HASS.Agent/HASS.Agent.Shared/HomeAssistant/Sensors/GeneralSensors/SingleValue/LastActiveSensor.cs
index 7796990c..5d7de85e 100644
--- a/src/HASS.Agent/HASS.Agent.Shared/HomeAssistant/Sensors/GeneralSensors/SingleValue/LastActiveSensor.cs
+++ b/src/HASS.Agent/HASS.Agent.Shared/HomeAssistant/Sensors/GeneralSensors/SingleValue/LastActiveSensor.cs
@@ -86,12 +86,12 @@ private static DateTime GetLastInputTime()
lastInputInfo.cbSize = Marshal.SizeOf(lastInputInfo);
lastInputInfo.dwTime = 0;
- var envTicks = Environment.TickCount;
+ var envTicks = Environment.TickCount64;
if (!GetLastInputInfo(ref lastInputInfo))
return DateTime.Now;
- var lastInputTick = Convert.ToDouble(lastInputInfo.dwTime);
+ var lastInputTick = (long)lastInputInfo.dwTime;
var idleTime = envTicks - lastInputTick;
return idleTime > 0 ? DateTime.Now - TimeSpan.FromMilliseconds(idleTime) : DateTime.Now;
From 3ab46fb972a16ce5b0d0d3df84dcf4878d1e43aa Mon Sep 17 00:00:00 2001
From: Bluscream
Date: Sun, 22 Mar 2026 11:57:07 +0100
Subject: [PATCH 08/13] Fix: NullReferenceException in Satellite Service on
unknown types
Thanks to @Bluscream for the PR!
---
.../Settings/StoredCommands.cs | 7 +++++--
.../Settings/StoredSensors.cs | 14 +++++++++++---
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredCommands.cs b/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredCommands.cs
index 0673e775..de838048 100644
--- a/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredCommands.cs
+++ b/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredCommands.cs
@@ -1,4 +1,4 @@
-using HASS.Agent.Shared.Enums;
+using HASS.Agent.Shared.Enums;
using HASS.Agent.Shared.Models.Config;
using HASS.Agent.Shared.HomeAssistant.Commands;
using HASS.Agent.Shared.HomeAssistant.Commands.CustomCommands;
@@ -56,7 +56,10 @@ internal static async Task LoadAsync()
// convert to abstract commands
await Task.Run(delegate
{
- foreach (var abstractCommand in configuredCommands.Select(ConvertConfiguredToAbstract)) Variables.Commands.Add(abstractCommand!);
+ foreach (var abstractCommand in configuredCommands.Select(ConvertConfiguredToAbstract))
+ {
+ if (abstractCommand != null) Variables.Commands.Add(abstractCommand);
+ }
});
// all good
diff --git a/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredSensors.cs b/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredSensors.cs
index ea81e57a..556c8086 100644
--- a/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredSensors.cs
+++ b/src/HASS.Agent/HASS.Agent.Satellite.Service/Settings/StoredSensors.cs
@@ -1,4 +1,4 @@
-using HASS.Agent.Shared.Enums;
+using HASS.Agent.Shared.Enums;
using HASS.Agent.Shared.Models.Config;
using HASS.Agent.Satellite.Service.Extensions;
using HASS.Agent.Shared.HomeAssistant.Sensors;
@@ -61,8 +61,16 @@ await Task.Run(delegate
{
foreach (var sensor in configuredSensors)
{
- if (sensor.IsSingleValue()) Variables.SingleValueSensors.Add(ConvertConfiguredToAbstractSingleValue(sensor)!);
- else Variables.MultiValueSensors.Add(ConvertConfiguredToAbstractMultiValue(sensor)!);
+ if (sensor.IsSingleValue())
+ {
+ var abstractSensor = ConvertConfiguredToAbstractSingleValue(sensor);
+ if (abstractSensor != null) Variables.SingleValueSensors.Add(abstractSensor);
+ }
+ else
+ {
+ var abstractSensor = ConvertConfiguredToAbstractMultiValue(sensor);
+ if (abstractSensor != null) Variables.MultiValueSensors.Add(abstractSensor);
+ }
}
});
From fdbeae63907a869fc12b680dead49ad57c6cc263 Mon Sep 17 00:00:00 2001
From: amadeo-alex <68441479+amadeo-alex@users.noreply.github.com>
Date: Thu, 28 May 2026 12:16:48 +0200
Subject: [PATCH 09/13] Fix: Hotkey Library Change (#449)
---
.../Onboarding/Onboarding-6-HotKey.cs | 68 ++++-
.../HASS.Agent/Forms/Configuration.cs | 259 +++++++++++++-----
src/HASS.Agent/HASS.Agent/Forms/Main.cs | 25 +-
.../Forms/QuickActions/QuickActionsConfig.cs | 2 +-
.../Forms/QuickActions/QuickActionsMod.cs | 77 ++++--
.../HASS.Agent/Functions/HelperFunctions.cs | 4 +-
src/HASS.Agent/HASS.Agent/HASS.Agent.csproj | 4 +-
.../HASS.Agent/Libraries/HotkeyListener.dll | Bin 448000 -> 0 bytes
...KeyManager.cs => InternalHotKeyManager.cs} | 103 +++++--
.../HASS.Agent/Settings/SettingsManager.cs | 3 +-
src/HASS.Agent/HASS.Agent/Variables.cs | 8 +-
11 files changed, 412 insertions(+), 141 deletions(-)
delete mode 100644 src/HASS.Agent/HASS.Agent/Libraries/HotkeyListener.dll
rename src/HASS.Agent/HASS.Agent/Managers/{HotKeyManager.cs => InternalHotKeyManager.cs} (51%)
diff --git a/src/HASS.Agent/HASS.Agent/Controls/Onboarding/Onboarding-6-HotKey.cs b/src/HASS.Agent/HASS.Agent/Controls/Onboarding/Onboarding-6-HotKey.cs
index d0313c97..a8c556f7 100644
--- a/src/HASS.Agent/HASS.Agent/Controls/Onboarding/Onboarding-6-HotKey.cs
+++ b/src/HASS.Agent/HASS.Agent/Controls/Onboarding/Onboarding-6-HotKey.cs
@@ -1,12 +1,13 @@
using HASS.Agent.Functions;
-using WK.Libraries.HotkeyListenerNS;
+using System.Windows.Forms;
namespace HASS.Agent.Controls.Onboarding
{
public partial class OnboardingHotKey : UserControl
{
- private readonly HotkeySelector _hotkeySelector = new();
-
+ private Keys _key = Keys.None;
+ private Keys _modifiers = Keys.None;
+
public OnboardingHotKey()
{
InitializeComponent();
@@ -14,19 +15,18 @@ public OnboardingHotKey()
private void OnboardingHotKey_Load(object sender, EventArgs e)
{
- // config quick actions hotkey selector
- _hotkeySelector.Enable(TbQuickActionsHotkey);
-
+ TbQuickActionsHotkey.ReadOnly = true;
+ TbQuickActionsHotkey.KeyDown += TbQuickActionsHotkey_KeyDown;
if (string.IsNullOrEmpty(Variables.AppSettings.QuickActionsHotKey))
{
// if nothing set, load default
LoadDefault();
}
- else if (Variables.AppSettings.QuickActionsHotKey == _hotkeySelector.EmptyHotkeyText)
+ else if (Variables.AppSettings.QuickActionsHotKey == string.Empty)
{
// if set to empty, show empty
- TbQuickActionsHotkey.Text = _hotkeySelector.EmptyHotkeyText;
+ TbQuickActionsHotkey.Text = string.Empty;
}
else
{
@@ -81,13 +81,61 @@ private void LoadSetValue()
internal bool Store()
{
Variables.AppSettings.QuickActionsHotKey = TbQuickActionsHotkey.Text;
- _hotkeySelector.Dispose();
+ TbQuickActionsHotkey.KeyDown -= TbQuickActionsHotkey_KeyDown;
return true;
}
private void BtnClear_Click(object sender, EventArgs e)
{
- TbQuickActionsHotkey.Text = _hotkeySelector.EmptyHotkeyText;
+ TbQuickActionsHotkey.Text = string.Empty;
+ }
+
+ private void TbQuickActionsHotkey_KeyDown(object sender, KeyEventArgs e)
+ {
+ e.SuppressKeyPress = true;
+
+ var key = e.KeyCode;
+
+ if (key is Keys.LControlKey or Keys.RControlKey
+ or Keys.LShiftKey or Keys.RShiftKey
+ or Keys.LWin or Keys.RWin
+ or Keys.Alt)
+ {
+ key = Keys.None;
+ }
+
+ if (key == Keys.Escape)
+ {
+ _key = Keys.None;
+ _modifiers = Keys.None;
+ TbQuickActionsHotkey.Text = string.Empty;
+
+ return;
+ }
+
+ _key = key;
+ TbQuickActionsHotkey.Text = FormatHotkey(_key, e.Modifiers);
+ }
+
+ private string FormatHotkey(Keys key, Keys modifiers)
+ {
+ var parts = new List();
+ if ((modifiers & Keys.Shift) != 0)
+ {
+ parts.Add(nameof(Keys.Shift));
+ }
+
+ if ((modifiers & Keys.Control) != 0)
+ {
+ parts.Add(nameof(Keys.Control));
+ }
+
+ if ((modifiers & Keys.Alt) != 0)
+ {
+ parts.Add(nameof(Keys.Alt));
+ }
+
+ return parts.Count > 0 ? string.Join(", ", parts) + " + " + key : key.ToString();
}
}
}
diff --git a/src/HASS.Agent/HASS.Agent/Forms/Configuration.cs b/src/HASS.Agent/HASS.Agent/Forms/Configuration.cs
index 8c081535..cf1f6baa 100644
--- a/src/HASS.Agent/HASS.Agent/Forms/Configuration.cs
+++ b/src/HASS.Agent/HASS.Agent/Forms/Configuration.cs
@@ -8,7 +8,6 @@
using HASS.Agent.Settings;
using HASS.Agent.Shared;
using HASS.Agent.Shared.Functions;
-using WK.Libraries.HotkeyListenerNS;
using Task = System.Threading.Tasks.Task;
using ConfigSatelliteService = HASS.Agent.Controls.Configuration.ConfigService;
using HASS.Agent.MQTT;
@@ -17,8 +16,7 @@ namespace HASS.Agent.Forms
{
public partial class Configuration : MetroForm
{
- private readonly HotkeySelector _hotkeySelector = new();
- private readonly Hotkey _previousHotkey = Variables.QuickActionsHotKey;
+ private readonly string _previousHotkey = Variables.QuickActionsHotKey;
private readonly string _previousDeviceName = Variables.AppSettings.DeviceName;
private readonly int _previousLocalApiPort = Variables.AppSettings.LocalApiPort;
@@ -41,6 +39,9 @@ public partial class Configuration : MetroForm
private bool _initializing = true;
+ private Keys _key = Keys.None;
+ private Keys _modifiers = Keys.None;
+
public Configuration()
{
InitializeComponent();
@@ -52,7 +53,7 @@ private void Configuration_Load(object sender, EventArgs e)
KeyPreview = true;
// suspend global hotkeys
- Variables.HotKeyListener.Suspend();
+ Variables.HotKeyListener.IsEnabled = false;
// load controls
TabGeneral.Controls.Add(_general);
@@ -79,18 +80,21 @@ private void Configuration_Load(object sender, EventArgs e)
LoadSettings();
// config quick actions hotkey selector
- if (Variables.QuickActionsHotKey != null) _hotkeySelector.Enable(_hotKey.TbQuickActionsHotkey, Variables.QuickActionsHotKey);
- else _hotkeySelector.Enable(_hotKey.TbQuickActionsHotkey);
+ _hotKey.TbQuickActionsHotkey.ReadOnly = true;
+ _hotKey.TbQuickActionsHotkey.KeyDown += TbQuickActionsHotkey_KeyDown;
+ if (Variables.QuickActionsHotKey != null)
+ {
+ _hotKey.TbQuickActionsHotkey.Text = Variables.QuickActionsHotKey;
+ }
}
private void Configuration_FormClosing(object sender, FormClosingEventArgs e)
{
// resume global hotkeys
- Variables.HotKeyListener.Resume();
+ Variables.HotKeyListener.IsEnabled = true;
- // remove hotkey selector
- _hotkeySelector?.Disable(_hotKey.TbQuickActionsHotkey);
- _hotkeySelector?.Dispose();
+ // clean hotkey selector
+ _hotKey.TbQuickActionsHotkey.KeyDown -= TbQuickActionsHotkey_KeyDown;
// dispose controls
_general.Dispose();
@@ -110,14 +114,62 @@ private void Configuration_FormClosing(object sender, FormClosingEventArgs e)
_nfc.Dispose();
}
+ private void TbQuickActionsHotkey_KeyDown(object sender, KeyEventArgs e)
+ {
+ e.SuppressKeyPress = true;
+
+ var key = e.KeyCode;
+
+ if (key is Keys.LControlKey or Keys.RControlKey
+ or Keys.LShiftKey or Keys.RShiftKey
+ or Keys.LWin or Keys.RWin
+ or Keys.Alt)
+ {
+ key = Keys.None;
+ }
+
+ if (key == Keys.Escape)
+ {
+ _key = Keys.None;
+ _modifiers = Keys.None;
+ _hotKey.TbQuickActionsHotkey.Text = string.Empty;
+
+ return;
+ }
+
+ _key = key;
+ _hotKey.TbQuickActionsHotkey.Text = FormatHotkey(_key, e.Modifiers);
+ }
+
+ private string FormatHotkey(Keys key, Keys modifiers)
+ {
+ var parts = new List();
+ if ((modifiers & Keys.Shift) != 0)
+ {
+ parts.Add(nameof(Keys.Shift));
+ }
+
+ if ((modifiers & Keys.Control) != 0)
+ {
+ parts.Add(nameof(Keys.Control));
+ }
+
+ if ((modifiers & Keys.Alt) != 0)
+ {
+ parts.Add(nameof(Keys.Alt));
+ }
+
+ return parts.Count > 0 ? string.Join(", ", parts) + " + " + key : key.ToString();
+ }
+
private void BindEvents()
{
// hass
_homeAssistantApi.CbHassAutoClientCertificate.CheckedChanged += CbHassAutoClientCertificate_CheckedChanged;
-
+
// mqtt
_mqtt.CbMqttTls.CheckedChanged += CbMqttTls_CheckedChanged;
-
+
// hotkey
_hotKey.BtnClearHotKey.Click += BtnClearHotKey_Click;
}
@@ -148,7 +200,8 @@ private async void ProcessChanges()
BtnStore.Text = Languages.Configuration_BtnStore_Busy;
// optionally sanitize device name
- if (_general.CbEnableDeviceNameSanitation.Checked) _general.TbDeviceName.Text = SharedHelperFunctions.GetSafeValue(_general.TbDeviceName.Text);
+ if (_general.CbEnableDeviceNameSanitation.Checked)
+ _general.TbDeviceName.Text = SharedHelperFunctions.GetSafeValue(_general.TbDeviceName.Text);
// store settings
await StoreSettingsAsync();
@@ -198,28 +251,32 @@ private async void ProcessChanges()
// disconnect mqtt so we don't get announced again
await Task.Run(Variables.MqttManager.Disconnect);
-
+
forceRestart = true;
}
// reserve the new local api's port if it's changed
if (Variables.AppSettings.LocalApiPort != _previousLocalApiPort)
{
- MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox2, Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
+ MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox2, Variables.MessageBoxTitle,
+ MessageBoxButtons.OK, MessageBoxIcon.Information);
// try to reserve elevated
if (!ApiManager.ExecuteElevatedPortReservation())
{
// failed, copy the command onto the clipboard
- Clipboard.SetText($"netsh http add urlacl url=http://+:{Variables.AppSettings.LocalApiPort}/ user=\"{SharedHelperFunctions.EveryoneLocalizedAccountName()}\"");
+ Clipboard.SetText(
+ $"netsh http add urlacl url=http://+:{Variables.AppSettings.LocalApiPort}/ user=\"{SharedHelperFunctions.EveryoneLocalizedAccountName()}\"");
// notify the user
- MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox3, Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
+ MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox3,
+ Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
// notify the user
- MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox4, Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
+ MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox4,
+ Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
// we need to restart, so go ahead, otherwise it's starting to look like popup-spam ..
forceRestart = true;
@@ -230,17 +287,22 @@ private async void ProcessChanges()
{
// prepare the restart without asking
var restartPrepared = HelperFunctions.Restart();
- if (!restartPrepared) MessageBoxAdv.Show(this, Languages.Configuration_MessageBox_RestartManually, Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
+ if (!restartPrepared)
+ MessageBoxAdv.Show(this, Languages.Configuration_MessageBox_RestartManually,
+ Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
// ask the user if they want to restart
- var question = MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox5, Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
+ var question = MessageBoxAdv.Show(this, Languages.Configuration_ProcessChanges_MessageBox5,
+ Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (question == DialogResult.Yes)
{
// prepare the restart
var restartPrepared = HelperFunctions.Restart();
- if (!restartPrepared) MessageBoxAdv.Show(this, Languages.Configuration_MessageBox_RestartManually, Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
+ if (!restartPrepared)
+ MessageBoxAdv.Show(this, Languages.Configuration_MessageBox_RestartManually,
+ Variables.MessageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
@@ -260,7 +322,8 @@ private bool CheckValues()
{
if (!SharedHelperFunctions.CheckHomeAssistantApiToken(hassApi))
{
- var q = MessageBoxAdv.Show(this, Languages.Configuration_CheckValues_MessageBox1, Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
+ var q = MessageBoxAdv.Show(this, Languages.Configuration_CheckValues_MessageBox1,
+ Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
if (q != DialogResult.Yes) return false;
}
}
@@ -271,7 +334,8 @@ private bool CheckValues()
{
if (!SharedHelperFunctions.CheckHomeAssistantUri(hassUri))
{
- var q = MessageBoxAdv.Show(this, Languages.Configuration_CheckValues_MessageBox2, Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
+ var q = MessageBoxAdv.Show(this, Languages.Configuration_CheckValues_MessageBox2,
+ Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
if (q != DialogResult.Yes) return false;
}
}
@@ -282,7 +346,8 @@ private bool CheckValues()
{
if (!SharedHelperFunctions.CheckMqttBrokerUri(mqttUri))
{
- var q = MessageBoxAdv.Show(this, Languages.Configuration_CheckValues_MessageBox3, Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
+ var q = MessageBoxAdv.Show(this, Languages.Configuration_CheckValues_MessageBox3,
+ Variables.MessageBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
if (q != DialogResult.Yes) return false;
}
}
@@ -298,28 +363,42 @@ private void LoadSettings()
{
// general
_general.TbDeviceName.Text = Variables.AppSettings.DeviceName;
- _general.CbEnableDeviceNameSanitation.CheckState = Variables.AppSettings.SanitizeName ? CheckState.Checked : CheckState.Unchecked;
+ _general.CbEnableDeviceNameSanitation.CheckState =
+ Variables.AppSettings.SanitizeName ? CheckState.Checked : CheckState.Unchecked;
_general.NumDisconnectGrace.Value = Variables.AppSettings.DisconnectedGracePeriodSeconds;
- _general.CbEnableStateNotifications.CheckState = Variables.AppSettings.EnableStateNotifications ? CheckState.Checked : CheckState.Unchecked;
+ _general.CbEnableStateNotifications.CheckState = Variables.AppSettings.EnableStateNotifications
+ ? CheckState.Checked
+ : CheckState.Unchecked;
// startup settings
Task.Run(_startup.DetermineStartOnLoginStatus);
// local api
_localApi.NumLocalApiPort.Value = Variables.AppSettings.LocalApiPort;
- _localApi.CbLocalApiActive.CheckState = Variables.AppSettings.LocalApiEnabled ? CheckState.Checked : CheckState.Unchecked;
+ _localApi.CbLocalApiActive.CheckState =
+ Variables.AppSettings.LocalApiEnabled ? CheckState.Checked : CheckState.Unchecked;
// notifications
- _notifications.CbAcceptNotifications.CheckState = Variables.AppSettings.NotificationsEnabled ? CheckState.Checked : CheckState.Unchecked;
- _notifications.CbNotificationsIgnoreImageCertErrors.CheckState = Variables.AppSettings.NotificationsIgnoreImageCertificateErrors ? CheckState.Checked : CheckState.Unchecked;
- _notifications.CbNotificationsOpenActionUri.CheckState = Variables.AppSettings.NotificationsOpenActionUri ? CheckState.Checked : CheckState.Unchecked;
+ _notifications.CbAcceptNotifications.CheckState = Variables.AppSettings.NotificationsEnabled
+ ? CheckState.Checked
+ : CheckState.Unchecked;
+ _notifications.CbNotificationsIgnoreImageCertErrors.CheckState =
+ Variables.AppSettings.NotificationsIgnoreImageCertificateErrors
+ ? CheckState.Checked
+ : CheckState.Unchecked;
+ _notifications.CbNotificationsOpenActionUri.CheckState = Variables.AppSettings.NotificationsOpenActionUri
+ ? CheckState.Checked
+ : CheckState.Unchecked;
// hass settings
_homeAssistantApi.TbHassIp.Text = Variables.AppSettings.HassUri;
_homeAssistantApi.TbHassApiToken.Text = Variables.AppSettings.HassToken;
_homeAssistantApi.TbHassClientCertificate.Text = Variables.AppSettings.HassClientCertificate;
- _homeAssistantApi.CbHassAutoClientCertificate.CheckState = Variables.AppSettings.HassAutoClientCertificate ? CheckState.Checked : CheckState.Unchecked;
- _homeAssistantApi.CbHassAllowUntrustedCertificates.CheckState = Variables.AppSettings.HassAllowUntrustedCertificates ? CheckState.Checked : CheckState.Unchecked;
+ _homeAssistantApi.CbHassAutoClientCertificate.CheckState = Variables.AppSettings.HassAutoClientCertificate
+ ? CheckState.Checked
+ : CheckState.Unchecked;
+ _homeAssistantApi.CbHassAllowUntrustedCertificates.CheckState =
+ Variables.AppSettings.HassAllowUntrustedCertificates ? CheckState.Checked : CheckState.Unchecked;
if (Variables.AppSettings.HassAutoClientCertificate)
{
_homeAssistantApi.TbHassClientCertificate.Text = string.Empty;
@@ -327,10 +406,13 @@ private void LoadSettings()
}
// hotkey
- _hotKey.CbEnableQuickActionsHotkey.CheckState = Variables.AppSettings.QuickActionsHotKeyEnabled ? CheckState.Checked : CheckState.Unchecked;
+ _hotKey.CbEnableQuickActionsHotkey.CheckState = Variables.AppSettings.QuickActionsHotKeyEnabled
+ ? CheckState.Checked
+ : CheckState.Unchecked;
// mqtt
- _mqtt.CbEnableMqtt.CheckState = Variables.AppSettings.MqttEnabled ? CheckState.Checked : CheckState.Unchecked;
+ _mqtt.CbEnableMqtt.CheckState =
+ Variables.AppSettings.MqttEnabled ? CheckState.Checked : CheckState.Unchecked;
_mqtt.TbMqttAddress.Text = Variables.AppSettings.MqttAddress;
_mqtt.NumMqttPort.Value = Variables.AppSettings.MqttPort;
_mqtt.CbMqttTls.CheckState = Variables.AppSettings.MqttUseTls ? CheckState.Checked : CheckState.Unchecked;
@@ -340,15 +422,25 @@ private void LoadSettings()
_mqtt.TbMqttClientId.Text = Variables.AppSettings.MqttClientId;
_mqtt.TbMqttRootCertificate.Text = Variables.AppSettings.MqttRootCertificate;
_mqtt.TbMqttClientCertificate.Text = Variables.AppSettings.MqttClientCertificate;
- _mqtt.CbAllowUntrustedCertificates.CheckState = Variables.AppSettings.MqttAllowUntrustedCertificates ? CheckState.Checked : CheckState.Unchecked;
- _mqtt.CbUseRetainFlag.CheckState = Variables.AppSettings.MqttUseRetainFlag ? CheckState.Checked : CheckState.Unchecked;
- _mqtt.CbUseWebSocket.CheckState = Variables.AppSettings.MqttUseWebSocket ? CheckState.Checked : CheckState.Unchecked;
- _mqtt.CbIgnoreGracePeriod.CheckState = Variables.AppSettings.MqttIgnoreGracePeriod ? CheckState.Checked : CheckState.Unchecked;
+ _mqtt.CbAllowUntrustedCertificates.CheckState = Variables.AppSettings.MqttAllowUntrustedCertificates
+ ? CheckState.Checked
+ : CheckState.Unchecked;
+ _mqtt.CbUseRetainFlag.CheckState =
+ Variables.AppSettings.MqttUseRetainFlag ? CheckState.Checked : CheckState.Unchecked;
+ _mqtt.CbUseWebSocket.CheckState =
+ Variables.AppSettings.MqttUseWebSocket ? CheckState.Checked : CheckState.Unchecked;
+ _mqtt.CbIgnoreGracePeriod.CheckState = Variables.AppSettings.MqttIgnoreGracePeriod
+ ? CheckState.Checked
+ : CheckState.Unchecked;
// updates
- _updates.CbUpdates.CheckState = Variables.AppSettings.CheckForUpdates ? CheckState.Checked : CheckState.Unchecked;
- _updates.CbBetaUpdates.CheckState = Variables.AppSettings.ShowBetaUpdates ? CheckState.Checked : CheckState.Unchecked;
- _updates.CbExecuteUpdater.CheckState = Variables.AppSettings.EnableExecuteUpdateInstaller ? CheckState.Checked : CheckState.Unchecked;
+ _updates.CbUpdates.CheckState =
+ Variables.AppSettings.CheckForUpdates ? CheckState.Checked : CheckState.Unchecked;
+ _updates.CbBetaUpdates.CheckState =
+ Variables.AppSettings.ShowBetaUpdates ? CheckState.Checked : CheckState.Unchecked;
+ _updates.CbExecuteUpdater.CheckState = Variables.AppSettings.EnableExecuteUpdateInstaller
+ ? CheckState.Checked
+ : CheckState.Unchecked;
// cache
_localStorage.TbImageCacheLocation.Text = Variables.ImageCachePath;
@@ -359,7 +451,9 @@ private void LoadSettings()
_localStorage.NumWebViewRetention.Value = Variables.AppSettings.WebViewCacheRetentionDays;
// logging
- _logging.CbExtendedLogging.CheckState = SettingsManager.GetExtendedLoggingSetting() ? CheckState.Checked : CheckState.Unchecked;
+ _logging.CbExtendedLogging.CheckState = SettingsManager.GetExtendedLoggingSetting()
+ ? CheckState.Checked
+ : CheckState.Unchecked;
// external tools
_externalTools.TbExternalBrowserName.Text = Variables.AppSettings.BrowserName;
@@ -369,20 +463,31 @@ private void LoadSettings()
_externalTools.TbExternalExecutorBinary.Text = Variables.AppSettings.CustomExecutorBinary;
// mediaplayer
- _mediaPlayer.CbEnableMediaPlayer.CheckState = Variables.AppSettings.MediaPlayerEnabled ? CheckState.Checked : CheckState.Unchecked;
+ _mediaPlayer.CbEnableMediaPlayer.CheckState = Variables.AppSettings.MediaPlayerEnabled
+ ? CheckState.Checked
+ : CheckState.Unchecked;
// tray icon
- _trayIcon.CbUseModernIcon.CheckState = Variables.AppSettings.TrayIconUseModern ? CheckState.Checked : CheckState.Unchecked;
- _trayIcon.CbDefaultMenu.CheckState = Variables.AppSettings.TrayIconShowDefaultMenu ? CheckState.Checked : CheckState.Unchecked;
- _trayIcon.CbShowWebView.CheckState = Variables.AppSettings.TrayIconShowWebView ? CheckState.Checked : CheckState.Unchecked;
+ _trayIcon.CbUseModernIcon.CheckState =
+ Variables.AppSettings.TrayIconUseModern ? CheckState.Checked : CheckState.Unchecked;
+ _trayIcon.CbDefaultMenu.CheckState = Variables.AppSettings.TrayIconShowDefaultMenu
+ ? CheckState.Checked
+ : CheckState.Unchecked;
+ _trayIcon.CbShowWebView.CheckState =
+ Variables.AppSettings.TrayIconShowWebView ? CheckState.Checked : CheckState.Unchecked;
_trayIcon.NumWebViewWidth.Value = Variables.AppSettings.TrayIconWebViewWidth;
_trayIcon.NumWebViewHeight.Value = Variables.AppSettings.TrayIconWebViewHeight;
- _trayIcon.SelectedScreen = Variables.AppSettings.TrayIconWebViewScreen;
+ _trayIcon.SelectedScreen = Variables.AppSettings.TrayIconWebViewScreen;
_trayIcon.TbWebViewUrl.Text = Variables.AppSettings.TrayIconWebViewUrl;
- _trayIcon.CbWebViewKeepLoaded.CheckState = Variables.AppSettings.TrayIconWebViewBackgroundLoading ? CheckState.Checked : CheckState.Unchecked;
- _trayIcon.CbWebViewShowMenuOnLeftClick.CheckState = Variables.AppSettings.TrayIconWebViewShowMenuOnLeftClick ? CheckState.Checked : CheckState.Unchecked;
+ _trayIcon.CbWebViewKeepLoaded.CheckState = Variables.AppSettings.TrayIconWebViewBackgroundLoading
+ ? CheckState.Checked
+ : CheckState.Unchecked;
+ _trayIcon.CbWebViewShowMenuOnLeftClick.CheckState = Variables.AppSettings.TrayIconWebViewShowMenuOnLeftClick
+ ? CheckState.Checked
+ : CheckState.Unchecked;
- _nfc.CbEnableNfc.CheckState = Variables.AppSettings.NfcScanningEnabled ? CheckState.Checked : CheckState.Unchecked;
+ _nfc.CbEnableNfc.CheckState =
+ Variables.AppSettings.NfcScanningEnabled ? CheckState.Checked : CheckState.Unchecked;
// done
_initializing = false;
@@ -394,10 +499,13 @@ private void LoadSettings()
private async Task StoreSettingsAsync()
{
// general
- var deviceName = string.IsNullOrEmpty(_general.TbDeviceName.Text) ? SharedHelperFunctions.GetSafeDeviceName() : _general.TbDeviceName.Text;
+ var deviceName = string.IsNullOrEmpty(_general.TbDeviceName.Text)
+ ? SharedHelperFunctions.GetSafeDeviceName()
+ : _general.TbDeviceName.Text;
Variables.AppSettings.DeviceName = deviceName;
Variables.AppSettings.SanitizeName = _general.CbEnableDeviceNameSanitation.CheckState == CheckState.Checked;
- Variables.AppSettings.EnableStateNotifications = _general.CbEnableStateNotifications.CheckState == CheckState.Checked;
+ Variables.AppSettings.EnableStateNotifications =
+ _general.CbEnableStateNotifications.CheckState == CheckState.Checked;
var uiLanguage = Variables.SupportedUILanguages.Find(x => x.DisplayName == _general.CbLanguage.Text);
Variables.AppSettings.InterfaceLanguage = uiLanguage?.Name ?? "en";
@@ -409,32 +517,38 @@ private async Task StoreSettingsAsync()
Variables.AppSettings.LocalApiEnabled = _localApi.CbLocalApiActive.CheckState == CheckState.Checked;
// notifications
- Variables.AppSettings.NotificationsEnabled = _notifications.CbAcceptNotifications.CheckState == CheckState.Checked;
- Variables.AppSettings.NotificationsIgnoreImageCertificateErrors = _notifications.CbNotificationsIgnoreImageCertErrors.CheckState == CheckState.Checked;
- Variables.AppSettings.NotificationsOpenActionUri = _notifications.CbNotificationsOpenActionUri.CheckState == CheckState.Checked;
+ Variables.AppSettings.NotificationsEnabled =
+ _notifications.CbAcceptNotifications.CheckState == CheckState.Checked;
+ Variables.AppSettings.NotificationsIgnoreImageCertificateErrors =
+ _notifications.CbNotificationsIgnoreImageCertErrors.CheckState == CheckState.Checked;
+ Variables.AppSettings.NotificationsOpenActionUri =
+ _notifications.CbNotificationsOpenActionUri.CheckState == CheckState.Checked;
// hass settings
Variables.AppSettings.HassUri = _homeAssistantApi.TbHassIp.Text;
Variables.AppSettings.HassToken = _homeAssistantApi.TbHassApiToken.Text;
Variables.AppSettings.HassClientCertificate = _homeAssistantApi.TbHassClientCertificate.Text;
- Variables.AppSettings.HassAutoClientCertificate = _homeAssistantApi.CbHassAutoClientCertificate.CheckState == CheckState.Checked;
- Variables.AppSettings.HassAllowUntrustedCertificates = _homeAssistantApi.CbHassAllowUntrustedCertificates.CheckState == CheckState.Checked;
+ Variables.AppSettings.HassAutoClientCertificate =
+ _homeAssistantApi.CbHassAutoClientCertificate.CheckState == CheckState.Checked;
+ Variables.AppSettings.HassAllowUntrustedCertificates =
+ _homeAssistantApi.CbHassAllowUntrustedCertificates.CheckState == CheckState.Checked;
// hotkey config
- Variables.AppSettings.QuickActionsHotKeyEnabled = _hotKey.CbEnableQuickActionsHotkey.CheckState == CheckState.Checked;
+ Variables.AppSettings.QuickActionsHotKeyEnabled =
+ _hotKey.CbEnableQuickActionsHotkey.CheckState == CheckState.Checked;
if (Variables.AppSettings.QuickActionsHotKeyEnabled)
{
// hotkey enabled, store and activate
- Variables.QuickActionsHotKey = new Hotkey(_hotKey.TbQuickActionsHotkey.Text);
+ Variables.QuickActionsHotKey = _hotKey.TbQuickActionsHotkey.Text;
Variables.AppSettings.QuickActionsHotKey = Variables.QuickActionsHotKey.ToString();
- Variables.HotKeyManager.QuickActionsHotKeyChanged(_previousHotkey);
+ Variables.InternalHotKeyManager.QuickActionsHotKeyChanged(_previousHotkey);
}
else
{
// hotkey disabled, remove and deactivate
Variables.QuickActionsHotKey = null;
Variables.AppSettings.QuickActionsHotKey = string.Empty;
- Variables.HotKeyManager.QuickActionsHotKeyChanged(_previousHotkey, false);
+ Variables.InternalHotKeyManager.QuickActionsHotKeyChanged(_previousHotkey, false);
}
// mqtt
@@ -448,7 +562,8 @@ private async Task StoreSettingsAsync()
Variables.AppSettings.MqttClientId = _mqtt.TbMqttClientId.Text;
Variables.AppSettings.MqttRootCertificate = _mqtt.TbMqttRootCertificate.Text;
Variables.AppSettings.MqttClientCertificate = _mqtt.TbMqttClientCertificate.Text;
- Variables.AppSettings.MqttAllowUntrustedCertificates = _mqtt.CbAllowUntrustedCertificates.CheckState == CheckState.Checked;
+ Variables.AppSettings.MqttAllowUntrustedCertificates =
+ _mqtt.CbAllowUntrustedCertificates.CheckState == CheckState.Checked;
Variables.AppSettings.MqttUseRetainFlag = _mqtt.CbUseRetainFlag.CheckState == CheckState.Checked;
Variables.AppSettings.MqttUseWebSocket = _mqtt.CbUseWebSocket.CheckState == CheckState.Checked;
Variables.AppSettings.MqttIgnoreGracePeriod = _mqtt.CbIgnoreGracePeriod.CheckState == CheckState.Checked;
@@ -459,7 +574,8 @@ private async Task StoreSettingsAsync()
// updates
Variables.AppSettings.CheckForUpdates = _updates.CbUpdates.CheckState == CheckState.Checked;
Variables.AppSettings.ShowBetaUpdates = _updates.CbBetaUpdates.CheckState == CheckState.Checked;
- Variables.AppSettings.EnableExecuteUpdateInstaller = _updates.CbExecuteUpdater.CheckState == CheckState.Checked;
+ Variables.AppSettings.EnableExecuteUpdateInstaller =
+ _updates.CbExecuteUpdater.CheckState == CheckState.Checked;
// cache
Variables.AppSettings.ImageCacheRetentionDays = (int)_localStorage.NumImageRetention.Value;
@@ -480,7 +596,8 @@ private async Task StoreSettingsAsync()
AgentSharedBase.SetCustomExecutorBinary(Variables.AppSettings.CustomExecutorBinary);
// mediaplayer
- Variables.AppSettings.MediaPlayerEnabled = _mediaPlayer.CbEnableMediaPlayer.CheckState == CheckState.Checked;
+ Variables.AppSettings.MediaPlayerEnabled =
+ _mediaPlayer.CbEnableMediaPlayer.CheckState == CheckState.Checked;
// tray icon
Variables.AppSettings.TrayIconUseModern = _trayIcon.CbUseModernIcon.CheckState == CheckState.Checked;
@@ -490,12 +607,16 @@ private async Task StoreSettingsAsync()
Variables.AppSettings.TrayIconWebViewHeight = (int)_trayIcon.NumWebViewHeight.Value;
Variables.AppSettings.TrayIconWebViewScreen = _trayIcon.NumWebViewScreen.SelectedIndex;
Variables.AppSettings.TrayIconWebViewUrl = _trayIcon.TbWebViewUrl.Text;
- Variables.AppSettings.TrayIconWebViewBackgroundLoading = _trayIcon.CbWebViewKeepLoaded.CheckState == CheckState.Checked;
- Variables.AppSettings.TrayIconWebViewShowMenuOnLeftClick = _trayIcon.CbWebViewShowMenuOnLeftClick.CheckState == CheckState.Checked;
+ Variables.AppSettings.TrayIconWebViewBackgroundLoading =
+ _trayIcon.CbWebViewKeepLoaded.CheckState == CheckState.Checked;
+ Variables.AppSettings.TrayIconWebViewShowMenuOnLeftClick =
+ _trayIcon.CbWebViewShowMenuOnLeftClick.CheckState == CheckState.Checked;
// nfc
Variables.AppSettings.NfcScanningEnabled = _nfc.CbEnableNfc.CheckState == CheckState.Checked;
- Variables.AppSettings.NfcSelectedScanner = _nfc.CbNfcScanner.SelectedItem == null ? string.Empty : _nfc.CbNfcScanner.SelectedItem.ToString();
+ Variables.AppSettings.NfcSelectedScanner = _nfc.CbNfcScanner.SelectedItem == null
+ ? string.Empty
+ : _nfc.CbNfcScanner.SelectedItem.ToString();
// save to file
SettingsManager.StoreAppSettings();
@@ -532,7 +653,7 @@ private void Configuration_KeyUp(object sender, KeyEventArgs e)
private void BtnClearHotKey_Click(object sender, EventArgs e)
{
- _hotKey.TbQuickActionsHotkey.Text = _hotkeySelector.EmptyHotkeyText;
+ _hotKey.TbQuickActionsHotkey.Text = string.Empty;
}
private void Configuration_ResizeEnd(object sender, EventArgs e)
@@ -571,4 +692,4 @@ private void CbHassAutoClientCertificate_CheckedChanged(object sender, EventArgs
private void BtnClose_Click(object sender, EventArgs e) => Close();
}
-}
+}
\ No newline at end of file
diff --git a/src/HASS.Agent/HASS.Agent/Forms/Main.cs b/src/HASS.Agent/HASS.Agent/Forms/Main.cs
index e79059ec..5bde6719 100644
--- a/src/HASS.Agent/HASS.Agent/Forms/Main.cs
+++ b/src/HASS.Agent/HASS.Agent/Forms/Main.cs
@@ -24,11 +24,12 @@
using Serilog;
using Syncfusion.Windows.Forms;
using WindowsDesktop;
-using WK.Libraries.HotkeyListenerNS;
using NativeMethods = HASS.Agent.Functions.NativeMethods;
using QuickActionsConfig = HASS.Agent.Forms.QuickActions.QuickActionsConfig;
using Task = System.Threading.Tasks.Task;
using Microsoft.Win32;
+using NHotkey;
+using NHotkey.WindowsForms;
namespace HASS.Agent.Forms
{
@@ -64,11 +65,11 @@ private async void Main_Load(object sender, EventArgs e)
// exception handlers
Application.ThreadException += Application_ThreadException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
- }
-
- if (SharedHelperFunctions.RunningElevated())
- {
- Log.Warning("[MAIN] Running with elevated privileges, this might cause issues for example with notifications!");
+ }
+
+ if (SharedHelperFunctions.RunningElevated())
+ {
+ Log.Warning("[MAIN] Running with elevated privileges, this might cause issues for example with notifications!");
}
// catch all key presses
@@ -88,7 +89,7 @@ private async void Main_Load(object sender, EventArgs e)
SetMqttStatus(ComponentStatus.Loading);
// create a hotkey listener
- Variables.HotKeyListener = new HotkeyListener();
+ Variables.HotKeyListener = HotkeyManager.Current;
// check for dpi scaling
CheckDpiScalingFactor();
@@ -124,7 +125,7 @@ private async void Main_Load(object sender, EventArgs e)
// prepare the tray icon config
SystemEvents.DisplaySettingsChanged += (s, a) => RefreshTrayIcon();
- ProcessTrayIcon();
+ ProcessTrayIcon();
InitializeHotkeys();
@@ -304,10 +305,10 @@ private static void CurrentDomain_UnhandledException(object sender, UnhandledExc
private void InitializeHotkeys()
{
// prepare listener
- Variables.HotKeyListener.HotkeyPressed += HotkeyListener_HotkeyPressed;
+ Variables.InternalHotKeyManager.HotkeyActivated += HotkeyListener_HotkeyPressed;
// bind quick actions hotkey (if configured)
- Variables.HotKeyManager.InitializeQuickActionsHotKeys();
+ Variables.InternalHotKeyManager.InitializeQuickActionsHotKeys();
}
///
@@ -317,10 +318,10 @@ private void InitializeHotkeys()
///
private void HotkeyListener_HotkeyPressed(object sender, HotkeyEventArgs e)
{
- if (e.Hotkey == Variables.QuickActionsHotKey)
+ if (e.Name == Variables.QuickActionsHotKey)
ShowQuickActions();
else
- HotKeyManager.ProcessQuickActionHotKey(e.Hotkey.ToString());
+ InternalHotKeyManager.ProcessQuickActionHotKey(e.Name);
}
///
diff --git a/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsConfig.cs b/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsConfig.cs
index 9a8285c4..7c86317c 100644
--- a/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsConfig.cs
+++ b/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsConfig.cs
@@ -163,7 +163,7 @@ private void BtnStore_Click(object sender, EventArgs e)
StoredQuickActions.Store();
// reload hotkey bindings
- Variables.HotKeyManager.ReloadQuickActionsHotKeys();
+ Variables.InternalHotKeyManager.ReloadQuickActionsHotKeys();
// done
Close();
diff --git a/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsMod.cs b/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsMod.cs
index e6dcff81..3b4008e0 100644
--- a/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsMod.cs
+++ b/src/HASS.Agent/HASS.Agent/Forms/QuickActions/QuickActionsMod.cs
@@ -6,17 +6,18 @@
using HASS.Agent.Shared.Enums;
using HASS.Agent.Shared.Functions;
using Syncfusion.Windows.Forms;
-using WK.Libraries.HotkeyListenerNS;
namespace HASS.Agent.Forms.QuickActions
{
public partial class QuickActionsMod : MetroForm
{
- private readonly HotkeySelector _hotkeySelector = new();
internal readonly QuickAction QuickAction;
private readonly Dictionary _hassDomainEntityTypes = new();
private readonly Dictionary _hassActionEntityTypes = new();
+
+ private Keys _key = Keys.None;
+ private Keys _modifiers = Keys.None;
public QuickActionsMod(QuickAction quickAction)
{
@@ -90,15 +91,17 @@ private async void QuickActionsMod_Load(object sender, EventArgs e)
}
LvDomain.EndUpdate();
+ TbHotkey.ReadOnly = true;
+ TbHotkey.KeyDown += TbQuickActionsHotkey_KeyDown;
+
// load or new quickaction?
if (QuickAction.Id == Guid.Empty)
{
// new quickaction
Text = Languages.QuickActionsMod_Title_New;
QuickAction.Id = Guid.NewGuid();
-
- _hotkeySelector.Enable(TbHotkey);
- TbHotkey.Text = _hotkeySelector.EmptyHotkeyText;
+
+ TbHotkey.Text = string.Empty;
LvDomain.Items[0].Selected = true;
if (CbEntity.Items.Count > 0) CbEntity.SelectedIndex = 0;
@@ -211,12 +214,7 @@ private void LoadQuickAction()
if (!string.IsNullOrWhiteSpace(TbDescription.Text)) TbDescription.SelectionStart = TbDescription.Text.Length;
// load the hotkey
- if (!string.IsNullOrEmpty(QuickAction.HotKey)) _hotkeySelector.Enable(TbHotkey, new Hotkey(QuickAction.HotKey));
- else
- {
- _hotkeySelector.Enable(TbHotkey);
- TbHotkey.Text = _hotkeySelector.EmptyHotkeyText;
- }
+ TbHotkey.Text = !string.IsNullOrEmpty(QuickAction.HotKey) ? QuickAction.HotKey : string.Empty;
}
///
@@ -426,16 +424,13 @@ private void CbEntity_SelectedIndexChanged(object sender, EventArgs e)
private void QuickActionsMod_FormClosing(object sender, FormClosingEventArgs e)
{
- // stop and dispose selector
- _hotkeySelector?.Disable(TbHotkey);
- _hotkeySelector?.Dispose();
+ // clean selector
+ TbHotkey.KeyDown -= TbQuickActionsHotkey_KeyDown;
}
private void TbHotkey_TextChanged(object sender, EventArgs e)
{
- if (string.IsNullOrWhiteSpace(TbHotkey.Text)
- || TbHotkey.Text == _hotkeySelector?.EmptyHotkeyText
- || TbHotkey.Text == _hotkeySelector?.InvalidHotkeyText)
+ if (string.IsNullOrWhiteSpace(TbHotkey.Text))
{
CbEnableHotkey.CheckState = CheckState.Unchecked;
return;
@@ -481,5 +476,53 @@ private void QuickActionsMod_Layout(object sender, LayoutEventArgs e)
// hide the pesky horizontal scrollbar
ListViewTheme.ShowScrollBar(LvDomain.Handle, ListViewTheme.SB_HORZ, false);
}
+
+ private void TbQuickActionsHotkey_KeyDown(object sender, KeyEventArgs e)
+ {
+ e.SuppressKeyPress = true;
+
+ var key = e.KeyCode;
+
+ if (key is Keys.LControlKey or Keys.RControlKey
+ or Keys.LShiftKey or Keys.RShiftKey
+ or Keys.LWin or Keys.RWin
+ or Keys.Alt)
+ {
+ key = Keys.None;
+ }
+
+ if (key == Keys.Escape)
+ {
+ _key = Keys.None;
+ _modifiers = Keys.None;
+ TbHotkey.Text = string.Empty;
+
+ return;
+ }
+
+ _key = key;
+ TbHotkey.Text = FormatHotkey(_key, e.Modifiers);
+ }
+
+ private string FormatHotkey(Keys key, Keys modifiers)
+ {
+ var parts = new List();
+ if ((modifiers & Keys.Shift) != 0)
+ {
+ parts.Add(nameof(Keys.Shift));
+ }
+
+ if ((modifiers & Keys.Control) != 0)
+ {
+ parts.Add(nameof(Keys.Control));
+ }
+
+ if ((modifiers & Keys.Alt) != 0)
+ {
+ parts.Add(nameof(Keys.Alt));
+ }
+
+ return parts.Count > 0 ? string.Join(", ", parts) + " + " + key : key.ToString();
+ }
}
}
diff --git a/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs b/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs
index 72fbb27f..30796038 100644
--- a/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs
+++ b/src/HASS.Agent/HASS.Agent/Functions/HelperFunctions.cs
@@ -172,8 +172,8 @@ internal static async Task ShutdownAsync(TimeSpan waitBeforeClosing)
// stop hotkey
Variables.MainForm?.Invoke(new MethodInvoker(delegate
{
- Variables.HotKeyListener?.RemoveAll();
- Variables.HotKeyListener?.Dispose();
+ Variables.InternalHotKeyManager?.ReloadQuickActionsHotKeys();
+ //Variables.HotKeyListener?.Dispose();
}));
// stop bt listener
diff --git a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj
index 42f43703..8d65e1eb 100644
--- a/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj
+++ b/src/HASS.Agent/HASS.Agent/HASS.Agent.csproj
@@ -72,6 +72,7 @@
+
@@ -93,9 +94,6 @@
Libraries\HADotNet.Core.dll
-
- Libraries\HotkeyListener.dll
-
diff --git a/src/HASS.Agent/HASS.Agent/Libraries/HotkeyListener.dll b/src/HASS.Agent/HASS.Agent/Libraries/HotkeyListener.dll
deleted file mode 100644
index 6907c33c43bd262abd0ebfee0519de5fa9b04486..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 448000
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