diff --git a/Home Assistant Taskbar Menu.sln b/Home Assistant Taskbar Menu.sln index 8d4b325..d8de845 100644 --- a/Home Assistant Taskbar Menu.sln +++ b/Home Assistant Taskbar Menu.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.1169 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32519.111 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Home Assistant Taskbar Menu", "Home Assistant Taskbar Menu\Home Assistant Taskbar Menu.csproj", "{B49305F6-8A11-43D6-AD36-864C95D4F015}" EndProject diff --git a/Home Assistant Taskbar Menu/App.config b/Home Assistant Taskbar Menu/App.config index 0290434..d0fade3 100644 --- a/Home Assistant Taskbar Menu/App.config +++ b/Home Assistant Taskbar Menu/App.config @@ -1,19 +1,18 @@ - - + - + - - + + - - + + - \ No newline at end of file + diff --git a/Home Assistant Taskbar Menu/App.xaml.cs b/Home Assistant Taskbar Menu/App.xaml.cs index 9683116..a1ccbce 100644 --- a/Home Assistant Taskbar Menu/App.xaml.cs +++ b/Home Assistant Taskbar Menu/App.xaml.cs @@ -35,13 +35,6 @@ private void OnStartup(object sender, StartupEventArgs e) private static void StartUi(ViewConfiguration viewConfiguration, Configuration configuration) { - var paletteHelper = new PaletteHelper(); - var theme = paletteHelper.GetTheme(); - theme.SetBaseTheme(viewConfiguration.GetProperty(ViewConfiguration.ThemeKey) == ViewConfiguration.LightTheme - ? new MaterialDesignLightTheme() - : (IBaseTheme) new MaterialDesignDarkTheme()); - paletteHelper.SetTheme(theme); - if (configuration == null) { ConsoleWriter.WriteLine("NO CONFIGURATION", ConsoleColor.Red); @@ -52,6 +45,35 @@ private static void StartUi(ViewConfiguration viewConfiguration, Configuration c ConsoleWriter.WriteLine($"configuration.Url = {configuration.Url}", ConsoleColor.Green); new MainWindow(configuration, viewConfiguration).Show(); } + + ReloadTheme(viewConfiguration); + } + + internal static void ReloadTheme(ViewConfiguration viewConfiguration) + { + var paletteHelper = new PaletteHelper(); + var theme = paletteHelper.GetTheme(); + + ViewConfiguration.Themes currentTheme; + Enum.TryParse(viewConfiguration.GetProperty(ViewConfiguration.ThemeKey), true, out currentTheme); + + switch (currentTheme) + { + case ViewConfiguration.Themes.Dark: + theme.SetBaseTheme(new MaterialDesignDarkTheme()); + break; + case ViewConfiguration.Themes.Auto: + var systemTheme = Theme.GetSystemTheme(); + if (systemTheme != null) + theme.SetBaseTheme(systemTheme.Value.GetBaseTheme()); + break; + case ViewConfiguration.Themes.Light: + default: + theme.SetBaseTheme(new MaterialDesignLightTheme()); + break; + } + + paletteHelper.SetTheme(theme); } private static void CallService(Configuration configuration, string service, string data) diff --git a/Home Assistant Taskbar Menu/Home Assistant Taskbar Menu.csproj b/Home Assistant Taskbar Menu/Home Assistant Taskbar Menu.csproj index 9ac2256..0773685 100644 --- a/Home Assistant Taskbar Menu/Home Assistant Taskbar Menu.csproj +++ b/Home Assistant Taskbar Menu/Home Assistant Taskbar Menu.csproj @@ -1,9 +1,5 @@  - - - - Debug @@ -12,7 +8,7 @@ WinExe Home_Assistant_Taskbar_Menu Home Assistant Taskbar Menu - v4.6.1 + v4.8 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 @@ -21,6 +17,7 @@ false + publish\ true Disk @@ -50,6 +47,7 @@ DEBUG;TRACE prompt 4 + true AnyCPU @@ -81,11 +79,12 @@ - true + false x64 true + bin\x64\Release\ true @@ -113,37 +112,15 @@ true + + x64 + TRACE;DEBUG + bin\x64\Debug\ + - - ..\packages\Hardcodet.NotifyIcon.Wpf.1.0.8\lib\net451\Hardcodet.Wpf.TaskbarNotification.dll - - - ..\packages\MaterialDesignColors.1.2.6\lib\net45\MaterialDesignColors.dll - - - ..\packages\MaterialDesignThemes.3.1.3\lib\net45\MaterialDesignThemes.Wpf.dll - - - ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll - - - ..\packages\System.Reactive.4.3.2\lib\net46\System.Reactive.dll - - - ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll - - - ..\packages\System.Threading.Channels.4.7.0\lib\netstandard2.0\System.Threading.Channels.dll - - - ..\packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll - - - ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll - @@ -158,9 +135,6 @@ 4.0 - - ..\packages\Websocket.Client.4.3.15\lib\netstandard2.0\Websocket.Client.dll - @@ -276,9 +250,6 @@ Resources.Designer.cs - - Designer - SettingsSingleFileGenerator @@ -303,20 +274,22 @@ false + + + 102.0.90 + + + 1.1.0 + + + 4.5.0 + + + 13.0.1 + + + 4.4.43 + + - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - - - - - \ No newline at end of file diff --git a/Home Assistant Taskbar Menu/Properties/Resources.Designer.cs b/Home Assistant Taskbar Menu/Properties/Resources.Designer.cs index 25312e2..66b6b06 100644 --- a/Home Assistant Taskbar Menu/Properties/Resources.Designer.cs +++ b/Home Assistant Taskbar Menu/Properties/Resources.Designer.cs @@ -8,18 +8,10 @@ // //------------------------------------------------------------------------------ -using System.CodeDom.Compiler; -using System.ComponentModel; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Resources; -using System.Runtime.CompilerServices; - -namespace Home_Assistant_Taskbar_Menu.Properties -{ - - +namespace Home_Assistant_Taskbar_Menu.Properties { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -27,51 +19,43 @@ namespace Home_Assistant_Taskbar_Menu.Properties // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [DebuggerNonUserCode()] - [CompilerGenerated()] - internal class Resources - { - - private static ResourceManager resourceMan; - - private static CultureInfo resourceCulture; - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// - [EditorBrowsable(EditorBrowsableState.Advanced)] - internal static ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { - ResourceManager temp = new ResourceManager("Home_Assistant_Taskbar_Menu.Properties.Resources", typeof(Resources).Assembly); + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Home_Assistant_Taskbar_Menu.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// - [EditorBrowsable(EditorBrowsableState.Advanced)] - internal static CultureInfo Culture - { - get - { + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { return resourceCulture; } - set - { + set { resourceCulture = value; } } diff --git a/Home Assistant Taskbar Menu/Properties/Settings.Designer.cs b/Home Assistant Taskbar Menu/Properties/Settings.Designer.cs index 6ccc6fa..90a6c47 100644 --- a/Home Assistant Taskbar Menu/Properties/Settings.Designer.cs +++ b/Home Assistant Taskbar Menu/Properties/Settings.Designer.cs @@ -8,25 +8,17 @@ // //------------------------------------------------------------------------------ -using System.CodeDom.Compiler; -using System.Configuration; -using System.Runtime.CompilerServices; - -namespace Home_Assistant_Taskbar_Menu.Properties -{ - - - [CompilerGenerated()] - [GeneratedCode("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] - internal sealed partial class Settings : ApplicationSettingsBase - { - - private static Settings defaultInstance = ((Settings)(Synchronized(new Settings()))); - - public static Settings Default - { - get - { +namespace Home_Assistant_Taskbar_Menu.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.3.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { return defaultInstance; } } diff --git a/Home Assistant Taskbar Menu/Utils/ViewConfiguration.cs b/Home Assistant Taskbar Menu/Utils/ViewConfiguration.cs index 010aec8..ddb5434 100644 --- a/Home Assistant Taskbar Menu/Utils/ViewConfiguration.cs +++ b/Home Assistant Taskbar Menu/Utils/ViewConfiguration.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Home_Assistant_Taskbar_Menu.Entities; @@ -7,8 +8,12 @@ namespace Home_Assistant_Taskbar_Menu.Utils public class ViewConfiguration { public const string ThemeKey = "Theme"; - public const string LightTheme = "Light"; - public const string DarkTheme = "Dark"; + public enum Themes + { + Auto, + Light, + Dark + } public const string MirrorNotificationsKey = "MirrorNotifications"; public Type NodeType { get; set; } @@ -41,7 +46,7 @@ public static ViewConfiguration Default() Children = new List(), Properties = new Dictionary { - {ThemeKey, LightTheme}, + {ThemeKey, Enum.GetName(typeof(ViewConfiguration.Themes), ViewConfiguration.Themes.Auto)}, {MirrorNotificationsKey, true.ToString()} } }; diff --git a/Home Assistant Taskbar Menu/Views/BrowserWindow.xaml b/Home Assistant Taskbar Menu/Views/BrowserWindow.xaml index 2a3cf1c..055a9a8 100644 --- a/Home Assistant Taskbar Menu/Views/BrowserWindow.xaml +++ b/Home Assistant Taskbar Menu/Views/BrowserWindow.xaml @@ -16,6 +16,7 @@ ResizeMode="CanResize" WindowStyle="SingleBorderWindow" Closed="BrowserWindow_OnClosed" + Activated="Window_Activated" WindowStartupLocation="Manual"> public partial class BrowserWindow : Window { + + private IntPtr _windowHandle; + protected override void OnSourceInitialized(EventArgs e) + { + base.OnSourceInitialized(e); + _windowHandle = new WindowInteropHelper(this).Handle; + } + [DllImport("user32.dll")] + static extern IntPtr GetForegroundWindow(); + private System.Timers.Timer focusLossTimer = new System.Timers.Timer(); + + private string Url { get; } public BrowserWindow(Configuration configuration) @@ -35,6 +50,18 @@ public BrowserWindow(Configuration configuration) Width = position.Value.width; Height = position.Value.height; } + + + focusLossTimer.Elapsed += (s, e) => { + if(GetForegroundWindow() != _windowHandle && Visibility == Visibility.Visible) + { + Debug.WriteLine("Hiding browser window due to focus loss"); + Application.Current.Dispatcher.Invoke(new Action(() => { Hide(); })); + } + }; + focusLossTimer.Interval = 500; + focusLossTimer.Enabled = true; + } private void MinimizeButton(object sender, RoutedEventArgs e) @@ -50,6 +77,7 @@ private void MaximizeRestoreButton(object sender, RoutedEventArgs e) private void CloseButton(object sender, RoutedEventArgs e) { Hide(); + focusLossTimer.Stop(); } private void HeaderMouseDown(object sender, MouseButtonEventArgs e) @@ -72,5 +100,10 @@ private void BrowserWindow_OnClosed(object sender, EventArgs e) { Storage.SavePosition((Left, Top, Width, Height)); } + + private void Window_Activated(object sender, EventArgs e) + { + focusLossTimer.Start(); + } } } \ No newline at end of file diff --git a/Home Assistant Taskbar Menu/Views/MainWindow.xaml b/Home Assistant Taskbar Menu/Views/MainWindow.xaml index e52dd61..6b0e655 100644 --- a/Home Assistant Taskbar Menu/Views/MainWindow.xaml +++ b/Home Assistant Taskbar Menu/Views/MainWindow.xaml @@ -15,8 +15,8 @@ diff --git a/Home Assistant Taskbar Menu/Views/MainWindow.xaml.cs b/Home Assistant Taskbar Menu/Views/MainWindow.xaml.cs index 67d281f..d6510eb 100644 --- a/Home Assistant Taskbar Menu/Views/MainWindow.xaml.cs +++ b/Home Assistant Taskbar Menu/Views/MainWindow.xaml.cs @@ -4,10 +4,12 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using System.Windows.Interop; using System.Windows.Media; using Home_Assistant_Taskbar_Menu.Connection; using Home_Assistant_Taskbar_Menu.Entities; @@ -34,6 +36,71 @@ public partial class MainWindow : Window public ObservableCollection Menu { get; set; } + #region Hotkeys + [DllImport("user32.dll")] + private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); + + [DllImport("user32.dll")] + private static extern bool UnregisterHotKey(IntPtr hWnd, int id); + + private const int HOTKEY_ID = 9000; + + //Modifiers: + private const uint MOD_NONE = 0x0000; //(none) + private const uint MOD_ALT = 0x0001; //ALT + private const uint MOD_CONTROL = 0x0002; //CTRL + private const uint MOD_SHIFT = 0x0004; //SHIFT + private const uint MOD_WIN = 0x0008; //WINDOWS + private const uint KEY_H = 0x48; + private const uint KEY_E = 0x45; + + private IntPtr _windowHandle; + private HwndSource _source; + + protected override void OnSourceInitialized(EventArgs e) + { + base.OnSourceInitialized(e); + + _windowHandle = new WindowInteropHelper(this).Handle; + _source = HwndSource.FromHwnd(_windowHandle); + _source.AddHook(HwndHook); + + RegisterHotKey(_windowHandle, HOTKEY_ID, MOD_WIN | MOD_SHIFT, KEY_H); // WIN + SHIFT + H + RegisterHotKey(_windowHandle, HOTKEY_ID, MOD_WIN | MOD_SHIFT, KEY_E); // WIN + SHIFT + E + } + + private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + const int WM_HOTKEY = 0x0312; + switch (msg) + { + case WM_HOTKEY: + switch (wParam.ToInt32()) + { + case HOTKEY_ID: + int vkey = (((int)lParam >> 16) & 0xFFFF); + if (vkey == KEY_H) + { + ToggleBrowser(null, null); + } else if (vkey == KEY_E) { + UIElement_OnKeyDown(null, null); + } + handled = true; + break; + } + break; + } + return IntPtr.Zero; + } + + protected override void OnClosed(EventArgs e) + { + _source.RemoveHook(HwndHook); + UnregisterHotKey(_windowHandle, HOTKEY_ID); + base.OnClosed(e); + } + #endregion + public MainWindow(Configuration configuration, ViewConfiguration viewConfiguration) { var latestVersion = ResourceProvider.LatestVersion(); @@ -80,7 +147,7 @@ private List CreateDefaultMenuItems(Configuration configuratio } }); CreateMenuIcon(grid, PackIconKind.HomeAssistant, "Open Home Assistant", - () => ShowBrowser(null, null)); + () => ToggleBrowser(null, null)); CreateMenuIcon(grid, PackIconKind.OpenInBrowser, "Open Home Assistant in Browser", () => Process.Start(configuration.HttpUrl())); CreateMenuIcon(grid, PackIconKind.About, "About HA Taskbar Menu", () => @@ -224,7 +291,7 @@ private void UpdateTree(bool authenticated = true) private void UIElement_OnKeyDown(object sender, KeyEventArgs e) { _searchWindow?.Close(); - _searchWindow = new SearchWindow(e.Key.ToString(), _stateObjects); + _searchWindow = new SearchWindow(e, _stateObjects); _searchWindow.ShowDialog(); } @@ -251,10 +318,20 @@ private Icon GetIcon() } } - private void ShowBrowser(object sender, RoutedEventArgs e) + private void ToggleBrowser(object sender, RoutedEventArgs e) + { + if(_browserWindow.Visibility != Visibility.Visible) { _browserWindow.Show(); _browserWindow.Activate(); + Debug.WriteLine("Showing browser window."); + } + else + { + _browserWindow.Hide(); + Debug.WriteLine("Hiding browser window."); + } + } } } \ No newline at end of file diff --git a/Home Assistant Taskbar Menu/Views/SearchWindow.xaml.cs b/Home Assistant Taskbar Menu/Views/SearchWindow.xaml.cs index e22e6b1..39a867c 100644 --- a/Home Assistant Taskbar Menu/Views/SearchWindow.xaml.cs +++ b/Home Assistant Taskbar Menu/Views/SearchWindow.xaml.cs @@ -16,7 +16,7 @@ public partial class SearchWindow : Window { private readonly List _entities; - public SearchWindow(string s, List entities) + public SearchWindow(KeyEventArgs s, List entities) { _entities = new List(entities); InitializeComponent(); @@ -29,9 +29,9 @@ public SearchWindow(string s, List entities) Dispatcher.Invoke(() => UpdateFoundList(null, null)); } }); - if (s.Length == 1) + if (s != null && s.Key.ToString().Length == 1) { - SearchBox.Text = s; + SearchBox.Text = s.Key.ToString(); } SearchBox.CaretIndex = int.MaxValue; diff --git a/Home Assistant Taskbar Menu/Views/ViewConfigurationDialog.xaml.cs b/Home Assistant Taskbar Menu/Views/ViewConfigurationDialog.xaml.cs index f31dbcb..2617142 100644 --- a/Home Assistant Taskbar Menu/Views/ViewConfigurationDialog.xaml.cs +++ b/Home Assistant Taskbar Menu/Views/ViewConfigurationDialog.xaml.cs @@ -15,17 +15,19 @@ public partial class ViewConfigurationDialog : Window public ViewConfiguration ViewConfiguration { get; set; } - public ViewConfigurationDialog(List stateObjects) + public ViewConfigurationDialog(List stateObjects, ViewConfigurationWindow owner) { InitializeComponent(); + this.Owner = owner; stateObjects.ForEach(s => EntityIdComboBox.Items.Add(s)); NameTextBox.ToolTip = "Leave empty to use name retrieved from Home Assistant"; _isEntity = true; } - public ViewConfigurationDialog() + public ViewConfigurationDialog(ViewConfigurationWindow owner) { InitializeComponent(); + this.Owner = owner; RowEntityId1.Height = new GridLength(0); RowEntityId2.Height = new GridLength(0); Height = 130; diff --git a/Home Assistant Taskbar Menu/Views/ViewConfigurationWindow.xaml b/Home Assistant Taskbar Menu/Views/ViewConfigurationWindow.xaml index ba4ca48..f880490 100644 --- a/Home Assistant Taskbar Menu/Views/ViewConfigurationWindow.xaml +++ b/Home Assistant Taskbar Menu/Views/ViewConfigurationWindow.xaml @@ -46,7 +46,7 @@ - +