/
githubmirror
/
PowerToys
Обзор
Документация
Войти
/
githubmirror
/
PowerToys
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/settings-ui/Settings.UI/ViewModels/ZoomItViewModel.cs
1 405 строк
51 KB
chakrik73
[ZoomIt] Add DemoMirror feature (#49607)
01 авг 2026, 05:39
Не верифицирован
01 авг 2026, 05:39
d2c53bf
Код
Авторство
О чём код?
// Copyright (c) Microsoft Corporation // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.ObjectModel; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text.Json; using global::PowerToys.GPOWrapper; using ManagedCommon; using Microsoft.PowerToys.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.Helpers; using Microsoft.PowerToys.Settings.UI.Library.Interfaces; using Microsoft.PowerToys.Settings.UI.Library.Utilities; using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands; using Microsoft.UI.Xaml.Media; using Microsoft.Windows.ApplicationModel.Resources; using Windows.Devices.Enumeration; namespace Microsoft.PowerToys.Settings.UI.ViewModels { public class ZoomItViewModel : Observable { private const string FormatGif = "GIF"; private const string FormatMp4 = "MP4"; private SettingsUtils SettingsUtils { get; set; } private GeneralSettings GeneralSettingsConfig { get; set; } private readonly ZoomItSettings _zoomItSettings; private Func<string, int> SendConfigMSG { get; } private Func<string, string, string, int, string> PickFileDialog { get; } private Func<LOGFONT, LOGFONT> PickFontDialog { get; } public ButtonClickCommand SelectDemoTypeFileCommand { get; set; } public ButtonClickCommand SelectBreakSoundFileCommand { get; set; } public ButtonClickCommand SelectBreakBackgroundFileCommand { get; set; } public ButtonClickCommand SelectWebcamBackgroundImageCommand { get; set; } public ButtonClickCommand SelectTypeFontCommand { get; set; } // These values should track what's in DemoType.h public int DemoTypeMaxTypingSpeed { get; } = 10; public int DemoTypeMinTypingSpeed { get; } = 100; public ObservableCollection<Tuple<string, string>> MicrophoneList { get; set; } = new ObservableCollection<Tuple<string, string>>(); public ObservableCollection<Tuple<string, string>> WebcamList { get; set; } = new ObservableCollection<Tuple<string, string>>(); private async void LoadMicrophoneList() { ResourceLoader resourceLoader = ResourceLoaderInstance.ResourceLoader; string recordDefaultMicrophone = resourceLoader.GetString("ZoomIt_Record_Microphones_Default_Name"); MicrophoneList.Add(new Tuple<string, string>(string.Empty, recordDefaultMicrophone)); var microphones = await DeviceInformation.FindAllAsync(DeviceClass.AudioCapture); foreach (var microphone in microphones) { MicrophoneList.Add(new Tuple<string, string>(microphone.Id, microphone.Name)); } // Normalize the stored device ID to match the casing from the system // enumeration so the case-sensitive ComboBox SelectedValue binding works. var storedMic = _zoomItSettings.Properties.MicrophoneDeviceId.Value; if (!string.IsNullOrEmpty(storedMic)) { foreach (var entry in MicrophoneList) { if (string.Equals(entry.Item1, storedMic, StringComparison.OrdinalIgnoreCase)) { if (entry.Item1 != storedMic) { _zoomItSettings.Properties.MicrophoneDeviceId.Value = entry.Item1; } break; } } } // Re-notify so the ComboBox re-resolves SelectedValue against the now-populated list. OnPropertyChanged(nameof(RecordMicrophoneDeviceId)); } private async void LoadWebcamList() { ResourceLoader resourceLoader = ResourceLoaderInstance.ResourceLoader; string defaultName = resourceLoader.GetString("ZoomIt_Record_WebcamDevices_Default_Name"); WebcamList.Add(new Tuple<string, string>(string.Empty, defaultName)); var webcams = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture); foreach (var webcam in webcams) { WebcamList.Add(new Tuple<string, string>(webcam.Id, webcam.Name)); } // Normalize the stored device ID to match the casing from the system // enumeration so the case-sensitive ComboBox SelectedValue binding works. var storedCam = _zoomItSettings.Properties.WebcamDeviceSymLink.Value; if (!string.IsNullOrEmpty(storedCam)) { foreach (var entry in WebcamList) { if (string.Equals(entry.Item1, storedCam, StringComparison.OrdinalIgnoreCase)) { if (entry.Item1 != storedCam) { _zoomItSettings.Properties.WebcamDeviceSymLink.Value = entry.Item1; } break; } } } // Re-notify so the ComboBox re-resolves SelectedValue against the now-populated list. OnPropertyChanged(nameof(WebcamDeviceSymLink)); } private static readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions { MaxDepth = 0, IncludeFields = true, }; public ZoomItViewModel(SettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc, Func<string, string, string, int, string> pickFileDialog, Func<LOGFONT, LOGFONT> pickFontDialog) { ArgumentNullException.ThrowIfNull(settingsUtils); SettingsUtils = settingsUtils; // To obtain the general settings configurations of PowerToys Settings. ArgumentNullException.ThrowIfNull(settingsRepository); GeneralSettingsConfig = settingsRepository.SettingsConfig; var zoomItSettings = global::PowerToys.ZoomItSettingsInterop.ZoomItSettings.LoadSettingsJson(); _zoomItSettings = JsonSerializer.Deserialize<ZoomItSettings>(zoomItSettings, _serializerOptions); InitializeEnabledValue(); // set the callback functions value to handle outgoing IPC message for the enabled value. SendConfigMSG = ipcMSGCallBackFunc; // set the callback for when we need the user to pick a file. PickFileDialog = pickFileDialog; // set the callback for when we need the user to pick a font. PickFontDialog = pickFontDialog; _typeFont = TypeFont; SelectDemoTypeFileCommand = new ButtonClickCommand(SelectDemoTypeFileAction); SelectBreakSoundFileCommand = new ButtonClickCommand(SelectBreakSoundFileAction); SelectBreakBackgroundFileCommand = new ButtonClickCommand(SelectBreakBackgroundFileAction); SelectWebcamBackgroundImageCommand = new ButtonClickCommand(SelectWebcamBackgroundImageAction); SelectTypeFontCommand = new ButtonClickCommand(SelectTypeFontAction); LoadMicrophoneList(); LoadWebcamList(); } private void InitializeEnabledValue() { _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredZoomItEnabledValue(); if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled) { // Get the enabled state from GPO. _enabledStateIsGPOConfigured = true; _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled; } else { _isEnabled = GeneralSettingsConfig.Enabled.ZoomIt; } } private void SendCustomAction(string actionName) { SendConfigMSG("{\"action\":{\"ZoomIt\":{\"action_name\":\"" + actionName + "\", \"value\":\"\"}}}"); } public bool IsEnabled { get => _isEnabled; set { if (_enabledStateIsGPOConfigured) { // If it's GPO configured, shouldn't be able to change this state. return; } if (value != _isEnabled) { _isEnabled = value; // Set the status in the general settings configuration GeneralSettingsConfig.Enabled.ZoomIt = value; OutGoingGeneralSettings snd = new OutGoingGeneralSettings(GeneralSettingsConfig); SendConfigMSG(snd.ToString()); OnPropertyChanged(nameof(IsEnabled)); } } } public bool IsEnabledGpoConfigured { get => _enabledStateIsGPOConfigured; } public bool ShowTrayIcon { get => _zoomItSettings.Properties.ShowTrayIcon.Value; set { if (_zoomItSettings.Properties.ShowTrayIcon.Value != value) { _zoomItSettings.Properties.ShowTrayIcon.Value = value; OnPropertyChanged(nameof(ShowTrayIcon)); NotifySettingsChanged(); } } } public HotkeySettings ZoomToggleKey { get => _zoomItSettings.Properties.ToggleKey.Value; set { if (_zoomItSettings.Properties.ToggleKey.Value != value) { _zoomItSettings.Properties.ToggleKey.Value = value ?? ZoomItProperties.DefaultToggleKey; OnPropertyChanged(nameof(ZoomToggleKey)); NotifySettingsChanged(); } } } public bool AnimateZoom { get => _zoomItSettings.Properties.AnimateZoom.Value; set { if (_zoomItSettings.Properties.AnimateZoom.Value != value) { _zoomItSettings.Properties.AnimateZoom.Value = value; OnPropertyChanged(nameof(AnimateZoom)); NotifySettingsChanged(); } } } public bool SmoothImage { get => _zoomItSettings.Properties.SmoothImage.Value; set { if (_zoomItSettings.Properties.SmoothImage.Value != value) { _zoomItSettings.Properties.SmoothImage.Value = value; OnPropertyChanged(nameof(SmoothImage)); NotifySettingsChanged(); } } } public bool SnipCopyToClipboard { get => _zoomItSettings.Properties.SnipCopyToClipboard.Value; set { if (_zoomItSettings.Properties.SnipCopyToClipboard.Value != value) { _zoomItSettings.Properties.SnipCopyToClipboard.Value = value; OnPropertyChanged(nameof(SnipCopyToClipboard)); NotifySettingsChanged(); } } } public int ZoominSliderLevel { get => _zoomItSettings.Properties.ZoominSliderLevel.Value; set { if (_zoomItSettings.Properties.ZoominSliderLevel.Value != value) { _zoomItSettings.Properties.ZoominSliderLevel.Value = value; OnPropertyChanged(nameof(ZoominSliderLevel)); NotifySettingsChanged(); } } } public HotkeySettings LiveZoomToggleKey { get => _zoomItSettings.Properties.LiveZoomToggleKey.Value; set { if (_zoomItSettings.Properties.LiveZoomToggleKey.Value != value) { _zoomItSettings.Properties.LiveZoomToggleKey.Value = value ?? ZoomItProperties.DefaultLiveZoomToggleKey; OnPropertyChanged(nameof(LiveZoomToggleKey)); OnPropertyChanged(nameof(LiveZoomToggleKeyDraw)); NotifySettingsChanged(); } } } public HotkeySettings LiveZoomToggleKeyDraw { get { var baseKey = _zoomItSettings.Properties.LiveZoomToggleKey.Value; if (baseKey == null) { return null; } // XOR with Shift: if Shift is present, remove it; if absent, add it return new HotkeySettings( baseKey.Win, baseKey.Ctrl, baseKey.Alt, !baseKey.Shift, // XOR with Shift baseKey.Code); } } public HotkeySettings DrawToggleKey { get => _zoomItSettings.Properties.DrawToggleKey.Value; set { if (_zoomItSettings.Properties.DrawToggleKey.Value != value) { _zoomItSettings.Properties.DrawToggleKey.Value = value ?? ZoomItProperties.DefaultDrawToggleKey; OnPropertyChanged(nameof(DrawToggleKey)); NotifySettingsChanged(); } } } public HotkeySettings RecordToggleKey { get => _zoomItSettings.Properties.RecordToggleKey.Value; set { if (_zoomItSettings.Properties.RecordToggleKey.Value != value) { _zoomItSettings.Properties.RecordToggleKey.Value = value ?? ZoomItProperties.DefaultRecordToggleKey; OnPropertyChanged(nameof(RecordToggleKey)); OnPropertyChanged(nameof(RecordToggleKeyCrop)); OnPropertyChanged(nameof(RecordToggleKeyWindow)); NotifySettingsChanged(); } } } public HotkeySettings RecordToggleKeyCrop { get { var baseKey = _zoomItSettings.Properties.RecordToggleKey.Value; if (baseKey == null) { return null; } // XOR with Shift: if Shift is present, remove it; if absent, add it. // If the result would have no modifier keys, return null to avoid displaying a bare-key shortcut label. if (baseKey.Shift && !baseKey.Win && !baseKey.Ctrl && !baseKey.Alt) { return null; } return new HotkeySettings( baseKey.Win, baseKey.Ctrl, baseKey.Alt, !baseKey.Shift, // XOR with Shift baseKey.Code); } } public HotkeySettings RecordToggleKeyWindow { get { var baseKey = _zoomItSettings.Properties.RecordToggleKey.Value; if (baseKey == null) { return null; } // XOR with Alt: if Alt is present, remove it; if absent, add it. // If the result would have no modifier keys, return null to avoid displaying a bare-key shortcut label. if (baseKey.Alt && !baseKey.Win && !baseKey.Ctrl && !baseKey.Shift) { return null; } return new HotkeySettings( baseKey.Win, baseKey.Ctrl, !baseKey.Alt, // XOR with Alt baseKey.Shift, baseKey.Code); } } public HotkeySettings MirrorToggleKey { get => _zoomItSettings.Properties.MirrorToggleKey.Value; set { if (_zoomItSettings.Properties.MirrorToggleKey.Value != value) { _zoomItSettings.Properties.MirrorToggleKey.Value = value ?? ZoomItProperties.DefaultMirrorToggleKey; OnPropertyChanged(nameof(MirrorToggleKey)); OnPropertyChanged(nameof(MirrorToggleKeyCrop)); OnPropertyChanged(nameof(MirrorToggleKeyWindow)); NotifySettingsChanged(); } } } public HotkeySettings MirrorToggleKeyCrop { get { var baseKey = _zoomItSettings.Properties.MirrorToggleKey.Value; if (baseKey == null) { return null; } // XOR with Shift: if Shift is present, remove it; if absent, add it. // If the result would have no modifier keys, return null to avoid displaying a bare-key shortcut label. if (baseKey.Shift && !baseKey.Win && !baseKey.Ctrl && !baseKey.Alt) { return null; } return new HotkeySettings( baseKey.Win, baseKey.Ctrl, baseKey.Alt, !baseKey.Shift, // XOR with Shift baseKey.Code); } } public HotkeySettings MirrorToggleKeyWindow { get { var baseKey = _zoomItSettings.Properties.MirrorToggleKey.Value; if (baseKey == null) { return null; } // XOR with Alt: if Alt is present, remove it; if absent, add it. // If the result would have no modifier keys, return null to avoid displaying a bare-key shortcut label. if (baseKey.Alt && !baseKey.Win && !baseKey.Ctrl && !baseKey.Shift) { return null; } return new HotkeySettings( baseKey.Win, baseKey.Ctrl, !baseKey.Alt, // XOR with Alt baseKey.Shift, baseKey.Code); } } public HotkeySettings SnipToggleKey { get => _zoomItSettings.Properties.SnipToggleKey.Value; set { if (_zoomItSettings.Properties.SnipToggleKey.Value != value) { _zoomItSettings.Properties.SnipToggleKey.Value = value ?? ZoomItProperties.DefaultSnipToggleKey; OnPropertyChanged(nameof(SnipToggleKey)); NotifySettingsChanged(); } } } public HotkeySettings SnipSaveToggleKey { get => _zoomItSettings.Properties.SnipSaveToggleKey.Value; set { if (_zoomItSettings.Properties.SnipSaveToggleKey.Value != value) { _zoomItSettings.Properties.SnipSaveToggleKey.Value = value ?? ZoomItProperties.DefaultSnipSaveToggleKey; OnPropertyChanged(nameof(SnipSaveToggleKey)); NotifySettingsChanged(); } } } public HotkeySettings SnipOcrToggleKey { get => _zoomItSettings.Properties.SnipOcrToggleKey.Value; set { if (_zoomItSettings.Properties.SnipOcrToggleKey.Value != value) { _zoomItSettings.Properties.SnipOcrToggleKey.Value = value ?? ZoomItProperties.DefaultSnipOcrToggleKey; OnPropertyChanged(nameof(SnipOcrToggleKey)); NotifySettingsChanged(); } } } public HotkeySettings SnipPanoramaToggleKey { get => _zoomItSettings.Properties.SnipPanoramaToggleKey.Value; set { if (_zoomItSettings.Properties.SnipPanoramaToggleKey.Value != value) { _zoomItSettings.Properties.SnipPanoramaToggleKey.Value = value ?? ZoomItProperties.DefaultSnipPanoramaToggleKey; OnPropertyChanged(nameof(SnipPanoramaToggleKey)); NotifySettingsChanged(); } } } public HotkeySettings SnipPanoramaSaveToggleKey { get => _zoomItSettings.Properties.SnipPanoramaSaveToggleKey.Value; set { if (_zoomItSettings.Properties.SnipPanoramaSaveToggleKey.Value != value) { _zoomItSettings.Properties.SnipPanoramaSaveToggleKey.Value = value ?? ZoomItProperties.DefaultSnipPanoramaSaveToggleKey; OnPropertyChanged(nameof(SnipPanoramaSaveToggleKey)); NotifySettingsChanged(); } } } public HotkeySettings BreakTimerKey { get => _zoomItSettings.Properties.BreakTimerKey.Value; set { if (_zoomItSettings.Properties.BreakTimerKey.Value != value) { _zoomItSettings.Properties.BreakTimerKey.Value = value ?? ZoomItProperties.DefaultBreakTimerKey; OnPropertyChanged(nameof(BreakTimerKey)); NotifySettingsChanged(); } } } public HotkeySettings DemoTypeToggleKey { get => _zoomItSettings.Properties.DemoTypeToggleKey.Value; set { if (_zoomItSettings.Properties.DemoTypeToggleKey.Value != value) { _zoomItSettings.Properties.DemoTypeToggleKey.Value = value ?? ZoomItProperties.DefaultDemoTypeToggleKey; OnPropertyChanged(nameof(DemoTypeToggleKey)); OnPropertyChanged(nameof(DemoTypeToggleKeyReset)); NotifySettingsChanged(); } } } public HotkeySettings DemoTypeToggleKeyReset { get { var baseKey = _zoomItSettings.Properties.DemoTypeToggleKey.Value; if (baseKey == null) { return null; } // XOR with Shift: if Shift is present, remove it; if absent, add it return new HotkeySettings( baseKey.Win, baseKey.Ctrl, baseKey.Alt, !baseKey.Shift, // XOR with Shift baseKey.Code); } } private LOGFONT _typeFont; public LOGFONT TypeFont { get { var encodedFont = _zoomItSettings.Properties.Font.Value; byte[] decodedFont = Convert.FromBase64String(encodedFont); int size = Marshal.SizeOf(typeof(LOGFONT)); if (size != decodedFont.Length) { throw new InvalidOperationException("Expected byte array from saved Settings doesn't match the LOGFONT structure size"); } // Allocate unmanaged memory to hold the byte array IntPtr ptr = Marshal.AllocHGlobal(size); try { // Copy the byte array into unmanaged memory Marshal.Copy(decodedFont, 0, ptr, size); // Marshal the unmanaged memory back to a LOGFONT structure return (LOGFONT)Marshal.PtrToStructure(ptr, typeof(LOGFONT)); } finally { // Free the unmanaged memory Marshal.FreeHGlobal(ptr); } } set { _typeFont = value; int size = Marshal.SizeOf(typeof(LOGFONT)); byte[] bytes = new byte[size]; // Allocate unmanaged memory for the LOGFONT structure IntPtr ptr = Marshal.AllocHGlobal(size); try { // Marshal the LOGFONT structure to the unmanaged memory Marshal.StructureToPtr(value, ptr, false); // Copy the unmanaged memory into the managed byte array Marshal.Copy(ptr, bytes, 0, size); } finally { // Free the unmanaged memory Marshal.FreeHGlobal(ptr); } _zoomItSettings.Properties.Font.Value = Convert.ToBase64String(bytes); OnPropertyChanged(nameof(DemoSampleFontFamily)); OnPropertyChanged(nameof(DemoSampleFontSize)); OnPropertyChanged(nameof(DemoSampleFontWeight)); OnPropertyChanged(nameof(DemoSampleFontStyle)); OnPropertyChanged(nameof(DemoSampleTextDecoration)); NotifySettingsChanged(); } } public FontFamily DemoSampleFontFamily { get { return new FontFamily(_typeFont.lfFaceName); } } public double DemoSampleFontSize { get { return _typeFont.lfHeight <= 0 ? 16 : _typeFont.lfHeight; // 16 is always the height we expect? } } public global::Windows.UI.Text.FontWeight DemoSampleFontWeight { get { if (_typeFont.lfWeight <= (int)FontWeight.FW_DONT_CARE) { return Microsoft.UI.Text.FontWeights.Normal; } else if (_typeFont.lfWeight <= (int)FontWeight.FW_THIN) { return Microsoft.UI.Text.FontWeights.Thin; } else if (_typeFont.lfWeight <= (int)FontWeight.FW_EXTRALIGHT) { return Microsoft.UI.Text.FontWeights.ExtraLight; } else if (_typeFont.lfWeight <= (int)FontWeight.FW_LIGHT) { return Microsoft.UI.Text.FontWeights.Light; } else if (_typeFont.lfWeight <= (int)FontWeight.FW_NORMAL) { return Microsoft.UI.Text.FontWeights.Normal; } else if (_typeFont.lfWeight <= (int)FontWeight.FW_MEDIUM) { return Microsoft.UI.Text.FontWeights.Medium; } else if (_typeFont.lfWeight <= (int)FontWeight.FW_SEMIBOLD) { return Microsoft.UI.Text.FontWeights.SemiBold; } else if (_typeFont.lfWeight <= (int)FontWeight.FW_BOLD) { return Microsoft.UI.Text.FontWeights.Bold; } else if (_typeFont.lfWeight <= (int)FontWeight.FW_EXTRABOLD) { return Microsoft.UI.Text.FontWeights.ExtraBold; } else { return Microsoft.UI.Text.FontWeights.Black; // FW_HEAVY } } } public global::Windows.UI.Text.FontStyle DemoSampleFontStyle { get => _typeFont.lfItalic != 0 ? global::Windows.UI.Text.FontStyle.Italic : global::Windows.UI.Text.FontStyle.Normal; } public global::Windows.UI.Text.TextDecorations DemoSampleTextDecoration { get => _typeFont.lfUnderline != 0 ? global::Windows.UI.Text.TextDecorations.Underline : global::Windows.UI.Text.TextDecorations.None; } public string DemoTypeFile { get => _zoomItSettings.Properties.DemoTypeFile.Value; set { if (_zoomItSettings.Properties.DemoTypeFile.Value != value) { _zoomItSettings.Properties.DemoTypeFile.Value = value; OnPropertyChanged(nameof(DemoTypeFile)); NotifySettingsChanged(); } } } public bool DemoTypeUserDrivenMode { get => _zoomItSettings.Properties.DemoTypeUserDrivenMode.Value; set { if (_zoomItSettings.Properties.DemoTypeUserDrivenMode.Value != value) { _zoomItSettings.Properties.DemoTypeUserDrivenMode.Value = value; OnPropertyChanged(nameof(DemoTypeUserDrivenMode)); NotifySettingsChanged(); } } } public int DemoTypeSpeedSlider { get => _zoomItSettings.Properties.DemoTypeSpeedSlider.Value; set { if (_zoomItSettings.Properties.DemoTypeSpeedSlider.Value != value) { _zoomItSettings.Properties.DemoTypeSpeedSlider.Value = value; OnPropertyChanged(nameof(DemoTypeSpeedSlider)); NotifySettingsChanged(); } } } public int BreakTimeout { get => _zoomItSettings.Properties.BreakTimeout.Value; set { if (_zoomItSettings.Properties.BreakTimeout.Value != value) { _zoomItSettings.Properties.BreakTimeout.Value = value; OnPropertyChanged(nameof(BreakTimeout)); NotifySettingsChanged(); } } } public bool BreakShowExpiredTime { get => _zoomItSettings.Properties.ShowExpiredTime.Value; set { if (_zoomItSettings.Properties.ShowExpiredTime.Value != value) { _zoomItSettings.Properties.ShowExpiredTime.Value = value; OnPropertyChanged(nameof(BreakShowExpiredTime)); NotifySettingsChanged(); } } } public bool BreakPlaySoundFile { get => _zoomItSettings.Properties.BreakPlaySoundFile.Value; set { if (_zoomItSettings.Properties.BreakPlaySoundFile.Value != value) { _zoomItSettings.Properties.BreakPlaySoundFile.Value = value; OnPropertyChanged(nameof(BreakPlaySoundFile)); NotifySettingsChanged(); } } } public string BreakSoundFile { get => _zoomItSettings.Properties.BreakSoundFile.Value; set { if (_zoomItSettings.Properties.BreakSoundFile.Value != value) { _zoomItSettings.Properties.BreakSoundFile.Value = value; OnPropertyChanged(nameof(BreakSoundFile)); NotifySettingsChanged(); } } } public double BreakTimerOpacity { get { return Math.Clamp(_zoomItSettings.Properties.BreakOpacity.Value, 1, 100); } set { int intValue = (int)value; if (_zoomItSettings.Properties.BreakOpacity.Value != intValue) { _zoomItSettings.Properties.BreakOpacity.Value = intValue; OnPropertyChanged(nameof(BreakTimerOpacity)); NotifySettingsChanged(); } } } public int BreakTimerPosition { get => _zoomItSettings.Properties.BreakTimerPosition.Value; set { if (_zoomItSettings.Properties.BreakTimerPosition.Value != value) { _zoomItSettings.Properties.BreakTimerPosition.Value = value; OnPropertyChanged(nameof(BreakTimerPosition)); NotifySettingsChanged(); } } } public bool BreakShowBackgroundFile { get => _zoomItSettings.Properties.BreakShowBackgroundFile.Value; set { if (_zoomItSettings.Properties.BreakShowBackgroundFile.Value != value) { _zoomItSettings.Properties.BreakShowBackgroundFile.Value = value; OnPropertyChanged(nameof(BreakShowBackgroundFile)); OnPropertyChanged(nameof(BreakBackgroundSelectionIndex)); NotifySettingsChanged(); } } } public bool BreakShowDesktop { get => _zoomItSettings.Properties.BreakShowDesktop.Value; set { if (_zoomItSettings.Properties.BreakShowDesktop.Value != value) { _zoomItSettings.Properties.BreakShowDesktop.Value = value; OnPropertyChanged(nameof(BreakShowDesktop)); OnPropertyChanged(nameof(BreakBackgroundSelectionIndex)); NotifySettingsChanged(); } } } public int BreakBackgroundSelectionIndex { get { if (!BreakShowBackgroundFile) { return 0; } return BreakShowDesktop ? 1 : 2; } set { int clampedValue = Math.Clamp(value, 0, 2); switch (clampedValue) { case 0: BreakShowBackgroundFile = false; break; case 1: if (!BreakShowBackgroundFile) { BreakShowBackgroundFile = true; } BreakShowDesktop = true; break; case 2: if (!BreakShowBackgroundFile) { BreakShowBackgroundFile = true; } BreakShowDesktop = false; break; default: break; } } } public string BreakBackgroundFile { get => _zoomItSettings.Properties.BreakBackgroundFile.Value; set { if (_zoomItSettings.Properties.BreakBackgroundFile.Value != value) { _zoomItSettings.Properties.BreakBackgroundFile.Value = value; OnPropertyChanged(nameof(BreakBackgroundFile)); NotifySettingsChanged(); } } } public bool BreakBackgroundStretch { get => _zoomItSettings.Properties.BreakBackgroundStretch.Value; set { if (_zoomItSettings.Properties.BreakBackgroundStretch.Value != value) { _zoomItSettings.Properties.BreakBackgroundStretch.Value = value; OnPropertyChanged(nameof(BreakBackgroundStretch)); NotifySettingsChanged(); } } } public bool BreakLockWorkstation { get => _zoomItSettings.Properties.BreakLockWorkstation.Value; set { if (_zoomItSettings.Properties.BreakLockWorkstation.Value != value) { _zoomItSettings.Properties.BreakLockWorkstation.Value = value; OnPropertyChanged(nameof(BreakLockWorkstation)); NotifySettingsChanged(); } } } public double RecordScaling { get { return Math.Clamp(_zoomItSettings.Properties.RecordScaling.Value / 100.0, 0.1, 1.0); } set { int newValue = (int)(value * 100); if (_zoomItSettings.Properties.RecordScaling.Value != newValue) { _zoomItSettings.Properties.RecordScaling.Value = newValue; OnPropertyChanged(nameof(RecordScaling)); NotifySettingsChanged(); } } } public int RecordFormatIndex { get { if (_zoomItSettings.Properties.RecordFormat.Value == FormatGif) { return 0; } if (_zoomItSettings.Properties.RecordFormat.Value == FormatMp4) { return 1; } return 0; } set { int format = 0; if (_zoomItSettings.Properties.RecordFormat.Value == FormatGif) { format = 0; } if (_zoomItSettings.Properties.RecordFormat.Value == FormatMp4) { format = 1; } if (format != value) { _zoomItSettings.Properties.RecordFormat.Value = value == 0 ? FormatGif : FormatMp4; OnPropertyChanged(nameof(RecordFormatIndex)); NotifySettingsChanged(); // Reload settings to get the new format's scaling value var reloadedSettings = global::PowerToys.ZoomItSettingsInterop.ZoomItSettings.LoadSettingsJson(); var reloaded = JsonSerializer.Deserialize<ZoomItSettings>(reloadedSettings, _serializerOptions); if (reloaded != null && reloaded.Properties != null) { _zoomItSettings.Properties.RecordScaling.Value = reloaded.Properties.RecordScaling.Value; OnPropertyChanged(nameof(RecordScaling)); } } } } public bool RecordCaptureSystemAudio { get => _zoomItSettings.Properties.CaptureSystemAudio.Value; set { if (_zoomItSettings.Properties.CaptureSystemAudio.Value != value) { _zoomItSettings.Properties.CaptureSystemAudio.Value = value; OnPropertyChanged(nameof(RecordCaptureSystemAudio)); NotifySettingsChanged(); } } } public bool RecordCaptureAudio { get => _zoomItSettings.Properties.CaptureAudio.Value; set { if (_zoomItSettings.Properties.CaptureAudio.Value != value) { _zoomItSettings.Properties.CaptureAudio.Value = value; OnPropertyChanged(nameof(RecordCaptureAudio)); NotifySettingsChanged(); } } } public bool RecordNoiseCancellation { get => _zoomItSettings.Properties.NoiseCancellation.Value; set { if (_zoomItSettings.Properties.NoiseCancellation.Value != value) { _zoomItSettings.Properties.NoiseCancellation.Value = value; OnPropertyChanged(nameof(RecordNoiseCancellation)); NotifySettingsChanged(); } } } public bool RecordMicMonoMix { get => _zoomItSettings.Properties.MicMonoMix.Value; set { if (_zoomItSettings.Properties.MicMonoMix.Value != value) { _zoomItSettings.Properties.MicMonoMix.Value = value; OnPropertyChanged(nameof(RecordMicMonoMix)); NotifySettingsChanged(); } } } public string RecordMicrophoneDeviceId { get => _zoomItSettings.Properties.MicrophoneDeviceId.Value ?? string.Empty; set { // Ignore null: the ComboBox sends null when SelectedValue can't be // matched (e.g. the async device list hasn't loaded yet). Accepting // null would overwrite the persisted device with empty string. if (value == null) { return; } if (_zoomItSettings.Properties.MicrophoneDeviceId.Value != value) { _zoomItSettings.Properties.MicrophoneDeviceId.Value = value; OnPropertyChanged(nameof(RecordMicrophoneDeviceId)); NotifySettingsChanged(); } } } public bool WebcamOverlay { get => _zoomItSettings.Properties.WebcamOverlay.Value; set { if (_zoomItSettings.Properties.WebcamOverlay.Value != value) { _zoomItSettings.Properties.WebcamOverlay.Value = value; OnPropertyChanged(nameof(WebcamOverlay)); NotifySettingsChanged(); } } } public string WebcamDeviceSymLink { get => _zoomItSettings.Properties.WebcamDeviceSymLink.Value ?? string.Empty; set { // Ignore null: the ComboBox sends null when SelectedValue can't be // matched (e.g. the async device list hasn't loaded yet). Accepting // null would overwrite the persisted device with empty string. if (value == null) { return; } if (_zoomItSettings.Properties.WebcamDeviceSymLink.Value != value) { _zoomItSettings.Properties.WebcamDeviceSymLink.Value = value; OnPropertyChanged(nameof(WebcamDeviceSymLink)); NotifySettingsChanged(); } } } public int WebcamPosition { get => _zoomItSettings.Properties.WebcamPosition.Value; set { if (_zoomItSettings.Properties.WebcamPosition.Value != value) { _zoomItSettings.Properties.WebcamPosition.Value = value; OnPropertyChanged(nameof(WebcamPosition)); NotifySettingsChanged(); } } } public int WebcamSize { get => _zoomItSettings.Properties.WebcamSize.Value; set { if (_zoomItSettings.Properties.WebcamSize.Value != value) { _zoomItSettings.Properties.WebcamSize.Value = value; OnPropertyChanged(nameof(WebcamSize)); NotifySettingsChanged(); } } } public int WebcamShape { get => _zoomItSettings.Properties.WebcamShape.Value; set { if (_zoomItSettings.Properties.WebcamShape.Value != value) { _zoomItSettings.Properties.WebcamShape.Value = value; OnPropertyChanged(nameof(WebcamShape)); NotifySettingsChanged(); } } } public int WebcamBackgroundMode { get => _zoomItSettings.Properties.WebcamBackgroundMode.Value; set { if (_zoomItSettings.Properties.WebcamBackgroundMode.Value != value) { _zoomItSettings.Properties.WebcamBackgroundMode.Value = value; OnPropertyChanged(nameof(WebcamBackgroundMode)); OnPropertyChanged(nameof(WebcamBackgroundIsImage)); NotifySettingsChanged(); } } } public bool WebcamBackgroundIsImage => _zoomItSettings.Properties.WebcamBackgroundMode.Value == 2; public string WebcamBackgroundImage { get => _zoomItSettings.Properties.WebcamBackgroundImage.Value ?? string.Empty; set { if (_zoomItSettings.Properties.WebcamBackgroundImage.Value != value) { _zoomItSettings.Properties.WebcamBackgroundImage.Value = value; OnPropertyChanged(nameof(WebcamBackgroundImage)); NotifySettingsChanged(); } } } public int WebcamBrightness { get => _zoomItSettings.Properties.WebcamBrightness.Value; set { if (_zoomItSettings.Properties.WebcamBrightness.Value != value) { _zoomItSettings.Properties.WebcamBrightness.Value = value; OnPropertyChanged(nameof(WebcamBrightness)); NotifySettingsChanged(); } } } public bool RecordAspectRatio { get => _zoomItSettings.Properties.RecordAspectRatio.Value; set { if (_zoomItSettings.Properties.RecordAspectRatio.Value != value) { _zoomItSettings.Properties.RecordAspectRatio.Value = value; OnPropertyChanged(nameof(RecordAspectRatio)); NotifySettingsChanged(); } } } public bool MirrorTrackWindow { get => _zoomItSettings.Properties.MirrorTrackWindow.Value; set { if (_zoomItSettings.Properties.MirrorTrackWindow.Value != value) { _zoomItSettings.Properties.MirrorTrackWindow.Value = value; OnPropertyChanged(nameof(MirrorTrackWindow)); NotifySettingsChanged(); } } } private void NotifySettingsChanged() { global::PowerToys.ZoomItSettingsInterop.ZoomItSettings.SaveSettingsJson( JsonSerializer.Serialize(_zoomItSettings)); SendCustomAction("refresh_settings"); } private void SelectDemoTypeFileAction() { try { ResourceLoader resourceLoader = ResourceLoaderInstance.ResourceLoader; string title = resourceLoader.GetString("ZoomIt_DemoType_File_Picker_Dialog_Title"); string allFilesFilter = resourceLoader.GetString("FilePicker_AllFilesFilter"); string pickedFile = PickFileDialog($"{allFilesFilter}\0*.*\0\0", title, null, 0); if (pickedFile != null) { DemoTypeFile = pickedFile; } } catch (Exception ex) { Logger.LogError("Error picking Demo Type file.", ex); } } private void SelectBreakSoundFileAction() { try { ResourceLoader resourceLoader = ResourceLoaderInstance.ResourceLoader; string title = resourceLoader.GetString("ZoomIt_Break_SoundFile_Picker_Dialog_Title"); string soundFilesFilter = resourceLoader.GetString("FilePicker_ZoomIt_SoundsFilter"); string allFilesFilter = resourceLoader.GetString("FilePicker_AllFilesFilter"); string initialDirectory = Environment.ExpandEnvironmentVariables("%WINDIR%\\Media"); string pickedFile = PickFileDialog($"{soundFilesFilter}\0*.wav\0{allFilesFilter}\0*.*\0\0", title, initialDirectory, 0); if (pickedFile != null) { BreakSoundFile = pickedFile; } } catch (Exception ex) { Logger.LogError("Error picking Break Sound file.", ex); } } private void SelectBreakBackgroundFileAction() { try { ResourceLoader resourceLoader = ResourceLoaderInstance.ResourceLoader; string title = resourceLoader.GetString("ZoomIt_Break_BackgroundFile_Picker_Dialog_Title"); string bitmapFilesFilter = resourceLoader.GetString("FilePicker_ZoomIt_BitmapFilesFilter"); string allPictureFilesFilter = resourceLoader.GetString("FilePicker_ZoomIt_AllPicturesFilter"); string allFilesFilter = resourceLoader.GetString("FilePicker_AllFilesFilter"); string initialDirectory = Environment.ExpandEnvironmentVariables("%USERPROFILE%\\Pictures"); string pickedFile = PickFileDialog($"{bitmapFilesFilter} (*.bmp;*.dib)\0*.bmp;*.dib\0PNG (*.png)\0*.png\0JPEG (*.jpg;*.jpeg;*.jpe;*.jfif)\0*.jpg;*.jpeg;*.jpe;*.jfif\0GIF (*.gif)\0*.gif\0{allPictureFilesFilter}\0*.bmp;*.dib;*.png;*.jpg;*.jpeg;*.jpe;*.jfif;*.gif\0{allFilesFilter}\0*.*\0\0", title, initialDirectory, 5); if (pickedFile != null) { BreakBackgroundFile = pickedFile; } } catch (Exception ex) { Logger.LogError("Error picking Break Background file.", ex); } } private void SelectWebcamBackgroundImageAction() { try { ResourceLoader resourceLoader = ResourceLoaderInstance.ResourceLoader; string title = resourceLoader.GetString("ZoomIt_Record_WebcamBackgroundImage_Picker_Dialog_Title"); string bitmapFilesFilter = resourceLoader.GetString("FilePicker_ZoomIt_BitmapFilesFilter"); string allPictureFilesFilter = resourceLoader.GetString("FilePicker_ZoomIt_AllPicturesFilter"); string allFilesFilter = resourceLoader.GetString("FilePicker_AllFilesFilter"); string initialDirectory = Environment.ExpandEnvironmentVariables("%USERPROFILE%\\Pictures"); string pickedFile = PickFileDialog($"{bitmapFilesFilter} (*.bmp;*.dib)\0*.bmp;*.dib\0PNG (*.png)\0*.png\0JPEG (*.jpg;*.jpeg;*.jpe;*.jfif)\0*.jpg;*.jpeg;*.jpe;*.jfif\0GIF (*.gif)\0*.gif\0{allPictureFilesFilter}\0*.bmp;*.dib;*.png;*.jpg;*.jpeg;*.jpe;*.jfif;*.gif\0{allFilesFilter}\0*.*\0\0", title, initialDirectory, 5); if (pickedFile != null) { WebcamBackgroundImage = pickedFile; } } catch (Exception ex) { Logger.LogError("Error picking Webcam Background image.", ex); } } private void SelectTypeFontAction() { try { LOGFONT result = PickFontDialog(_typeFont); if (result != null) { TypeFont = result; } } catch (Exception ex) { Logger.LogError("Error picking Type font.", ex); } } public void RefreshEnabledState() { InitializeEnabledValue(); OnPropertyChanged(nameof(IsEnabled)); } private GpoRuleConfigured _enabledGpoRuleConfiguration; private bool _enabledStateIsGPOConfigured; private bool _isEnabled; } }