public EyeAurasSettingsViewModel(
     [NotNull] IHotkeyConverter hotkeyConverter,
     [NotNull] IConfigProvider <EyeAurasConfig> configProvider)
 {
     this.hotkeyConverter = hotkeyConverter;
     this.configProvider  = configProvider;
 }
示例#2
0
 public HotkeyEditorViewModel(IHotkeyConverter hotkeyConverter)
 {
     this.hotkeyConverter = hotkeyConverter;
     this.WhenAnyValue(x => x.Key, x => x.AlternativeKey, x => x.SuppressKey)
     .Select(x => SaveToHotkeyConfig())
     .SubscribeSafe(x => Properties = x, Log.HandleUiException)
     .AddTo(Anchors);
 }
示例#3
0
        public HotkeyIsActiveTrigger(
            [NotNull] IHotkeyConverter hotkeyConverter,
            [NotNull] IKeyboardEventsSource eventSource,
            [NotNull][Dependency(WellKnownWindows.MainWindow)] IWindowTracker mainWindowTracker,
            [NotNull][Dependency(WellKnownSchedulers.UI)] IScheduler uiScheduler)
        {
            this.hotkeyConverter = hotkeyConverter;
            Disposable
            .Create(() => Log.Debug($"Disposing HotkeyTrigger, gesture: {Hotkey} (mode: {HotkeyMode})"))
            .AddTo(Anchors);
            IsActive = true;
            this.RaiseWhenSourceValue(x => x.Properties, this, x => x.IsActive).AddTo(Anchors);

            this.WhenAnyValue(x => x.Hotkey)
            .Select(hotkey => hotkey == null ? Observable.Empty <HotkeyData>() : BuildHotkeySubscription(eventSource))
            .Switch()
            .DistinctUntilChanged(x => new { x.Hotkey, x.KeyDown })
            .Where(
                hotkeyData =>
            {
                /*
                 * This method MUST be executed on the same thread which emitted Key/Mouse event
                 * otherwise .Handled value will be ignored due to obvious concurrency reasons
                 */
                if (mainWindowTracker.ActiveProcessId != CurrentProcessId)
                {
                    Log.Debug($"Application is NOT active, processing hotkey {hotkeyData.Hotkey} (isDown: {hotkeyData.KeyDown}, suppressKey: {suppressKey},  configuredKey: {Hotkey}, mode: {HotkeyMode})");
                    if (suppressKey)
                    {
                        hotkeyData.MarkAsHandled();
                    }
                    return(true);
                }

                Log.Debug($"Application is active, skipping hotkey {hotkeyData.Hotkey} (isDown: {hotkeyData.KeyDown}, suppressKey: {suppressKey},  configuredKey: {Hotkey}, mode: {HotkeyMode})");
                return(false);
            })
            .Subscribe(
                hotkeyData =>
            {
                Log.Debug($"Hotkey {hotkeyData.Hotkey} pressed, state: {(hotkeyData.KeyDown ? "down" : "up")}, suppressed: {suppressKey}");

                if (HotkeyMode == HotkeyMode.Click)
                {
                    if (hotkeyData.KeyDown)
                    {
                        IsActive = !IsActive;
                    }
                }
                else
                {
                    IsActive = !IsActive;
                }
            },
                Log.HandleUiException)
            .AddTo(Anchors);
        }
示例#4
0
        public ComplexHotkeyTracker(
            [NotNull] IHotkeyConverter hotkeyConverter,
            [NotNull] IConfigProvider <MicSwitchConfig> configProvider,
            [NotNull] IFactory <IHotkeyTracker> hotkeyTrackerFactory)
        {
            this.hotkeyConverter      = hotkeyConverter;
            this.configProvider       = configProvider;
            this.hotkeyTrackerFactory = hotkeyTrackerFactory;
            Log.Debug($"Scheduling HotkeyTracker initialization using background scheduler");

            var bgThread = new Thread(x => Initialize())
            {
                IsBackground   = true,
                ApartmentState = ApartmentState.STA,
                Name           = "HotkeyTracker"
            };

            bgThread.Start();
        }
