using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Threading.Tasks; using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.WinUI; using Microsoft.Extensions.DependencyInjection; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls.Primitives; using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Navigation; using Windows.Foundation; using Wino.Calendar.Controls; using Wino.Calendar.Views; using Wino.Calendar.ViewModels; using Wino.Core.Domain; using Wino.Core.Domain.Entities.Mail; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.MenuItems; using Wino.Core.Domain.Models; using Wino.Core.Domain.Models.Folders; using Wino.Core.Domain.Models.MailItem; using Wino.Core.Domain.Models.Navigation; using Wino.Mail.ViewModels; using Wino.Mail.ViewModels.Data; using Wino.Mail.WinUI.Controls; using Wino.MenuFlyouts; using Wino.MenuFlyouts.Context; using Wino.Messaging.Client.Accounts; using Wino.Messaging.Client.Calendar; using Wino.Messaging.Client.Mails; using Wino.Messaging.Client.Shell; using Wino.Messaging.UI; using Wino.Views.Mail; using Wino.Views; using Wino.Views.Settings; using Windows.System; namespace Wino.Mail.WinUI.Views; public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract, IShellHost, IRecipient, IRecipient, IRecipient, IRecipient, IRecipient { private const string StateHorizontalCalendar = "HorizontalCalendar"; private const string StateVerticalCalendar = "VerticalCalendar"; private const string StateDefaultShellContent = "DefaultShellContentState"; private const string StateEventDetailsContent = "EventDetailsContentState"; private WinoApplicationMode? _activeMode; private bool _isSyncingNavigationViewSelection; public WinoAppShell() { InitializeComponent(); var pageDispatcher = new WinUIDispatcher(DispatcherQueue); ViewModel.MailClient.Dispatcher = pageDispatcher; ViewModel.CalendarClient.Dispatcher = pageDispatcher; ViewModel.GetClient(WinoApplicationMode.Contacts).Dispatcher = pageDispatcher; ViewModel.GetClient(WinoApplicationMode.Settings).Dispatcher = pageDispatcher; ViewModel.MailClient.PropertyChanged += MailClientPropertyChanged; ViewModel.CalendarClient.PropertyChanged += CalendarClientPropertyChanged; ViewModel.PropertyChanged += ViewModelPropertyChanged; ViewModel.StatePersistenceService.StatePropertyChanged += StatePersistenceServiceChanged; CalendarTypeSelector.RegisterPropertyChangedCallback(WinoCalendarTypeSelectorControl.SelectedTypeProperty, CalendarTypeSelectorSelectedTypeChanged); InitializeCalendarControls(); ManageCalendarDisplayType(ViewModel.CalendarClient.StatePersistenceService.CalendarDisplayType); UpdateEventDetailsVisualState(); ApplyTitleBarContent(); } public bool HasShellContent => InnerShellFrame.Content != null; public Frame GetShellFrame() => InnerShellFrame; public void ActivateMode(WinoApplicationMode mode, ShellModeActivationContext activationContext) { if (_activeMode == mode && InnerShellFrame.Content != null) return; DeactivateCurrentMode(); ResetShellModeNavigationState(); _activeMode = mode; ViewModel.SetCurrentMode(mode); RefreshNavigationViewBindings(syncMailSelection: mode != WinoApplicationMode.Mail); ApplyModeLayout(); UpdateTitleBarSubtitle(); ViewModel.CurrentClient.Activate(activationContext); ResetShellModeNavigationState(); ApplyTitleBarContent(); } protected override void OnNavigatedFrom(NavigationEventArgs e) { base.OnNavigatedFrom(e); DeactivateCurrentMode(); Bindings.StopTracking(); } private void OnLoaded(object sender, RoutedEventArgs e) { UpdateNavigationPaneLayout(navigationView.DisplayMode); RefreshNavigationViewBindings(); RefreshCalendarControls(); if (_activeMode == null) { ActivateMode(ViewModel.StatePersistenceService.ApplicationMode, new ShellModeActivationContext { IsInitialActivation = true }); } } private void ApplyModeLayout() { var isCalendarMode = ViewModel.IsCalendarMode; CalendarShellContentRoot.Visibility = isCalendarMode ? Visibility.Visible : Visibility.Collapsed; DynamicPageShellContentPresenter.Visibility = isCalendarMode ? Visibility.Collapsed : Visibility.Visible; RefreshCalendarControls(); ManageCalendarDisplayType(ViewModel.CalendarClient.StatePersistenceService.CalendarDisplayType); UpdateEventDetailsVisualState(); UpdateTitleBarSubtitle(); UpdateNavigationPaneLayout(navigationView.DisplayMode); ApplyTitleBarContent(); } private void DeactivateCurrentMode() { if (_activeMode == WinoApplicationMode.Mail) { WeakReferenceMessenger.Default.Send(new ClearMailSelectionsRequested()); WeakReferenceMessenger.Default.Send(new DisposeRenderingFrameRequested()); ViewModel.StatePersistenceService.IsReadingMail = false; ViewModel.MailClient.Deactivate(); } else if (_activeMode == WinoApplicationMode.Calendar) { ViewModel.StatePersistenceService.IsEventDetailsVisible = false; ViewModel.CalendarClient.Deactivate(); } else if (_activeMode == WinoApplicationMode.Contacts) { ViewModel.CurrentClient.Deactivate(); } else if (_activeMode == WinoApplicationMode.Settings) { if (InnerShellFrame.Content is SettingsPage settingsPage) { settingsPage.ResetForModeSwitch(); } ViewModel.CurrentClient.Deactivate(); } DynamicPageShellContentPresenter.Content = null; } private void ResetShellModeNavigationState() { ViewModel.StatePersistenceService.HasCurrentModeBackStack = false; InnerShellFrame.BackStack.Clear(); InnerShellFrame.ForwardStack.Clear(); } private void ApplyTitleBarContent() { if (ViewModel.IsCalendarMode) { CalendarShellContentRoot.Visibility = Visibility.Visible; DynamicPageShellContentPresenter.Visibility = Visibility.Collapsed; return; } CalendarShellContentRoot.Visibility = Visibility.Collapsed; DynamicPageShellContentPresenter.Visibility = Visibility.Visible; DynamicPageShellContentPresenter.Content = InnerShellFrame.Content is BasePage page ? page.ShellContent : null; } private void UpdateTitleBarSubtitle() { if (ViewModel.IsContactsMode) { ViewModel.StatePersistenceService.CoreWindowTitle = string.Empty; return; } if (ViewModel.IsCalendarMode) { ViewModel.StatePersistenceService.CoreWindowTitle = string.Empty; return; } ViewModel.StatePersistenceService.CoreWindowTitle = string.Empty; } private void ManageCalendarDisplayType(Core.Domain.Enums.CalendarDisplayType displayType) { DayHeaderNavigationItemsFlipView.DisplayType = displayType; if (CalendarTypeSelector.SelectedType != displayType) { CalendarTypeSelector.SelectedType = displayType; } VisualStateManager.GoToState(this, displayType == Core.Domain.Enums.CalendarDisplayType.Month ? StateVerticalCalendar : StateHorizontalCalendar, false); } private void InitializeCalendarControls() { CalendarTypeSelector.TodayClickedCommand = ViewModel.CalendarClient.TodayClickedCommand; CalendarView.DateClickedCommand = ViewModel.CalendarClient.DateClickedCommand; DayHeaderNavigationItemsFlipView.ItemsSource = ViewModel.CalendarClient.DateNavigationHeaderItems; CalendarHostListView.ItemsSource = ViewModel.CalendarClient.GroupedAccountCalendars; RefreshCalendarControls(); } private void RefreshCalendarControls() { DayHeaderNavigationItemsFlipView.ItemsSource = ViewModel.CalendarClient.DateNavigationHeaderItems; DayHeaderNavigationItemsFlipView.SelectedIndex = ViewModel.CalendarClient.SelectedDateNavigationHeaderIndex; CalendarTypeSelector.DisplayDayCount = ViewModel.CalendarClient.StatePersistenceService.DayDisplayCount; CalendarView.HighlightedDateRange = ViewModel.CalendarClient.HighlightedDateRange; CalendarHostListView.ItemsSource = ViewModel.CalendarClient.GroupedAccountCalendars; } private void RefreshNavigationViewBindings(bool syncMailSelection = true) { navigationView.MenuItemsSource = ViewModel.CurrentMenuItems; SetNavigationViewSelectedItem(ViewModel.CurrentClient.HandlesNavigationSelection && syncMailSelection ? ViewModel.SelectedMenuItem : null); } private void UpdateEventDetailsVisualState() { VisualStateManager.GoToState(this, ViewModel.StatePersistenceService.IsEventDetailsVisible ? StateEventDetailsContent : StateDefaultShellContent, false); } private void CalendarTypeSelectorSelectedTypeChanged(DependencyObject sender, DependencyProperty dp) { var selectedType = CalendarTypeSelector.SelectedType; if (ViewModel.CalendarClient.StatePersistenceService.CalendarDisplayType != selectedType) { ViewModel.CalendarClient.StatePersistenceService.CalendarDisplayType = selectedType; } } private async void NewCalendarEventNavigationItemTapped(object sender, TappedRoutedEventArgs e) { e.Handled = true; await InvokeNewCalendarEventAsync(); } private async void NewCalendarEventNavigationItemKeyDown(object sender, KeyRoutedEventArgs e) { if (e.Key is not (VirtualKey.Enter or VirtualKey.Space)) return; e.Handled = true; await InvokeNewCalendarEventAsync(); } private void PreviousDateClicked(object sender, RoutedEventArgs e) => WeakReferenceMessenger.Default.Send(new GoPreviousDateRequestedMessage()); private void NextDateClicked(object sender, RoutedEventArgs e) => WeakReferenceMessenger.Default.Send(new GoNextDateRequestedMessage()); private Task InvokeNewCalendarEventAsync() => ViewModel.CalendarClient.HandleNavigationItemInvokedAsync(new NewCalendarEventMenuItem()); public void Receive(CalendarDisplayTypeChangedMessage message) => ManageCalendarDisplayType(message.NewDisplayType); public void Receive(AccountCreatedMessage message) { _ = DispatcherQueue.EnqueueAsync(async () => { ViewModel.NavigationService.ChangeApplicationMode(WinoApplicationMode.Mail); await ViewModel.MailClient.HandleAccountCreatedAsync(message.Account); }); } private async void NavigationViewItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args) { if (_isSyncingNavigationViewSelection) return; if (ViewModel.IsCalendarMode) { if (args.InvokedItemContainer is FrameworkElement { DataContext: IMenuItem menuItem }) { await ViewModel.CalendarClient.HandleNavigationItemInvokedAsync(menuItem); } return; } if (args.InvokedItemContainer is WinoNavigationViewItem winoNavigationViewItem) { if (winoNavigationViewItem.SelectsOnInvoked) return; await ViewModel.CurrentClient.HandleNavigationItemInvokedAsync(winoNavigationViewItem.DataContext as IMenuItem); } } private async void MenuSelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args) { if (_isSyncingNavigationViewSelection) return; if (!ViewModel.CurrentClient.HandlesNavigationSelection) return; if (ReferenceEquals(args.SelectedItem, ViewModel.SelectedMenuItem)) return; if (args.SelectedItem is IMenuItem invokedMenuItem) { await ViewModel.CurrentClient.HandleNavigationSelectionChangedAsync(invokedMenuItem); } } public void Receive(AccountMenuItemExtended message) { if (!ViewModel.IsMailMode) return; _ = DispatcherQueue.EnqueueAsync(async () => { if (message.FolderId == default) return; if (ViewModel.MailClient.MenuItems!.TryGetFolderMenuItem(message.FolderId, out IBaseFolderMenuItem foundMenuItem)) { foundMenuItem.Expand(); await ViewModel.MailClient.NavigateFolderAsync(foundMenuItem); SetNavigationViewSelectedItem(foundMenuItem); if (message.NavigateMailItem != null) { WeakReferenceMessenger.Default.Send(new MailItemNavigationRequested(message.NavigateMailItem.UniqueId, ScrollToItem: true)); } return; } if (message.NavigateMailItem == null) return; if (ViewModel.MailClient.MenuItems!.TryGetAccountMenuItem(message.NavigateMailItem.AssignedAccount.Id, out IAccountMenuItem accountMenuItem)) { await ViewModel.MailClient.ChangeLoadedAccountAsync(accountMenuItem, navigateInbox: false); if (ViewModel.MailClient.MenuItems!.TryGetFolderMenuItem(message.FolderId, out IBaseFolderMenuItem accountFolderMenuItem)) { accountFolderMenuItem.Expand(); await ViewModel.MailClient.NavigateFolderAsync(accountFolderMenuItem); SetNavigationViewSelectedItem(accountFolderMenuItem); WeakReferenceMessenger.Default.Send(new MailItemNavigationRequested(message.NavigateMailItem.UniqueId, ScrollToItem: true)); } } }); } public void Receive(NavigateMailFolderEvent message) { if (!ViewModel.IsMailMode || message.BaseFolderMenuItem == null) return; if (navigationView.SelectedItem != message.BaseFolderMenuItem) { var navigateFolderArgs = new NavigateMailFolderEventArgs(message.BaseFolderMenuItem, message.FolderInitLoadAwaitTask); ViewModel.NavigationService.Navigate(WinoPage.MailListPage, navigateFolderArgs, NavigationReferenceFrame.InnerShellFrame); SetNavigationViewSelectedItem(message.BaseFolderMenuItem); } else { message.FolderInitLoadAwaitTask?.TrySetResult(true); } } private void ShellFrameContentNavigated(object sender, NavigationEventArgs e) { ApplyTitleBarContent(); if (ViewModel.IsMailMode) { RefreshNavigationViewBindings(); } } private async void MenuItemContextRequested(UIElement sender, ContextRequestedEventArgs args) { if (!ViewModel.IsMailMode) return; if (sender is WinoNavigationViewItem menuItem && menuItem.DataContext is IBaseFolderMenuItem baseFolderMenuItem && baseFolderMenuItem.IsMoveTarget && args.TryGetPosition(sender, out Point p)) { args.Handled = true; var source = new TaskCompletionSource(); var actions = ViewModel.MailClient.GetFolderContextMenuActions(baseFolderMenuItem); var flyout = new FolderOperationFlyout(actions, source); flyout.ShowAt(menuItem, new FlyoutShowOptions { ShowMode = FlyoutShowMode.Standard, Position = new Point(p.X + 30, p.Y - 20) }); var operation = await source.Task; flyout.Dispose(); if (operation != null) { await ViewModel.MailClient.PerformFolderOperationAsync(operation.Operation, baseFolderMenuItem); } } } public void Receive(CreateNewMailWithMultipleAccountsRequested message) { if (!ViewModel.IsMailMode) return; var container = navigationView.ContainerFromMenuItem(ViewModel.MailClient.CreatePrimaryMenuItem); var flyout = new AccountSelectorFlyout(message.AllAccounts, ViewModel.MailClient.CreateNewMailForAsync); flyout.ShowAt(container, new FlyoutShowOptions { ShowMode = FlyoutShowMode.Auto, Placement = FlyoutPlacementMode.Right }); } private void NavigationPaneOpening(NavigationView sender, object args) { if (!ViewModel.IsMailMode) return; if (sender.DisplayMode == NavigationViewDisplayMode.Minimal && sender.SelectedItem is IFolderMenuItem selectedFolderMenuItem) { selectedFolderMenuItem.Expand(); } } private void NavigationPaneOpened(NavigationView sender, object args) => UpdateNavigationPaneLayout(sender.DisplayMode); private void NavigationPaneClosed(NavigationView sender, object args) => UpdateNavigationPaneLayout(sender.DisplayMode); private void NavigationViewDisplayModeChanged(NavigationView sender, NavigationViewDisplayModeChangedEventArgs args) => UpdateNavigationPaneLayout(args.DisplayMode); private void MailClientPropertyChanged(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(IShellClient.SelectedMenuItem) && ViewModel.IsMailMode) { SetNavigationViewSelectedItem(ViewModel.MailClient.SelectedMenuItem); } } private void CalendarClientPropertyChanged(object? sender, PropertyChangedEventArgs e) { if (!DispatcherQueue.HasThreadAccess) { var enqueued = DispatcherQueue.TryEnqueue(() => CalendarClientPropertyChanged(sender, e)); if (!enqueued) throw new InvalidOperationException("Could not marshal calendar property changes onto the UI thread."); return; } if (e.PropertyName == nameof(ICalendarShellClient.DateNavigationHeaderItems)) { DayHeaderNavigationItemsFlipView.ItemsSource = ViewModel.CalendarClient.DateNavigationHeaderItems; return; } if (e.PropertyName == nameof(ICalendarShellClient.SelectedDateNavigationHeaderIndex)) { DayHeaderNavigationItemsFlipView.SelectedIndex = ViewModel.CalendarClient.SelectedDateNavigationHeaderIndex; return; } if (e.PropertyName == nameof(ICalendarShellClient.HighlightedDateRange)) { CalendarView.HighlightedDateRange = ViewModel.CalendarClient.HighlightedDateRange; UpdateTitleBarSubtitle(); } } private void ViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName != nameof(ViewModel.SelectedMenuItem) || !ViewModel.CurrentClient.HandlesNavigationSelection) return; SetNavigationViewSelectedItem(ViewModel.SelectedMenuItem); } private void SetNavigationViewSelectedItem(object? item) { if (ReferenceEquals(navigationView.SelectedItem, item)) return; _isSyncingNavigationViewSelection = true; try { navigationView.SelectedItem = item; } finally { _isSyncingNavigationViewSelection = false; } } private void StatePersistenceServiceChanged(object? sender, string propertyName) { if (propertyName == nameof(IStatePersistanceService.CalendarDisplayType)) { ManageCalendarDisplayType(ViewModel.CalendarClient.StatePersistenceService.CalendarDisplayType); return; } if (propertyName == nameof(IStatePersistanceService.DayDisplayCount)) { CalendarTypeSelector.DisplayDayCount = ViewModel.CalendarClient.StatePersistenceService.DayDisplayCount; return; } if (propertyName == nameof(IStatePersistanceService.IsEventDetailsVisible)) { UpdateEventDetailsVisualState(); } } private void UpdateNavigationPaneLayout(NavigationViewDisplayMode displayMode) { if (displayMode == NavigationViewDisplayMode.Expanded && navigationView.IsPaneOpen) { if (ViewModel.IsCalendarMode) { PaneCustomContent.Visibility = Visibility.Visible; CalendarPaneContent.Visibility = Visibility.Visible; ContactsPaneContent.Visibility = Visibility.Collapsed; InnerShellFrame.Margin = new Thickness(0); return; } if (ViewModel.IsContactsMode) { PaneCustomContent.Visibility = Visibility.Visible; CalendarPaneContent.Visibility = Visibility.Collapsed; ContactsPaneContent.Visibility = Visibility.Visible; InnerShellFrame.Margin = new Thickness(0); return; } } CalendarPaneContent.Visibility = Visibility.Collapsed; ContactsPaneContent.Visibility = Visibility.Collapsed; PaneCustomContent.Visibility = Visibility.Collapsed; InnerShellFrame.Margin = displayMode == NavigationViewDisplayMode.Minimal ? new Thickness(7, 0, 0, 0) : new Thickness(0); } private async void OnPreviewKeyDown(object sender, KeyRoutedEventArgs e) { if (e.KeyStatus.RepeatCount > 1 || ShouldIgnoreShortcut()) return; var key = NormalizeKey(e.Key); if (string.IsNullOrEmpty(key)) return; var mode = ViewModel.CurrentMode; var shortcutService = WinoApplication.Current.Services.GetRequiredService(); var shortcut = await shortcutService.GetShortcutForKeyAsync(mode, key, GetCurrentModifierKeys()); if (shortcut == null) return; var details = new KeyboardShortcutTriggerDetails { ShortcutId = shortcut.Id, Mode = shortcut.Mode, Action = shortcut.Action, Key = shortcut.Key, ModifierKeys = shortcut.ModifierKeys, Sender = sender, Origin = FocusManager.GetFocusedElement(XamlRoot) }; await ViewModel.CurrentClient.KeyboardShortcutHook(details); if (InnerShellFrame.Content is BasePage activePage && activePage.AssociatedViewModel != null) { await activePage.AssociatedViewModel.KeyboardShortcutHook(details); } if (details.Handled) { e.Handled = true; } } private bool ShouldIgnoreShortcut() { var focusedElement = FocusManager.GetFocusedElement(XamlRoot); if (focusedElement is TextBox or AutoSuggestBox or PasswordBox or RichEditBox or ComboBox) return true; if (focusedElement is FrameworkElement frameworkElement) { var typeName = frameworkElement.GetType().Name; if (typeName.Contains("WebView", StringComparison.OrdinalIgnoreCase)) return true; } return false; } private async void ItemDroppedOnFolder(object sender, DragEventArgs e) { if (sender is WinoNavigationViewItem droppedContainer) { droppedContainer.IsDraggingItemOver = false; if (CanContinueDragDrop(droppedContainer, e) && droppedContainer.DataContext is IBaseFolderMenuItem draggingFolder) { var dragPackage = e.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage; if (dragPackage == null) return; e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move; var mailCopies = ExtractMailCopies(dragPackage).ToList(); await ViewModel.MailClient.PerformMoveOperationAsync(mailCopies, draggingFolder); } } } private void ItemDragLeaveFromFolder(object sender, DragEventArgs e) { if (sender is WinoNavigationViewItem leavingContainer) { leavingContainer.IsDraggingItemOver = false; } } private bool CanContinueDragDrop(WinoNavigationViewItem interactingContainer, DragEventArgs args) { if (!ViewModel.IsMailMode || !args.DataView.Properties.ContainsKey(nameof(MailDragPackage))) return false; var dragPackage = args.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage; if (dragPackage == null || !dragPackage.DraggingMails.Any()) return false; if (interactingContainer.IsSelected) return false; if (interactingContainer.DataContext is not IBaseFolderMenuItem folderMenuItem || !folderMenuItem.IsMoveTarget) return false; var draggedAccountIds = folderMenuItem.HandlingFolders.Select(a => a.MailAccountId); var draggedMails = ExtractMailCopies(dragPackage).ToList(); return draggedMails.Any() && draggedMails.Any(a => draggedAccountIds.Contains(a.AssignedAccount.Id)); } private static IEnumerable ExtractMailCopies(MailDragPackage dragPackage) { foreach (var item in dragPackage.DraggingMails) { if (item is MailCopy mailCopy) { yield return mailCopy; } else if (item is MailItemViewModel singleMailItemViewModel) { yield return singleMailItemViewModel.MailCopy; } else if (item is ThreadMailItemViewModel threadViewModel) { foreach (var threadMail in threadViewModel.ThreadEmails) { yield return threadMail.MailCopy; } } } } private void ItemDragEnterOnFolder(object sender, DragEventArgs e) { if (sender is WinoNavigationViewItem droppedContainer && CanContinueDragDrop(droppedContainer, e)) { droppedContainer.IsDraggingItemOver = true; if (droppedContainer.DataContext is IBaseFolderMenuItem draggingFolder) { e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move; e.DragUIOverride.Caption = string.Format(Translator.DragMoveToFolderCaption, draggingFolder.FolderName); } } } private static ModifierKeys GetCurrentModifierKeys() { var modifiers = ModifierKeys.None; if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Control).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down)) modifiers |= ModifierKeys.Control; if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Menu).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down)) modifiers |= ModifierKeys.Alt; if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Shift).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down)) modifiers |= ModifierKeys.Shift; if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.LeftWindows).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down) || Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.RightWindows).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down)) { modifiers |= ModifierKeys.Windows; } return modifiers; } private static string NormalizeKey(Windows.System.VirtualKey key) { return key switch { Windows.System.VirtualKey.Control or Windows.System.VirtualKey.LeftControl or Windows.System.VirtualKey.RightControl or Windows.System.VirtualKey.Menu or Windows.System.VirtualKey.LeftMenu or Windows.System.VirtualKey.RightMenu or Windows.System.VirtualKey.Shift or Windows.System.VirtualKey.LeftShift or Windows.System.VirtualKey.RightShift or Windows.System.VirtualKey.LeftWindows or Windows.System.VirtualKey.RightWindows => string.Empty, _ => key.ToString() }; } protected override void RegisterRecipients() { base.RegisterRecipients(); WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); } protected override void UnregisterRecipients() { base.UnregisterRecipients(); WeakReferenceMessenger.Default.Unregister(this); WeakReferenceMessenger.Default.Unregister(this); WeakReferenceMessenger.Default.Unregister(this); WeakReferenceMessenger.Default.Unregister(this); WeakReferenceMessenger.Default.Unregister(this); } }