diff --git a/FluentFlyoutWPF/App.config b/FluentFlyoutWPF/App.config index 2042071..829f367 100644 --- a/FluentFlyoutWPF/App.config +++ b/FluentFlyoutWPF/App.config @@ -46,6 +46,12 @@ 2 + + False + + + 2000 + \ No newline at end of file diff --git a/FluentFlyoutWPF/FluentFlyout.csproj b/FluentFlyoutWPF/FluentFlyout.csproj index 09e282a..0bfb338 100644 --- a/FluentFlyoutWPF/FluentFlyout.csproj +++ b/FluentFlyoutWPF/FluentFlyout.csproj @@ -22,6 +22,7 @@ + @@ -38,6 +39,9 @@ Always + + Always + Always diff --git a/FluentFlyoutWPF/MainWindow.xaml.cs b/FluentFlyoutWPF/MainWindow.xaml.cs index f41c716..8447da1 100644 --- a/FluentFlyoutWPF/MainWindow.xaml.cs +++ b/FluentFlyoutWPF/MainWindow.xaml.cs @@ -7,20 +7,17 @@ using System.Windows.Media.Imaging; using Windows.Storage.Streams; using MicaWPF.Controls; -using System.IO; using System.Windows.Media.Animation; using FluentFlyout; using FluentFlyout.Properties; using Microsoft.Win32; -using System.Reflection; using System.Drawing; using System.Windows.Controls; using Wpf.Ui.Controls; -using Wpf.Ui.Appearance; using FluentFlyout.Classes; using MicaWPF.Core.Extensions; -using MicaWPF.Core.Services; -using Windows.UI.Composition; +using FluentFlyout.Windows; +using System.Windows.Input; namespace FluentFlyoutWPF @@ -54,6 +51,8 @@ public partial class MainWindow : MicaWindow private NextUpWindow? nextUpWindow = null; // to prevent multiple instances of NextUpWindow private string currentTitle = ""; // to prevent NextUpWindow from showing the same song + private LockWindow lockWindow; + public MainWindow() { WindowHelper.SetNoActivate(this); // prevents some fullscreen apps from minimizing @@ -120,51 +119,61 @@ public EasingFunctionBase getEasingStyle(bool easeOut) return easingStyle; } - public void OpenAnimation(MicaWindow window) + public void OpenAnimation(MicaWindow window, bool alwaysBottom = false) { - var eventTriggers = window.Triggers[0] as EventTrigger; var beginStoryboard = eventTriggers.Actions[0] as BeginStoryboard; var storyboard = beginStoryboard.Storyboard; DoubleAnimation moveAnimation = (DoubleAnimation)storyboard.Children[0]; - _position = Settings.Default.Position; - if (_position == 0) + + if (alwaysBottom == false) { - window.Left = 16; - moveAnimation.From = SystemParameters.WorkArea.Height - window.Height + 4; - moveAnimation.To = SystemParameters.WorkArea.Height - window.Height - 16; + _position = Settings.Default.Position; + if (_position == 0) + { + window.Left = 16; + moveAnimation.From = SystemParameters.WorkArea.Height - window.Height + 4; + moveAnimation.To = SystemParameters.WorkArea.Height - window.Height - 16; + } + else if (_position == 1) + { + window.Left = SystemParameters.WorkArea.Width / 2 - window.Width / 2; + moveAnimation.From = SystemParameters.WorkArea.Height - window.Height - 60; + moveAnimation.To = SystemParameters.WorkArea.Height - window.Height - 80; + } + else if (_position == 2) + { + window.Left = SystemParameters.WorkArea.Width - window.Width - 16; + moveAnimation.From = SystemParameters.WorkArea.Height - window.Height + 4; + moveAnimation.To = SystemParameters.WorkArea.Height - window.Height - 16; + } + else if (_position == 3) + { + window.Left = 16; + moveAnimation.From = -4; + moveAnimation.To = 16; + } + else if (_position == 4) + { + window.Left = SystemParameters.WorkArea.Width / 2 - window.Width / 2; + moveAnimation.From = -4; + moveAnimation.To = 16; + } + else if (_position == 5) + { + window.Left = SystemParameters.WorkArea.Width - window.Width - 16; + moveAnimation.From = -4; + moveAnimation.To = 16; + } } - else if (_position == 1) + else { window.Left = SystemParameters.WorkArea.Width / 2 - window.Width / 2; - moveAnimation.From = SystemParameters.WorkArea.Height - window.Height - 60; - moveAnimation.To = SystemParameters.WorkArea.Height - window.Height - 80; - } - else if (_position == 2) - { - window.Left = SystemParameters.WorkArea.Width - window.Width - 16; moveAnimation.From = SystemParameters.WorkArea.Height - window.Height + 4; moveAnimation.To = SystemParameters.WorkArea.Height - window.Height - 16; } - else if (_position == 3) - { - window.Left = 16; - moveAnimation.From = -4; - moveAnimation.To = 16; - } - else if (_position == 4) - { - window.Left = SystemParameters.WorkArea.Width / 2 - window.Width / 2; - moveAnimation.From = -4; - moveAnimation.To = 16; - } - else if (_position == 5) - { - window.Left = SystemParameters.WorkArea.Width - window.Width - 16; - moveAnimation.From = -4; - moveAnimation.To = 16; - } + int msDuration = getDuration(); DoubleAnimation opacityAnimation = (DoubleAnimation)storyboard.Children[1]; @@ -179,29 +188,39 @@ public void OpenAnimation(MicaWindow window) storyboard.Begin(window); } - public void CloseAnimation(MicaWindow window) + public void CloseAnimation(MicaWindow window, bool alwaysBottom = false) { var eventTriggers = window.Triggers[0] as EventTrigger; var beginStoryboard = eventTriggers.Actions[0] as BeginStoryboard; var storyboard = beginStoryboard.Storyboard; DoubleAnimation moveAnimation = (DoubleAnimation)storyboard.Children[0]; - _position = Settings.Default.Position; - if (_position == 0 || _position == 2) - { - moveAnimation.From = SystemParameters.WorkArea.Height - window.Height - 16; - moveAnimation.To = SystemParameters.WorkArea.Height - window.Height + 4; - } - else if (_position == 1) + + if (alwaysBottom == false) { - moveAnimation.From = SystemParameters.WorkArea.Height - window.Height - 80; - moveAnimation.To = SystemParameters.WorkArea.Height - window.Height - 60; + _position = Settings.Default.Position; + if (_position == 0 || _position == 2) + { + moveAnimation.From = SystemParameters.WorkArea.Height - window.Height - 16; + moveAnimation.To = SystemParameters.WorkArea.Height - window.Height + 4; + } + else if (_position == 1) + { + moveAnimation.From = SystemParameters.WorkArea.Height - window.Height - 80; + moveAnimation.To = SystemParameters.WorkArea.Height - window.Height - 60; + } + else if (_position == 3 || _position == 4 || _position == 5) + { + moveAnimation.From = 16; + moveAnimation.To = -4; + } } - else if (_position == 3 || _position == 4 || _position == 5) + else { - moveAnimation.From = 16; - moveAnimation.To = -4; + moveAnimation.From = SystemParameters.WorkArea.Height - window.Height - 16; + moveAnimation.To = SystemParameters.WorkArea.Height - window.Height + 4; } + int msDuration = getDuration(); DoubleAnimation opacityAnimation = (DoubleAnimation)storyboard.Children[1]; @@ -285,15 +304,25 @@ private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) ShowMediaFlyout(); } - if (vkCode == 0x14) // Caps Lock - { - - } - - if (vkCode == 0x90) // Num Lock + if (Settings.Default.LockKeysEnabled == true) { + if (vkCode == 0x14) // Caps Lock + { + lockWindow ??= new LockWindow(); + lockWindow.ShowLockFlyout("Caps Lock", Keyboard.IsKeyToggled(Key.CapsLock)); + } - } + if (vkCode == 0x90) // Num Lock + { + lockWindow ??= new LockWindow(); + lockWindow.ShowLockFlyout("Num Lock", Keyboard.IsKeyToggled(Key.NumLock)); + } + if (vkCode == 0x91) // Scroll Lock + { + lockWindow ??= new LockWindow(); + lockWindow.ShowLockFlyout("Scroll Lock", Keyboard.IsKeyToggled(Key.Scroll)); + } + } } return CallNextHookEx(_hookId, nCode, wParam, lParam); } diff --git a/FluentFlyoutWPF/Properties/Settings.Designer.cs b/FluentFlyoutWPF/Properties/Settings.Designer.cs index 5134587..f8a4fed 100644 --- a/FluentFlyoutWPF/Properties/Settings.Designer.cs +++ b/FluentFlyoutWPF/Properties/Settings.Designer.cs @@ -178,5 +178,29 @@ public int FlyoutAnimationEasingStyle { this["FlyoutAnimationEasingStyle"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool LockKeysEnabled { + get { + return ((bool)(this["LockKeysEnabled"])); + } + set { + this["LockKeysEnabled"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("2000")] + public int LockKeysDuration { + get { + return ((int)(this["LockKeysDuration"])); + } + set { + this["LockKeysDuration"] = value; + } + } } } diff --git a/FluentFlyoutWPF/Properties/Settings.settings b/FluentFlyoutWPF/Properties/Settings.settings index 2a50a25..0848b8e 100644 --- a/FluentFlyoutWPF/Properties/Settings.settings +++ b/FluentFlyoutWPF/Properties/Settings.settings @@ -41,5 +41,11 @@ 2 + + False + + + 2000 + \ No newline at end of file diff --git a/FluentFlyoutWPF/Resources/FluentFlyoutDemo5.1.png b/FluentFlyoutWPF/Resources/FluentFlyoutDemo5.1.png new file mode 100644 index 0000000..b4cb4e8 Binary files /dev/null and b/FluentFlyoutWPF/Resources/FluentFlyoutDemo5.1.png differ diff --git a/FluentFlyoutWPF/SettingsWindow.xaml b/FluentFlyoutWPF/SettingsWindow.xaml index 65b88b5..c0aa47f 100644 --- a/FluentFlyoutWPF/SettingsWindow.xaml +++ b/FluentFlyoutWPF/SettingsWindow.xaml @@ -157,6 +157,44 @@ + + + + + + + + + + + Check your lock key status at a glance. + Appears after pressing Caps Lock, Num Lock or Scroll Lock. + Convenient for laptops/keyboards without lock key indicators. + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FluentFlyoutWPF/SettingsWindow.xaml.cs b/FluentFlyoutWPF/SettingsWindow.xaml.cs index e3077e6..d808949 100644 --- a/FluentFlyoutWPF/SettingsWindow.xaml.cs +++ b/FluentFlyoutWPF/SettingsWindow.xaml.cs @@ -48,6 +48,8 @@ public SettingsWindow() nIconLeftClickComboBox.SelectedIndex = Settings.Default.nIconLeftClick; CenterTitleArtistSwitch.IsChecked = Settings.Default.CenterTitleArtist; AnimationEasingStylesComboBox.SelectedIndex = Settings.Default.FlyoutAnimationEasingStyle; + LockKeysSwitch.IsChecked = Settings.Default.LockKeysEnabled; + LockKeysDurationTextBox.Text = Settings.Default.LockKeysDuration.ToString(); try // gets the version of the app, works only in release mode { @@ -60,6 +62,23 @@ public SettingsWindow() } } + public static void ShowInstance() + { + if (instance == null) + { + new SettingsWindow().Show(); + } + else + { + if (instance.WindowState == WindowState.Minimized) + { + instance.WindowState = WindowState.Normal; + } + instance.Activate(); + instance.Focus(); + } + } + private void SaveButton_Click(object sender, RoutedEventArgs e) { Close(); @@ -103,23 +122,6 @@ private void FlyoutAnimationSpeedComboBox_SelectionChanged(object sender, System Settings.Default.Save(); } - public static void ShowInstance() - { - if (instance == null) - { - new SettingsWindow().Show(); - } - else - { - if (instance.WindowState == WindowState.Minimized) - { - instance.WindowState = WindowState.Normal; - } - instance.Activate(); - instance.Focus(); - } - } - private void NextUpSwitch_Click(object sender, RoutedEventArgs e) { Settings.Default.NextUpEnabled = NextUpSwitch.IsChecked ?? false; @@ -260,5 +262,44 @@ private void StartupHyperlink_RequestNavigate(object sender, System.Windows.Navi Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true }); e.Handled = true; } + + private void LockKeysSwitch_Click(object sender, RoutedEventArgs e) + { + Settings.Default.LockKeysEnabled = LockKeysSwitch.IsChecked ?? false; + Settings.Default.Save(); + } + + private void LockKeysDurationTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) + { + string text = LockKeysDurationTextBox.Text.Trim(); + string numericText = new string(text.Where(char.IsDigit).ToArray()); + + if (string.IsNullOrEmpty(numericText)) + { + LockKeysDurationTextBox.Text = "0"; + Settings.Default.LockKeysDuration = 0; + } + else + { + LockKeysDurationTextBox.Text = numericText; + if (int.TryParse(numericText, out int duration)) + { + if (duration > 10000) + { + duration = 10000; + } + LockKeysDurationTextBox.Text = duration.ToString(); + Settings.Default.LockKeysDuration = duration; + } + else + { + LockKeysDurationTextBox.Text = "2000"; + Settings.Default.LockKeysDuration = 2000; + } + } + + LockKeysDurationTextBox.CaretIndex = LockKeysDurationTextBox.Text.Length; + Settings.Default.Save(); + } } } diff --git a/FluentFlyoutWPF/Windows/LockWindow.xaml b/FluentFlyoutWPF/Windows/LockWindow.xaml new file mode 100644 index 0000000..bca1e03 --- /dev/null +++ b/FluentFlyoutWPF/Windows/LockWindow.xaml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FluentFlyoutWPF/Windows/LockWindow.xaml.cs b/FluentFlyoutWPF/Windows/LockWindow.xaml.cs new file mode 100644 index 0000000..5f8e1be --- /dev/null +++ b/FluentFlyoutWPF/Windows/LockWindow.xaml.cs @@ -0,0 +1,83 @@ +using FluentFlyout.Classes; +using FluentFlyout.Properties; +using FluentFlyoutWPF; +using MicaWPF.Controls; +using MicaWPF.Core.Extensions; +using System.Windows; +using Windows.UI; + + +namespace FluentFlyout.Windows +{ + /// + /// Interaction logic for LockWindow.xaml + /// + public partial class LockWindow : MicaWindow + { + private CancellationTokenSource cts; + MainWindow mainWindow = (MainWindow)Application.Current.MainWindow; + + public LockWindow() + { + WindowHelper.SetNoActivate(this); + InitializeComponent(); + WindowHelper.SetTopmost(this); + CustomWindowChrome.CaptionHeight = 0; + + WindowStartupLocation = WindowStartupLocation.Manual; + Left = SystemParameters.WorkArea.Width / 2 - Width / 2; + cts = new CancellationTokenSource(); + mainWindow.OpenAnimation(this, true); + } + + private void setStatus(string key, bool isOn) + { + Dispatcher.Invoke(() => + { + this.EnableBackdrop(); + + LockTextBlock.Text = key + " is " + (isOn ? "on" : "off"); + if (isOn) + { + LockIndicatorRectangle.Opacity = 1; + LockSymbol.Symbol = Wpf.Ui.Controls.SymbolRegular.LockClosed24; + } + else + { + LockIndicatorRectangle.Opacity = 0.2; + LockSymbol.Symbol = Wpf.Ui.Controls.SymbolRegular.LockOpen24; + } + }); + } + + public async void ShowLockFlyout(string key, bool isOn) + { + setStatus(key, isOn); + + if (Visibility == Visibility.Hidden) + { + mainWindow.OpenAnimation(this, true); + } + cts.Cancel(); + cts = new CancellationTokenSource(); + var token = cts.Token; + Visibility = Visibility.Visible; + Topmost = true; + try + { + while (!token.IsCancellationRequested) + { + await Task.Delay(Settings.Default.LockKeysDuration, token); + mainWindow.CloseAnimation(this, true); + await Task.Delay(mainWindow.getDuration()); + Hide(); + break; + } + } + catch (TaskCanceledException) + { + // do nothing + } + } + } +}