示例#5
0
        public ComplexHotkeyTracker(
            [NotNull] IHotkeyConverter hotkeyConverter,
            [NotNull] IConfigProvider <MicSwitchHotkeyConfig> configProvider,
            [NotNull] IFactory <IHotkeyTracker> hotkeyTrackerFactory)
        {
            this.hotkeyConverter = hotkeyConverter;
            this.configProvider  = configProvider;
            this.hotkeyTracker   = hotkeyTrackerFactory.Create();
            Log.Debug($"Scheduling HotkeyTracker initialization using background scheduler");
            this.RaiseWhenSourceValue(x => x.IsActive, hotkeyTracker, x => x.IsActive).AddTo(Anchors);

            var bgThread = new Thread(x => Initialize())
            {
                IsBackground   = true,
                ApartmentState = ApartmentState.STA,
                Name           = "HotkeyTracker"
            };

            bgThread.Start();
        }
示例#6
0
        public MainWindowViewModel(
            [NotNull] IFactory <IOverlayAuraViewModel, OverlayAuraProperties> auraViewModelFactory,
            [NotNull] IApplicationUpdaterViewModel appUpdater,
            [NotNull] IClipboardManager clipboardManager,
            [NotNull] IConfigSerializer configSerializer,
            [NotNull] IGenericSettingsViewModel settingsViewModel,
            [NotNull] IMessageBoxViewModel messageBox,
            [NotNull] IHotkeyConverter hotkeyConverter,
            [NotNull] IFactory <HotkeyIsActiveTrigger> hotkeyTriggerFactory,
            [NotNull] IConfigProvider <EyeAurasConfig> configProvider,
            [NotNull] IConfigProvider rootConfigProvider,
            [NotNull] IPrismModuleStatusViewModel moduleStatus,
            [NotNull] IMainWindowBlocksProvider mainWindowBlocksProvider,
            [NotNull] IFactory <IRegionSelectorService> regionSelectorServiceFactory,
            [NotNull] ISharedContext sharedContext,
            [NotNull] IComparisonService comparisonService,
            [NotNull][Dependency(WellKnownSchedulers.UI)] IScheduler uiScheduler)
        {
            using var unused = new OperationTimer(elapsed => Log.Debug($"{nameof(MainWindowViewModel)} initialization took {elapsed.TotalMilliseconds:F0}ms"));

            TabsList     = new ReadOnlyObservableCollection <IEyeAuraViewModel>(sharedContext.AuraList);
            ModuleStatus = moduleStatus.AddTo(Anchors);
            var executingAssemblyName = Assembly.GetExecutingAssembly().GetName();

            Title = $"{(AppArguments.Instance.IsDebugMode ? "[D]" : "")} {executingAssemblyName.Name} v{executingAssemblyName.Version}";
            Disposable.Create(() => Log.Info("Disposing Main view model")).AddTo(Anchors);

            ApplicationUpdater = appUpdater.AddTo(Anchors);
            MessageBox         = messageBox.AddTo(Anchors);
            Settings           = settingsViewModel.AddTo(Anchors);
            StatusBarItems     = mainWindowBlocksProvider.StatusBarItems;

            this.auraViewModelFactory  = auraViewModelFactory;
            this.configProvider        = configProvider;
            this.sharedContext         = sharedContext;
            this.regionSelectorService = regionSelectorServiceFactory.Create();
            this.clipboardManager      = clipboardManager;
            this.configSerializer      = configSerializer;
            this.hotkeyConverter       = hotkeyConverter;
            this.hotkeyTriggerFactory  = hotkeyTriggerFactory;

            CreateNewTabCommand = CommandWrapper.Create(() => AddNewCommandExecuted(OverlayAuraProperties.Default));
            CloseTabCommand     = CommandWrapper
                                  .Create <IOverlayAuraViewModel>(CloseTabCommandExecuted, CloseTabCommandCanExecute)
                                  .RaiseCanExecuteChangedWhen(this.WhenAnyProperty(x => x.SelectedTab));

            DuplicateTabCommand = CommandWrapper
                                  .Create(DuplicateTabCommandExecuted, DuplicateTabCommandCanExecute)
                                  .RaiseCanExecuteChangedWhen(this.WhenAnyProperty(x => x.SelectedTab));
            CopyTabToClipboardCommand = CommandWrapper
                                        .Create(CopyTabToClipboardExecuted, CopyTabToClipboardCommandCanExecute)
                                        .RaiseCanExecuteChangedWhen(this.WhenAnyProperty(x => x.SelectedTab).Select(x => x));

            PasteTabCommand             = CommandWrapper.Create(PasteTabCommandExecuted);
            UndoCloseTabCommand         = CommandWrapper.Create(UndoCloseTabCommandExecuted, UndoCloseTabCommandCanExecute);
            OpenAppDataDirectoryCommand = CommandWrapper.Create(OpenAppDataDirectory);
            SelectRegionCommand         = CommandWrapper.Create(SelectRegionCommandExecuted);

            Observable
            .FromEventPattern <OrderChangedEventArgs>(h => positionMonitor.OrderChanged += h, h => positionMonitor.OrderChanged -= h)
            .Select(x => x.EventArgs)
            .Subscribe(OnTabOrderChanged, Log.HandleUiException)
            .AddTo(Anchors);

            sharedContext
            .AuraList
            .ToObservableChangeSet()
            .ObserveOn(uiScheduler)
            .OnItemAdded(x => SelectedTab = x)
            .Subscribe()
            .AddTo(Anchors);

            this.WhenAnyValue(x => x.SelectedTab)
            .Subscribe(x => Log.Debug($"Selected tab: {x}"))
            .AddTo(Anchors);

            LoadConfig();
            rootConfigProvider.Save();

            if (sharedContext.AuraList.Count == 0)
            {
                CreateNewTabCommand.Execute(null);
            }

            configUpdateSubject
            .Sample(ConfigSaveSamplingTimeout)
            .Subscribe(SaveConfig, Log.HandleException)
            .AddTo(Anchors);

            Observable.Merge(
                this.WhenAnyProperty(x => x.Left, x => x.Top, x => x.Width, x => x.Height)
                .Sample(ConfigSaveSamplingTimeout)
                .Select(x => $"[{x.Sender}] Main window property change: {x.EventArgs.PropertyName}"),
                sharedContext.AuraList.ToObservableChangeSet()
                .Sample(ConfigSaveSamplingTimeout)
                .Select(x => "Tabs list change"),
                sharedContext.AuraList.ToObservableChangeSet()
                .WhenPropertyChanged(x => x.Properties)
                .Sample(ConfigSaveSamplingTimeout)
                .WithPrevious((prev, curr) => new { prev, curr })
                .Select(x => new { x.curr.Sender, ComparisonResult = comparisonService.Compare(x.prev?.Value, x.curr.Value) })
                .Where(x => !x.ComparisonResult.AreEqual)
                .Select(x => $"[{x.Sender.TabName}] Tab properties change: {x.ComparisonResult.DifferencesString}"))
            .Buffer(ConfigSaveSamplingTimeout)
            .Where(x => x.Count > 0)
            .Subscribe(
                reasons =>
            {
                const int maxReasonsToOutput = 50;
                Log.Debug(
                    $"Config Save reasons{(reasons.Count <= maxReasonsToOutput ? string.Empty : $"first {maxReasonsToOutput} of {reasons.Count} items")}:\r\n\t{reasons.Take(maxReasonsToOutput).DumpToTable()}");
                configUpdateSubject.OnNext(Unit.Default);
            },