mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-04 02:06:36 +02:00
* Upgraded projects to target .NET 8 * Updated .NET runtime package targets to use latest .NET 8 build * Updated PowerToys Interop to target .NET 8 * Switch to use ArgumentNullException.ThrowIfNull * ArgumentNullException.ThrowIfNull for CropAndLockViewModel * Switching to ObjectDisposedException.ThrowIf * Upgrade System.ComponentModel.Composition to 8.0 * ArgumentNullException.ThrowIfNull in Helper * Switch to StartsWith using StringComparison.Ordinal * Disabled CA1859, CA1716, SYSLIB1096 analyzers * Update RIDs to reflect breaking changes in .NET 8 * Updated Microsoft NuGet packages to RC1 * Updated Analyzer package to latest .NET 8 preview package * CA1854: Use TryGetValue instead of ContainsKey * [Build] Update TFM to .NET 8 for publish profiles * [Analyzers] Remove CA1309, CA1860-CA1865, CA1869, CA2208 from warning. * [Analyzers] Fix for C26495 * [Analyzers] Disable CS1615, CS9191 * [CI] Target .NET 8 in YAML * [CI] Add .NET preview version flag temporarily. * [FileLocksmith] Update TFM to .NET 8 * [CI] Switch to preview agent * [CI] Update NOTICE.md * [CI] Update Release to target .NET 8 and use Preview agent * [Analyzers] Disable CA1854 * Fix typo * Updated Microsoft.CodeAnalysis.NetAnalyzers to latest preview Updated packages to rc2 * [Analyzers][CPP] Turn off warning for 5271 * [Analyzers][CPP] Turn off warning for 26493 * [KeyboardListener] Add mutex include to resolve error * [PT Run][Folder] Use static SearchValues to resolve CA1870 * [PowerLauncher] Fix TryGetValue * [MouseJumpSettings] Use ArgumentNullException.ThrowIfNull * [Build] Disable parallel dotnet tool restore * [Build] No cache of dotnet tool packages * [Build] Temporarily move .NET 8 SDK task before XAML formatting * [Build][Temp] Try using .NET 7 prior to XAML formatting and then switch to .NET 8 after * [Build] Use .NET 6 for XAML Styler * [CI] Updated NOTICE.md * [FancyZones] Update TFM to .NET 8 * [EnvVar] Update TFM to .NET 8 and update RID * [EnvVar] Use ArgumentNullException.ThrowIfNull * [Dev] Updated packages to .NET 8 RTM version * [Dev] Updated Microsoft.CodeAnalysis.NetAnalyzers to latest * [CI] Updated NOTICE.md with latest package versions * Fix new utility target fameworks and runtimeids * Don't use preview images anymore * [CI] Add script to update VCToolsVersion environment variable * [CI] Add Step to Verify VCToolsVersion * [CI] Use latest flag for vswhere to set proper VCToolsVersion * Add VCToolsVersion checking to release.yml * Remove net publishing from local/ PR CI builds * Revert "Remove net publishing from local/ PR CI builds" This reverts commitf469778996. * Only publish necessary projects * Add verbosity to release pipelines builds of PowerTOys * Set VCToolsVersion for publish.cmd when called from installer * [Installer] Moved project publish logic to MSBuild Task * [CI] Revert using publish.cmd * [CI] Set VCToolsVersion and unset ClearDevCommandPromptEnvVars property * Installer publishes for x64 too * Revert "Add verbosity to release pipelines builds of PowerTOys" This reverts commit654d4a7f78. * [Dev] Update CodeAnalysis library to non-preview package * Remove unneeded warning removal * Fix Notice.md * Rename VCToolsVersion file and task name * Remove unneeded mutex header include --------- Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
585 lines
19 KiB
C#
585 lines
19 KiB
C#
// 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.Generic;
|
|
using System.Globalization;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text.Json;
|
|
using System.Threading.Tasks;
|
|
using global::PowerToys.GPOWrapper;
|
|
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;
|
|
|
|
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|
{
|
|
public class VideoConferenceViewModel : Observable
|
|
{
|
|
private readonly ISettingsUtils _settingsUtils;
|
|
|
|
private VideoConferenceSettings Settings { get; set; }
|
|
|
|
private GeneralSettings GeneralSettingsConfig { get; set; }
|
|
|
|
private const string ModuleName = "Video Conference";
|
|
|
|
private Func<string, int> SendConfigMSG { get; }
|
|
|
|
private Func<string> PickFileDialog { get; }
|
|
|
|
private string _settingsConfigFileFolder = string.Empty;
|
|
|
|
public VideoConferenceViewModel(
|
|
ISettingsUtils settingsUtils,
|
|
ISettingsRepository<GeneralSettings> settingsRepository,
|
|
ISettingsRepository<VideoConferenceSettings> videoConferenceSettingsRepository,
|
|
Func<string, int> ipcMSGCallBackFunc,
|
|
Func<string> pickFileDialog,
|
|
string configFileSubfolder = "")
|
|
{
|
|
PickFileDialog = pickFileDialog;
|
|
|
|
ArgumentNullException.ThrowIfNull(settingsRepository);
|
|
|
|
GeneralSettingsConfig = settingsRepository.SettingsConfig;
|
|
|
|
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
|
|
|
|
SendConfigMSG = ipcMSGCallBackFunc;
|
|
|
|
_settingsConfigFileFolder = configFileSubfolder;
|
|
|
|
ArgumentNullException.ThrowIfNull(videoConferenceSettingsRepository);
|
|
|
|
Settings = videoConferenceSettingsRepository.SettingsConfig;
|
|
|
|
CameraNames = interop.CommonManaged.GetAllVideoCaptureDeviceNames();
|
|
MicrophoneNames = interop.CommonManaged.GetAllActiveMicrophoneDeviceNames();
|
|
MicrophoneNames.Insert(0, "[All]");
|
|
|
|
var shouldSaveSettings = false;
|
|
|
|
if (string.IsNullOrEmpty(Settings.Properties.SelectedCamera.Value) && CameraNames.Count != 0)
|
|
{
|
|
_selectedCameraIndex = 0;
|
|
Settings.Properties.SelectedCamera.Value = CameraNames[0];
|
|
shouldSaveSettings = true;
|
|
}
|
|
else
|
|
{
|
|
_selectedCameraIndex = CameraNames.FindIndex(name => name == Settings.Properties.SelectedCamera.Value);
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(Settings.Properties.SelectedMicrophone.Value))
|
|
{
|
|
_selectedMicrophoneIndex = 0;
|
|
Settings.Properties.SelectedMicrophone.Value = MicrophoneNames[0];
|
|
shouldSaveSettings = true;
|
|
}
|
|
else
|
|
{
|
|
_selectedMicrophoneIndex = MicrophoneNames.FindIndex(name => name == Settings.Properties.SelectedMicrophone.Value);
|
|
}
|
|
|
|
InitializeEnabledValue();
|
|
|
|
_cameraAndMicrophoneMuteHotkey = Settings.Properties.MuteCameraAndMicrophoneHotkey.Value;
|
|
_microphoneMuteHotkey = Settings.Properties.MuteMicrophoneHotkey.Value;
|
|
_microphonePushToTalkHotkey = Settings.Properties.PushToTalkMicrophoneHotkey.Value;
|
|
_pushToReverseEnabled = Settings.Properties.PushToReverseEnabled.Value;
|
|
_cameraMuteHotkey = Settings.Properties.MuteCameraHotkey.Value;
|
|
CameraImageOverlayPath = Settings.Properties.CameraOverlayImagePath.Value;
|
|
SelectOverlayImage = new ButtonClickCommand(SelectOverlayImageAction);
|
|
ClearOverlayImage = new ButtonClickCommand(ClearOverlayImageAction);
|
|
|
|
switch (Settings.Properties.ToolbarPosition.Value)
|
|
{
|
|
case "Top left corner":
|
|
_toolbarPositionIndex = 0;
|
|
break;
|
|
case "Top center":
|
|
_toolbarPositionIndex = 1;
|
|
break;
|
|
case "Top right corner":
|
|
_toolbarPositionIndex = 2;
|
|
break;
|
|
case "Bottom left corner":
|
|
_toolbarPositionIndex = 3;
|
|
break;
|
|
case "Bottom center":
|
|
_toolbarPositionIndex = 4;
|
|
break;
|
|
case "Bottom right corner":
|
|
_toolbarPositionIndex = 5;
|
|
break;
|
|
}
|
|
|
|
switch (Settings.Properties.ToolbarMonitor.Value)
|
|
{
|
|
case "Main monitor":
|
|
_toolbarMonitorIndex = 0;
|
|
break;
|
|
|
|
case "All monitors":
|
|
_toolbarMonitorIndex = 1;
|
|
break;
|
|
}
|
|
|
|
switch (Settings.Properties.ToolbarHide.Value)
|
|
{
|
|
case "Never":
|
|
_toolbarHideIndex = 0;
|
|
break;
|
|
case "When both camera and microphone are unmuted":
|
|
_toolbarHideIndex = 1;
|
|
break;
|
|
case "When both camera and microphone are muted":
|
|
_toolbarHideIndex = 2;
|
|
break;
|
|
case "After timeout":
|
|
_toolbarHideIndex = 3;
|
|
break;
|
|
}
|
|
|
|
switch (Settings.Properties.StartupAction.Value)
|
|
{
|
|
case "Nothing":
|
|
_startupActionIndex = 0;
|
|
break;
|
|
case "Unmute":
|
|
_startupActionIndex = 1;
|
|
break;
|
|
case "Mute":
|
|
_startupActionIndex = 2;
|
|
break;
|
|
}
|
|
|
|
if (shouldSaveSettings)
|
|
{
|
|
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
|
|
}
|
|
}
|
|
|
|
private void InitializeEnabledValue()
|
|
{
|
|
_enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredVideoConferenceMuteEnabledValue();
|
|
if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
|
|
{
|
|
// Get the enabled state from GPO.
|
|
_enabledStateIsGPOConfigured = true;
|
|
_isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
|
|
}
|
|
else
|
|
{
|
|
_isEnabled = GeneralSettingsConfig.Enabled.VideoConference;
|
|
}
|
|
}
|
|
|
|
private GpoRuleConfigured _enabledGpoRuleConfiguration;
|
|
private bool _enabledStateIsGPOConfigured;
|
|
private bool _isEnabled;
|
|
private int _toolbarPositionIndex;
|
|
private int _toolbarMonitorIndex;
|
|
private int _toolbarHideIndex;
|
|
private int _startupActionIndex;
|
|
private HotkeySettings _cameraAndMicrophoneMuteHotkey;
|
|
private HotkeySettings _microphoneMuteHotkey;
|
|
private HotkeySettings _microphonePushToTalkHotkey;
|
|
private HotkeySettings _cameraMuteHotkey;
|
|
private bool _pushToReverseEnabled;
|
|
private int _selectedCameraIndex = -1;
|
|
private int _selectedMicrophoneIndex;
|
|
|
|
public List<string> CameraNames { get; }
|
|
|
|
public List<string> MicrophoneNames { get; }
|
|
|
|
public string CameraImageOverlayPath { get; set; }
|
|
|
|
public ButtonClickCommand SelectOverlayImage { get; set; }
|
|
|
|
public ButtonClickCommand ClearOverlayImage { get; set; }
|
|
|
|
private void ClearOverlayImageAction()
|
|
{
|
|
CameraImageOverlayPath = string.Empty;
|
|
Settings.Properties.CameraOverlayImagePath = string.Empty;
|
|
RaisePropertyChanged(nameof(CameraImageOverlayPath));
|
|
}
|
|
|
|
private void SelectOverlayImageAction()
|
|
{
|
|
try
|
|
{
|
|
string pickedImage = PickFileDialog();
|
|
if (pickedImage != null)
|
|
{
|
|
CameraImageOverlayPath = pickedImage;
|
|
Settings.Properties.CameraOverlayImagePath = pickedImage;
|
|
RaisePropertyChanged(nameof(CameraImageOverlayPath));
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
public int SelectedCameraIndex
|
|
{
|
|
get
|
|
{
|
|
return _selectedCameraIndex;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_selectedCameraIndex != value)
|
|
{
|
|
_selectedCameraIndex = value;
|
|
if (_selectedCameraIndex >= 0 && _selectedCameraIndex < CameraNames.Count)
|
|
{
|
|
Settings.Properties.SelectedCamera.Value = CameraNames[_selectedCameraIndex];
|
|
RaisePropertyChanged();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public int SelectedMicrophoneIndex
|
|
{
|
|
get
|
|
{
|
|
return _selectedMicrophoneIndex;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_selectedMicrophoneIndex != value)
|
|
{
|
|
_selectedMicrophoneIndex = value;
|
|
if (_selectedMicrophoneIndex >= 0 && _selectedMicrophoneIndex < MicrophoneNames.Count)
|
|
{
|
|
Settings.Properties.SelectedMicrophone.Value = MicrophoneNames[_selectedMicrophoneIndex];
|
|
RaisePropertyChanged();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsEnabled
|
|
{
|
|
get
|
|
{
|
|
return _isEnabled;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_enabledStateIsGPOConfigured)
|
|
{
|
|
// If it's GPO configured, shouldn't be able to change this state.
|
|
return;
|
|
}
|
|
|
|
if (value != _isEnabled)
|
|
{
|
|
_isEnabled = value;
|
|
GeneralSettingsConfig.Enabled.VideoConference = value;
|
|
OutGoingGeneralSettings snd = new OutGoingGeneralSettings(GeneralSettingsConfig);
|
|
|
|
SendConfigMSG(snd.ToString());
|
|
OnPropertyChanged(nameof(IsEnabled));
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsEnabledGpoConfigured
|
|
{
|
|
get => _enabledStateIsGPOConfigured;
|
|
}
|
|
|
|
public bool CanUserChangeEnabledState
|
|
{
|
|
get
|
|
{
|
|
return IsElevated && !IsEnabledGpoConfigured;
|
|
}
|
|
}
|
|
|
|
public bool IsElevated
|
|
{
|
|
get
|
|
{
|
|
return GeneralSettingsConfig.IsElevated;
|
|
}
|
|
}
|
|
|
|
public HotkeySettings CameraAndMicrophoneMuteHotkey
|
|
{
|
|
get
|
|
{
|
|
return _cameraAndMicrophoneMuteHotkey;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value != _cameraAndMicrophoneMuteHotkey)
|
|
{
|
|
var hotkey = value ?? Settings.Properties.DefaultMuteCameraAndMicrophoneHotkey;
|
|
_cameraAndMicrophoneMuteHotkey = hotkey;
|
|
Settings.Properties.MuteCameraAndMicrophoneHotkey.Value = hotkey;
|
|
RaisePropertyChanged(nameof(CameraAndMicrophoneMuteHotkey));
|
|
}
|
|
}
|
|
}
|
|
|
|
public HotkeySettings MicrophoneMuteHotkey
|
|
{
|
|
get
|
|
{
|
|
return _microphoneMuteHotkey;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value != _microphoneMuteHotkey)
|
|
{
|
|
var hotkey = value ?? Settings.Properties.DefaultMuteMicrophoneHotkey;
|
|
_microphoneMuteHotkey = hotkey;
|
|
Settings.Properties.MuteMicrophoneHotkey.Value = hotkey;
|
|
RaisePropertyChanged(nameof(MicrophoneMuteHotkey));
|
|
}
|
|
}
|
|
}
|
|
|
|
public HotkeySettings MicrophonePushToTalkHotkey
|
|
{
|
|
get
|
|
{
|
|
return _microphonePushToTalkHotkey;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value != _microphonePushToTalkHotkey)
|
|
{
|
|
var hotkey = value ?? Settings.Properties.DefaultMuteMicrophoneHotkey;
|
|
_microphonePushToTalkHotkey = hotkey;
|
|
Settings.Properties.PushToTalkMicrophoneHotkey.Value = hotkey;
|
|
RaisePropertyChanged(nameof(MicrophonePushToTalkHotkey));
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool PushToReverseEnabled
|
|
{
|
|
get
|
|
{
|
|
return _pushToReverseEnabled;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value != _pushToReverseEnabled)
|
|
{
|
|
_pushToReverseEnabled = value;
|
|
Settings.Properties.PushToReverseEnabled.Value = value;
|
|
RaisePropertyChanged(nameof(PushToReverseEnabled));
|
|
}
|
|
}
|
|
}
|
|
|
|
public HotkeySettings CameraMuteHotkey
|
|
{
|
|
get
|
|
{
|
|
return _cameraMuteHotkey;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value != _cameraMuteHotkey)
|
|
{
|
|
var hotkey = value ?? Settings.Properties.DefaultMuteCameraHotkey;
|
|
_cameraMuteHotkey = hotkey;
|
|
Settings.Properties.MuteCameraHotkey.Value = hotkey;
|
|
RaisePropertyChanged(nameof(CameraMuteHotkey));
|
|
}
|
|
}
|
|
}
|
|
|
|
public int ToolbarPositionIndex
|
|
{
|
|
get
|
|
{
|
|
return _toolbarPositionIndex;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_toolbarPositionIndex != value)
|
|
{
|
|
_toolbarPositionIndex = value;
|
|
switch (_toolbarPositionIndex)
|
|
{
|
|
case 0:
|
|
Settings.Properties.ToolbarPosition.Value = "Top left corner";
|
|
break;
|
|
|
|
case 1:
|
|
Settings.Properties.ToolbarPosition.Value = "Top center";
|
|
break;
|
|
|
|
case 2:
|
|
Settings.Properties.ToolbarPosition.Value = "Top right corner";
|
|
break;
|
|
|
|
case 3:
|
|
Settings.Properties.ToolbarPosition.Value = "Bottom left corner";
|
|
break;
|
|
|
|
case 4:
|
|
Settings.Properties.ToolbarPosition.Value = "Bottom center";
|
|
break;
|
|
|
|
case 5:
|
|
Settings.Properties.ToolbarPosition.Value = "Bottom right corner";
|
|
break;
|
|
}
|
|
|
|
RaisePropertyChanged(nameof(ToolbarPositionIndex));
|
|
}
|
|
}
|
|
}
|
|
|
|
public int ToolbarMonitorIndex
|
|
{
|
|
get
|
|
{
|
|
return _toolbarMonitorIndex;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_toolbarMonitorIndex != value)
|
|
{
|
|
_toolbarMonitorIndex = value;
|
|
switch (_toolbarMonitorIndex)
|
|
{
|
|
case 0:
|
|
Settings.Properties.ToolbarMonitor.Value = "Main monitor";
|
|
break;
|
|
|
|
case 1:
|
|
Settings.Properties.ToolbarMonitor.Value = "All monitors";
|
|
break;
|
|
}
|
|
|
|
RaisePropertyChanged(nameof(ToolbarMonitorIndex));
|
|
}
|
|
}
|
|
}
|
|
|
|
public int ToolbarHideIndex
|
|
{
|
|
get
|
|
{
|
|
return _toolbarHideIndex;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value != _toolbarHideIndex)
|
|
{
|
|
_toolbarHideIndex = value;
|
|
switch (_toolbarHideIndex)
|
|
{
|
|
case 0:
|
|
Settings.Properties.ToolbarHide.Value = "Never";
|
|
break;
|
|
case 1:
|
|
Settings.Properties.ToolbarHide.Value = "When both camera and microphone are unmuted";
|
|
break;
|
|
case 2:
|
|
Settings.Properties.ToolbarHide.Value = "When both camera and microphone are muted";
|
|
break;
|
|
case 3:
|
|
Settings.Properties.ToolbarHide.Value = "After timeout";
|
|
break;
|
|
}
|
|
|
|
RaisePropertyChanged(nameof(ToolbarHideIndex));
|
|
}
|
|
}
|
|
}
|
|
|
|
public int StartupActionIndex
|
|
{
|
|
get
|
|
{
|
|
return _startupActionIndex;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value != _startupActionIndex)
|
|
{
|
|
_startupActionIndex = value;
|
|
switch (_startupActionIndex)
|
|
{
|
|
case 0:
|
|
Settings.Properties.StartupAction.Value = "Nothing";
|
|
break;
|
|
case 1:
|
|
Settings.Properties.StartupAction.Value = "Unmute";
|
|
break;
|
|
case 2:
|
|
Settings.Properties.StartupAction.Value = "Mute";
|
|
break;
|
|
}
|
|
|
|
RaisePropertyChanged(nameof(_startupActionIndex));
|
|
}
|
|
}
|
|
}
|
|
|
|
public string GetSettingsSubPath()
|
|
{
|
|
return _settingsConfigFileFolder + (string.IsNullOrEmpty(_settingsConfigFileFolder) ? string.Empty : "\\") + ModuleName;
|
|
}
|
|
|
|
public void RaisePropertyChanged([CallerMemberName] string propertyName = null)
|
|
{
|
|
OnPropertyChanged(propertyName);
|
|
|
|
_settingsUtils.SaveSettings(Settings.ToJsonString(), GetSettingsSubPath());
|
|
|
|
SendConfigMSG(
|
|
string.Format(
|
|
CultureInfo.InvariantCulture,
|
|
"{{ \"powertoys\": {{ \"{0}\": {1} }} }}",
|
|
ModuleName,
|
|
JsonSerializer.Serialize(Settings)));
|
|
}
|
|
|
|
public void RefreshEnabledState()
|
|
{
|
|
InitializeEnabledValue();
|
|
OnPropertyChanged(nameof(IsEnabled));
|
|
}
|
|
}
|
|
|
|
[ComImport]
|
|
[Guid("3E68D4BD-7135-4D10-8018-9FB6D9F33FA1")]
|
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
public interface IInitializeWithWindow
|
|
{
|
|
void Initialize(IntPtr hwnd);
|
|
}
|
|
}
|