Full Code of File-New-Project/EarTrumpet for AI

master b6ad9a786d28 cached
424 files
2.0 MB
552.2k tokens
1439 symbols
1 requests
Download .txt
Showing preview only (2,200K chars total). Download the full file or copy to clipboard to get everything.
Repository: File-New-Project/EarTrumpet
Branch: master
Commit: b6ad9a786d28
Files: 424
Total size: 2.0 MB

Directory structure:
gitextract_y35wddg7/

├── .azure-pipelines.yml
├── .chocolatey/
│   ├── eartrumpet.nuspec
│   └── tools/
│       ├── LICENSE.txt
│       ├── VERIFICATION.txt
│       ├── chocolateybeforemodify.ps1
│       ├── chocolateyinstall.ps1
│       └── chocolateyuninstall.ps1
├── .gitattributes
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yml
│   │   └── config.yml
│   └── workflows/
│       ├── main.yml
│       ├── sponsors.yml
│       └── translators.yml
├── .gitignore
├── CHANGELOG.md
├── COMPILING.md
├── CONTRIBUTING.md
├── EarTrumpet/
│   ├── Addons/
│   │   └── EarTrumpet.Actions/
│   │       ├── AddonResources.xaml
│   │       ├── Controls/
│   │       │   ├── LinkedTextBlock.cs
│   │       │   └── MenuButton.cs
│   │       ├── DataModel/
│   │       │   ├── Enum/
│   │       │   │   ├── AudioAppEventKind.cs
│   │       │   │   ├── AudioDeviceEventKind.cs
│   │       │   │   ├── BoolValue.cs
│   │       │   │   ├── ComparisonBoolKind.cs
│   │       │   │   ├── EarTrumpetEventKind.cs
│   │       │   │   ├── MuteKind.cs
│   │       │   │   ├── ProcessEventKind.cs
│   │       │   │   ├── ProcessStateKind.cs
│   │       │   │   └── SetVolumeKind.cs
│   │       │   ├── IPartWithApp.cs
│   │       │   ├── IPartWithDevice.cs
│   │       │   ├── IPartWithText.cs
│   │       │   ├── IPartWithVolume.cs
│   │       │   ├── LocalVariablesContainer.cs
│   │       │   ├── Part.cs
│   │       │   ├── ProcessWatcher.cs
│   │       │   ├── Processing/
│   │       │   │   ├── ActionProcessor.cs
│   │       │   │   ├── AudioTriggerManager.cs
│   │       │   │   ├── ConditionProcessor.cs
│   │       │   │   └── TriggerManager.cs
│   │       │   └── Serialization/
│   │       │       ├── Actions.cs
│   │       │       ├── App.cs
│   │       │       ├── Conditions.cs
│   │       │       ├── Device.cs
│   │       │       ├── EarTrumpetAction.cs
│   │       │       └── Triggers.cs
│   │       ├── EarTrumpetActionsAddon.cs
│   │       ├── Interop/
│   │       │   ├── Helpers/
│   │       │   │   └── WindowWatcher.cs
│   │       │   └── User32.cs
│   │       └── ViewModel/
│   │           ├── Actions/
│   │           │   ├── SetAppMuteActionViewModel.cs
│   │           │   ├── SetAppVolumeActionViewModel.cs
│   │           │   ├── SetDefaultDeviceActionViewModel.cs
│   │           │   ├── SetDeviceMuteActionViewModel.cs
│   │           │   ├── SetDeviceVolumeActionViewModel.cs
│   │           │   └── SetVariableActionViewModel.cs
│   │           ├── ActionsCategoryViewModel.cs
│   │           ├── AppListViewModel.cs
│   │           ├── Conditions/
│   │           │   ├── DefaultDeviceConditionViewModel.cs
│   │           │   ├── ProcessConditionViewModel.cs
│   │           │   └── VariableConditionViewModel.cs
│   │           ├── DefaultPlaybackDeviceViewModel.cs
│   │           ├── DeviceListViewModel.cs
│   │           ├── DeviceViewModel.cs
│   │           ├── DeviceViewModelBase.cs
│   │           ├── EarTrumpetActionPageHeaderViewModel.cs
│   │           ├── EarTrumpetActionViewModel.cs
│   │           ├── EveryAppViewModel.cs
│   │           ├── ForegroundAppViewModel.cs
│   │           ├── HotkeyViewModel.cs
│   │           ├── IOptionViewModel.cs
│   │           ├── ImportExportPageViewModel.cs
│   │           ├── Option.cs
│   │           ├── OptionViewModel.cs
│   │           ├── PartViewModel.cs
│   │           ├── PartViewModelFactory.cs
│   │           ├── TextViewModel.cs
│   │           ├── Triggers/
│   │           │   ├── AppEventTriggerViewModel.cs
│   │           │   ├── ContextMenuTriggerViewModel.cs
│   │           │   ├── DeviceEventTriggerViewModel.cs
│   │           │   ├── EventTriggerViewModel.cs
│   │           │   ├── HotkeyTriggerViewModel.cs
│   │           │   └── ProcessTriggerViewModel.cs
│   │           └── VolumeViewModel.cs
│   ├── App.config
│   ├── App.manifest
│   ├── App.xaml
│   ├── App.xaml.cs
│   ├── AppSettings.cs
│   ├── BindableBase.cs
│   ├── DataModel/
│   │   ├── AppInformation/
│   │   │   ├── AppInformationFactory.cs
│   │   │   ├── IAppInfo.cs
│   │   │   └── Internal/
│   │   │       ├── DesktopAppInfo.cs
│   │   │       ├── ModernAppInfo.cs
│   │   │       ├── SystemSoundsAppInfo.cs
│   │   │       └── ZombieProcessException.cs
│   │   ├── Audio/
│   │   │   ├── IAudioDevice.cs
│   │   │   ├── IAudioDeviceManager.cs
│   │   │   ├── IAudioDeviceSession.cs
│   │   │   ├── IAudioDeviceSessionComparer.cs
│   │   │   ├── IStreamWithVolumeControl.cs
│   │   │   ├── Mocks/
│   │   │   │   ├── AudioDevice.cs
│   │   │   │   └── AudioDeviceSession.cs
│   │   │   └── SessionState.cs
│   │   ├── FilteredCollectionChain.cs
│   │   ├── ProcessWatcherService.cs
│   │   ├── Storage/
│   │   │   ├── ISettingsBag.cs
│   │   │   ├── Internal/
│   │   │   │   ├── NamespacedSettingsBag.cs
│   │   │   │   ├── RegistrySettingsBag.cs
│   │   │   │   └── WindowsStorageSettingsBag.cs
│   │   │   ├── Serializer.cs
│   │   │   └── StorageFactory.cs
│   │   ├── SystemSettings.cs
│   │   └── WindowsAudio/
│   │       ├── AudioDeviceKind.cs
│   │       ├── IAudioDeviceChannel.cs
│   │       ├── IAudioDeviceManagerWindowsAudio.cs
│   │       ├── IAudioDeviceSessionChannel.cs
│   │       ├── IAudioDeviceWindowsAudio.cs
│   │       ├── Internal/
│   │       │   ├── AudioDevice.cs
│   │       │   ├── AudioDeviceChannel.cs
│   │       │   ├── AudioDeviceChannelCollection.cs
│   │       │   ├── AudioDeviceManager.cs
│   │       │   ├── AudioDeviceSession.cs
│   │       │   ├── AudioDeviceSessionChannel.cs
│   │       │   ├── AudioDeviceSessionChannelCollection.cs
│   │       │   ├── AudioDeviceSessionChannelMultiplexer.cs
│   │       │   ├── AudioDeviceSessionCollection.cs
│   │       │   ├── AudioDeviceSessionGroup.cs
│   │       │   ├── AudioPolicyConfigService.cs
│   │       │   ├── Helpers.cs
│   │       │   ├── IAudioDeviceInternal.cs
│   │       │   └── IAudioDeviceSessionInternal.cs
│   │       └── WindowsAudioFactory.cs
│   ├── DebugHelpers.cs
│   ├── Diagnosis/
│   │   ├── CircularBufferTraceListener.cs
│   │   ├── ErrorReporter.cs
│   │   ├── LocalDataExporter.cs
│   │   └── SnapshotData.cs
│   ├── EarTrumpet.csproj
│   ├── Extensibility/
│   │   ├── EarTrumpetAddon.cs
│   │   ├── EarTrumpetAddonManifest.cs
│   │   ├── Hosting/
│   │   │   ├── AddonHost.cs
│   │   │   ├── AddonManager.cs
│   │   │   └── AddonResolver.cs
│   │   ├── IEarTrumpetAddonAppContent.cs
│   │   ├── IEarTrumpetAddonDeviceContent.cs
│   │   ├── IEarTrumpetAddonEvents.cs
│   │   ├── IEarTrumpetAddonNotificationAreaContextMenu.cs
│   │   ├── IEarTrumpetAddonSettingsPage.cs
│   │   └── Shared/
│   │       ├── PlaybackDataModelHost.cs
│   │       ├── ResourceLoader.cs
│   │       └── ServiceBus.cs
│   ├── Extensions/
│   │   ├── CollectionExtensions.cs
│   │   ├── ColorExtensions.cs
│   │   ├── DependencyObjectExtensions.cs
│   │   ├── EarTrumpetAddonExtensions.cs
│   │   ├── EventBinding/
│   │   │   ├── EventBindingExtension.cs
│   │   │   └── HandledEventBindingExtension.cs
│   │   ├── ExceptionExtensions.cs
│   │   ├── FloatExtensions.cs
│   │   ├── FrameworkElementExtensions.cs
│   │   ├── IEnumerableExtensions.cs
│   │   ├── IPropertyStoreExtensions.cs
│   │   ├── IconExtensions.cs
│   │   ├── ListExtensions.cs
│   │   ├── OperatingSystemExtensions.cs
│   │   ├── RegistryKeyExtensions.cs
│   │   ├── VisualExtensions.cs
│   │   └── WindowExtensions.cs
│   ├── Features.cs
│   ├── Interop/
│   │   ├── AppBarData.cs
│   │   ├── AppBarEdge.cs
│   │   ├── AppBarMessage.cs
│   │   ├── ApplicationResolver.cs
│   │   ├── CLSCTX.cs
│   │   ├── Combase.cs
│   │   ├── DwmApi.cs
│   │   ├── FolderIds.cs
│   │   ├── GPS.cs
│   │   ├── Gdi32.cs
│   │   ├── HRESULT.cs
│   │   ├── Helpers/
│   │   │   ├── AccentPolicyLibrary.cs
│   │   │   ├── AudioPolicyConfigFactory.cs
│   │   │   ├── AudioPolicyConfigFactoryImplFor21H2.cs
│   │   │   ├── AudioPolicyConfigFactoryImplForDownlevel.cs
│   │   │   ├── HotkeyData.cs
│   │   │   ├── HotkeyManager.cs
│   │   │   ├── IconHelper.cs
│   │   │   ├── ImmersiveSystemColors.cs
│   │   │   ├── InputHelper.cs
│   │   │   ├── Kernel32Helper.cs
│   │   │   ├── LegacyControlPanelHelper.cs
│   │   │   ├── MouseHook.cs
│   │   │   ├── PackageHelper.cs
│   │   │   ├── ProcessHelper.cs
│   │   │   ├── SettingsPageHelper.cs
│   │   │   ├── SingleInstanceAppMutex.cs
│   │   │   ├── Win32Window.cs
│   │   │   ├── WindowSizeHelper.cs
│   │   │   └── WindowsTaskbar.cs
│   │   ├── IPropertyStore.cs
│   │   ├── IShellItem.cs
│   │   ├── IShellItem2.cs
│   │   ├── IShellItemImageFactory.cs
│   │   ├── Kernel32.cs
│   │   ├── MMDeviceAPI/
│   │   │   ├── AUDIO_VOLUME_NOTIFICATION_DATA.cs
│   │   │   ├── AudioSessionDisconnectReason.cs
│   │   │   ├── AudioSessionState.cs
│   │   │   ├── DeviceState.cs
│   │   │   ├── EDataFlow.cs
│   │   │   ├── ERole.cs
│   │   │   ├── IAudioEndpointVolume.cs
│   │   │   ├── IAudioEndpointVolumeCallback.cs
│   │   │   ├── IAudioMeterInformation.cs
│   │   │   ├── IAudioPolicyConfigFactory.cs
│   │   │   ├── IAudioPolicyConfigFactoryVariantFor21H2.cs
│   │   │   ├── IAudioPolicyConfigFactoryVariantForDownlevel.cs
│   │   │   ├── IAudioSessionControl.cs
│   │   │   ├── IAudioSessionControl2.cs
│   │   │   ├── IAudioSessionEnumerator.cs
│   │   │   ├── IAudioSessionEvents.cs
│   │   │   ├── IAudioSessionManager.cs
│   │   │   ├── IAudioSessionManager2.cs
│   │   │   ├── IAudioSessionNotification.cs
│   │   │   ├── IAudioVolumeDuckNotification.cs
│   │   │   ├── IChannelAudioVolume.cs
│   │   │   ├── IDeviceTopology.cs
│   │   │   ├── IMMDevice.cs
│   │   │   ├── IMMDeviceCollection.cs
│   │   │   ├── IMMDeviceEnumerator.cs
│   │   │   ├── IMMEndpoint.cs
│   │   │   ├── IMMNotificationClient.cs
│   │   │   ├── IPolicyConfig.cs
│   │   │   ├── ISimpleAudioVolume.cs
│   │   │   ├── MMDeviceEnumerator.cs
│   │   │   └── PolicyConfigClient.cs
│   │   ├── NotifyIconData.cs
│   │   ├── Ntdll.cs
│   │   ├── Ole32.cs
│   │   ├── PropVariant.cs
│   │   ├── PropVariantUnion.cs
│   │   ├── PropertyKeys.cs
│   │   ├── RECT.cs
│   │   ├── SFGAO.cs
│   │   ├── SICHINT.cs
│   │   ├── SIGDN.cs
│   │   ├── SIZE.cs
│   │   ├── STGM.cs
│   │   ├── SafeHandles/
│   │   │   └── HMODULE.cs
│   │   ├── Shell32.cs
│   │   ├── SndVolSSO.cs
│   │   ├── User32.cs
│   │   ├── Uxtheme.cs
│   │   └── shlwapi.cs
│   ├── Properties/
│   │   ├── AssemblyInfo.cs
│   │   ├── Resources.Designer.cs
│   │   ├── Resources.af-ZA.resx
│   │   ├── Resources.ar-SA.resx
│   │   ├── Resources.bs-latn-ba.resx
│   │   ├── Resources.ca-ES.resx
│   │   ├── Resources.cs-CZ.resx
│   │   ├── Resources.da-DK.resx
│   │   ├── Resources.de-DE.resx
│   │   ├── Resources.el-GR.resx
│   │   ├── Resources.es-ES.resx
│   │   ├── Resources.fi-FI.resx
│   │   ├── Resources.fr-FR.resx
│   │   ├── Resources.he-IL.resx
│   │   ├── Resources.hr-HR.resx
│   │   ├── Resources.hu-HU.resx
│   │   ├── Resources.it-IT.resx
│   │   ├── Resources.ja-JP.resx
│   │   ├── Resources.ko-KR.resx
│   │   ├── Resources.nl-NL.resx
│   │   ├── Resources.no-NO.resx
│   │   ├── Resources.pl-PL.resx
│   │   ├── Resources.pt-BR.resx
│   │   ├── Resources.pt-PT.resx
│   │   ├── Resources.resx
│   │   ├── Resources.ro-RO.resx
│   │   ├── Resources.ru-RU.resx
│   │   ├── Resources.sl-SI.resx
│   │   ├── Resources.sv-SE.resx
│   │   ├── Resources.ta-IN.resx
│   │   ├── Resources.th-TH.resx
│   │   ├── Resources.tr-TR.resx
│   │   ├── Resources.uk-UA.resx
│   │   ├── Resources.vi-VN.resx
│   │   ├── Resources.zh-CN.resx
│   │   └── Resources.zh-TW.resx
│   ├── README.md
│   ├── UI/
│   │   ├── Behaviors/
│   │   │   ├── ButtonEx.cs
│   │   │   ├── ComboBoxEx.cs
│   │   │   ├── FrameworkElementEx.cs
│   │   │   ├── ScrollViewerEx.cs
│   │   │   └── TextBoxEx.cs
│   │   ├── Controls/
│   │   │   ├── AppPopup.cs
│   │   │   ├── ImageEx.cs
│   │   │   ├── ListView.cs
│   │   │   ├── ListViewItem.cs
│   │   │   ├── MenuItemTemplateSelector.cs
│   │   │   ├── SearchBox.xaml
│   │   │   └── VolumeSlider.cs
│   │   ├── Helpers/
│   │   │   ├── FlyoutViewState.cs
│   │   │   ├── IAppIconSource.cs
│   │   │   ├── IShellNotifyIconSource.cs
│   │   │   ├── NavigationCookie.cs
│   │   │   ├── RelayCommand.cs
│   │   │   ├── ShellNotifyIcon.cs
│   │   │   ├── SystemSoundsHelper.cs
│   │   │   ├── TaskbarIconSource.cs
│   │   │   ├── WindowAnimationLibrary.cs
│   │   │   ├── WindowHolder.cs
│   │   │   └── WindowViewState.cs
│   │   ├── Mutable.xaml
│   │   ├── Themes/
│   │   │   ├── AcrylicBrush.cs
│   │   │   ├── Brush.cs
│   │   │   ├── BrushValueParser.cs
│   │   │   ├── Manager.cs
│   │   │   ├── OS.cs
│   │   │   ├── Options.cs
│   │   │   ├── Ref.cs
│   │   │   ├── Rule.cs
│   │   │   └── ThemeBindingInfo.cs
│   │   ├── ViewModels/
│   │   │   ├── AddonAboutPageViewModel.cs
│   │   │   ├── AdvertisedCategorySettingsViewModel.cs
│   │   │   ├── AppItemViewModel.cs
│   │   │   ├── AudioSessionViewModel.cs
│   │   │   ├── BackstackViewModel.cs
│   │   │   ├── ContextMenuItem.cs
│   │   │   ├── DeviceCollectionViewModel.cs
│   │   │   ├── DeviceViewModel.cs
│   │   │   ├── EarTrumpetAboutPageViewModel.cs
│   │   │   ├── EarTrumpetCommunitySettingsPageViewModel.cs
│   │   │   ├── EarTrumpetLegacySettingsPageViewModel.cs
│   │   │   ├── EarTrumpetMouseSettingsPageViewModel.cs
│   │   │   ├── EarTrumpetShortcutsPageViewModel.cs
│   │   │   ├── FlyoutViewModel.cs
│   │   │   ├── FocusedAppItemViewModel.cs
│   │   │   ├── FocusedDeviceViewModel.cs
│   │   │   ├── FullWindowViewModel.cs
│   │   │   ├── HotkeyViewModel.cs
│   │   │   ├── IAppItemViewModel.cs
│   │   │   ├── IDeviceViewModel.cs
│   │   │   ├── IFlyoutViewModel.cs
│   │   │   ├── IFocusedViewModel.cs
│   │   │   ├── IPopupHostViewModel.cs
│   │   │   ├── ISettingsViewModel.cs
│   │   │   ├── ModalDialogViewModel.cs
│   │   │   ├── SettingsAppItemViewModel.cs
│   │   │   ├── SettingsCategoryViewModel.cs
│   │   │   ├── SettingsDialogViewModel.cs
│   │   │   ├── SettingsPageHeaderViewModel.cs
│   │   │   ├── SettingsPageViewModel.cs
│   │   │   ├── SettingsSearchItemViewModel.cs
│   │   │   ├── SettingsViewModel.cs
│   │   │   ├── TemporaryAppItemViewModel.cs
│   │   │   ├── ToolbarItemViewModel.cs
│   │   │   └── WelcomeViewModel.cs
│   │   └── Views/
│   │       ├── AppItemView.xaml
│   │       ├── AppItemView.xaml.cs
│   │       ├── DeviceView.xaml
│   │       ├── DeviceView.xaml.cs
│   │       ├── DialogWindow.xaml
│   │       ├── DialogWindow.xaml.cs
│   │       ├── FlyoutWindow.xaml
│   │       ├── FlyoutWindow.xaml.cs
│   │       ├── FullWindow.xaml
│   │       ├── FullWindow.xaml.cs
│   │       ├── SettingsWindow.xaml
│   │       └── SettingsWindow.xaml.cs
│   ├── packages.config
│   └── prebuild.ps1
├── EarTrumpet.ColorTool/
│   ├── App.config
│   ├── App.xaml
│   ├── App.xaml.cs
│   ├── ColorItemViewModel.cs
│   ├── ColorViewModel.cs
│   ├── EarTrumpet.ColorTool.csproj
│   ├── MainWindow.xaml
│   ├── MainWindow.xaml.cs
│   └── Properties/
│       └── AssemblyInfo.cs
├── EarTrumpet.Package/
│   ├── EarTrumpet.Package.wapproj
│   ├── Package.StoreAssociation.xml
│   ├── Package.appxmanifest
│   └── Package.xml
├── EarTrumpet.vs15.sln
├── GitVersion.yml
├── LICENSE
├── PRIVACY.md
├── Packaging/
│   └── MicrosoftStore/
│       ├── PDPs/
│       │   ├── ar-SA/
│       │   │   └── pdp.xml
│       │   ├── bs-latn-ba/
│       │   │   └── pdp.xml
│       │   ├── ca-ES/
│       │   │   └── pdp.xml
│       │   ├── cs-CZ/
│       │   │   └── pdp.xml
│       │   ├── da-DK/
│       │   │   └── pdp.xml
│       │   ├── de-DE/
│       │   │   └── pdp.xml
│       │   ├── el-GR/
│       │   │   └── pdp.xml
│       │   ├── en-us/
│       │   │   └── pdp.xml
│       │   ├── es-ES/
│       │   │   └── pdp.xml
│       │   ├── fr-FR/
│       │   │   └── pdp.xml
│       │   ├── he-IL/
│       │   │   └── pdp.xml
│       │   ├── hr-HR/
│       │   │   └── pdp.xml
│       │   ├── hu-HU/
│       │   │   └── pdp.xml
│       │   ├── it-IT/
│       │   │   └── pdp.xml
│       │   ├── ja-JP/
│       │   │   └── pdp.xml
│       │   ├── ko-KR/
│       │   │   └── pdp.xml
│       │   ├── nl-NL/
│       │   │   └── pdp.xml
│       │   ├── no-NO/
│       │   │   └── pdp.xml
│       │   ├── pl-PL/
│       │   │   └── pdp.xml
│       │   ├── pt-BR/
│       │   │   └── pdp.xml
│       │   ├── pt-PT/
│       │   │   └── pdp.xml
│       │   ├── ro-RO/
│       │   │   └── pdp.xml
│       │   ├── ru-RU/
│       │   │   └── pdp.xml
│       │   ├── sl-SI/
│       │   │   └── pdp.xml
│       │   ├── sv-SE/
│       │   │   └── pdp.xml
│       │   ├── th-TH/
│       │   │   └── pdp.xml
│       │   ├── tr-TR/
│       │   │   └── pdp.xml
│       │   ├── uk-UA/
│       │   │   └── pdp.xml
│       │   ├── vi-VN/
│       │   │   └── pdp.xml
│       │   ├── zh-CN/
│       │   │   └── pdp.xml
│       │   └── zh-TW/
│       │       └── pdp.xml
│       └── sbconfig.json
├── README.md
└── crowdin.yml

================================================
FILE CONTENTS
================================================

================================================
FILE: .azure-pipelines.yml
================================================
trigger:
  branches:
    include:
      - master
      - review/*
      - experiment/*
      - dev
  paths:
    exclude:
      - '**/*.md'
      - '.github/**/*'
pr:
  branches:
    include:
      - dev
  paths:
    exclude:
      - '**/*.md'
      - '.github/**/*'

variables:
- group: 'Bugsnag'
- name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE
  value: true
- name: Solution
  value: 'EarTrumpet.vs15.sln'
- name: BuildConfiguration
  value: 'Release'
- name: BuildPlatform
  value: 'x86'

jobs:
- job: Build
  continueOnError: 'false'
  pool:
    vmImage: vs2017-win2016

  strategy:
    matrix:
      AppInstaller:
        Channel: AppInstaller
        Publisher: 'CN=File-New-Project, O=File-New-Project, L=Purcellville, S=Virginia, C=US'
      Store:
        Channel: Store
        Publisher: 'CN=6099D0EF-9374-47ED-BDFE-A82136831235'
    maxParallel: 2

  steps:
  - task: GitVersion@4
    displayName: 'Initialize Git Version'
    inputs:
      updateAssemblyInfo: false

  - task: PowerShell@2
    displayName: 'Set build number'
    inputs:
      targetType: inline
      script: |
        Write-Host "##vso[build.updatebuildnumber]$(GitVersion.SemVer)"

  - task: PowerShell@2
    displayName: 'Generate versioning metadata'
    inputs:
      targetType: inline
      script: |
        New-Item -ItemType Directory "$(Build.ArtifactStagingDirectory)\Metadata" -ErrorAction Ignore
        Set-Content "$(Build.ArtifactStagingDirectory)\Metadata\semver.txt" "$(GitVersion.SemVer)"
        Set-Content "$(Build.ArtifactStagingDirectory)\Metadata\branch.txt" "$(GitVersion.BranchName)"
        Set-Content "$(Build.ArtifactStagingDirectory)\Metadata\commits.txt" "$(GitVersion.CommitsSinceVersionSource)"

        if("$(Channel)" -eq "Store") {
          $Version = "$(GitVersion.MajorMinorPatch).0"
        } else {
          $Version = "$(GitVersion.AssemblySemVer)"
        }

        Set-Content "$(Build.ArtifactStagingDirectory)\Metadata\$(Channel).version.txt" $Version

  - task: NuGetToolInstaller@0
    displayName: 'Install NuGet Tooling'

  - task: NuGetCommand@2
    displayName: 'Restore NuGet Packages'
    inputs:
      restoreSolution: '$(solution)'

  - task: PowerShell@2
    displayName: 'Set Bugsnag API Key'
    inputs:
      targetType: inline
      script: |
        $cfg = Get-Content ".\EarTrumpet\app.config"
        $cfg | ForEach-Object { $_.Replace("{bugsnag.apikey}", "$(bugsnag.apikey)") } | Set-Content ".\EarTrumpet\app.config"

  - task: PowerShell@2
    displayName: 'Adjust manifest and store association'
    inputs:
      targetType: inline
      script: |
        $manifestPath = ".\EarTrumpet.Package\Package.appxmanifest"
        $storeAssociationPath = ".\EarTrumpet.Package\Package.StoreAssociation.xml"

        $manifest = [xml](Get-Content $manifestPath)
        $manifest.Package.Identity.Publisher = "$(Publisher)"
        if("$(Channel)" -eq "AppInstaller") {
          $manifest.Package.Properties.DisplayName = "EarTrumpet ($(GitVersion.BranchName))"
          $manifest.Package.Applications.Application.VisualElements.DisplayName = "EarTrumpet ($(GitVersion.BranchName))"
        }
        $manifest.Save($manifestPath)

        $storeAssociation = [xml](Get-Content $storeAssociationPath)
        $storeAssociation.StoreAssociation.Publisher = "$(Publisher)"
        if("$(Channel)" -eq "AppInstaller") {
          $storeAssociation.StoreAssociation.ProductReservedInfo.ReservedNames.ReservedName = "EarTrumpet ($(GitVersion.BranchName))"
        }
        $storeAssociation.Save($storeAssociationPath)

  - task: MSBuild@1
    displayName: 'Build EarTrumpet appxupload package'
    inputs:
      solution: 'EarTrumpet.Package/EarTrumpet.Package.wapproj'
      platform: 'x86'
      configuration: '$(buildConfiguration)'
      msbuildArguments: '/p:AppxBundle=Always /p:Channel=$(Channel) /p:AppxPackageDir="$(Build.ArtifactStagingDirectory)/AppxUpload" /p:AppxPackageSigningEnabled=false /p:UapAppxPackageBuildMode=CI'
      maximumCpuCount: true
    condition: and(succeeded(), eq(variables['Channel'], 'Store'))

  - task: PublishBuildArtifacts@1
    displayName: 'Publish appxupload artifacts'
    inputs:
      pathToPublish: '$(Build.ArtifactStagingDirectory)/AppxUpload'
      artifactName: 'AppxUpload'
    condition: and(succeeded(), eq(variables['Channel'], 'Store'))

  - task: MSBuild@1
    displayName: 'Build EarTrumpet appinstaller/sideload package'
    inputs:
      solution: 'EarTrumpet.Package/EarTrumpet.Package.wapproj'
      platform: 'x86'
      configuration: '$(buildConfiguration)'
      msbuildArguments: '/p:AppxBundle=Always /p:Channel=$(Channel) /p:AppxPackageDir="$(Build.ArtifactStagingDirectory)/Sideload" /p:AppxPackageSigningEnabled=false /p:UapAppxPackageBuildMode=SideloadOnly /p:GenerateAppInstallerFile=true /p:AppxPackageTestDir="$(Build.ArtifactStagingDirectory)/Sideload/" /p:AppInstallerUri=https://install.eartrumpet.app'
      maximumCpuCount: true
    condition: and(succeeded(), eq(variables['Channel'], 'AppInstaller'))

  - task: PowerShell@2
    displayName: 'Adjust appinstaller manifest'
    inputs:
      targetType: inline
      script: |
        $manifestPath = "$(Build.ArtifactStagingDirectory)/Sideload/EarTrumpet.Package.appinstaller"
        $manifest = [xml](Get-Content $manifestPath)
        $manifest.AppInstaller.Uri = "https://install.eartrumpet.app/$(GitVersion.BranchName)/EarTrumpet.Package.appinstaller"
        $manifest.AppInstaller.MainBundle.Uri = "https://install.eartrumpet.app/$(GitVersion.BranchName)/EarTrumpet.Package_$(GitVersion.MajorMinorPatch).$(GitVersion.CommitsSinceVersionSource)_x86.appxbundle"
        $manifest.AppInstaller.MainBundle.Publisher = "$(Publisher)"
        $manifest.Save($manifestPath)
      pwsh: true
    condition: and(succeeded(), eq(variables['Channel'], 'AppInstaller'))

  - task: PublishBuildArtifacts@1
    displayName: 'Publish appinstaller/sideload package artifacts'
    inputs:
      pathToPublish: '$(Build.ArtifactStagingDirectory)/Sideload'
      artifactName: 'Sideload'
    condition: and(succeeded(), eq(variables['Channel'], 'AppInstaller'))

  - task: CopyFiles@2
    displayName: 'Stage packaging metadata'
    inputs:
      SourceFolder: 'Packaging'
      Contents: '**'
      TargetFolder: '$(Build.ArtifactStagingDirectory)/Metadata/Packaging'
    condition: and(succeeded(), eq(variables['Channel'], 'Store'))

  - task: PublishBuildArtifacts@1
    displayName: 'Publish metadata artifacts'
    inputs:
      pathToPublish: '$(Build.ArtifactStagingDirectory)/Metadata'
      artifactName: 'Metadata'


================================================
FILE: .chocolatey/eartrumpet.nuspec
================================================
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
  <metadata>
    <id>eartrumpet</id>
    <version>2.1.7.0</version>
    <packageSourceUrl>https://github.com/File-New-Project/EarTrumpet/tree/master/.chocolatey</packageSourceUrl>
    <owners>File-New-Project</owners>
    <title>EarTrumpet</title>
    <authors>EarTrumpet Contributors</authors>
    <projectUrl>https://github.com/File-New-Project/EarTrumpet</projectUrl>
    <iconUrl>https://raw.githubusercontent.com/File-New-Project/EarTrumpet/master/.chocolatey/logo.png</iconUrl>
    <copyright>2015 File-New-Project</copyright>
    <licenseUrl>https://github.com/File-New-Project/EarTrumpet/blob/master/LICENSE</licenseUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <projectSourceUrl>https://github.com/File-New-Project/EarTrumpet</projectSourceUrl>
    <bugTrackerUrl>https://github.com/File-New-Project/EarTrumpet/issues</bugTrackerUrl>
    <tags>EarTrumpet</tags>
    <description>EarTrumpet is a powerful volume control app for Windows</description>
  </metadata>
  <files>
    <file src="tools\**" target="tools" />
  </files>
</package>


================================================
FILE: .chocolatey/tools/LICENSE.txt
================================================
From: https://github.com/File-New-Project/EarTrumpet/blob/master/LICENSE

LICENSE

The MIT License (MIT)

Copyright (c) 2015

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: .chocolatey/tools/VERIFICATION.txt
================================================
VERIFICATION
Verification is intended to assist the Chocolatey moderators and community
in verifying that this package's contents are trustworthy.
 
This package is published directly by File-New-Project, the team that owns EarTrumpet.

================================================
FILE: .chocolatey/tools/chocolateybeforemodify.ps1
================================================
$process = Get-Process -Name EarTrumpet -ErrorAction SilentlyContinue
if ($process) {
  $process | Stop-Process -Force
}

================================================
FILE: .chocolatey/tools/chocolateyinstall.ps1
================================================
$ErrorActionPreference = 'Stop'
$toolsDir   = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
$installPath = Join-Path $toolsDir 'EarTrumpet'
$exePath = Join-Path $toolsDir 'EarTrumpet\EarTrumpet.exe'
$zipPath = Join-Path $toolsDir 'Release.zip'

Install-ChocolateyZipPackage -PackageName "$packageName" `
                             -Url "$zipPath" `
                             -UnzipLocation "$installPath"
                             
Write-Output "Adding shortcut to Start Menu"
Install-ChocolateyShortcut -ShortcutFilePath "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\EarTrumpet.lnk" -TargetPath $exePath

Write-Output "Adding shortcut to Startup"
New-ItemProperty -LiteralPath 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run' -Name 'EarTrumpet' -Value $exePath -PropertyType String -Force -ea SilentlyContinue | Out-Null

================================================
FILE: .chocolatey/tools/chocolateyuninstall.ps1
================================================
Remove-Item "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\EarTrumpet.lnk" -ErrorAction Continue
Remove-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name "EarTrumpet"

================================================
FILE: .gitattributes
================================================
[core]
* text eol=crlf

*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.mov binary
*.mp4 binary
*.mp3 binary
*.flv binary
*.fla binary
*.swf binary
*.gz binary
*.zip binary
*.7z binary
*.ttf binary
*.eot binary
*.woff binary
*.pyc binary
*.pdf binary
*.ez binary
*.bz2 binary
*.swp binary
*.pfx binary


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

## Supported
github: File-New-Project

## Currently unsupported
patreon:
open_collective:
ko_fi:
tidelift:
community_bridge:
liberapay:
issuehunt:
otechie:
lfx_crowdfunding:
custom:


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: Bug report
description: Report a problem with EarTrumpet or related add-on
body:
  - type: textarea
    id: summary
    attributes:
      label: Summary
      description: A clear explaination of what the problem is.
    validations:
      required: true
  - type: textarea
    id: steps
    attributes:
      label: Steps to reproduce
    validations:
      required: true
  - type: input
    id: eartrumpet_version
    attributes:
      label: EarTrumpet version
      description: Right-click the EarTrumpet icon, then click Settings > General > About.
    validations:
      required: true
  - type: input
    id: windows_version
    attributes:
      label: Windows version
      description: Open the Command Prompt and observe the version shown on the first line.
      placeholder: 10.0.22000.1024
    validations:
      required: true
  - type: textarea
    id: additional_info
    attributes:
      label: Additional information
      description: Screenshots, logs, and other supplemental data go here.


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
contact_links:
  - name: Request a feature
    url: https://github.com/File-New-Project/EarTrumpet/discussions/new?category=ideas
    about: Share an idea or suggest a change to EarTrumpet or related add-on
  - name: Ask a question
    url: https://github.com/File-New-Project/EarTrumpet/discussions/new?category=Q-A
    about: Ask a question about EarTrumpet or anything related

================================================
FILE: .github/workflows/main.yml
================================================
name: EarTrumpet-CI
on:
  push:
    branches:
      - master
      - dev
      - rafael/*
      - dave/*
      - david/*
    paths-ignore:
      - "**/*.md"
      - ".github/ISSUE_TEMPLATE/*"
      - ".github/workflows/sponsors.yml"
      - ".github/workflows/translators.yml"
      - "Graphics/*"
  pull_request:
    branches:
      - dev
    paths-ignore:
      - "**/*.md"
      - crowdin.yml
env:
  DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
  DOTNET_CLI_TELEMETRY_OPTOUT: true
  BUILD_CONFIGURATION: Release
  BUILD_PLATFORM: x86
  ARTIFACTS_BASE: '${{ github.workspace }}\artifacts'

jobs:
  build:
    runs-on: windows-2019
    strategy:
      matrix:
        channel: [AppInstaller, Store, Chocolatey]
        include:
          - channel: AppInstaller
            publisher:
              "CN=File-New-Project, O=File-New-Project, L=Purcellville, S=Virginia, C=US"
          - channel: Store
            publisher: CN=6099D0EF-9374-47ED-BDFE-A82136831235
          - channel: Chocolatey
            publisher:
              "CN=File-New-Project, O=File-New-Project, L=Purcellville, S=Virginia, C=US"
      max-parallel: 3
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Fetch all history for all tags and branches
        run: git fetch --prune --unshallow

      - name: Install GitVersion
        uses: gittools/actions/gitversion/setup@v0.9.15
        with:
          versionSpec: "5.x"
          includePrerelease: false

      - name: Use GitVersion
        id: gitversion
        uses: gittools/actions/gitversion/execute@v0.9.15

      - name: Create artifact layout
        shell: powershell
        run: |
          $ErrorActionPreference = 'Ignore'
          New-Item -ItemType Directory "$env:ARTIFACTS_BASE"
          New-Item -ItemType Directory "$env:ARTIFACTS_BASE\appxupload"
          New-Item -ItemType Directory "$env:ARTIFACTS_BASE\sideload"
          New-Item -ItemType Directory "$env:ARTIFACTS_BASE\chocolatey"
          New-Item -ItemType Directory "$env:ARTIFACTS_BASE\loose"
          New-Item -ItemType Directory "$env:ARTIFACTS_BASE\metadata"

      - name: Generate versioning metadata
        shell: powershell
        run: |
          Set-Content "$env:ARTIFACTS_BASE\metadata\semver.txt" "${{ steps.gitversion.outputs.semVer }}"
          Set-Content "$env:ARTIFACTS_BASE\metadata\branch.txt" "${{ steps.gitversion.outputs.branchName }}"
          Set-Content "$env:ARTIFACTS_BASE\metadata\commits.txt" "${{ steps.gitversion.outputs.commitsSinceVersionSource }}"

          if("${{ matrix.channel }}" -eq "Store") {
            $Version = "${{ steps.gitversion.outputs.majorMinorPatch }}.0"
          } else {
            $Version = "${{ steps.gitversion.outputs.majorMinorPatch }}.${{ steps.gitversion.outputs.commitsSinceVersionSource }}"
          }

          Set-Content "$env:ARTIFACTS_BASE\metadata\${{ matrix.channel }}.version.txt" $Version

      - name: Install NuGet
        uses: NuGet/setup-nuget@v1
        with:
          nuget-version: latest

      - name: Restore NuGet Packages
        run: nuget restore EarTrumpet.vs15.sln

      - name: Set Bugsnag API Key
        shell: powershell
        run: |
          $cfg = Get-Content ".\EarTrumpet\app.config"
          $cfg | ForEach-Object { $_.Replace("{bugsnag.apikey}", "${{ secrets.bugsnag_api_key }}") } | Set-Content ".\EarTrumpet\app.config"

      - name: Adjust manifest and store association
        if: matrix.channel == 'Store' || matrix.channel == 'AppInstaller'
        shell: powershell
        run: |
          $manifestPath = ".\EarTrumpet.Package\Package.appxmanifest"
          $storeAssociationPath = ".\EarTrumpet.Package\Package.StoreAssociation.xml"

          $manifest = [xml](Get-Content $manifestPath)
          $manifest.Package.Identity.Publisher = "${{ matrix.publisher }}"
          if("${{ matrix.channel }}" -eq "AppInstaller") {
            if("${{ steps.gitversion.outputs.branchName }}" -eq "master") {
              $manifest.Package.Properties.DisplayName = "EarTrumpet"
              $manifest.Package.Applications.Application.VisualElements.DisplayName = "EarTrumpet"
            } else {
              $manifest.Package.Properties.DisplayName = $manifest.Package.Properties.DisplayName + " (${{ steps.gitversion.outputs.branchName }})"
            $manifest.Package.Applications.Application.VisualElements.DisplayName = "EarTrumpet (${{ steps.gitversion.outputs.branchName }})"
            }
          }
          $manifest.Save($manifestPath)

          $storeAssociation = [xml](Get-Content $storeAssociationPath)
          $storeAssociation.StoreAssociation.Publisher = "${{ matrix.publisher }}"
          if("${{ matrix.channel }}" -eq "AppInstaller") {
            if("${{ steps.gitversion.outputs.branchName }}" -eq "master") {
              $storeAssociation.StoreAssociation.ProductReservedInfo.ReservedNames.ReservedName = "EarTrumpet"
            } else {
              $storeAssociation.StoreAssociation.ProductReservedInfo.ReservedNames.ReservedName = "EarTrumpet (${{ steps.gitversion.outputs.branchName }})"
            }
          }
          $storeAssociation.Save($storeAssociationPath)

      - name: Set up MSBuild
        uses: microsoft/setup-msbuild@v1

      - name: Build EarTrumpet appxupload package
        if: matrix.channel == 'Store'
        shell: cmd
        run:
          msbuild EarTrumpet.Package/EarTrumpet.Package.wapproj
          /p:Platform=%BUILD_PLATFORM% /p:Configuration=%BUILD_CONFIGURATION%
          /p:AppxBundle=Always /p:Channel=${{ matrix.channel }}
          /p:AppxPackageDir=%ARTIFACTS_BASE%\appxupload\
          /p:AppxPackageSigningEnabled=false /p:UapAppxPackageBuildMode=CI
          -maxcpucount

      - name: Upload appxupload artifact
        if: matrix.channel == 'Store' && github.event_name != 'pull_request'
        uses: actions/upload-artifact@v3
        with:
          name: appxupload
          path: artifacts/appxupload

      - name: Build EarTrumpet
        if: matrix.channel == 'Chocolatey'
        shell: cmd
        run:
          msbuild EarTrumpet/EarTrumpet.csproj /p:Platform=%BUILD_PLATFORM%
          /p:Configuration=%BUILD_CONFIGURATION% /p:Channel=${{ matrix.channel
          }} /p:OutputPath=%ARTIFACTS_BASE%\loose\ -maxcpucount

      - name: Upload loose artifacts
        if:
          matrix.channel == 'Chocolatey' && github.event_name != 'pull_request'
        uses: actions/upload-artifact@v3
        with:
          name: loose
          path: artifacts/loose

      - name: Build EarTrumpet appinstaller/sideload package
        if: matrix.channel == 'AppInstaller' || matrix.channel == 'Chocolatey'
        shell: cmd
        run:
          msbuild EarTrumpet.Package/EarTrumpet.Package.wapproj
          /p:Platform=%BUILD_PLATFORM% /p:Configuration=%BUILD_CONFIGURATION%
          /p:AppxBundle=Always /p:Channel=${{ matrix.channel }}
          /p:AppxPackageDir=%ARTIFACTS_BASE%\sideload\
          /p:AppxPackageSigningEnabled=false
          /p:UapAppxPackageBuildMode=SideloadOnly
          /p:GenerateAppInstallerFile=true
          /p:AppxPackageTestDir=%ARTIFACTS_BASE%\sideload\
          /p:AppInstallerUri="https://install.eartrumpet.app" -maxcpucount

      - name: Adjust appinstaller manifest
        if:
          matrix.channel == 'AppInstaller' && github.event_name !=
          'pull_request'
        shell: powershell
        run: |
          $manifestPath = "$env:ARTIFACTS_BASE/sideload/EarTrumpet.Package.appinstaller"
          $manifest = [xml](Get-Content $manifestPath)
          $manifest.AppInstaller.Uri = "https://install.eartrumpet.app/${{ steps.gitversion.outputs.branchName }}/EarTrumpet.Package.appinstaller"
          $manifest.AppInstaller.MainBundle.Uri = "https://install.eartrumpet.app/${{ steps.gitversion.outputs.branchName }}/EarTrumpet.Package_${{ steps.gitversion.outputs.majorMinorPatch }}.${{ steps.gitversion.outputs.commitsSinceVersionSource }}_x86.appxbundle"
          $manifest.AppInstaller.MainBundle.Publisher = "${{ matrix.publisher }}"

          $fragment = [xml]'<AppInstaller xmlns="http://schemas.microsoft.com/appx/appinstaller/2017/2"><Dependencies><Package Name="Microsoft.VCLibs.140.00.UWPDesktop" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" Version="14.0.30704.0" ProcessorArchitecture="x86" Uri="https://aka.ms/Microsoft.VCLibs.x86.14.00.Desktop.appx" /></Dependencies></AppInstaller>'
          $manifest.AppInstaller.InsertAfter($manifest.ImportNode($fragment.AppInstaller.Dependencies, $true), $manifest.AppInstaller.MainBundle)

          $manifest.Save($manifestPath)

      - name: Upload appinstaller/sideload package artifacts
        if:
          matrix.channel == 'AppInstaller' && github.event_name !=
          'pull_request'
        uses: actions/upload-artifact@v3
        with:
          name: sideload
          path: artifacts/sideload

      - name: Fix up PDPs
        if: matrix.channel == 'Store' && github.event_name != 'pull_request'
        shell: pwsh
        run: |
          Set-Location packaging\MicrosoftStore\PDPs
          Get-ChildItem | ForEach-Object {
              $locale = $_.Name
              $pdp = [xml](Get-Content "$locale\pdp.xml")
              $pdp.ProductDescription.language = $locale
              $pdp.ProductDescription.lang = $locale
              $pdp.ProductDescription
              $pdp.Save((Resolve-Path "$locale\pdp.xml"))
          }

      - name: Stage msix packaging metadata
        if: matrix.channel == 'Store' && github.event_name != 'pull_request'
        shell: powershell
        run: |
          Copy-Item packaging\ -Recurse "$env:ARTIFACTS_BASE\metadata\"

      - name: Upload metadata artifacts
        uses: actions/upload-artifact@v3
        with:
          name: metadata
          path: artifacts/metadata

      - name: Stage chocolatey packaging metadata
        if:
          matrix.channel == 'Chocolatey' && github.event_name != 'pull_request'
        shell: powershell
        run: |
          Copy-Item .chocolatey\* -Recurse "$env:ARTIFACTS_BASE\chocolatey\"

      - name: Upload chocolatey artifacts
        uses: actions/upload-artifact@v3
        with:
          name: chocolatey
          path: artifacts/chocolatey
  release:
    needs: build
    runs-on: windows-2019
    if: github.event_name != 'pull_request'
    strategy:
      matrix:
        channel: [AppInstaller, Store, Chocolatey]
      max-parallel: 3
    env:
      AZURE_TENANT_ID: ${{ secrets.azure_tenant_id }}
      AZURE_CLIENT_ID: ${{ secrets.azure_client_id }}
      AZURE_CLIENT_SECRET: ${{ secrets.azure_client_secret }}
    steps:
      - name: Download artifacts
        uses: actions/download-artifact@v3
        with:
          path: artifacts

      - name: Install NuGet
        uses: NuGet/setup-nuget@v1
        with:
          nuget-version: latest

      - name: Install Build Tools
        run: nuget install Microsoft.Windows.SDK.BuildTools

      - name: Install Azure Codesigning
        shell: pwsh
        env:
          ACS_PACKAGE_URI: ${{ secrets.acs_package_uri }}
          ACS_METADATA_URI: ${{ secrets.acs_metadata_uri }}
          GITHUB_RUN_ID: ${{ github.run_id }}
        run: |
          Invoke-WebRequest $env:ACS_PACKAGE_URI -UseBasicParsing -OutFile package.zip
          Expand-Archive package.zip -DestinationPath acs
          Invoke-WebRequest $env:ACS_METADATA_URI -UseBasicParsing -OutFile acs\metadata.json

      - name: Sign and repackage Store artifacts
        if: matrix.channel == 'Store'
        shell: pwsh
        run: |
          $MetadataPath = "$env:ARTIFACTS_BASE\metadata"
          $Version = [Version](Get-Content "$MetadataPath\Store.version.txt")
          $AppxUploadPath = "$env:ARTIFACTS_BASE\AppxUpload"
          $BundleFilename = "EarTrumpet.Package_${Version}_x86.appxbundle"
          $SymbolsBundleFilename = "EarTrumpet.Package_${Version}_x86.appxsym"
          $AppxFilename = "EarTrumpet.Package_${Version}_x86.appx"
          $StoreBundleFilename = "EarTrumpet.Package_${Version}_x86_bundle.appxupload"

          ### Expand bundle and appx package within
          $ExtractedPath = "$env:ARTIFACTS_BASE\Extracted"
          Expand-Archive "$AppxUploadPath\$StoreBundleFilename" "$ExtractedPath\AppxUpload"
          Expand-Archive "$ExtractedPath\AppxUpload\$SymbolsBundleFilename" "$ExtractedPath\Symbols"
          Expand-Archive "$ExtractedPath\AppxUpload\$BundleFilename" "$ExtractedPath\Bundle"
          Expand-Archive "$ExtractedPath\Bundle\$AppxFilename" "$ExtractedPath\Package"

          ### Place symbols next to executable image
          Copy-Item "$ExtractedPath\Symbols\EarTrumpet.pdb" "$ExtractedPath\Package\EarTrumpet\"

          ### Sign executable image
          & (Resolve-Path "Microsoft.Windows.SDK.BuildTools.*\bin\*\x64\signtool.exe") sign /v /fd SHA256 /td SHA256 /tr http://timestamp.acs.microsoft.com /dlib "acs\bin\x64\Azure.CodeSigning.Dlib.dll" /dmdf "acs\metadata.json" "$ExtractedPath\Package\EarTrumpet\EarTrumpet.exe"

          $SignedPath = "$env:ARTIFACTS_BASE\Signed"
          New-Item -ItemType Directory "$SignedPath"
          New-Item -ItemType Directory "$SignedPath\Package"
          New-Item -ItemType Directory "$SignedPath\Bundle"
          New-Item -ItemType Directory "$SignedPath\AppxUpload"

          ### Repackage appx package
          & "C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86\makeappx.exe" pack /l /h sha256 /d "$ExtractedPath\Package" /o /p "$SignedPath\Package\$AppxFilename"

          Set-ItemProperty "$SignedPath\Package\$AppxFilename" -Name IsReadOnly -Value $true
          Copy-Item "$ExtractedPath\Bundle\*.appx" "$SignedPath\Package\" -ErrorAction Ignore
          Set-ItemProperty "$SignedPath\Package\$AppxFilename" -Name IsReadOnly -Value $false

          ### Repackage appx bundle
          & "C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86\makeappx.exe" bundle /d "$SignedPath\Package" /bv $Version /o /p "$SignedPath\Bundle\$BundleFilename"

          ### Repackage appxupload
          Copy-Item "$ExtractedPath\AppxUpload\$SymbolsBundleFilename" "$SignedPath\Bundle"
          Compress-Archive -Path "$SignedPath\Bundle\*" -DestinationPath "$SignedPath\AppxUpload\$StoreBundleFilename" -CompressionLevel Optimal

      - name: Sign AppInstaller artifacts
        if: matrix.channel == 'AppInstaller'
        shell: pwsh
        run: |
          $MetadataPath = "$env:ARTIFACTS_BASE\metadata"
          $Version = [Version](Get-Content "$MetadataPath\AppInstaller.version.txt")
          $Branch = Get-Content "$MetadataPath\branch.txt"
          $Semver= Get-Content "$MetadataPath\semver.txt"
          $BundleFilename = "EarTrumpet.Package_${Version}_x86.appxbundle"
          $SymbolsBundleFilename = "EarTrumpet.Package_${Version}_x86.appxsym"
          $AppxFilename = "EarTrumpet.Package_${Version}_x86.appx"

          $SideloadPath = "$env:ARTIFACTS_BASE\sideload"
          $SignedPath = "$env:ARTIFACTS_BASE\sideload\signed"

          ### Expand bundle and appx package within
          $ExtractedPath = "$env:TEMP\extracted"
          Expand-Archive "$SideloadPath\$SymbolsBundleFilename" "$ExtractedPath\Symbols"
          Expand-Archive "$SideloadPath\$BundleFilename" "$ExtractedPath\Bundle"
          Write-Output "Expand $ExtractedPath\Bundle\EarTrumpet.Package_${Version}_x86.appx"
          Expand-Archive "$ExtractedPath\Bundle\EarTrumpet.Package_${Version}_x86.appx" "$ExtractedPath\Package"

          ### Place symbols next to executable image
          Copy-Item "$ExtractedPath\Symbols\EarTrumpet.pdb" "$ExtractedPath\Package\EarTrumpet\"

          ### Sign executable image
          Write-Output "Signing $ExtractedPath\Package\EarTrumpet\EarTrumpet.exe"
          & (Resolve-Path "Microsoft.Windows.SDK.BuildTools.*\bin\*\x64\signtool.exe") sign /v /fd SHA256 /td SHA256 /tr http://timestamp.acs.microsoft.com /dlib "acs\bin\x64\Azure.CodeSigning.Dlib.dll" /dmdf "acs\metadata.json" "$ExtractedPath\Package\EarTrumpet\EarTrumpet.exe"

          New-Item -ItemType Directory "$SignedPath"
          New-Item -ItemType Directory "$SignedPath\Package"
          New-Item -ItemType Directory "$SignedPath\Bundle"

          ### Repackage appx package
          & "C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86\makeappx.exe" pack /l /h sha256 /d "$ExtractedPath\Package" /o /p "$SignedPath\Package\$AppxFilename"

          Set-ItemProperty "$SignedPath\Package\EarTrumpet.Package_${Version}_x86.appx" -Name IsReadOnly -Value $true
          Copy-Item "$ExtractedPath\Bundle\*.appx" "$SignedPath\Package\" -ErrorAction Ignore
          Set-ItemProperty "$SignedPath\Package\EarTrumpet.Package_${Version}_x86.appx" -Name IsReadOnly -Value $false

          ### Repackage appx bundle
          & "C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86\makeappx.exe" bundle /d "$SignedPath\Package" /bv $Version /o /p "$SignedPath\Bundle\$BundleFilename"

          ### Sign appx bundle
          Write-Output "Signing $SignedPath\Bundle\$BundleFilename"
          & (Resolve-Path "Microsoft.Windows.SDK.BuildTools.*\bin\*\x64\signtool.exe") sign /v /fd SHA256 /td SHA256 /tr http://timestamp.acs.microsoft.com /dlib "acs\bin\x64\Azure.CodeSigning.Dlib.dll" /dmdf "acs\metadata.json" "$SignedPath\Bundle\$BundleFilename"

          Copy-Item "$SideloadPath\*.appinstaller" "$SignedPath\Bundle"

      - name: Sign and repackage Chocolatey artifacts
        if: matrix.channel == 'Chocolatey'
        shell: pwsh
        run: |
          $MetadataPath = "$env:ARTIFACTS_BASE\metadata"
          $Branch = Get-Content "$MetadataPath\branch.txt"
          $Semver= Get-Content "$MetadataPath\semver.txt"
          $LooseFilesPath = "$env:ARTIFACTS_BASE\loose"

          ### Sign executable image
          & (Resolve-Path "Microsoft.Windows.SDK.BuildTools.*\bin\*\x64\signtool.exe") sign /v /fd SHA256 /td SHA256 /tr http://timestamp.acs.microsoft.com /dlib "acs\bin\x64\Azure.CodeSigning.Dlib.dll" /dmdf "acs\metadata.json" "$LooseFilesPath\EarTrumpet.exe"

          ### Package for release
          Compress-Archive -Path "$LooseFilesPath\*" -DestinationPath "$env:ARTIFACTS_BASE\chocolatey\tools\release.zip" -CompressionLevel Optimal

      - name: Adjust nuspec
        if: matrix.channel == 'Chocolatey'
        shell: pwsh
        run: |
          $MetadataPath = "$env:ARTIFACTS_BASE\metadata"
          $Version = [Version](Get-Content "$MetadataPath\Chocolatey.version.txt")
          $NuspecPath = "$env:ARTIFACTS_BASE\chocolatey\eartrumpet.nuspec"

          $nuspec = [xml](Get-Content -Path $NuspecPath)
          $nuspec.package.metadata.version = $Version
          $nuspec.Save($NuspecPath)

      - name: Create chocolatey package
        if: matrix.channel == 'Chocolatey'
        shell: powershell
        run: |
          choco pack "$env:ARTIFACTS_BASE\chocolatey\eartrumpet.nuspec" --out "$env:ARTIFACTS_BASE\chocolatey"

      - name: Upload chocolatey artifact
        if: matrix.channel == 'Chocolatey'
        uses: actions/upload-artifact@v3
        with:
          name: chocolatey-package
          path: artifacts/chocolatey/*.nupkg

      - name: Install OpenSSH FOD
        if: matrix.channel == 'AppInstaller' || matrix.channel == 'Store'
        shell: powershell
        run: |
          Set-Service -Name wuauserv -StartupType Manual
          Start-Service -Name wuauserv
          Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

      - name: Prepare for staging
        if: matrix.channel == 'AppInstaller' || matrix.channel == 'Store'
        shell: powershell
        run: |
          "${{ secrets.staging_userkey }}" | Out-File -Encoding ascii staging.key | Out-Null

      - name: Stage AppInstaller artifacts via SCP
        if: matrix.channel == 'AppInstaller'
        shell: pwsh
        run: |
          icacls .\staging.key /inheritance:r
          icacls .\staging.key /grant:r "$env:USERNAME`:(R)"
          $Branch = Get-Content $env:ARTIFACTS_BASE\metadata\branch.txt
          ssh -i staging.key -o "StrictHostKeyChecking no" ${{ secrets.staging_username }}@${{ secrets.staging_host }} "mkdir -p /var/www/html/$Branch"
          scp -B -i staging.key -o "StrictHostKeyChecking no" $env:ARTIFACTS_BASE\sideload\signed\bundle\* ${{ secrets.staging_username }}@${{ secrets.staging_host }}:/var/www/html/$Branch
          del staging.key

      - name: Stage Store artifacts via SCP
        if: matrix.channel == 'Store'
        shell: pwsh
        run: |
          icacls .\staging.key /inheritance:r
          icacls .\staging.key /grant:r "$env:USERNAME`:(R)"
          $Branch = Get-Content $env:ARTIFACTS_BASE\metadata\branch.txt
          ssh -i staging.key -o "StrictHostKeyChecking no" ${{ secrets.staging_username }}@${{ secrets.staging_host }} "mkdir -p /var/www/html/store/$Branch"
          scp -B -i staging.key -o "StrictHostKeyChecking no" $env:ARTIFACTS_BASE\signed\appxupload\* ${{ secrets.staging_username }}@${{ secrets.staging_host }}:/var/www/html/store/$Branch
          del staging.key

      - name: Push release to Partner Center via StoreBroker
        if: matrix.channel == 'Store'
        shell: powershell
        run: |
          Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted
          Install-Module -Name StoreBroker

          $Password = ConvertTo-SecureString '${{ secrets.partnercenter_clientkey }}' -AsPlainText -Force
          $Credentials = New-Object System.Management.Automation.PSCredential ('${{ secrets.partnercenter_clientid }}', $Password)
          Set-StoreBrokerAuthentication -TenantId '${{ secrets.partnercenter_tenantid }}' -Credential $Credentials -Verbose

          $MetadataPath = "$env:ARTIFACTS_BASE\metadata"
          $PackagingRoot = "$MetadataPath\Packaging\MicrosoftStore"
          $SubmissionRoot = "$env:TEMP\Packaging\Submission"
          $Version = [Version](Get-Content "$MetadataPath\Store.version.txt")
          $StoreBundleFilename = "EarTrumpet.Package_${Version}_x86_bundle.appxupload"

          New-SubmissionPackage -ConfigPath "$PackagingRoot\SBConfig.json" -PDPRootPath "$PackagingRoot\PDPs" -ImagesRootPath "$PackagingRoot\PDPs" -AppxPath "$env:ARTIFACTS_BASE\Signed\AppxUpload\$StoreBundleFilename" -MediaFallbackLanguage en-US -OutPath "$SubmissionRoot" -OutName EarTrumpet -Verbose
          $submissionId, $submissionUrl = Update-ApplicationSubmission -AppId "${{ secrets.partnercenter_appid }}" -SubmissionDataPath "$SubmissionRoot\EarTrumpet.json" -PackagePath "$SubmissionRoot\EarTrumpet.zip" -AddPackages -UpdateListings -UpdatePublishModeAndVisibility -UpdatePricingAndAvailability -UpdateAppProperties -UpdateNotesForCertification -TargetPublishMode Manual -Force -Verbose
          Complete-ApplicationSubmission -AppId "${{ secrets.partnercenter_appid }}" -SubmissionId $submissionId -Verbose


================================================
FILE: .github/workflows/sponsors.yml
================================================
name: Generate Sponsors
on:
  workflow_dispatch:
  schedule:
    - cron: 0 12 1-31 * *
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Generate Sponsors
        uses: JamesIves/github-sponsors-readme-action@v1
        with:
          token: ${{ secrets.SPONSORS_PAT }}
          file: 'README.md'
          organization: true
          template: '<a href="https://github.com/{{{ login }}}"><img src="https://github.com/{{{ login }}}.png" width="60px" alt="{{{ name }}}" title="{{{ name }}}" /></a> '

      - name: Deploy to GitHub Pages
        uses: JamesIves/github-pages-deploy-action@v4
        with:
          branch: master
          folder: '.'


================================================
FILE: .github/workflows/translators.yml
================================================
name: Update Translators List

on:
  schedule:
    - cron: '0 0 * * 0' # Run weekly on Sunday at 00:00
  workflow_dispatch:

jobs:
  update-translators:
    runs-on: windows-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Update README.md
        shell: pwsh
        run: |
          $headers = @{
            "Authorization" = "Bearer ${{ secrets.CROWDIN_API_TOKEN }}"
          }

          $response = Invoke-RestMethod `
            -Uri "https://api.crowdin.com/api/v2/projects/407880/members" `
            -Headers $headers
          $translators = $response.data.data

          $html = ($translators | Sort-Object -Property @{Expression={ $_.fullName }}, @{Expression={ $_.username }} | ForEach-Object {
              $translator = $_
              $translatorName = if ($translator.fullName) { $translator.fullName } else { $translator.username }
              $avatarUrl = $translator.avatarUrl
              "<img src=`"$avatarUrl`" width=`"60`" alt=`"$translatorName`" title=`"$translatorName`" />"
          }) -join " "
          $html = "<!-- begin-translators -->`n$html`n<!-- end-translators -->"

          $readmeContent = Get-Content -Path .\README.md -Raw
          $readmeContent -match "(?<sof>[\s\S]*?)<!-- begin-translators -->[\s\S]*?<!-- end-translators -->(?<eof>[\s\S]*)"
          $readmeContent = $matches["sof"] + $html + $matches["eof"]

          Set-Content -Path .\README.md -Value $readmeContent

      - name: Commit changes
        run: |
          git config --local user.email "action@github.com"
          git config --local user.name "GitHub Action"
          git add README.md
          git commit -m "Update translators via GitHub Actions" || exit 0
          git push origin master


================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.

# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/

# Visual Studo 2015 cache/options directory
.vs/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUNIT
*.VisualState.xml
TestResult.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile

# Visual Studio profiler
*.psess
*.vsp
*.vspx

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# JustCode is a .NET coding addin-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# NCrunch
_NCrunch_*
.*crunch*.local.xml

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings 
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# NuGet Packages
#*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
#!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config

# Windows Azure Build Output
csx/
*.build.csdef

# Windows Store app package directory
AppPackages/

# Others
*.[Cc]ache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm

# SQL Server files
*.mdf
*.ldf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings

# Microsoft Fakes
FakesAssemblies/

# Node.js Tools for Visual Studio
.ntvs_analysis.dat

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio databases
*.VC.db
*.VC.VC.opendb
*.vs15.VC.db
*.vs15.VC.VC.opendb

*.lastcodeanalysissucceeded
*.CodeAnalysisLog.xml
*.filters

# Auto-generated files
BundleArtifacts/
_pkginfo.txt

# Choco
.chocolatey/*.nupkg
.chocolatey/tools/Release.zip
/artifacts/sideload
/Tools


================================================
FILE: CHANGELOG.md
================================================
# Changelog

## 2.3.0.0
- Added setting to turn on/off ability to change volume with the scroll wheel anywhere (thanks @Tester798!)
- Added setting to turn on/off ability to change volume with the scroll wheel when hovering over the EarTrumpet icon (thanks @Tester798!)
- Added new community settings area
- Added new community setting to turn on/off use of a logarithmic volume scale (thanks @yonatan-mitmit!)
- Added legacy shortcuts to the context menu pointing to [App volume and device preferences] / [Volume mixer]
- Added ability to use the Windows key in shortcuts (thanks @iamevn!)
- Added linguistic display name sorting for audio devices (thanks @Tester798!)
- Added a workaround for Windows Search (CortanaUI) showing a default asset (X) icon
- Fixed an issue where installation of EarTrumpet via AppInstaller would fail if the Visual C++ libs package was not installed
- Fixed an issue where EarTrumpet tooltips were not updating live while scrolling the mouse wheel on Windows 10 (thanks @krlvm!)
- Forced EarTrumpet to render in software-only mode to keep it off power hungry GPUs.
- Improved the flyout animation (thanks @krlvm!)

## 2.2.2.0
- Fixed an issue with the volume changing when scrolling in certain scenarios (e.g. virtual reality)
- Updated Japanese translations
- Cleaned up old language resources

## 2.2.1.0
- Fixed touch context menu behavior on Windows 11 machines with future "ShyTaskbar" enabled
- Fixed appearance of flyout on Windows 10 with light mode enabled (thanks @xmha97)
- Fixed flyout animation not respecting correct system settings on Windows 10 and Windows 11
- Upgraded GIF playback library to reduce memory usage (thanks @rocksdanister)
- Reduced use of a workaround for Acrylic slowdowns for most builds of Windows (thanks @krlvm)
- Updated translations from Crowdin contributors
- Updated Microsoft Store Product Detail Page metadata to correct localization issues

## 2.2.0.0
- Added hotkeys to control volume of multiple devices at once (thanks @Taknok!)
- Adjusted how application data is stored to increase reliability
- Fixed crash that could occur when the flyout Acrylic was toggled on/off in certain scenarios
- Fixed an issue with the expanded flyout becoming too tall on Windows 11
- Updated Japanese, Greek, Croatian, and Russian translations (thank you Crowdin contributors!)

## 2.1.10.0
- Flyout now remembers if it was expanded/collapsed between launches (thanks @Tester798!)
- Fixed an issue with the flyout open animation behaving erratically with some mice
- Fixed an issue where devices without certain characteristics would interfere with mute and other actions
- Fixed an issue with device names not appearing correctly if they contained underscores
- Fixed an issue with the flyout opening outside the working area in additional cases
- Adjusted the flyout position from the edge of the screen to match Windows 11 look and feel
- Removed solid color plating behind application icons
- Updated Finnish, German, and other translations

## 2.1.9.0
- Added basic support for Windows 11
- Added/updated Italian, Hungarian, Spanish, Portuguese, Turkish, Chinese, Norwegian, Arabic, Czech, Polish, Swedish, Romanian, and Russian translations
- Fixed an issue with the flyout opening outside the working area
- Fixed an issue with slow window movement when dragging

## 2.1.8.0
- Added Hungarian, Swedish, Korean, and Tamil translations
- Updated Japanese translations
- Added a fluent icon
- Fixed an issue with missing Czech and Afrikaans translations 
- Fixed an issue with icons not appearing for packaged desktop applications (e.g. Microsoft Flight Simulator)
- Fixed an issue with the [Windows Legacy > Sound settings] menu item opening the wrong panel
- Fixed an issue with notification area icon handling
- Fixed an issue that prevented the use of system keys in keyboard shortcuts

## 2.1.7.0
- Fixed crash when retrieving region info for GDPR compliance on some machines

## 2.1.6.0
- Added ability to turn on/off crash reporting
- Added missing translations
- Added privacy policy link
- Fixed an icon display issue with libmpv-based apps (e.g. Plex)
- Fixed an issue that made volume sliders difficult to manipulate with a mouse at high DPI
- Restored pre-2.1.2.0 tray icon behavior until we can address icon duplication issues

## 2.1.5.0
- Fixed an issue with line in icon not appearing
- Fixed an issue with context menu submenus disappearing unexpectedly

## 2.1.4.0
- Fixed various bugs with the search textbox in Settings
- Fixed tray icon disappearing when the Windows Shell crashes/restarts
- Fixed master volume slider dimming on mute
- Fixed flyout track color in light theme
- Fixed mute icon when at zero volume
- Added mixer window width constraints when a high number of audio devices are present
- Added Slovenian language support
- Added hover states to buttons
- Additional crash bugfixes

## 2.1.3.0
- Fixed a crash causing EarTrumpet disappear on startup
- Fixed various potential leaks
- Added a help dialog to assist when EarTrumpet can't start due to broken fonts

## 2.1.2.0
- Fixed icon handle leak that caused a crash
- Fixed hotkeys not being properly unregistered
- Fixed arrow keys changing the default device volume
- Fixed High Contrast theme colors
- Fixed settings window covering the Taskbar when maximized
- Tray icon should remain in place after updates going forward
- Tray and app icons will now scale correctly
- Tray icon supports scrolling without opening the flyout
- Removed unwanted metadata from telemetry

## 2.1.1.0
- Fixed a crash when parsing numbers on non-English systems

## 2.1.0.0
- Added new settings experience
- Added support for Windows light mode
- Added keyboard shortcuts for opening the mixer and settings windows
- Reduced clutter in the context menu
- Fixed various display issues when using RTL writing systems
- Changed app naming behavior to align with Windows
- Added mute text to the notification area icon
- Added 'Open sound settings' link to context menu
- Added text to notification area icon tooltip to indicate mute state
- Re-added flyout window shadow and borders
- Added additional telemetry points
- Removed Arabic, Hungarian, Korean, Norwegian Bokm�l, Portuguese, Romanian, and Turkish until we complete localization
- Additional bugfixes

## 2.0.8.0
- Changed grouping behavior to key off app install path vs. executable name
- Disabled flyout window blur when not visible to ensure it doesn't appear in task switcher
- Fixed an issue where the Enhancements tab was missing in playback devices dialog
- Fixed an issue where the flyout was too tall when the taskbar is configured to auto-hide
- Fixed an issue where disabled or unplugged devices would unexpectedly appear
- Fixed a crash when no default audio endpoint was present
- Fixed a crash when right-clicking an audio session after moving it

## 2.0.7.0
- Added additional support for high contrast themes
- Added per-monitor DPI support
- Added internal diagnostic logging buffer limit
- Disabled Alt+Space on the flyout window
- Fixed a rendering issue when the DPI was greater than 100% and there were more devices than would fit in the flyout without a scrollbar
- Fixed a rendering issue where the Notification Area icon becomes blurry at DPIs geater than 100%
- Fixed the icon and name of recording devices in 'Listen' mode
- Fixed Notification Area icon scaling
- Fixed overflow flyout at greater than 100% DPI

## 2.0.6.0
- Fixed an issue that affected localization on non-English systems

## 2.0.5.0
- Fixed System Sounds icon on ARM64
- High Contrast colors updated
- Added collection of debug information when device enumeration fails

## 2.0.4.0
- Scoped the mouse wheel scrolling to only over the Notification Area icon.
- Added support for RS3.
- Fixed a bug that caused the flyout to show 'It doesn't look like you have any playback devices.' when removing the default device.
- Fixed a crash during adding/removing devices.
- Removed non-fatal errors from telemetry.

## 2.0.3.0
- Fixed an issue with certain apps (e.g. Sea of Thieves) not appearing correctly
- Added additional languages (Arabic, Spanish, Hungarian, Korean, Turkish, and Ukrainian)

## 2.0.2.0
- Changes to telemetry 

## 2.0.1.0
- Fixed a crash when a device is quickly added/removed
- Fixed a crash with multi-process audio sessions
- Fixed a crash launching web links
- Fixed a crash when closing EarTrumpet windows
- Fixed a crash when expanding/collapsing the main window
- Fixed a crash when Taskbar auto-hide is in use
- Fixed a crash when the registry has invalid personalization data
- Fixed a crash when calling application data storage APIs

## 2.0.0.0
- Added middle click on notification area icon to mute
- Added ability to use mouse wheel to change device volume when window is open
- Added multi-channel peak metering
- Added ability to move apps between devices
- Added ability to view multiple devices
- Added volume mixer window
- Enhanced app session grouping
- Enhanced keyboarding
- Added keyboard shortcut to open flyout
- Added support for Windows light/dark mode
- Added Sounds, Recording, etc. links to context menu
- Enhanced animations and detail work
- Additional fixes for RTL, Accessibility, and apps without icons

## 1.5.3.0
- Improved slider performance
- Fixed Acrylic Blur compatibility for Windows 10 1803

## 1.5.2.0

## 1.5.1.0

## 1.5.0.0

## 1.4.4.0

## 1.4.3.0

## 1.4.2.0

## 1.4.1.0

## 1.4.0.0

## 1.3.2.0
- Fixed changing audio devices in Windows 10 (RS1)

## 1.3.1.0
- Fixed DWM scaling issue where window appeared in the wrong position
- Fixed UI issues when no audio devices found
- Fixed changing audio devices in Windows 10 (TH1) and Windows 10 November Update (TH2)
- Fixed multiple sessions not appearing for some applications
- Added company metadata for Task Manager

## 1.3.0.0
- Fixed Speech Runtime display
- Fixed positioning when Taskbar auto-hide is enabled
- Installer/uninstaller now checks if the app is running
- Added ability to change default audio device (right-click the tray icon)
- Added ability to mute apps/audio device
- Added default audio device master volume slider

## 1.2.0.0
- Fixed issue with a number of apps not appearing in Ear Trumpet when using background audio services (e.g. iHeartRadio)
- Fixed issue with a number of apps not appearing in Ear Trumpet when playing protected media (e.g. Netflix)
- Fixed issue with apps not showing due to unexpected logo/icon paths (e.g. Skype Translator)
- Added base localization to Ear Trumpet (defaults to English for now - feel free to provide translations as pull requests)

## 1.1.1.0

## 1.1.0.0
- Fixed DPI scaling issue
- Fixed Ear Trumpet not displaying correctly when the Taskbar was in a different location or not on the primary monitor
- Initial fix for modern app missing extracted logo
- Ear Trumpet will now only allow one open instance
- GitHub readme updated with details and minimum versions
- Installer no longer allows installs on Windows versions before Windows 10
- Fixed issue with Windows 10 tablet mode
- Fixed Ear Trumpet window not having the correct border and drop shadow 

## 1.0.0.0
- Initial release


================================================
FILE: COMPILING.md
================================================
# Compiling EarTrumpet

## Requirements
* [Visual Studio 2017](https://visualstudio.microsoft.com/vs/community/) (or newer)
* [Git for Windows](https://git-scm.com/download/win)
* [Windows 10 Anniversary Update](https://blogs.windows.com/windowsexperience/2016/08/02/how-to-get-the-windows-10-anniversary-update/#GD97Eq04wJA7S4P7.97) (or newer)
* [.NET Framework 4.6.2 Developer Pack](https://www.microsoft.com/net/download/thank-you/net462-developer-pack)
* [Windows 10 SDK (10.0.14393.0)](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive)

## Step-by-step
1. Install Visual Studio 2017 with the `.NET desktop development` and `Universal Windows Platform development` workloads. 
2. Install the `Windows 10 SDK (10.0.14393.0)` SDK.
3. Install the .NET Framework 4.6.2 Developer Pack.
4. Install Git for Windows.
5. Clone the EarTrumpet repository (`git clone https://github.com/File-New-Project/EarTrumpet.git`).
6. Open `EarTrumpet.vs15.sln` in Visual Studio.
7. Change the target platform to `x86` and build the `EarTrumpet.Package` project.
8. You're done. If you plan on submitting your changes to us, please review the [Contributing guide](https://github.com/File-New-Project/EarTrumpet/blob/master/CONTRIBUTING.md) first.


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to EarTrumpet
Thanks for your interest in contributing to EarTrumpet!

You can contribute to EarTrumpet with issues and pull requests (PRs). Simply filing issues for problems you encounter is a great way to contribute. Contributing code via the below workflow is greatly appreciated.

## Copyright

EarTrumpet copyright is held by "Rafael Rivera, David Golden, David "Dave" Amenta, and Contributors".

## Contribution Workflow

Before contributing code, we require the following workflow:

1. Create an issue for your work or reuse an existing issue on the topic, if there is one.

2. Get agreement from the team that your proposed change is OK. (You can alternatively email the `team@eartrumpet.app`.)

3. Clearly state that you are going to take on the bug/enhancement work and we will assign the task to you.

4. Create a fork of the repository on GitHub (if you don't already have one).

5. Create a branch from **dev** (`git checkout -b mybranch dev`).

6. Name the branch so that it clearly communicates your intentions, such as issue-123 or feature-456.

7. Build the repository with your changes. Make sure that the builds are clean in all configurations (i.e. `Debug`, `Release`, and `VSDebug`).

8. Commit and push your changes to your fork.

9. Create a pull request (PR) against our **dev** branch.

    ℹ It is OK for your PR to include a large number of commits. We will squash them on merge.

    ℹ It is also OK to create your PR as "[WIP]" before the implementation is done. This can be useful if you'd like to start the feedback process while you finish your implementation. State that this is the case in the initial PR comment.

================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/AddonResources.xaml
================================================
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:Event="clr-namespace:EarTrumpet.Extensions.EventBinding"
                    xmlns:Theme="clr-namespace:EarTrumpet.UI.Themes"
                    xmlns:conv="clr-namespace:EarTrumpet.UI.Converters"
                    xmlns:ctl="clr-namespace:EarTrumpet.UI.Controls"
                    xmlns:etctl="clr-namespace:EarTrumpet.Actions.Controls"
                    xmlns:etvm="clr-namespace:EarTrumpet.UI.ViewModels"
                    xmlns:resx="clr-namespace:EarTrumpet.Properties"
                    xmlns:ui="clr-namespace:EarTrumpet.UI"
                    xmlns:vm="clr-namespace:EarTrumpet.Actions.ViewModel">
    <Style x:Key="RunStyle" TargetType="Run">
        <Setter Property="FontSize" Value="15" />
        <Setter Property="Theme:Brush.Foreground" Value="Text" />
    </Style>
    <Style x:Key="ThinListStyle"
           BasedOn="{StaticResource {x:Type ListView}}"
           TargetType="{x:Type ListView}">
        <Setter Property="Margin" Value="0,0,24,0" />
    </Style>
    <Style x:Key="HyperlinkStyle"
           BasedOn="{StaticResource {x:Type Hyperlink}}"
           TargetType="{x:Type Hyperlink}">
        <Setter Property="TextDecorations">
            <Setter.Value>
                <TextDecorationCollection>
                    <TextDecoration Location="Underline" PenOffset="3" />
                </TextDecorationCollection>
            </Setter.Value>
        </Setter>
    </Style>
    <DataTemplate DataType="{x:Type vm:EarTrumpetActionPageHeaderViewModel}">
        <Border BorderBrush="Transparent" BorderThickness="0">
            <Grid Height="64">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>
                <TextBox Name="txtHeader"
                         MinWidth="200"
                         Margin="12,0,6,0"
                         HorizontalAlignment="Left"
                         VerticalAlignment="Bottom"
                         HorizontalContentAlignment="Left"
                         FontSize="26"
                         Text="{Binding DisplayName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                    <TextBox.Style>
                        <Style BasedOn="{StaticResource {x:Type TextBox}}" TargetType="TextBox">
                            <Setter Property="Theme:Brush.BorderBrush" Value="Transparent" />
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding IsEditClicked}" Value="True">
                                    <Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=txtHeader}" />
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </TextBox.Style>
                </TextBox>
                <ItemsControl Name="Toolbar"
                              Grid.Column="1"
                              Margin="0,0,24,0"
                              VerticalAlignment="Bottom"
                              IsTabStop="False"
                              ItemsSource="{Binding Toolbar}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Horizontal" />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemTemplate>
                        <DataTemplate DataType="{x:Type etvm:ToolbarItemViewModel}">
                            <Button VerticalAlignment="Center"
                                    HorizontalContentAlignment="Stretch"
                                    AutomationProperties.Name="{Binding DisplayName}"
                                    BorderThickness="0"
                                    Command="{Binding Command}"
                                    ToolTipService.ToolTip="{Binding DisplayName}">
                                <Button.Style>
                                    <Style BasedOn="{StaticResource ToolbarButtonStyle}" TargetType="Button">
                                        <Style.Triggers>
                                            <MultiDataTrigger>
                                                <MultiDataTrigger.Conditions>
                                                    <Condition Binding="{Binding Id}" Value="Save" />
                                                    <Condition Binding="{Binding ElementName=Toolbar, Path=DataContext.IsWorkSaved}" Value="True" />
                                                </MultiDataTrigger.Conditions>
                                                <MultiDataTrigger.Setters>
                                                    <Setter Property="IsEnabled" Value="False" />
                                                </MultiDataTrigger.Setters>
                                            </MultiDataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                </Button.Style>
                                <TextBlock FontSize="{Binding GlyphFontSize}" Text="{Binding Glyph}">
                                    <TextBlock.Style>
                                        <Style BasedOn="{StaticResource GlyphTextBlockStyle}" TargetType="TextBlock">
                                            <Style.Triggers>
                                                <MultiDataTrigger>
                                                    <MultiDataTrigger.Conditions>
                                                        <Condition Binding="{Binding Id}" Value="Save" />
                                                        <Condition Binding="{Binding ElementName=Toolbar, Path=DataContext.IsWorkSaved}" Value="False" />
                                                    </MultiDataTrigger.Conditions>
                                                    <MultiDataTrigger.Setters>
                                                        <Setter Property="Theme:Brush.Foreground" Value="SystemAccent" />
                                                    </MultiDataTrigger.Setters>
                                                </MultiDataTrigger>
                                            </Style.Triggers>
                                        </Style>
                                    </TextBlock.Style>
                                </TextBlock>
                            </Button>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </Grid>

        </Border>
    </DataTemplate>
    <DataTemplate x:Key="PartListItemTemplate" DataType="vm:PartViewModel">
        <Grid Margin="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>

            <Border Margin="0"
                    VerticalAlignment="Center"
                    ClipToBounds="True">
                <!--  The negative bottom margin below achieves vertical alignment along with LineStackingStrategy=MaxHeight and ClipTobounds on the parent  -->
                <etctl:LinkedTextBlock Margin="0,0,0,-8"
                                       Padding="12,14"
                                       HorizontalAlignment="Left"
                                       VerticalAlignment="Center"
                                       DataItem="{Binding}"
                                       FormatText="{Binding LinkText}"
                                       HyperlinkStyle="{DynamicResource HyperlinkStyle}"
                                       LineHeight="30"
                                       LineStackingStrategy="MaxHeight"
                                       RunStyle="{DynamicResource RunStyle}"
                                       TextWrapping="Wrap">
                    <etctl:LinkedTextBlock.ContextMenu2>
                        <ContextMenu Theme:Options.Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Theme:Options.Source)}"
                                     ItemContainerTemplateSelector="{StaticResource MenuSelector}"
                                     Placement="Mouse"
                                     UsesItemContainerTemplate="True" />
                    </etctl:LinkedTextBlock.ContextMenu2>
                    <etctl:LinkedTextBlock.Popup>
                        <Popup Width="260"
                               Theme:Options.Source="App"
                               AllowsTransparency="False"
                               FocusVisualStyle="{x:Null}"
                               Focusable="False"
                               Placement="Mouse"
                               PopupAnimation="None"
                               StaysOpen="False"
                               TextOptions.TextFormattingMode="Display"
                               UseLayoutRounding="True">
                            <Popup.Style>
                                <Style TargetType="Popup">
                                    <Style.Triggers>
                                        <Trigger Property="IsOpen" Value="False">
                                            <Setter Property="Visibility" Value="Collapsed" />
                                        </Trigger>
                                    </Style.Triggers>
                                </Style>
                            </Popup.Style>

                            <Border x:Name="SubmenuBorder"
                                    Theme:Brush.Background="Theme={Theme}ChromeMediumLow, HighContrast=Menu"
                                    Theme:Brush.BorderBrush="Light=LightChromeHigh, Dark=ControlDarkAppButtonTextDisabled/0.9, HighContrast=ControlText"
                                    BorderThickness="1"
                                    SnapsToDevicePixels="True">
                                <ContentControl Theme:Brush.Foreground="Theme=Text" Content="{Binding}" />
                            </Border>
                        </Popup>
                    </etctl:LinkedTextBlock.Popup>
                </etctl:LinkedTextBlock>
            </Border>
            <Button Grid.Column="1"
                    HorizontalAlignment="Right"
                    VerticalAlignment="Center"
                    AutomationProperties.Name="{x:Static resx:Resources.RemoveButtonAccessibleName}"
                    Command="{Binding Remove}"
                    CommandParameter="{Binding}"
                    Style="{StaticResource ToolbarButtonStyle}">
                <TextBlock FontSize="14"
                           Style="{StaticResource GlyphTextBlockStyle}"
                           Text="&#xE107;" />
            </Button>
            <TextBlock Margin="12,-10,0,0"
                       VerticalAlignment="Top"
                       Theme:Brush.Foreground="GrayText"
                       FontSize="14"
                       IsHitTestVisible="False"
                       Text="{Binding AdditionalText}" />
        </Grid>
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:ImportExportPageViewModel}">
        <StackPanel Orientation="Vertical">
            <TextBlock Style="{DynamicResource HeadingText}" Text="{x:Static resx:Resources.ExportHeaderText}" />
            <TextBlock Style="{DynamicResource BodyText}" Text="{x:Static resx:Resources.ExportHelpText}" />
            <Button HorizontalAlignment="Left"
                    Command="{Binding Export}"
                    Content="{x:Static resx:Resources.ExportHeaderText}" />
            <TextBlock Style="{DynamicResource HeadingText}" Text="{x:Static resx:Resources.ImportHeaderText}" />
            <TextBlock Style="{DynamicResource BodyText}" Text="{x:Static resx:Resources.ImportHelpText}" />
            <Button HorizontalAlignment="Left"
                    Command="{Binding Import}"
                    Content="{x:Static resx:Resources.ImportHeaderText}" />
        </StackPanel>
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:EarTrumpetActionViewModel}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>

            <TextBlock Grid.Row="1"
                       Style="{DynamicResource HeadingText}"
                       Text="{x:Static resx:Resources.TriggerVerbText}" />
            <ListView Grid.Row="2"
                      IsSynchronizedWithCurrentItem="True"
                      ItemTemplate="{DynamicResource PartListItemTemplate}"
                      ItemsSource="{Binding Triggers}"
                      Style="{DynamicResource ThinListStyle}" />
            <etctl:MenuButton Grid.Row="3"
                              HorizontalAlignment="Stretch"
                              Content="{x:Static resx:Resources.AddTriggerText}"
                              PreviewMouseRightButtonUp="{Event:HandledBinding}"
                              Style="{DynamicResource AddButtonStyle}">
                <etctl:MenuButton.ContextMenu>
                    <ContextMenu Theme:Options.Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Theme:Options.Source)}"
                                 ItemContainerTemplateSelector="{DynamicResource MenuSelector}"
                                 ItemsSource="{Binding NewTriggers}"
                                 UsesItemContainerTemplate="True" />
                </etctl:MenuButton.ContextMenu>
            </etctl:MenuButton>

            <TextBlock Grid.Row="4"
                       Style="{DynamicResource HeadingText}"
                       Text="{x:Static resx:Resources.ActionVerbText}" />
            <ListView Grid.Row="5"
                      IsSynchronizedWithCurrentItem="True"
                      ItemTemplate="{DynamicResource PartListItemTemplate}"
                      ItemsSource="{Binding Actions}"
                      Style="{DynamicResource ThinListStyle}" />
            <etctl:MenuButton Grid.Row="6"
                              HorizontalAlignment="Stretch"
                              Content="{x:Static resx:Resources.AddActionText}"
                              PreviewMouseRightButtonUp="{Event:HandledBinding}"
                              Style="{DynamicResource AddButtonStyle}">
                <etctl:MenuButton.ContextMenu>
                    <ContextMenu Theme:Options.Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Theme:Options.Source)}"
                                 ItemContainerTemplateSelector="{DynamicResource MenuSelector}"
                                 ItemsSource="{Binding NewActions}"
                                 UsesItemContainerTemplate="True" />
                </etctl:MenuButton.ContextMenu>
            </etctl:MenuButton>

            <Grid Grid.Row="7">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>

                <TextBlock Style="{DynamicResource HeadingText}" Text="{x:Static resx:Resources.ConditionVerbText}" />
                <TextBlock Grid.Row="1"
                           Style="{DynamicResource BodyText}"
                           Text="{x:Static resx:Resources.ConditionsHelpText}" />

                <ListView Grid.Row="2"
                          IsSynchronizedWithCurrentItem="True"
                          ItemTemplate="{DynamicResource PartListItemTemplate}"
                          ItemsSource="{Binding Conditions}"
                          Style="{DynamicResource ThinListStyle}" />

                <etctl:MenuButton Grid.Row="3"
                                  HorizontalAlignment="Stretch"
                                  Content="{x:Static resx:Resources.AddConditionText}"
                                  PreviewMouseRightButtonUp="{Event:HandledBinding}"
                                  Style="{DynamicResource AddButtonStyle}">
                    <etctl:MenuButton.ContextMenu>
                        <ContextMenu Theme:Options.Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Theme:Options.Source)}"
                                     ItemContainerTemplateSelector="{DynamicResource MenuSelector}"
                                     ItemsSource="{Binding NewConditions}"
                                     UsesItemContainerTemplate="True" />
                    </etctl:MenuButton.ContextMenu>
                </etctl:MenuButton>

                <TextBlock Grid.Row="4"
                           Style="{DynamicResource HeadingText}"
                           Text="{x:Static resx:Resources.RemoveActionHeadingText}" />
                <TextBlock Grid.Row="5"
                           Style="{DynamicResource BodyText}"
                           Text="{x:Static resx:Resources.RemoveActionDescriptionText}" />
                <Button Grid.Row="6"
                        Command="{Binding Delete}"
                        Content="{x:Static resx:Resources.RemoveActionButtonText}" />
            </Grid>
        </Grid>
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:VolumeViewModel}">

        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="{DynamicResource Mutable_VolumeCellWidth}" />
            </Grid.ColumnDefinitions>
            <ctl:VolumeSlider Margin="12"
                              Maximum="100"
                              Minimum="0"
                              Style="{DynamicResource {x:Type Slider}}"
                              Value="{Binding Volume, Mode=TwoWay}" />
            <TextBlock Grid.Column="1"
                       Style="{StaticResource AppVolumeTextStyle}"
                       Text="{Binding Volume, Mode=OneWay}" />
        </Grid>
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:HotkeyViewModel}">
        <ContentControl Content="{Binding Hotkey}" IsTabStop="False" />
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:TextViewModel}">
        <Grid Margin="12">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <TextBlock Text="{Binding PromptText}" />
            <TextBox Grid.Row="1" Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </Grid>
    </DataTemplate>

    <DataTemplate DataType="{x:Type vm:DefaultPlaybackDeviceViewModel}">
        <Grid Margin="6">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <Border Grid.RowSpan="2"
                    Width="32"
                    Height="32"
                    Margin="12,0"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center">
                <TextBlock FontSize="20"
                           Style="{StaticResource GlyphTextBlockStyle}"
                           Text="&#xEC61;" />
            </Border>
            <TextBlock Grid.Column="1"
                       HorizontalAlignment="Left"
                       VerticalAlignment="Center"
                       Text="{Binding DisplayName}" />
            <TextBlock Grid.Row="2"
                       Grid.Column="1"
                       HorizontalAlignment="Left"
                       VerticalAlignment="Center"
                       Opacity="0.5"
                       Text="{Binding InterfaceName}" />
        </Grid>
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:DeviceViewModel}">
        <Grid Margin="6">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <ctl:ImageEx Grid.RowSpan="3"
                         Width="32"
                         Height="32"
                         Margin="12,0"
                         HorizontalAlignment="Center"
                         VerticalAlignment="Center"
                         SourceEx="{Binding}" />

            <TextBlock Grid.Column="1"
                       HorizontalAlignment="Left"
                       VerticalAlignment="Center"
                       Text="{Binding DeviceDescription}" />
            <TextBlock Grid.Row="2"
                       Grid.Column="1"
                       HorizontalAlignment="Left"
                       VerticalAlignment="Center"
                       Opacity="0.5"
                       Text="{Binding InterfaceName}" />
        </Grid>
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:DeviceListViewModel}">
        <Grid>
            <Grid.Resources>
                <CollectionViewSource x:Key="cvs"
                                      IsLiveGroupingRequested="True"
                                      Source="{Binding All}">
                    <CollectionViewSource.GroupDescriptions>
                        <PropertyGroupDescription PropertyName="GroupName" />
                    </CollectionViewSource.GroupDescriptions>
                </CollectionViewSource>
            </Grid.Resources>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <TextBlock Margin="12"
                       Style="{StaticResource HeadingText}"
                       Text="{x:Static resx:Resources.ChooseADeviceTitle}" />

            <ctl:ListView Grid.Row="1"
                          MaxHeight="300"
                          ItemContainerStyle="{DynamicResource HoverListItemStyle}"
                          ItemInvoked="{Event:Binding OnInvoked}"
                          ItemsSource="{Binding Source={StaticResource cvs}}">
                <ListView.Style>
                    <Style BasedOn="{StaticResource {x:Type ListView}}" TargetType="ListView">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="ListView">
                                    <Border Background="{TemplateBinding Background}">
                                        <ScrollViewer Padding="{TemplateBinding Padding}" Focusable="false">
                                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                                        </ScrollViewer>
                                    </Border>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </ListView.Style>
                <ListView.GroupStyle>
                    <GroupStyle>
                        <GroupStyle.HeaderTemplate>
                            <DataTemplate>
                                <TextBlock Margin="16,12,0,6"
                                           Theme:Brush.Foreground="GrayText"
                                           FontSize="15"
                                           Text="{Binding Name}">
                                    <TextBlock.Style>
                                        <Style TargetType="TextBlock">
                                            <Style.Triggers>
                                                <DataTrigger Binding="{Binding Name}" Value="{x:Null}">
                                                    <Setter Property="Visibility" Value="Collapsed" />
                                                </DataTrigger>
                                            </Style.Triggers>
                                        </Style>
                                    </TextBlock.Style>
                                </TextBlock>
                            </DataTemplate>
                        </GroupStyle.HeaderTemplate>
                    </GroupStyle>
                </ListView.GroupStyle>
            </ctl:ListView>
        </Grid>

    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:ForegroundAppViewModel}">
        <Grid Margin="6">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <Grid Width="{DynamicResource Mutable_AppIconSize}"
                  Height="{DynamicResource Mutable_AppIconSize}"
                  HorizontalAlignment="Center"
                  VerticalAlignment="Center">
                <TextBlock Theme:Brush.Foreground="SystemAccentLight2"
                           FontSize="18"
                           Style="{StaticResource GlyphTextBlockStyle}"
                           Text="&#xF5EE;" />
                <TextBlock FontSize="18"
                           Style="{StaticResource GlyphTextBlockStyle}"
                           Text="&#xF5ED;" />
            </Grid>
            <TextBlock Grid.Column="1"
                       Margin="12,2"
                       HorizontalAlignment="Left"
                       VerticalAlignment="Center"
                       Text="{x:Static resx:Resources.ForegroundAppText}" />
        </Grid>
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:EveryAppViewModel}">
        <Grid Margin="6">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Border Width="{DynamicResource Mutable_AppIconSize}"
                    Height="{DynamicResource Mutable_AppIconSize}"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center">
                <TextBlock FontSize="18"
                           Style="{StaticResource GlyphTextBlockStyle}"
                           Text="&#xE71D;" />
            </Border>

            <TextBlock Grid.Column="1"
                       Margin="12,2"
                       HorizontalAlignment="Left"
                       VerticalAlignment="Center"
                       Text="{x:Static resx:Resources.EveryAppText}" />
        </Grid>
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:AppListViewModel}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <TextBlock Margin="12"
                       Style="{StaticResource HeadingText}"
                       Text="{x:Static resx:Resources.ChooseAnAppTitle}" />
            <ctl:ListView Grid.Row="1"
                          MaxHeight="300"
                          ItemContainerStyle="{DynamicResource HoverListItemStyle}"
                          ItemInvoked="{Event:Binding OnInvoked}"
                          ItemsSource="{Binding All}">
                <ListView.Style>
                    <Style BasedOn="{StaticResource {x:Type ListView}}" TargetType="ListView">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="ListView">
                                    <Border Background="{TemplateBinding Background}">
                                        <ScrollViewer Padding="{TemplateBinding Padding}" Focusable="false">
                                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                                        </ScrollViewer>
                                    </Border>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </ListView.Style>
            </ctl:ListView>
            <TextBlock Grid.Row="2"
                       Margin="12"
                       Style="{StaticResource BodyText}"
                       Text="{x:Static resx:Resources.ChooseAnAppHelpText}" />
        </Grid>
    </DataTemplate>
</ResourceDictionary>

================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/Controls/LinkedTextBlock.cs
================================================
using EarTrumpet.Extensions;
using EarTrumpet.UI.Helpers;
using EarTrumpet.UI.ViewModels;
using EarTrumpet.Actions.ViewModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;

namespace EarTrumpet.Actions.Controls
{
    public class LinkedTextBlock : TextBlock
    {
        public Popup Popup
        {
            get { return (Popup)this.GetValue(PopupProperty); }
            set { this.SetValue(PopupProperty, value); }
        }
        public static readonly DependencyProperty PopupProperty = DependencyProperty.Register(
          "Popup", typeof(Popup), typeof(LinkedTextBlock), new PropertyMetadata(null));

        // We avoid ContextMenu because something external connects it to right-click behavior that (seemingly) can't be prevented.
        public ContextMenu ContextMenu2
        {
            get { return (ContextMenu)this.GetValue(ContextMenuProperty2); }
            set { this.SetValue(ContextMenuProperty2, value); }
        }
        public static readonly DependencyProperty ContextMenuProperty2 = DependencyProperty.Register(
          "ContextMenu2", typeof(ContextMenu), typeof(LinkedTextBlock), new PropertyMetadata(null));

        public object DataItem
        {
            get { return (object)this.GetValue(DataItemProperty); }
            set { this.SetValue(DataItemProperty, value); }
        }
        public static readonly DependencyProperty DataItemProperty = DependencyProperty.Register(
          "DataItem", typeof(object), typeof(LinkedTextBlock), new PropertyMetadata(null, new PropertyChangedCallback(DataItemChanged)));

        private static void DataItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => ((LinkedTextBlock)d).DataItemChanged();

        public string FormatText
        {
            get { return (string)this.GetValue(FormatTextProperty); }
            set { this.SetValue(FormatTextProperty, value); }
        }
        public static readonly DependencyProperty FormatTextProperty = DependencyProperty.Register(
          "FormatText", typeof(string), typeof(LinkedTextBlock), new PropertyMetadata("", new PropertyChangedCallback(FormatTextChanged)));

        private static void FormatTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => ((LinkedTextBlock)d).PropertiesChanged();

        public Style HyperlinkStyle
        {
            get { return (Style)this.GetValue(HyperlinkStyleProperty); }
            set { this.SetValue(HyperlinkStyleProperty, value); }
        }
        public static readonly DependencyProperty HyperlinkStyleProperty = DependencyProperty.Register(
          "HyperlinkStyle", typeof(Style), typeof(LinkedTextBlock), new PropertyMetadata(null, new PropertyChangedCallback(HyperlinkStyleChanged)));

        public Style RunStyle
        {
            get { return (Style)this.GetValue(RunStyleProperty); }
            set { this.SetValue(RunStyleProperty, value); }
        }
        public static readonly DependencyProperty RunStyleProperty = DependencyProperty.Register(
          "RunStyle", typeof(Style), typeof(LinkedTextBlock), new PropertyMetadata(null, new PropertyChangedCallback(RunStyleChanged)));


        private static void HyperlinkStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => ((LinkedTextBlock)d).PropertiesChanged();
        private static void RunStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => ((LinkedTextBlock)d).PropertiesChanged();

        private void DataItemChanged()
        {
            ((INotifyPropertyChanged)DataItem).PropertyChanged += (s, e) => PropertiesChanged();
        }

        private void PropertiesChanged()
        {
            this.Inlines.Clear();

            if (ContextMenu != null && Popup != null)
            {
                ContextMenu.Loaded += ContextMenu_Loaded;
                Popup.Loaded += Popup_Loaded;
            }

            ReadLinksAndText(FormatText, (text, isLink) =>
            {
                text = text.Trim();
                if (!isLink)
                {
                    var run = new Run(text);
                    run.Style = RunStyle;
                    this.Inlines.Add(run);
                }
                else
                {
                    var resolvedPropertyObject = DataItem.GetType().GetProperty(text).GetValue(DataItem, null);
                    var link = new Hyperlink(new Run(resolvedPropertyObject.ToString()));
                    link.NavigateUri = new Uri("about:none");
                    link.Style = HyperlinkStyle;

                    link.RequestNavigate += (s, e) =>
                    {
                        // Take focus now so that we get return focus when the user leaves.
                        link.Focus();
                        var dpiX = Window.GetWindow(this).DpiX();
                        var dpiY = Window.GetWindow(this).DpiY();

                        if (resolvedPropertyObject is IOptionViewModel)
                        {
                            ContextMenu2.Opacity = 0;
                            ContextMenu2.ItemsSource = GetContextMenuFromOptionViewModel((IOptionViewModel)resolvedPropertyObject).OrderBy(menu => menu.DisplayName);
                            ContextMenu2.UpdateLayout();
                            ContextMenu2.IsOpen = true;
                            ContextMenu2.Dispatcher.BeginInvoke((Action)(() =>
                            {
                                ContextMenu2.Opacity = 1;
                                ContextMenu2.HorizontalOffset = -1 * (ContextMenu2.RenderSize.Width / dpiX) / 2;
                                ContextMenu2.VerticalOffset = -1 * (ContextMenu2.RenderSize.Height / dpiY) / 2;
                                ContextMenu2.Focus();
                            }),
                            System.Windows.Threading.DispatcherPriority.DataBind, null);
                        }
                        else
                        {
                            Popup.PreviewKeyDown += (_, ee) =>
                            {
                                if (ee.Key == Key.Escape)
                                {
                                    Popup.IsOpen = false;
                                }
                            };
                            Popup.Opacity = 0;
                            Popup.DataContext = resolvedPropertyObject;
                            Popup.UpdateLayout();
                            Popup.Child.UpdateLayout();
                            Popup.IsOpen = true;
                            Popup.Dispatcher.BeginInvoke((Action)(() =>
                            {
                                Popup.Opacity = 1;
                                Popup.HorizontalOffset = -1 * (Popup.Child.RenderSize.Width / dpiX) / 2;
                                Popup.VerticalOffset = -1 * (Popup.Child.RenderSize.Height / dpiY) / 2;
                                Keyboard.Focus(Popup.Child.FindVisualChild<Control>());
                            }),
                            System.Windows.Threading.DispatcherPriority.DataBind, null);
                        }
                    };
                    this.Inlines.Add(link);
                }
                this.Inlines.Add(new Run(" "));
            });
        }

        private void Popup_Loaded(object sender, RoutedEventArgs e)
        {
            Popup.UpdateLayout();
            Popup.Child.UpdateLayout();
            Popup.HorizontalOffset = -1 * Popup.Child.RenderSize.Width / 2;
            Popup.VerticalOffset = -1 * Popup.Child.RenderSize.Height / 2;
        }

        private void ContextMenu_Loaded(object sender, RoutedEventArgs e)
        {
            ContextMenu2.UpdateLayout();
            ContextMenu2.HorizontalOffset = -1 * ContextMenu2.RenderSize.Width / 2;
            ContextMenu2.VerticalOffset = -1 * ContextMenu2.RenderSize.Height / 2;
        }

        private List<ContextMenuItem> GetContextMenuFromOptionViewModel(IOptionViewModel options)
        {
            return options.All.Select(item => new ContextMenuItem
            {
                DisplayName = item.DisplayName,
                IsChecked = (item == options.Selected),
                Command = new RelayCommand(() => options.Selected = item),
            }).ToList();
        }

        private void ReadLinksAndText(string text, Action<string, bool> callback)
        {
            int ptr = 0;
            for (int i = 0; i < text.Length; i++)
            {
                if (text[i] == '{')
                {
                    if (i > 0)
                    {
                        callback(text.Substring(ptr, i - 1 - ptr), false);
                    }
                    ptr = i + 1;
                }
                else if (text[i] == '}')
                {
                    callback(text.Substring(ptr, i - ptr), true);
                    ptr = i + 1;
                }
            }

            if (ptr < text.Length - 1)
            {
                callback(text.Substring(ptr, text.Length - ptr), false);
            }
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/Controls/MenuButton.cs
================================================
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace EarTrumpet.Actions.Controls
{
    public class MenuButton : Button
    {
        public MenuButton()
        {
            Click += Button_Click;
        }

        private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            var btn = (Button)sender;

            btn.ContextMenu.Opened += (_, __) =>
            {
                ((Popup)btn.ContextMenu.Parent).PopupAnimation = PopupAnimation.None;
            };

            btn.ContextMenu.PlacementTarget = btn;
            btn.ContextMenu.Placement = PlacementMode.Bottom;
            btn.ContextMenu.IsOpen = true;
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/AudioAppEventKind.cs
================================================
namespace EarTrumpet.Actions.DataModel.Enum
{
    public enum AudioAppEventKind
    {
        Added,
        Removed,
        PlayingSound,
        NotPlayingSound,
        Muted,
        Unmuted,
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/AudioDeviceEventKind.cs
================================================
namespace EarTrumpet.Actions.DataModel.Enum
{
    public enum AudioDeviceEventKind
    {
        Added,
        Removed,
        BecomingDefault,
        LeavingDefault,
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/BoolValue.cs
================================================
namespace EarTrumpet.Actions.DataModel.Enum
{
    public enum BoolValue
    {
        True,
        False,
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/ComparisonBoolKind.cs
================================================
namespace EarTrumpet.Actions.DataModel.Enum
{
    public enum ComparisonBoolKind
    {
        Is,
        IsNot,
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/EarTrumpetEventKind.cs
================================================
namespace EarTrumpet.Actions.DataModel.Enum
{
    public enum EarTrumpetEventKind
    {
        Startup,
        Shutdown,
    };
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/MuteKind.cs
================================================
namespace EarTrumpet.Actions.DataModel.Enum
{
    public enum MuteKind
    {
        Mute,
        Unmute,
        ToggleMute,
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/ProcessEventKind.cs
================================================
namespace EarTrumpet.Actions.DataModel.Enum
{
    public enum ProcessEventKind
    {
        Start,
        Stop,
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/ProcessStateKind.cs
================================================
namespace EarTrumpet.Actions.DataModel.Enum
{
    public enum ProcessStateKind
    {
        Running,
        NotRunning
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/SetVolumeKind.cs
================================================
namespace EarTrumpet.Actions.DataModel.Enum
{
    public enum SetVolumeKind
    {
        Set,
        Increment,
        Decrement,
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/IPartWithApp.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.DataModel
{
    interface IPartWithApp
    {
        AppRef App { get; set; }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/IPartWithDevice.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.DataModel
{
    public interface IPartWithDevice
    {
        Device Device { get; set; }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/IPartWithText.cs
================================================
namespace EarTrumpet.Actions.DataModel
{
    interface IPartWithText
    {
        string Text { get; set; }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/IPartWithVolume.cs
================================================
namespace EarTrumpet.Actions.DataModel
{
    public interface IPartWithVolume
    {
        double Volume { get; set; }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/LocalVariablesContainer.cs
================================================
using EarTrumpet.DataModel.Storage;

namespace EarTrumpet.Actions.DataModel
{
    public class LocalVariablesContainer
    {
        public bool this[string key]
        {
            get => _settings.Get($"{s_localVariablePrefix}{key}", false);
            set => _settings.Set($"{s_localVariablePrefix}{key}", value);
        }

        private const string s_localVariablePrefix = "LocalVariable.";
        private readonly ISettingsBag _settings;

        public LocalVariablesContainer(ISettingsBag settings)
        {
            _settings = settings;
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Part.cs
================================================
namespace EarTrumpet.Actions.DataModel
{
    public abstract class Part { }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/ProcessWatcher.cs
================================================
using EarTrumpet.Interop;
using EarTrumpet.Actions.Interop.Helpers;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;

namespace EarTrumpet.Actions.DataModel
{
    public class ProcessWatcher
    {
        class ProcessInfo
        {
            public List<IntPtr> Windows = new List<IntPtr>();
        }

        class WatcherInfo
        {
            public List<Action> StartCallbacks = new List<Action>();
            public List<Action> StopCallbacks = new List<Action>();
            public Dictionary<int, ProcessInfo> RunningProcesses = new Dictionary<int, ProcessInfo>();
        }

        public static ProcessWatcher Current { get; } = new ProcessWatcher();

        WindowWatcher _watcher = new WindowWatcher();
        Dictionary<string, WatcherInfo> _info = new Dictionary<string, WatcherInfo>();

        public ProcessWatcher()
        {
            _watcher.WindowCreated += OnWindowCreated;
        }

        // Used only by the condition processor, so we use realtime data only.
        public bool IsRunning(string procName)
        {
            try
            {
                return Process.GetProcessesByName(procName).Any();
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
            }
            return false;
        }

        private void OnWindowCreated(IntPtr hwnd)
        {
            try
            {
                User32.GetWindowThreadProcessId(hwnd, out uint pid);

                using (var proc = Process.GetProcessById((int)pid))
                {
                    if (_info.ContainsKey(proc.ProcessName.ToLower()))
                    {
                        FoundNewRelevantProcess(proc);
                    }
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
            }
        }

        bool FoundNewRelevantProcess(Process proc)
        {
            var info = _info[proc.ProcessName.ToLower()];

            if (!info.RunningProcesses.ContainsKey(proc.Id))
            {
                var procInfo = new ProcessInfo();
                info.RunningProcesses[proc.Id] = procInfo;

                new Thread(() =>
                {
                    Thread.CurrentThread.IsBackground = true;

                    var procName = proc.ProcessName;
                    proc.WaitForExit();
                    Trace.WriteLine($"ProcessWatcher STOP {procName}");
                    info.StopCallbacks.ForEach(s => s.Invoke());
                }).Start();

                Trace.WriteLine($"ProcessWatcher START {proc.ProcessName}");
                info.StartCallbacks.ForEach(s => s.Invoke());
                return true;
            }
            return false;
        }

        public void RegisterStop(string text, Action callback)
        {
            Trace.WriteLine($"ProcessWatcher RegisterStop {text}");
            text = text.ToLower();
            WatcherInfo info = _info.ContainsKey(text) ? _info[text] : _info[text] = new WatcherInfo();
            info.StopCallbacks.Add(callback);

            try
            {
                var runningProcs = Process.GetProcessesByName(text);
                foreach (var proc in runningProcs)
                {
                    FoundNewRelevantProcess(proc);
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
            }
        }

        public void RegisterStart(string text, Action callback)
        {
            Trace.WriteLine($"ProcessWatcher RegisterStart {text}");
            text = text.ToLower();
            WatcherInfo info = _info.ContainsKey(text) ? _info[text] : new WatcherInfo();
            info.StartCallbacks.Add(callback);

            try
            {
                bool didSignal = false;
                var runningProcs = Process.GetProcessesByName(text);
                foreach (var proc in runningProcs)
                {
                    didSignal = didSignal || FoundNewRelevantProcess(proc);
                }

                if (runningProcs.Any() && !didSignal)
                {
                    // We were already watching so we didn't signal but the process is running.
                    callback();
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
            }
        }

        public void Clear()
        {
            Trace.WriteLine("ProcessWatcher Clear");
            _info = new Dictionary<string, WatcherInfo>();
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Processing/ActionProcessor.cs
================================================
using EarTrumpet.Interop;
using EarTrumpet.Actions.DataModel.Serialization;
using EarTrumpet.Actions.DataModel.Enum;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using EarTrumpet.DataModel.Audio;
using EarTrumpet.DataModel.WindowsAudio;
using EarTrumpet.DataModel.AppInformation;

namespace EarTrumpet.Actions.DataModel.Processing
{
    class ActionProcessor
    {
        public static void Invoke(BaseAction a)
        {
            Trace.WriteLine($"ActionProcessor Invoke: {a.GetType().Name}");
            if (a is SetVariableAction)
            {
                EarTrumpetActionsAddon.Current.LocalVariables[((SetVariableAction)a).Text] = (((SetVariableAction)a).Value == BoolValue.True);
            }
            else if (a is SetDefaultDeviceAction)
            {
                var mgr = WindowsAudioFactory.Create((AudioDeviceKind)System.Enum.Parse(typeof(AudioDeviceKind), ((SetDefaultDeviceAction)a).Device.Kind));

                var dev = mgr.Devices.FirstOrDefault(d => d.Id == ((SetDefaultDeviceAction)a).Device.Id);
                if (dev != null)
                {
                    mgr.Default = dev;
                }
            }
            else if (a is SetAppVolumeAction)
            {
                var action = (SetAppVolumeAction)a;
                var mgr = WindowsAudioFactory.Create((AudioDeviceKind)System.Enum.Parse(typeof(AudioDeviceKind), ((SetAppVolumeAction)a).Device.Kind));

                var device = (action.Device?.Id == null) ?
                    mgr.Default : mgr.Devices.FirstOrDefault(d => d.Id == action.Device.Id);
                if (device != null)
                {
                    if (action.App.Id == AppRef.ForegroundAppId)
                    {
                        var app = FindForegroundApp(device.Groups);
                        if (app != null)
                        {
                            DoAudioAction(action.Option, app, action);
                        }
                    }
                    else
                    {
                        foreach (var app in device.Groups.Where(app => action.App.Id == AppRef.EveryAppId || app.AppId == action.App.Id))
                        {
                            DoAudioAction(action.Option, app, action);
                        }
                    }
                }
            }
            else if (a is SetAppMuteAction)
            {
                var action = (SetAppMuteAction)a;
                var mgr = WindowsAudioFactory.Create((AudioDeviceKind)System.Enum.Parse(typeof(AudioDeviceKind), ((SetAppMuteAction)a).Device.Kind));

                var device = (action.Device?.Id == null) ?
                    mgr.Default : mgr.Devices.FirstOrDefault(d => d.Id == action.Device.Id);
                if (device != null)
                {
                    if (action.App.Id == AppRef.ForegroundAppId)
                    {
                        var app = FindForegroundApp(device.Groups);
                        if (app != null)
                        {
                            DoAudioAction(action.Option, app);
                        }
                    }
                    else
                    {
                        foreach (var app in device.Groups.Where(app => action.App.Id == AppRef.EveryAppId || app.AppId == action.App.Id))
                        {
                            DoAudioAction(action.Option, app);
                        }
                    }
                }
            }
            else if (a is SetDeviceVolumeAction)
            {
                var action = (SetDeviceVolumeAction)a;

                var mgr = WindowsAudioFactory.Create((AudioDeviceKind)System.Enum.Parse(typeof(AudioDeviceKind), ((SetDeviceVolumeAction)a).Device.Kind));

                var device = (action.Device?.Id == null) ?
                    mgr.Default : mgr.Devices.FirstOrDefault(d => d.Id == action.Device.Id);
                if (device != null)
                {
                    DoAudioAction(action.Option, device, action);
                }
            }
            else if (a is SetDeviceMuteAction)
            {
                var action = (SetDeviceMuteAction)a;
                var mgr = WindowsAudioFactory.Create((AudioDeviceKind)System.Enum.Parse(typeof(AudioDeviceKind), ((SetDeviceMuteAction)a).Device.Kind));

                var device = (action.Device?.Id == null) ?
                    mgr.Default : mgr.Devices.FirstOrDefault(d => d.Id == action.Device.Id);
                if (device != null)
                {
                    DoAudioAction(action.Option, device);
                }
            }
            else
            {
                throw new NotImplementedException();
            }
        }

        private static IAudioDeviceSession FindForegroundApp(ObservableCollection<IAudioDeviceSession> groups)
        {
            var hWnd = User32.GetForegroundWindow();
            var foregroundClassName = new StringBuilder(User32.MAX_CLASSNAME_LENGTH);
            User32.GetClassName(hWnd, foregroundClassName, foregroundClassName.Capacity);

            if (hWnd == IntPtr.Zero)
            {
                Trace.WriteLine($"ActionProcessor FindForegroundApp: No Window (1)");
                return null;
            }

            // ApplicationFrameWindow.exe, find the real hosted process in the child CoreWindow.
            if (foregroundClassName.ToString() == "ApplicationFrameWindow")
            {
                hWnd = User32.FindWindowEx(hWnd, IntPtr.Zero, "Windows.UI.Core.CoreWindow", IntPtr.Zero);
            }

            if (hWnd == IntPtr.Zero)
            {
                Trace.WriteLine($"ActionProcessor FindForegroundApp: No Window (2)");
                return null;
            }

            User32.GetWindowThreadProcessId(hWnd, out uint processId);

            try
            {
                var appInfo = AppInformationFactory.CreateForProcess((int)processId);

                foreach(var group in groups)
                {
                    if (group.AppId == appInfo.PackageInstallPath)
                    {
                        Trace.WriteLine($"ActionProcessor FindForegroundApp: {group.DisplayName}");
                        return group;
                    }
                }
            }
            catch(Exception ex)
            {
                Trace.WriteLine(ex);
            }
            Trace.WriteLine("ActionProcessor FindForegroundApp Didn't locate foreground app");
            return null;
        }

        private static void DoAudioAction(MuteKind action, IStreamWithVolumeControl stream)
        {
            switch (action)
            {
                case MuteKind.Mute:
                    stream.IsMuted = true;
                    break;
                case MuteKind.ToggleMute:
                    stream.IsMuted = !stream.IsMuted;
                    break;
                case MuteKind.Unmute:
                    stream.IsMuted = false;
                    break;
            }
        }

        private static void DoAudioAction(SetVolumeKind action, IStreamWithVolumeControl stream, IPartWithVolume part)
        {
            var vol = (float)(part.Volume / 100f);
            switch (action)
            {
                case SetVolumeKind.Set:
                    stream.Volume = vol;
                    break;
                case SetVolumeKind.Increment:
                    stream.Volume += vol;
                    break;
                case SetVolumeKind.Decrement:
                    stream.Volume -= vol;
                    break;
            }
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Processing/AudioTriggerManager.cs
================================================
using EarTrumpet.Actions.DataModel.Enum;
using EarTrumpet.Actions.DataModel.Serialization;
using System;
using System.Collections.Generic;
using EarTrumpet.DataModel.Audio;
using EarTrumpet.DataModel.WindowsAudio;
using EarTrumpet.Extensibility.Shared;

namespace EarTrumpet.Actions.DataModel.Processing
{
    class AudioTriggerManager
    {
        public event Action<BaseTrigger> Triggered;

        private readonly PlaybackDataModelHost _playbackManager;
        private readonly IAudioDeviceManager _recordingManager;
        private readonly List<AppEventTrigger> _appTriggers = new List<AppEventTrigger>();
        private readonly List<DeviceEventTrigger> _deviceTriggers = new List<DeviceEventTrigger>();
        private IAudioDevice _defaultPlaybackDevice;
        private IAudioDevice _defaultRecordingDevice;

        public AudioTriggerManager()
        {
            _playbackManager = PlaybackDataModelHost.Current;
            _playbackManager.AppPropertyChanged += OnAppPropertyChanged;
            _playbackManager.AppAdded += (a) => OnAppAddOrRemove(a, AudioAppEventKind.Added);
            _playbackManager.AppRemoved += (a) => OnAppAddOrRemove(a, AudioAppEventKind.Removed);
            _playbackManager.DeviceAdded += (d) => OnDeviceAddOrRemove(d, AudioDeviceEventKind.Added);
            _playbackManager.DeviceRemoved += (d) => OnDeviceAddOrRemove(d, AudioDeviceEventKind.Removed);
            _playbackManager.DeviceManager.DefaultChanged += PlaybackDeviceManager_DefaultChanged;
            _defaultPlaybackDevice = _playbackManager.DeviceManager.Default;

            _recordingManager = WindowsAudioFactory.Create(AudioDeviceKind.Recording);
            _recordingManager.DefaultChanged += RecordingMgr_DefaultChanged;
            _defaultRecordingDevice = _recordingManager.Default;
        }

        public void Register(BaseTrigger trigger)
        {
            if (trigger is DeviceEventTrigger)
            {
                _deviceTriggers.Add((DeviceEventTrigger)trigger);
            }
            else if (trigger is AppEventTrigger)
            {
                _appTriggers.Add((AppEventTrigger)trigger);
            }
            else throw new NotImplementedException();
        }

        public void Clear()
        {
            _appTriggers.Clear();
            _deviceTriggers.Clear();
        }

        private void PlaybackDeviceManager_DefaultChanged(object sender, EarTrumpet.DataModel.Audio.IAudioDevice newDefault)
        {
            if (newDefault == null) return;

            ProcessDefaultChanged(newDefault);

            _defaultPlaybackDevice = newDefault;
        }

        private void RecordingMgr_DefaultChanged(object sender, IAudioDevice newDefault)
        {
            if (newDefault == null) return;

            ProcessDefaultChanged(newDefault);

            _defaultRecordingDevice = newDefault;
        }

        private void ProcessDefaultChanged(IAudioDevice newDefault)
        {
            foreach (var trigger in _deviceTriggers)
            {
                if (trigger.Device.Id == _defaultPlaybackDevice?.Id &&
                    trigger.Option == AudioDeviceEventKind.LeavingDefault)
                {
                    Triggered?.Invoke(trigger);
                }

                if (trigger.Device.Id == newDefault.Id &&
                    trigger.Option == AudioDeviceEventKind.BecomingDefault)
                {
                    Triggered?.Invoke(trigger);
                }
            }
        }

        private void OnDeviceAddOrRemove(IAudioDevice device, AudioDeviceEventKind option)
        {
            foreach (var trigger in _deviceTriggers)
            {
                if (trigger.Option == option)
                {
                    // Default device: not supported
                    if (trigger.Device.Id == device.Id)
                    {
                        Triggered?.Invoke(trigger);
                    }
                }
            }
        }

        private void OnAppAddOrRemove(IAudioDeviceSession app, AudioAppEventKind option)
        {
            foreach (var trigger in _appTriggers)
            {
                if (trigger.Option == option)
                {
                    var device = app.Parent;
                    if ((trigger.Device?.Id == null && device == _playbackManager.DeviceManager.Default) ||
                         trigger.Device?.Id == device.Id)
                    {
                        if (trigger.App.Id == app.AppId)
                        {
                            Triggered?.Invoke(trigger);
                        }
                    }
                }
            }
        }

        private void OnAppPropertyChanged(IAudioDeviceSession app, string propertyName)
        {
            foreach (var trigger in _appTriggers)
            {
                var device = app.Parent;
                if ((trigger.Device?.Id == null && device == _playbackManager.DeviceManager.Default) || trigger.Device?.Id == device.Id)
                {
                    if (trigger.App.Id == app.AppId)
                    {
                        switch (trigger.Option)
                        {
                            case AudioAppEventKind.Muted:
                                if (propertyName == nameof(app.IsMuted) && app.IsMuted)
                                {
                                    Triggered?.Invoke(trigger);
                                }
                                break;
                            case AudioAppEventKind.Unmuted:
                                if (propertyName == nameof(app.IsMuted) && !app.IsMuted)
                                {
                                    Triggered?.Invoke(trigger);
                                }
                                break;
                            case AudioAppEventKind.PlayingSound:
                                if (propertyName == nameof(app.State) && app.State == SessionState.Active)
                                {
                                    Triggered?.Invoke(trigger);
                                }
                                break;
                            case AudioAppEventKind.NotPlayingSound:
                                if (propertyName == nameof(app.State) && app.State != SessionState.Active)
                                {
                                    Triggered?.Invoke(trigger);
                                }
                                break;
                        }
                    }
                }
            }
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Processing/ConditionProcessor.cs
================================================
using EarTrumpet.Actions.DataModel.Enum;
using EarTrumpet.Actions.DataModel.Serialization;
using System;
using EarTrumpet.DataModel.WindowsAudio;

namespace EarTrumpet.Actions.DataModel.Processing
{
    class ConditionProcessor
    {
        public static bool IsMet(BaseCondition condition)
        {
            if (condition is ProcessCondition)
            {
                bool isProcessRunning = ProcessWatcher.Current.IsRunning(((ProcessCondition)condition).Text);
                switch (((ProcessCondition)condition).Option)
                {
                    case ProcessStateKind.Running:
                        return isProcessRunning;
                    case ProcessStateKind.NotRunning:
                        return !isProcessRunning;
                    default:
                        throw new NotImplementedException();
                }
            }
            else if (condition is DefaultDeviceCondition)
            {
                var mgr = WindowsAudioFactory.Create((AudioDeviceKind)System.Enum.Parse(typeof(AudioDeviceKind), ((DefaultDeviceCondition)condition).Device.Kind));

                var isDeviceCurrentlyDefault = ((DefaultDeviceCondition)condition).Device.Id == mgr.Default?.Id;
                switch (((DefaultDeviceCondition)condition).Option)
                {
                    case ComparisonBoolKind.Is:
                        return isDeviceCurrentlyDefault;
                    case ComparisonBoolKind.IsNot:
                        return !isDeviceCurrentlyDefault;
                    default:
                        throw new NotImplementedException();
                }
            }
            else if (condition is VariableCondition)
            {
                return (EarTrumpetActionsAddon.Current.LocalVariables[((VariableCondition)condition).Text] == (((VariableCondition)condition).Value == BoolValue.True));
            }
            throw new NotImplementedException();
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Processing/TriggerManager.cs
================================================
using EarTrumpet.Extensibility;
using EarTrumpet.Interop.Helpers;
using EarTrumpet.Actions.DataModel.Enum;
using EarTrumpet.Actions.DataModel.Serialization;
using System;
using System.Collections.Generic;

namespace EarTrumpet.Actions.DataModel.Processing
{
    class TriggerManager
    {
        public event Action<BaseTrigger> Triggered;

        private List<EventTrigger> _eventTriggers = new List<EventTrigger>();
        private AudioTriggerManager _audioManager;

        public TriggerManager()
        {
            _audioManager = new AudioTriggerManager();
            _audioManager.Triggered += (t) => Triggered?.Invoke(t);
        }

        public void Clear()
        {
            ProcessWatcher.Current.Clear();
            _eventTriggers.Clear();
            _audioManager.Clear();
        }

        public void OnEvent(AddonEventKind evt)
        {
            foreach (var trigger in _eventTriggers)
            {
                if ((trigger.Option == EarTrumpetEventKind.Startup && evt == AddonEventKind.InitializeAddon) ||
                    (trigger.Option == EarTrumpetEventKind.Shutdown && evt == AddonEventKind.AppShuttingDown))
                {
                    Triggered?.Invoke(trigger);
                }
            }
        }

        public void Register(BaseTrigger trig)
        {
            if (trig is ProcessTrigger)
            {
                var trigger = (ProcessTrigger)trig;
                if (!string.IsNullOrWhiteSpace(trigger.Text))
                {
                    if (trigger.Option == ProcessEventKind.Start)
                    {
                        ProcessWatcher.Current.RegisterStart(trigger.Text, () => Triggered?.Invoke(trig));
                    }
                    else
                    {
                        ProcessWatcher.Current.RegisterStop(trigger.Text, () => Triggered?.Invoke(trig));
                    }
                }
            }
            else if (trig is EventTrigger)
            {
                _eventTriggers.Add((EventTrigger)trig);
            }
            else if (trig is DeviceEventTrigger)
            {
                _audioManager.Register(trig);
            }
            else if (trig is AppEventTrigger)
            {
                _audioManager.Register(trig);
            }
            else if (trig is HotkeyTrigger)
            {
                var trigger = (HotkeyTrigger)trig;

                HotkeyManager.Current.Register(trigger.Option);
                HotkeyManager.Current.KeyPressed += (data) =>
                {
                    if (data.Equals(trigger.Option))
                    {
                        Triggered?.Invoke(trig);
                    }
                };
            }
            else if (trig is ContextMenuTrigger)
            {
                // Nothing to do.
            }
            else throw new NotImplementedException();
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/Actions.cs
================================================
using EarTrumpet.Actions.DataModel.Enum;
using System.Xml.Serialization;

namespace EarTrumpet.Actions.DataModel.Serialization
{
    [XmlInclude(typeof(SetAppVolumeAction))]
    [XmlInclude(typeof(SetAppMuteAction))]
    [XmlInclude(typeof(SetDeviceVolumeAction))]
    [XmlInclude(typeof(SetDeviceMuteAction))]
    [XmlInclude(typeof(SetDefaultDeviceAction))]
    [XmlInclude(typeof(SetVariableAction))]
    public abstract class BaseAction : Part { }

    public class SetAppMuteAction : BaseAction, IPartWithDevice, IPartWithApp
    {
        public Device Device { get; set; }
        public AppRef App { get; set; }
        public MuteKind Option { get; set; }
    }

    public class SetAppVolumeAction : BaseAction, IPartWithVolume, IPartWithDevice, IPartWithApp
    {
        public Device Device { get; set; }
        public AppRef App { get; set; }
        public SetVolumeKind Option { get; set; }
        public double Volume { get; set; }
    }

    public class SetDefaultDeviceAction : BaseAction, IPartWithDevice
    {
        public Device Device { get; set; }
    }

    public class SetDeviceMuteAction : BaseAction, IPartWithDevice
    {
        public Device Device { get; set; }
        public MuteKind Option { get; set; }
    }

    public class SetDeviceVolumeAction : BaseAction, IPartWithDevice, IPartWithVolume
    {
        public Device Device { get; set; }
        public SetVolumeKind Option { get; set; }
        public double Volume { get; set; }
    }

    public class SetVariableAction : BaseAction, IPartWithText
    {
        public string Text { get; set; }
        public BoolValue Value { get; set; }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/App.cs
================================================
namespace EarTrumpet.Actions.DataModel.Serialization
{
    public class AppRef
    {
        public static readonly string EveryAppId = "EarTrumpet.EveryApp";
        public static readonly string ForegroundAppId = "EarTrumpet.ForegroundApp";

        public string Id { get; set; }

        public override int GetHashCode()
        {
            return Id == null ? 0 : Id.GetHashCode();
        }

        public bool Equals(AppRef other)
        {
            return other.Id == Id;
        }
    }
}

================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/Conditions.cs
================================================
using EarTrumpet.Actions.DataModel.Enum;
using System.Xml.Serialization;

namespace EarTrumpet.Actions.DataModel.Serialization
{
    [XmlInclude(typeof(DefaultDeviceCondition))]
    [XmlInclude(typeof(ProcessCondition))]
    [XmlInclude(typeof(VariableCondition))]
    public abstract class BaseCondition : Part { }

    public class DefaultDeviceCondition : BaseCondition, IPartWithDevice
    {
        public Device Device { get; set; }
        public ComparisonBoolKind Option { get; set; }
    }

    public class ProcessCondition : BaseCondition, IPartWithText
    {
        public string Text { get; set; }
        public ProcessStateKind Option { get; set; }
    }

    public class VariableCondition : BaseCondition, IPartWithText
    {
        public string Text { get; set; }
        public BoolValue Value { get; set; }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/Device.cs
================================================
namespace EarTrumpet.Actions.DataModel.Serialization
{
    public class Device
    {
        public string Id { get; set; }

        public string Kind { get; set; }

        public override int GetHashCode()
        {
            return Id == null ? 0 : Id.GetHashCode();
        }

        public bool Equals(Device other)
        {
            return other.Id == Id;
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/EarTrumpetAction.cs
================================================
using System;
using System.Collections.ObjectModel;

namespace EarTrumpet.Actions.DataModel.Serialization
{
    public class EarTrumpetAction
    {
        public string DisplayName { get; set; }
        public Guid Id { get; set; } = Guid.NewGuid();
        public ObservableCollection<BaseTrigger> Triggers { get; set; } = new ObservableCollection<BaseTrigger>();
        public ObservableCollection<BaseCondition> Conditions { get; set; } = new ObservableCollection<BaseCondition>();
        public ObservableCollection<BaseAction> Actions { get; set; } = new ObservableCollection<BaseAction>();
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/Triggers.cs
================================================
using EarTrumpet.Interop.Helpers;
using EarTrumpet.Actions.DataModel.Enum;
using System.Xml.Serialization;

namespace EarTrumpet.Actions.DataModel.Serialization
{
    [XmlInclude(typeof(EventTrigger))]
    [XmlInclude(typeof(HotkeyTrigger))]
    [XmlInclude(typeof(DeviceEventTrigger))]
    [XmlInclude(typeof(AppEventTrigger))]
    [XmlInclude(typeof(ProcessTrigger))]
    [XmlInclude(typeof(ContextMenuTrigger))]
    public abstract class BaseTrigger : Part { }

    public class AppEventTrigger : BaseTrigger, IPartWithDevice, IPartWithApp
    {
        public Device Device { get; set; }
        public AppRef App { get; set; }
        public AudioAppEventKind Option { get; set; }
    }

    public class ContextMenuTrigger : BaseTrigger { }

    public class DeviceEventTrigger : BaseTrigger, IPartWithDevice
    {
        public Device Device { get; set; }
        public AudioDeviceEventKind Option { get; set; }
    }

    public class EventTrigger : BaseTrigger
    {
        public EarTrumpetEventKind Option { get; set; }
    }

    public class HotkeyTrigger : BaseTrigger
    {
        public HotkeyData Option { get; set; } = new HotkeyData();
    }

    public class ProcessTrigger : BaseTrigger, IPartWithText
    {
        public string Text { get; set; }
        public ProcessEventKind Option { get; set; }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/EarTrumpetActionsAddon.cs
================================================
using EarTrumpet.Actions.DataModel;
using EarTrumpet.Actions.DataModel.Processing;
using EarTrumpet.Actions.DataModel.Serialization;
using EarTrumpet.Actions.ViewModel;
using EarTrumpet.DataModel.Storage;
using EarTrumpet.Extensibility;
using EarTrumpet.UI.Helpers;
using EarTrumpet.UI.ViewModels;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;

namespace EarTrumpet.Actions
{
    [Export(typeof(EarTrumpetAddon))]
    public class EarTrumpetActionsAddon : EarTrumpetAddon, IEarTrumpetAddonEvents, IEarTrumpetAddonSettingsPage, IEarTrumpetAddonNotificationAreaContextMenu
    {
        public static EarTrumpetActionsAddon Current { get; private set; }
        public LocalVariablesContainer LocalVariables { get; private set; }

        public EarTrumpetActionsAddon() : base()
        {
            DisplayName = Properties.Resources.MyActionsText;
        }

        public EarTrumpetAction[] Actions
        {
            get => _actions;
            set
            {
                Settings.Set(c_actionsSettingKey, value);
                LoadAndRegister();
            }
        }

        private readonly string c_actionsSettingKey = "ActionsData";
        private EarTrumpetAction[] _actions = new EarTrumpetAction[] { };
        private TriggerManager _triggerManager = new TriggerManager();

        public void OnAddonEvent(AddonEventKind evt)
        {
            if (evt == AddonEventKind.AddonsInitialized)
            {
                Current = this;
                LocalVariables = new LocalVariablesContainer(Settings);

                _triggerManager.Triggered += OnTriggered;
                LoadAndRegister();

                _triggerManager.OnEvent(AddonEventKind.InitializeAddon);
            }
            else if (evt == AddonEventKind.AppShuttingDown)
            {
                _triggerManager.OnEvent(AddonEventKind.AppShuttingDown);
            }
        }

        public SettingsCategoryViewModel GetSettingsCategory()
        {
            LoadAddonResources();
            return new ActionsCategoryViewModel();
        }

        public IEnumerable<ContextMenuItem> NotificationAreaContextMenuItems
        {
            get
            {
                var ret = new List<ContextMenuItem>();

                if (EarTrumpetActionsAddon.Current == null)
                {
                    return ret;
                }

                foreach (var item in EarTrumpetActionsAddon.Current.Actions.Where(a => a.Triggers.FirstOrDefault(ax => ax is ContextMenuTrigger) != null))
                {
                    ret.Add(new ContextMenuItem
                    {
                        Glyph = "\xE1CE",
                        IsChecked = true,
                        DisplayName = item.DisplayName,
                        Command = new RelayCommand(() => EarTrumpetActionsAddon.Current.TriggerAction(item))
                    });
                }
                return ret;
            }
        }

        private void LoadAndRegister()
        {
            _triggerManager.Clear();
            _actions = Settings.Get(c_actionsSettingKey, new EarTrumpetAction[] { });
            _actions.SelectMany(a => a.Triggers).ToList().ForEach(t => _triggerManager.Register(t));
        }

        public void Import(string fileName)
        {
            var imported = Serializer.FromString<EarTrumpetAction[]>(File.ReadAllText(fileName)).ToList();
            foreach(var imp in imported)
            {
                imp.Id = Guid.NewGuid();
            }
            imported.AddRange(Actions);
            Actions = imported.ToArray();
        }

        public string Export()
        {
            return Settings.Get(c_actionsSettingKey, "");
        }

        private void OnTriggered(BaseTrigger trigger)
        {
            var action = Actions.FirstOrDefault(a => a.Triggers.Contains(trigger));
            if (action != null && action.Conditions.All(c => ConditionProcessor.IsMet(c)))
            {
                TriggerAction(action);
            }
        }

        public void TriggerAction(EarTrumpetAction action)
        {
            action.Actions.ToList().ForEach(a => ActionProcessor.Invoke(a));
        }
    }
}

================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/Interop/Helpers/WindowWatcher.cs
================================================
using EarTrumpet.Interop.Helpers;
using System;
using System.Diagnostics;
using System.Windows.Forms;

namespace EarTrumpet.Actions.Interop.Helpers
{
    class WindowWatcher
    {
        public event Action<IntPtr> WindowCreated;
        public event Action<IntPtr> WindowDestroyed;
        readonly Win32Window _window;
        readonly uint _ShellNotifyMsg;

        public WindowWatcher()
        {
            _window = new Win32Window();
            _window.Initialize(WndProc);
            _ShellNotifyMsg = User32.RegisterWindowMessageW(User32.SHELLHOOK);
            if (!User32.RegisterShellHookWindow(_window.Handle))
            {
                Trace.WriteLine("Failed to register shell hook window");
            }
        }

        void WndProc(Message m)
        {
            if (m.Msg == _ShellNotifyMsg)
            {
                if (m.WParam.ToInt32() == User32.HSHELL_WINDOWCREATED)
                {
                    WindowCreated?.Invoke(m.LParam);
                }
                else if (m.WParam.ToInt32() == User32.HSHELL_WINDOWDESTROYED)
                {
                    WindowDestroyed?.Invoke(m.LParam);
                }
            }
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/Interop/User32.cs
================================================
using System;
using System.Runtime.InteropServices;

namespace EarTrumpet.Actions.Interop
{
    class User32
    {
        public static readonly string SHELLHOOK = "SHELLHOOK";
        public const int HSHELL_WINDOWCREATED = 1;
        public const int HSHELL_WINDOWDESTROYED = 2;

        [DllImport("user32.dll", PreserveSig = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool RegisterShellHookWindow(IntPtr hWnd);

        [DllImport("user32.dll", PreserveSig = true)]
        public static extern uint RegisterWindowMessageW([MarshalAs(UnmanagedType.LPWStr)] string msg);
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetAppMuteActionViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel.Actions
{
    class SetAppMuteActionViewModel : PartViewModel
    {
        public OptionViewModel Option { get; }
        public DeviceListViewModel Device { get; }
        public AppListViewModel App { get; }

        private SetAppMuteAction _action;

        public SetAppMuteActionViewModel(SetAppMuteAction action) : base(action)
        {
            _action = action;

            Option = new OptionViewModel(action, nameof(action.Option));
            App = new AppListViewModel(action, AppListViewModel.AppKind.EveryApp | AppListViewModel.AppKind.ForegroundApp);
            Device = new DeviceListViewModel(action, DeviceListViewModel.DeviceListKind.DefaultPlayback);

            Attach(Option);
            Attach(App);
            Attach(Device);
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetAppVolumeActionViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;
using EarTrumpet.Actions.DataModel.Enum;

namespace EarTrumpet.Actions.ViewModel.Actions
{
    class SetAppVolumeActionViewModel : PartViewModel
    {
        public OptionViewModel Option { get; }
        public DeviceListViewModel Device { get; }
        public AppListViewModel App { get; }
        public VolumeViewModel Volume { get; }

        private SetAppVolumeAction _action;

        public SetAppVolumeActionViewModel(SetAppVolumeAction action) : base(action)
        {
            _action = action;

            Option = new OptionViewModel(action, nameof(action.Option));
            App = new AppListViewModel(action, AppListViewModel.AppKind.EveryApp | AppListViewModel.AppKind.ForegroundApp);
            Device = new DeviceListViewModel(action, DeviceListViewModel.DeviceListKind.DefaultPlayback);
            Volume = new VolumeViewModel(action);

            Attach(Option);
            Attach(App);
            Attach(Device);
            Attach(Volume);
        }

        public override string LinkText
        {
            get
            {
                if (_action.Option == SetVolumeKind.Set)
                {
                    return base.LinkText;
                }
                else
                {
                    return Properties.Resources.SetAppVolumeAction_LinkTextIncrement;
                }
            }
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetDefaultDeviceActionViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel.Actions
{
    class SetDefaultDeviceActionViewModel : PartViewModel
    {
        public DeviceListViewModel Device { get; }

        public SetDefaultDeviceActionViewModel(SetDefaultDeviceAction action) : base(action)
        {
            Device = new DeviceListViewModel(action, DeviceListViewModel.DeviceListKind.Recording);
            Attach(Device);
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetDeviceMuteActionViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel.Actions
{
    class SetDeviceMuteActionViewModel : PartViewModel
    {
        public OptionViewModel Option { get; }
        public DeviceListViewModel Device { get; }

        private SetDeviceMuteAction _action;

        public SetDeviceMuteActionViewModel(SetDeviceMuteAction action) : base(action)
        {
            _action = action;
            Option = new OptionViewModel(action, nameof(action.Option));
            Device = new DeviceListViewModel(action, DeviceListViewModel.DeviceListKind.Recording | DeviceListViewModel.DeviceListKind.DefaultPlayback);

            Attach(Option);
            Attach(Device);
        }

        public override string LinkText
        {
            get
            {
                if (_action.Option == DataModel.Enum.MuteKind.ToggleMute)
                {
                    return Properties.Resources.SetDeviceMuteAction_LinkTextToggle;
                }
                else
                {
                    return base.LinkText;
                }
            }
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetDeviceVolumeActionViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Enum;
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel.Actions
{
    class SetDeviceVolumeActionViewModel : PartViewModel
    {
        public OptionViewModel Option { get; }
        public DeviceListViewModel Device { get; }
        public VolumeViewModel Volume { get; }

        private SetDeviceVolumeAction _action;

        public SetDeviceVolumeActionViewModel(SetDeviceVolumeAction action) : base(action)
        {
            _action = action;
            Option = new OptionViewModel(action, nameof(action.Option));
            Device = new DeviceListViewModel(action, DeviceListViewModel.DeviceListKind.Recording | DeviceListViewModel.DeviceListKind.DefaultPlayback);
            Volume = new VolumeViewModel(action);

            Attach(Option);
            Attach(Device);
            Attach(Volume);
        }

        public override string LinkText
        {
            get
            {
                if (_action.Option == SetVolumeKind.Set)
                {
                    return base.LinkText;
                }
                else
                {
                    return Properties.Resources.SetDeviceVolumeAction_LinkTextIncrement;
                }
            }
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetVariableActionViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel.Actions
{
    class SetVariableActionViewModel : PartViewModel
    {
        public OptionViewModel Option { get; }
        public TextViewModel Text { get; }

        public SetVariableActionViewModel(SetVariableAction action) : base(action)
        {
            Option = new OptionViewModel(action, nameof(action.Value));
            Text = new TextViewModel(action);

            Attach(Option);
            Attach(Text);
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/ActionsCategoryViewModel.cs
================================================
using EarTrumpet.Extensions;
using EarTrumpet.UI.Helpers;
using EarTrumpet.UI.ViewModels;
using EarTrumpet.Actions.DataModel.Serialization;
using System;
using System.Collections.ObjectModel;
using System.Linq;

namespace EarTrumpet.Actions.ViewModel
{
    public class ActionsCategoryViewModel : SettingsCategoryViewModel
    {
        public ActionsCategoryViewModel()
            : base(Properties.Resources.MyActionsText, "\xE950", Properties.Resources.AddonDescriptionText, EarTrumpetActionsAddon.Current.Manifest.Id, new ObservableCollection<SettingsPageViewModel>())
        {
            // Get a 'fresh' copy so that we can edit the objects and still go back later.
            var actions = EarTrumpetActionsAddon.Current.Actions;
            EarTrumpetActionsAddon.Current.Actions = EarTrumpetActionsAddon.Current.Actions;

            Pages.AddRange(actions.Select(a => new EarTrumpetActionViewModel(this, a)));
            Pages.Add(new ImportExportPageViewModel(this));

            Toolbar = new ToolbarItemViewModel[] { new ToolbarItemViewModel{
                Command = new RelayCommand(() =>
                {
                    var vm = new EarTrumpetActionViewModel(this, new EarTrumpetAction { DisplayName = Properties.Resources.NewActionText });
                    vm.IsWorkSaved = false;
                    vm.IsPersisted = false;

                    vm.PropertyChanged += (_, e) =>
                    {
                        if (e.PropertyName == nameof(vm.IsSelected) &&
                            vm.IsSelected && !Pages.Contains(vm))
                        {
                            Pages.Insert(0, vm);
                        }
                    };

                    Selected = vm;
                }),
                DisplayName = Properties.Resources.NewActionText,
                Glyph = "\xE948",
                GlyphFontSize = 15,
            } };

            if (Pages.Count == 2)
            {
                Toolbar[0].Command.Execute(null);
            }
        }

        internal void ReloadSavedPages()
        {
            foreach (var item in Pages.Where(p => p is EarTrumpetActionViewModel).ToList())
            {
                Pages.Remove(item);
            }

            Pages.InsertRange(0, new System.Collections.ObjectModel.ObservableCollection<SettingsPageViewModel>(EarTrumpetActionsAddon.Current.Actions.Select(a => new EarTrumpetActionViewModel(this, a))));
            Selected = Pages[0];
        }

        public void Delete(EarTrumpetActionViewModel earTrumpetActionViewModel, bool promptOverride = false)
        {
            Action doRemove = () =>
            {
                var actions = EarTrumpetActionsAddon.Current.Actions.ToList();
                if (actions.Any(a => a.Id == earTrumpetActionViewModel.Id))
                {
                    actions.Remove(item => item.Id == earTrumpetActionViewModel.Id);
                }
                EarTrumpetActionsAddon.Current.Actions = actions.ToArray();

                if (Pages.Any(a => a == earTrumpetActionViewModel))
                {
                    Pages.Remove(earTrumpetActionViewModel);
                }
            };

            if (earTrumpetActionViewModel.IsPersisted && !promptOverride)
            {
                _parent.ShowDialog(Properties.Resources.DeleteActionDialogTitle, Properties.Resources.DeleteActionDialogText,
                    Properties.Resources.DeleteActionDialogYesText, Properties.Resources.DeleteActionDialogNoText, doRemove, () => { });
            }
            else
            {
                doRemove();
            }
        }

        public void Save(EarTrumpetActionViewModel earTrumpetActionViewModel)
        {
            var actions = EarTrumpetActionsAddon.Current.Actions.ToList();
            if (actions.Any(a => a.Id == earTrumpetActionViewModel.Id))
            {
                actions.Remove(item => item.Id == earTrumpetActionViewModel.Id);
            }
            actions.Insert(0, earTrumpetActionViewModel.GetAction());
            EarTrumpetActionsAddon.Current.Actions = actions.ToArray();
            earTrumpetActionViewModel.IsWorkSaved = true;

            if (Pages.Any(a => a == earTrumpetActionViewModel))
            {
                Pages.Remove(earTrumpetActionViewModel);
            }
            Pages.Insert(0, earTrumpetActionViewModel);
            Selected = Pages[0];
        }

        public void CompleteNavigation(NavigationCookie cookie)
        {
            _parent.CompleteNavigation(cookie);
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/AppListViewModel.cs
================================================
using EarTrumpet.Extensions;
using EarTrumpet.UI.ViewModels;
using EarTrumpet.Actions.DataModel;
using EarTrumpet.Actions.DataModel.Serialization;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls.Primitives;
using EarTrumpet.DataModel.WindowsAudio;
using EarTrumpet.DataModel.Audio;

namespace EarTrumpet.Actions.ViewModel
{
    class AppListViewModel : BindableBase
    {
        [Flags]
        public enum AppKind
        {
            Default = 0,
            EveryApp = 1,
            ForegroundApp = 2,
        }

        public ObservableCollection<IAppItemViewModel> All { get; }

        private IPartWithApp _part;

        public AppListViewModel(IPartWithApp part, AppKind flags)
        {
            _part = part;
            All = new ObservableCollection<IAppItemViewModel>();

            GetApps(flags);

            if (part.App?.Id == null)
            {
                _part.App = new AppRef { Id = All[0].Id };
            }
        }

        public void OnInvoked(object sender, IAppItemViewModel vivewModel)
        {
            _part.App = new AppRef { Id = vivewModel.Id };
            RaisePropertyChanged("");  // Signal change so ToString will be called.

            var popup = ((DependencyObject)sender).FindVisualParent<Popup>();
            popup.IsOpen = false;
        }

        public override string ToString()
        {
            var existing = All.FirstOrDefault(d => d.Id == _part.App?.Id);
            if (existing != null)
            {
                return existing.DisplayName;
            }
            return _part.App?.Id;
        }

        public void GetApps(AppKind flags)
        {
            if ((flags & AppKind.EveryApp) == AppKind.EveryApp)
            {
                All.Add(new EveryAppViewModel());
            }

            if ((flags & AppKind.ForegroundApp) == AppKind.ForegroundApp)
            {
                All.Add(new ForegroundAppViewModel());
            }

            foreach (var app in WindowsAudioFactory.Create(AudioDeviceKind.Playback).Devices.SelectMany(d => d.Groups).Distinct(IAudioDeviceSessionComparer.Instance).OrderBy(d => d.DisplayName).OrderBy(d => d.DisplayName))
            {
                All.Add(new SettingsAppItemViewModel(app));
            }
        }
    }
}

================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Conditions/DefaultDeviceConditionViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel.Conditions
{
    class DefaultDeviceConditionViewModel : PartViewModel
    {
        public DeviceListViewModel Device { get; }

        public OptionViewModel Option { get; }

        public DefaultDeviceConditionViewModel(DefaultDeviceCondition condition) : base(condition)
        {
            Option = new OptionViewModel(condition, nameof(condition.Option));
            Device = new DeviceListViewModel(condition, DeviceListViewModel.DeviceListKind.Recording);

            Attach(Option);
            Attach(Device);
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Conditions/ProcessConditionViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel.Conditions
{
    class ProcessConditionViewModel : PartViewModel
    {
        public OptionViewModel Option { get; }

        public TextViewModel Text { get; }

        public ProcessConditionViewModel(ProcessCondition condition) : base(condition)
        {
            Option = new OptionViewModel(condition, nameof(condition.Option));
            Text = new TextViewModel(condition);

            Attach(Option);
            Attach(Text);
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Conditions/VariableConditionViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel.Conditions
{
    class VariableConditionViewModel : PartViewModel
    {
        public OptionViewModel Option { get; }
        public TextViewModel Text { get; }

        public VariableConditionViewModel(VariableCondition condition) : base(condition)
        {
            Option = new OptionViewModel(condition, nameof(condition.Value));
            Text = new TextViewModel(condition);

            Attach(Option);
            Attach(Text);
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/DefaultPlaybackDeviceViewModel.cs
================================================
using EarTrumpet.DataModel.WindowsAudio;

namespace EarTrumpet.Actions.ViewModel
{
    class DefaultPlaybackDeviceViewModel : DeviceViewModelBase
    {
        public DefaultPlaybackDeviceViewModel()
        {
            DisplayName = Properties.Resources.DefaultPlaybackDeviceText;
            Kind = AudioDeviceKind.Playback.ToString();
            GroupName = Properties.Resources.PlaybackDeviceGroupText;
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/DeviceListViewModel.cs
================================================
using EarTrumpet.Extensions;
using EarTrumpet.Actions.DataModel;
using EarTrumpet.Actions.DataModel.Serialization;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls.Primitives;
using EarTrumpet.DataModel.WindowsAudio;

namespace EarTrumpet.Actions.ViewModel
{
    public class DeviceListViewModel : BindableBase
    {
        [Flags]
        public enum DeviceListKind
        {
            Playback = 0,
            Recording = 1,
            DefaultPlayback = 2
        }

        public ObservableCollection<DeviceViewModelBase> All { get; }

        public void OnInvoked(object sender, DeviceViewModelBase vivewModel)
        {
            _part.Device = new Device { Id = vivewModel.Id, Kind = vivewModel.Kind };
            RaisePropertyChanged("");  // Signal change so ToString will be called.

            var popup = ((DependencyObject)sender).FindVisualParent<Popup>();
            popup.IsOpen = false;
        }

        private IPartWithDevice _part;

        public DeviceListViewModel(IPartWithDevice part, DeviceListKind flags)
        {
            _part = part;
            All = new ObservableCollection<DeviceViewModelBase>();
            GetDevices(flags);

            if (_part.Device == null)
            {
                _part.Device = new Device { Id = All[0].Id, Kind = All[0].Kind };
            }
        }

        public override string ToString()
        {
            var existing = All.FirstOrDefault(d => d.Id == _part.Device?.Id);
            if (existing != null)
            {
                return existing.DisplayName;
            }
            return _part.Device?.Id;
        }

        void GetDevices(DeviceListKind flags)
        {
            bool isRecording = (flags & DeviceListKind.Recording) == DeviceListKind.Recording;

            if ((flags & DeviceListKind.DefaultPlayback) == DeviceListKind.DefaultPlayback)
            {
                All.Add(new DefaultPlaybackDeviceViewModel());
            }

            foreach (var device in WindowsAudioFactory.Create(AudioDeviceKind.Playback).Devices.OrderBy(d => d.DisplayName))
            {
                All.Add(new DeviceViewModel(device));
            }

            if (isRecording)
            {
                foreach (var device in WindowsAudioFactory.Create(AudioDeviceKind.Recording).Devices.OrderBy(d => d.DisplayName))
                {
                    All.Add(new DeviceViewModel(device));
                }
            }
        }
    }
}

================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/DeviceViewModel.cs
================================================
using EarTrumpet.DataModel.Audio;
using EarTrumpet.DataModel.WindowsAudio;
using EarTrumpet.UI.Helpers;

namespace EarTrumpet.Actions.ViewModel
{
    public class DeviceViewModel : DeviceViewModelBase, IAppIconSource
    {
        public bool IsDesktopApp => true;
        public string IconPath => _device.IconPath;
        public string DeviceDescription => ((IAudioDeviceWindowsAudio)_device).DeviceDescription;
        public string EnumeratorName => ((IAudioDeviceWindowsAudio)_device).EnumeratorName;
        public string InterfaceName => ((IAudioDeviceWindowsAudio)_device).InterfaceName;

        private readonly IAudioDevice _device;

        public DeviceViewModel(IAudioDevice device)
        {
            _device = device;
            Id = _device.Id;
            DisplayName = _device.DisplayName;
            Kind = _device.Parent.Kind;

            GroupName = _device.Parent.Kind == AudioDeviceKind.Playback.ToString() ?
                Properties.Resources.PlaybackDeviceGroupText :
                Properties.Resources.RecordingDeviceGroupText;
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/DeviceViewModelBase.cs
================================================
namespace EarTrumpet.Actions.ViewModel
{
    public class DeviceViewModelBase : BindableBase
    {
        public string DisplayName { get; set; }
        public string GroupName { get; set; }
        public string Id { get; set; }
        public string Kind { get; set; }

    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/EarTrumpetActionPageHeaderViewModel.cs
================================================
using EarTrumpet.UI.ViewModels;
using System.ComponentModel;

namespace EarTrumpet.Actions.ViewModel
{
    public class EarTrumpetActionPageHeaderViewModel : SettingsPageHeaderViewModel
    {
        EarTrumpetActionViewModel _parent;

        public ToolbarItemViewModel[] Toolbar => _parent.Toolbar;
        public string DisplayName { get => _parent.DisplayName; set => _parent.DisplayName = value; }
        public bool IsEditClicked { get => _parent.IsEditClicked; set => _parent.IsEditClicked = value; }
        public bool IsWorkSaved => _parent.IsWorkSaved;
        public EarTrumpetActionPageHeaderViewModel(EarTrumpetActionViewModel parent) : base(parent)
        {
            _parent = parent;
            ((INotifyPropertyChanged)_parent).PropertyChanged += EarTrumpetActionPageHeaderViewModel_PropertyChanged;
        }

        private void EarTrumpetActionPageHeaderViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            RaisePropertyChanged(e.PropertyName);
        }
    }
}

================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/EarTrumpetActionViewModel.cs
================================================
using EarTrumpet.UI.Helpers;
using EarTrumpet.UI.ViewModels;
using EarTrumpet.Actions.DataModel;
using EarTrumpet.Actions.DataModel.Serialization;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;

namespace EarTrumpet.Actions.ViewModel
{
    public class EarTrumpetActionViewModel : SettingsPageViewModel
    {
        public ToolbarItemViewModel[] Toolbar { get; private set; }
        public ICommand Delete => new RelayCommand(() => _parent.Delete(this));
        public Guid Id => _action.Id;

        public string DisplayName
        {
            get => _action.DisplayName;
            set
            {
                if (DisplayName != value)
                {
                    _action.DisplayName = value;
                    RaisePropertyChanged(nameof(DisplayName));
                    Title = DisplayName;

                    IsWorkSaved = false;
                    IsPersisted = true;
                }
            }
        }

        private bool _isEditClicked;
        public bool IsEditClicked
        {
            get => _isEditClicked;
            set
            {
                if (_isEditClicked != value)
                {
                    _isEditClicked = value;
                    RaisePropertyChanged(nameof(IsEditClicked));

                    // Immediately unset the value so we can go again.
                    _isEditClicked = false;
                    RaisePropertyChanged(nameof(IsEditClicked));
                }
            }
        }

        private bool _isWorkSaved;
        public bool IsWorkSaved
        {
            get => _isWorkSaved;
            set
            {
                if (_isWorkSaved != value)
                {
                    _isWorkSaved = value;
                    RaisePropertyChanged(nameof(IsWorkSaved));
                }
            }
        }

        public List<ContextMenuItem> NewTriggers => PartViewModelFactory.Create<BaseTrigger>().Select(t => MakeItem(t)).OrderBy(t => t.DisplayName).ToList();
        public List<ContextMenuItem> NewConditions => PartViewModelFactory.Create<BaseCondition>().Select(t => MakeItem(t)).OrderBy(t => t.DisplayName).ToList();
        public List<ContextMenuItem> NewActions => PartViewModelFactory.Create<BaseAction>().Select(t => MakeItem(t)).OrderBy(t => t.DisplayName).ToList();

        public ObservableCollection<PartViewModel> Triggers { get; private set; }
        public ObservableCollection<PartViewModel> Conditions { get; private set; }
        public ObservableCollection<PartViewModel> Actions { get; private set; }
        public bool IsPersisted { get; set; } = true;

        private EarTrumpetAction _action;
        private ActionsCategoryViewModel _parent;

        public EarTrumpetActionViewModel(ActionsCategoryViewModel parent, EarTrumpetAction action) : base("Saved Actions")
        {
            _parent = parent;
            Reset(action);
            Header = new EarTrumpetActionPageHeaderViewModel(this);
            Toolbar = new ToolbarItemViewModel[]
            {
                new ToolbarItemViewModel
                {
                     Command = new RelayCommand(() =>
                     {
                         IsEditClicked = true;
                     }),
                     DisplayName = Properties.Resources.ToolbarEditText,
                     Glyph = "\xE70F",
                     GlyphFontSize = 15,
                },
                new ToolbarItemViewModel
                {
                     Command = new RelayCommand(() =>
                     {
                         IsPersisted = true;
                         _parent.Save(this);
                     }),
                     DisplayName = Properties.Resources.ToolbarSaveText,
                     Id = "Save",
                     Glyph = "\xE105",
                     GlyphFontSize = 15,
                },
            };

            Glyph = "\xE1CE";
            Title = DisplayName;
        }

        public void Reset(EarTrumpetAction action)
        {
            _action = action;

            Title = DisplayName;
            Triggers = new ObservableCollection<PartViewModel>(action.Triggers.Select(t => CreatePartViewModel(t)));
            Conditions = new ObservableCollection<PartViewModel>(action.Conditions.Select(t => CreatePartViewModel(t)));
            Actions = new ObservableCollection<PartViewModel>(action.Actions.Select(t => CreatePartViewModel(t)));

            Triggers.CollectionChanged += Parts_CollectionChanged;
            Conditions.CollectionChanged += Parts_CollectionChanged;
            Actions.CollectionChanged += Parts_CollectionChanged;

            Parts_CollectionChanged(Triggers, null);
            Parts_CollectionChanged(Conditions, null);
            Parts_CollectionChanged(Actions, null);
            RaisePropertyChanged(nameof(Triggers));
            RaisePropertyChanged(nameof(Conditions));
            RaisePropertyChanged(nameof(Actions));
            RaisePropertyChanged(nameof(DisplayName));
            IsWorkSaved = true;
        }


        public override bool NavigatingFrom(NavigationCookie cookie)
        {
            if (!IsWorkSaved && IsPersisted)
            {
                _parent.ShowDialog(Properties.Resources.LeavingPageDialogTitle, Properties.Resources.LeavingPageDialogText, Properties.Resources.LeavingPageDialogYesText, () =>
                {
                    _parent.CompleteNavigation(cookie);

                    var existing = EarTrumpetActionsAddon.Current.Actions.FirstOrDefault(a => a.Id == Id);
                    if (existing == null)
                    {
                        _parent.Delete(this, true);
                    }
                    else
                    {
                        Reset(existing);
                    }
                    
                }, Properties.Resources.LeavingPageDialogNoText, () => { });
                return false;
            }
            return base.NavigatingFrom(cookie);
        }

        public EarTrumpetAction GetAction()
        {
            _action.DisplayName = DisplayName;
            _action.Triggers = new ObservableCollection<BaseTrigger>(Triggers.Select(t => (BaseTrigger)t.Part));
            _action.Conditions = new ObservableCollection<BaseCondition>(Conditions.Select(t => (BaseCondition)t.Part));
            _action.Actions = new ObservableCollection<BaseAction>(Actions.Select(t => (BaseAction)t.Part));
            return _action;
        }

        private void Parts_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            var col = (ObservableCollection<PartViewModel>)sender;

            for (var i = 0; i < col.Count; i++)
            {
                col[i].IsShowingAdditionalText = i != 0;
            }
            IsWorkSaved = false;
            IsPersisted = true;
        }

        private ContextMenuItem MakeItem(PartViewModel part)
        {
            return new ContextMenuItem
            {
                DisplayName = part.AddText,
                Command = new RelayCommand(() =>
                {
                    InitializeViewModel(part);
                    GetListFromPart(part).Add(part);
                }),
            };
        }

        private PartViewModel CreatePartViewModel(Part part)
        {
            var ret = PartViewModelFactory.Create(part);
            InitializeViewModel(ret);
            return ret;
        }

        private void InitializeViewModel(PartViewModel part)
        {
            part.PropertyChanged += (_, __) => IsWorkSaved = false;
            part.Remove = new RelayCommand(() => GetListFromPart(part).Remove(part));
        }

        private ObservableCollection<PartViewModel> GetListFromPart(PartViewModel part)
        {
            if (part.Part is BaseTrigger)
            {
                return Triggers;
            }
            else if (part.Part is BaseCondition)
            {
                return Conditions;
            }
            else if (part.Part is BaseAction)
            {
                return Actions;
            }
            else
            {
                throw new NotImplementedException();
            }
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/EveryAppViewModel.cs
================================================
using EarTrumpet.UI.ViewModels;
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel
{
    class EveryAppViewModel : SettingsAppItemViewModel
    {
        public EveryAppViewModel()
        {
            DisplayName = Properties.Resources.EveryAppText;
            Id = AppRef.EveryAppId;
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/ForegroundAppViewModel.cs
================================================
using EarTrumpet.UI.ViewModels;
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel
{
    class ForegroundAppViewModel : SettingsAppItemViewModel
    {
        public ForegroundAppViewModel()
        {
            Id = AppRef.ForegroundAppId;
            DisplayName = Properties.Resources.ForegroundAppText;
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/HotkeyViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;
using System;

namespace EarTrumpet.Actions.ViewModel
{
    public class HotkeyViewModel : BindableBase
    {
        public EarTrumpet.UI.ViewModels.HotkeyViewModel Hotkey { get; }

        private HotkeyTrigger _trigger;

        public HotkeyViewModel(HotkeyTrigger trigger)
        {
            _trigger = trigger;
            Hotkey = new EarTrumpet.UI.ViewModels.HotkeyViewModel(_trigger.Option, (newHotkey) =>
            {
                _trigger.Option = newHotkey;
                RaisePropertyChanged(nameof(Hotkey));
            });
        }

        public override string ToString()
        {
            if (_trigger.Option.IsEmpty)
            {
                return ResolveResource("EmptyText");
            }
            else
            {
                return _trigger.Option.ToString();
            }
        }

        private string ResolveResource(string suffix)
        {
            var res = $"{_trigger.GetType().Name}_{suffix}";
            var ret = Properties.Resources.ResourceManager.GetString(res);
            if (string.IsNullOrWhiteSpace(ret))
            {
                throw new NotImplementedException($"Missing resource: {res}");
            }
            return ret;
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/IOptionViewModel.cs
================================================
using System.Collections.ObjectModel;

namespace EarTrumpet.Actions.ViewModel
{
    interface IOptionViewModel
    {
        ObservableCollection<Option> All { get; }
        Option Selected { get; set; }
    }
}

================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/ImportExportPageViewModel.cs
================================================
using EarTrumpet.UI.Helpers;
using EarTrumpet.UI.ViewModels;
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows.Input;

namespace EarTrumpet.Actions.ViewModel
{
    public class ImportExportPageViewModel : SettingsPageViewModel
    {
        public ICommand Import { get; }
        public ICommand Export { get; }

        ActionsCategoryViewModel _parent;

        public ImportExportPageViewModel(ActionsCategoryViewModel parent) : base(DefaultManagementGroupName)
        {
            _parent = parent;
            Title = Properties.Resources.ImportAndExportTitle;
            Glyph = "\xE148";

            Import = new RelayCommand(OnImport);
            Export = new RelayCommand(OnExport);
        }

        void OnImport()
        {
            var dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.FileName = ".eta-xml";
            dlg.DefaultExt = ".eta-xml";
            dlg.Filter = $"{Properties.Resources.EtaXmlFileText}|*.eta-xml";

            if (dlg.ShowDialog() == true)
            {
                try
                {
                    EarTrumpetActionsAddon.Current.Import(dlg.FileName);
                    _parent.ReloadSavedPages();
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex);
                }
            }
        }

        void OnExport()
        {
            var dlg = new Microsoft.Win32.SaveFileDialog();
            dlg.FileName = ".eta-xml";
            dlg.DefaultExt = ".eta-xml";
            dlg.Filter = $"{Properties.Resources.EtaXmlFileText}|*.eta-xml";

            if (dlg.ShowDialog() == true)
            {
                try
                {
                    File.WriteAllText(dlg.FileName, EarTrumpetActionsAddon.Current.Export(), Encoding.Unicode);
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex);
                }
            }
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Option.cs
================================================
using System;

namespace EarTrumpet.Actions.ViewModel
{
    public class Option : IEquatable<Option>
    {
        public string DisplayName { get; set; }
        public object Value { get; set; }

        public Option(string displayName, object value)
        {
            DisplayName = displayName;
            Value = value;
        }

        public bool Equals(Option other)
        {
            return other.DisplayName.Equals(DisplayName);
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/OptionViewModel.cs
================================================
using System;
using System.Collections.ObjectModel;
using System.Linq;

namespace EarTrumpet.Actions.ViewModel
{
    class OptionViewModel : BindableBase, IOptionViewModel
    {
        public ObservableCollection<Option> All { get; }

        public Option Selected
        {
            get
            {
                var value = (int)_target.GetType().GetProperty(_property).GetValue(_target);
                return All.First(o => o.Value.Equals(value));
            }
            set
            {
                if (Selected != value)
                {
                    _target.GetType().GetProperty(_property).SetValue(_target, value.Value);
                    RaisePropertyChanged(nameof(Selected));
                }
            }
        }

        private readonly object _target;
        private readonly string _property;

        public OptionViewModel(object target, string property)
        {
            _target = target;
            _property = property;

            var propType = target.GetType().GetProperty(property).PropertyType;
            All = new ObservableCollection<Option>(Enum.GetValues(propType).Cast<int>().Select(v => 
            new Option(GetLocalizedString(Enum.GetName(propType, v)), v)));
        }

        public override string ToString()
        {
            return Selected?.DisplayName;
        }

        private string GetLocalizedString(string name)
        {
            var propType = _target.GetType().GetProperty(_property).PropertyType;
            var resourceName = $"{propType.Name}_{name}";
            var ret = Properties.Resources.ResourceManager.GetString(resourceName);
            if (string.IsNullOrWhiteSpace(ret))
            {
                throw new NotImplementedException(resourceName);
            }
            return ret;
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/PartViewModel.cs
================================================
using EarTrumpet.Actions.DataModel;
using EarTrumpet.Actions.DataModel.Serialization;
using System;
using System.ComponentModel;
using System.Windows.Input;

namespace EarTrumpet.Actions.ViewModel
{
    public class PartViewModel : BindableBase
    {
        public Part Part { get; }
        public string AddText => ResolveResource("AddText");
        public virtual string LinkText => ResolveResource("LinkText");

        private string _additionalText;
        public string AdditionalText
        {
            get => _additionalText;
            set
            {
                _additionalText = value;
                RaisePropertyChanged(nameof(AdditionalText));
            }
        }

        public bool IsShowingAdditionalText
        {
            get => !string.IsNullOrWhiteSpace(_additionalText);
            set
            {
                if (value)
                {
                    if (Part is BaseTrigger)
                    {
                        AdditionalText = Properties.Resources.TriggerAdditionalText;
                    }
                    else if (Part is BaseCondition)
                    {
                        AdditionalText = Properties.Resources.ConditionAdditionalText;
                    }
                    else
                    {
                        AdditionalText = Properties.Resources.ActionAdditionalText;
                    }
                }
                else
                {
                    AdditionalText = null;
                }
            }
        }

        public ICommand Remove { get; set; }

        public PartViewModel(Part part)
        {
            Part = part;
        }

        protected void Attach(INotifyPropertyChanged obj)
        {
            obj.PropertyChanged += (s, e) =>
            {
                RaisePropertyChanged(e.PropertyName);
                RaisePropertyChanged(nameof(LinkText));
            };
        }

        private string ResolveResource(string suffix)
        {
            var res = $"{Part.GetType().Name}_{suffix}";
            var ret = Properties.Resources.ResourceManager.GetString(res);
            if (string.IsNullOrWhiteSpace(ret))
            {
                throw new NotImplementedException($"Missing resource: {res}");
            }
            return ret;
        }
    }
}

================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/PartViewModelFactory.cs
================================================
using EarTrumpet.Actions.DataModel;
using System;
using System.Collections.Generic;
using System.Linq;

namespace EarTrumpet.Actions.ViewModel
{
    class PartViewModelFactory
    {
        class TypeInfo
        {
            public Type Type { get; set; }
            public Type ConstructorType { get; set; }
        }

        private static List<TypeInfo> s_partViewModelClasses;

        public static PartViewModel Create(Part part)
        {
            PopulateCache();

            var type = (s_partViewModelClasses.First(t => t.ConstructorType == part.GetType()));
            return (PartViewModel)Activator.CreateInstance(type.Type, part);
        }

        public static IEnumerable<PartViewModel> Create<T>() where T : Part
        {
            PopulateCache();

            return s_partViewModelClasses.Where(info =>
                (typeof(T).IsAssignableFrom(info.ConstructorType))).Select(p => Create(p));
        }

        private static PartViewModel Create(TypeInfo info)
        {
            return (PartViewModel)Activator.CreateInstance(info.Type, args: (Activator.CreateInstance(info.ConstructorType)));
        }

        private static void PopulateCache()
        {
            if (s_partViewModelClasses == null)
            {
                s_partViewModelClasses = typeof(PartViewModel).Assembly.GetTypes().Where(t =>
                    typeof(PartViewModel).IsAssignableFrom(t)).Select(t =>
                        new TypeInfo
                        {
                            Type = t,
                            ConstructorType = t.GetConstructors()[0].GetParameters()[0].ParameterType,
                        }).ToList();
            }
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/TextViewModel.cs
================================================
using EarTrumpet.Actions.DataModel;
using System;

namespace EarTrumpet.Actions.ViewModel
{
    class TextViewModel : BindableBase
    {
        public string PromptText => ResolveResource("PromptText");

        public string Text
        {
            get => _part.Text;
            set
            {
                _part.Text = value;
                RaisePropertyChanged(nameof(Text));
            }
        }

        private IPartWithText _part;

        public TextViewModel(IPartWithText part)
        {
            _part = part;
        }

        public override string ToString()
        {
            if (string.IsNullOrWhiteSpace(_part.Text))
            {
                return ResolveResource("EmptyText");
            }
            else
            { 
                return _part.Text;
            }
        }

        private string ResolveResource(string suffix)
        {
            var res = $"{_part.GetType().Name}_{suffix}";
            var ret = Properties.Resources.ResourceManager.GetString(res);
            if (string.IsNullOrWhiteSpace(ret))
            {
                throw new NotImplementedException($"Missing resource: {res}");
            }
            return ret;
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/AppEventTriggerViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel.Triggers
{
    class AppEventTriggerViewModel : PartViewModel
    {
        public OptionViewModel Option { get; }

        public DeviceListViewModel Device { get; }

        public AppListViewModel App { get; }

        public AppEventTriggerViewModel(AppEventTrigger trigger) : base(trigger)
        {
            Option = new OptionViewModel(trigger, nameof(trigger.Option));
            Device = new DeviceListViewModel(trigger, DeviceListViewModel.DeviceListKind.DefaultPlayback);
            App = new AppListViewModel(trigger, AppListViewModel.AppKind.Default);

            Attach(Option);
            Attach(Device);
            Attach(App);
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/ContextMenuTriggerViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel.Triggers
{
    class ContextMenuTriggerViewModel : PartViewModel
    {
        public ContextMenuTriggerViewModel(ContextMenuTrigger trigger) : base(trigger) { }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/DeviceEventTriggerViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel.Triggers
{
    class DeviceEventTriggerViewModel : PartViewModel
    {
        public OptionViewModel Option { get; }

        public DeviceListViewModel Device { get; }

        public DeviceEventTriggerViewModel(DeviceEventTrigger trigger) : base(trigger)
        {
            Option = new OptionViewModel(trigger, nameof(trigger.Option));
            Device = new DeviceListViewModel(trigger, DeviceListViewModel.DeviceListKind.DefaultPlayback | DeviceListViewModel.DeviceListKind.Recording);

            Attach(Option);
            Attach(Device);
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/EventTriggerViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel.Triggers
{
    class EventTriggerViewModel : PartViewModel
    {
        public OptionViewModel Option { get; }

        public EventTriggerViewModel(EventTrigger trigger) : base(trigger)
        {
            Option = new OptionViewModel(trigger, nameof(trigger.Option));
            Attach(Option);
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/HotkeyTriggerViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel.Triggers
{
    class HotkeyTriggerViewModel : PartViewModel
    {
        public HotkeyViewModel Hotkey { get; }

        private HotkeyTrigger _trigger;

        public HotkeyTriggerViewModel(HotkeyTrigger trigger) : base(trigger)
        {
            _trigger = trigger;

            Hotkey = new HotkeyViewModel(trigger);
            Attach(Hotkey);
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/ProcessTriggerViewModel.cs
================================================
using EarTrumpet.Actions.DataModel.Serialization;

namespace EarTrumpet.Actions.ViewModel.Triggers
{
    class ProcessTriggerViewModel : PartViewModel
    {
        public OptionViewModel Option { get; }
        public TextViewModel Text { get; }

        public ProcessTriggerViewModel(ProcessTrigger trigger) : base(trigger)
        {
            Option = new OptionViewModel(trigger, nameof(trigger.Option));
            Text = new TextViewModel(trigger);

            Attach(Option);
            Attach(Text);
        }
    }
}


================================================
FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/VolumeViewModel.cs
================================================
using EarTrumpet.Actions.DataModel;

namespace EarTrumpet.Actions.ViewModel
{
    public class VolumeViewModel : BindableBase
    {
        public int Volume
        {
            get => (int)_part.Volume;
            set
            {
                _part.Volume = value;
                RaisePropertyChanged(nameof(Volume));
            }
        }

        private IPartWithVolume _part;
        public VolumeViewModel(IPartWithVolume part)
        {
            _part = part;
        }

        public override string ToString()
        {
            return $"{Volume}%";
        }
    }
}


================================================
FILE: EarTrumpet/App.config
================================================
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
		<section name="bugsnag" type="Bugsnag.ConfigurationSection.Configuration, Bugsnag.ConfigurationSection" />
    </configSections>
    <bugsnag apiKey="{bugsnag.apikey}" />
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
    </startup>
    <runtime>
        <AppContextSwitchOverrides value="Switch.System.Windows.DoNotScaleForDpiChanges=false" />
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <dependentAssembly>
                <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
                <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
            </dependentAssembly>
        </assemblyBinding>
    </runtime>
</configuration>


================================================
FILE: EarTrumpet/App.manifest
================================================
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application>
            <!-- Windows 10 -->
            <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
        </application>
    </compatibility>
    <dependency>
        <dependentAssembly>
            <assemblyIdentity
                type="win32"
                name="Microsoft.Windows.Common-Controls"
                version="6.0.0.0"
                processorArchitecture="*"
                publicKeyToken="6595b64144ccf1df"
                language="*" />
        </dependentAssembly>
    </dependency>
    <application xmlns="urn:schemas-microsoft-com:asm.v3">
        <windowsSettings>
          <!-- The combination of below two tags have the following effect : 
          1) Per-Monitor for >= Windows 10 Anniversary Update
          2) System < Windows 10 Anniversary Update -->
            <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitor</dpiAwareness>
            <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
        </windowsSettings>
    </application>
</assembly>


================================================
FILE: EarTrumpet/App.xaml
================================================
<Application x:Class="EarTrumpet.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:Event="clr-namespace:EarTrumpet.Extensions.EventBinding"
             xmlns:Theme="clr-namespace:EarTrumpet.UI.Themes"
             xmlns:b="clr-namespace:EarTrumpet.UI.Behaviors"
             xmlns:bcl="clr-namespace:System;assembly=mscorlib"
             xmlns:ctl="clr-namespace:EarTrumpet.UI.Controls"
             xmlns:gif="https://github.com/XamlAnimatedGif/XamlAnimatedGif"
             xmlns:local="clr-namespace:EarTrumpet"
             xmlns:resx="clr-namespace:EarTrumpet.Properties"
             xmlns:views="clr-namespace:EarTrumpet.UI.Views"
             xmlns:vm="clr-namespace:EarTrumpet.UI.ViewModels"
             xmlns:win="clr-namespace:System.Windows;assembly=PresentationFramework"
             Startup="OnAppStartup">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="UI\Mutable.xaml" />
            </ResourceDictionary.MergedDictionaries>

            <Theme:Manager x:Key="ThemeManager">
                <Theme:Manager.References>
                    <Theme:Ref Key="Text" Value="Theme=ApplicationText{Theme}Theme, HighContrast=WindowText" />
                    <Theme:Ref Key="GrayText" Value="Light=LightSecondaryText, Dark=LightDisabledText" />
                    <Theme:Ref Key="Background" Value="Light=ApplicationBackgroundLightTheme, Dark=#FF151515, HighContrast=Window" />
                    <Theme:Ref Key="SearchClearGlyph" Value="#FF4F4F4F" />
                    <Theme:Ref Key="AcrylicBackgroundFallback" Value="Light=LightAcrylicWindowBackdropFallback, Dark=#FF1F1F1F" />
                    <Theme:Ref Key="PopupBackground">
                        <Theme:Ref.Rules>
                            <Theme:Rule On="UseAccentColor" Value=":=Background, Flyout:=SystemAccentDark1" />
                            <Theme:Rule Value="Background" />
                        </Theme:Ref.Rules>
                    </Theme:Ref>
                    <Theme:Ref Key="FlyoutThemeTrackRightBackground">
                        <Theme:Ref.Rules>
                            <Theme:Rule On="UseAccentColor" Value="Control
Download .txt
gitextract_y35wddg7/

├── .azure-pipelines.yml
├── .chocolatey/
│   ├── eartrumpet.nuspec
│   └── tools/
│       ├── LICENSE.txt
│       ├── VERIFICATION.txt
│       ├── chocolateybeforemodify.ps1
│       ├── chocolateyinstall.ps1
│       └── chocolateyuninstall.ps1
├── .gitattributes
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yml
│   │   └── config.yml
│   └── workflows/
│       ├── main.yml
│       ├── sponsors.yml
│       └── translators.yml
├── .gitignore
├── CHANGELOG.md
├── COMPILING.md
├── CONTRIBUTING.md
├── EarTrumpet/
│   ├── Addons/
│   │   └── EarTrumpet.Actions/
│   │       ├── AddonResources.xaml
│   │       ├── Controls/
│   │       │   ├── LinkedTextBlock.cs
│   │       │   └── MenuButton.cs
│   │       ├── DataModel/
│   │       │   ├── Enum/
│   │       │   │   ├── AudioAppEventKind.cs
│   │       │   │   ├── AudioDeviceEventKind.cs
│   │       │   │   ├── BoolValue.cs
│   │       │   │   ├── ComparisonBoolKind.cs
│   │       │   │   ├── EarTrumpetEventKind.cs
│   │       │   │   ├── MuteKind.cs
│   │       │   │   ├── ProcessEventKind.cs
│   │       │   │   ├── ProcessStateKind.cs
│   │       │   │   └── SetVolumeKind.cs
│   │       │   ├── IPartWithApp.cs
│   │       │   ├── IPartWithDevice.cs
│   │       │   ├── IPartWithText.cs
│   │       │   ├── IPartWithVolume.cs
│   │       │   ├── LocalVariablesContainer.cs
│   │       │   ├── Part.cs
│   │       │   ├── ProcessWatcher.cs
│   │       │   ├── Processing/
│   │       │   │   ├── ActionProcessor.cs
│   │       │   │   ├── AudioTriggerManager.cs
│   │       │   │   ├── ConditionProcessor.cs
│   │       │   │   └── TriggerManager.cs
│   │       │   └── Serialization/
│   │       │       ├── Actions.cs
│   │       │       ├── App.cs
│   │       │       ├── Conditions.cs
│   │       │       ├── Device.cs
│   │       │       ├── EarTrumpetAction.cs
│   │       │       └── Triggers.cs
│   │       ├── EarTrumpetActionsAddon.cs
│   │       ├── Interop/
│   │       │   ├── Helpers/
│   │       │   │   └── WindowWatcher.cs
│   │       │   └── User32.cs
│   │       └── ViewModel/
│   │           ├── Actions/
│   │           │   ├── SetAppMuteActionViewModel.cs
│   │           │   ├── SetAppVolumeActionViewModel.cs
│   │           │   ├── SetDefaultDeviceActionViewModel.cs
│   │           │   ├── SetDeviceMuteActionViewModel.cs
│   │           │   ├── SetDeviceVolumeActionViewModel.cs
│   │           │   └── SetVariableActionViewModel.cs
│   │           ├── ActionsCategoryViewModel.cs
│   │           ├── AppListViewModel.cs
│   │           ├── Conditions/
│   │           │   ├── DefaultDeviceConditionViewModel.cs
│   │           │   ├── ProcessConditionViewModel.cs
│   │           │   └── VariableConditionViewModel.cs
│   │           ├── DefaultPlaybackDeviceViewModel.cs
│   │           ├── DeviceListViewModel.cs
│   │           ├── DeviceViewModel.cs
│   │           ├── DeviceViewModelBase.cs
│   │           ├── EarTrumpetActionPageHeaderViewModel.cs
│   │           ├── EarTrumpetActionViewModel.cs
│   │           ├── EveryAppViewModel.cs
│   │           ├── ForegroundAppViewModel.cs
│   │           ├── HotkeyViewModel.cs
│   │           ├── IOptionViewModel.cs
│   │           ├── ImportExportPageViewModel.cs
│   │           ├── Option.cs
│   │           ├── OptionViewModel.cs
│   │           ├── PartViewModel.cs
│   │           ├── PartViewModelFactory.cs
│   │           ├── TextViewModel.cs
│   │           ├── Triggers/
│   │           │   ├── AppEventTriggerViewModel.cs
│   │           │   ├── ContextMenuTriggerViewModel.cs
│   │           │   ├── DeviceEventTriggerViewModel.cs
│   │           │   ├── EventTriggerViewModel.cs
│   │           │   ├── HotkeyTriggerViewModel.cs
│   │           │   └── ProcessTriggerViewModel.cs
│   │           └── VolumeViewModel.cs
│   ├── App.config
│   ├── App.manifest
│   ├── App.xaml
│   ├── App.xaml.cs
│   ├── AppSettings.cs
│   ├── BindableBase.cs
│   ├── DataModel/
│   │   ├── AppInformation/
│   │   │   ├── AppInformationFactory.cs
│   │   │   ├── IAppInfo.cs
│   │   │   └── Internal/
│   │   │       ├── DesktopAppInfo.cs
│   │   │       ├── ModernAppInfo.cs
│   │   │       ├── SystemSoundsAppInfo.cs
│   │   │       └── ZombieProcessException.cs
│   │   ├── Audio/
│   │   │   ├── IAudioDevice.cs
│   │   │   ├── IAudioDeviceManager.cs
│   │   │   ├── IAudioDeviceSession.cs
│   │   │   ├── IAudioDeviceSessionComparer.cs
│   │   │   ├── IStreamWithVolumeControl.cs
│   │   │   ├── Mocks/
│   │   │   │   ├── AudioDevice.cs
│   │   │   │   └── AudioDeviceSession.cs
│   │   │   └── SessionState.cs
│   │   ├── FilteredCollectionChain.cs
│   │   ├── ProcessWatcherService.cs
│   │   ├── Storage/
│   │   │   ├── ISettingsBag.cs
│   │   │   ├── Internal/
│   │   │   │   ├── NamespacedSettingsBag.cs
│   │   │   │   ├── RegistrySettingsBag.cs
│   │   │   │   └── WindowsStorageSettingsBag.cs
│   │   │   ├── Serializer.cs
│   │   │   └── StorageFactory.cs
│   │   ├── SystemSettings.cs
│   │   └── WindowsAudio/
│   │       ├── AudioDeviceKind.cs
│   │       ├── IAudioDeviceChannel.cs
│   │       ├── IAudioDeviceManagerWindowsAudio.cs
│   │       ├── IAudioDeviceSessionChannel.cs
│   │       ├── IAudioDeviceWindowsAudio.cs
│   │       ├── Internal/
│   │       │   ├── AudioDevice.cs
│   │       │   ├── AudioDeviceChannel.cs
│   │       │   ├── AudioDeviceChannelCollection.cs
│   │       │   ├── AudioDeviceManager.cs
│   │       │   ├── AudioDeviceSession.cs
│   │       │   ├── AudioDeviceSessionChannel.cs
│   │       │   ├── AudioDeviceSessionChannelCollection.cs
│   │       │   ├── AudioDeviceSessionChannelMultiplexer.cs
│   │       │   ├── AudioDeviceSessionCollection.cs
│   │       │   ├── AudioDeviceSessionGroup.cs
│   │       │   ├── AudioPolicyConfigService.cs
│   │       │   ├── Helpers.cs
│   │       │   ├── IAudioDeviceInternal.cs
│   │       │   └── IAudioDeviceSessionInternal.cs
│   │       └── WindowsAudioFactory.cs
│   ├── DebugHelpers.cs
│   ├── Diagnosis/
│   │   ├── CircularBufferTraceListener.cs
│   │   ├── ErrorReporter.cs
│   │   ├── LocalDataExporter.cs
│   │   └── SnapshotData.cs
│   ├── EarTrumpet.csproj
│   ├── Extensibility/
│   │   ├── EarTrumpetAddon.cs
│   │   ├── EarTrumpetAddonManifest.cs
│   │   ├── Hosting/
│   │   │   ├── AddonHost.cs
│   │   │   ├── AddonManager.cs
│   │   │   └── AddonResolver.cs
│   │   ├── IEarTrumpetAddonAppContent.cs
│   │   ├── IEarTrumpetAddonDeviceContent.cs
│   │   ├── IEarTrumpetAddonEvents.cs
│   │   ├── IEarTrumpetAddonNotificationAreaContextMenu.cs
│   │   ├── IEarTrumpetAddonSettingsPage.cs
│   │   └── Shared/
│   │       ├── PlaybackDataModelHost.cs
│   │       ├── ResourceLoader.cs
│   │       └── ServiceBus.cs
│   ├── Extensions/
│   │   ├── CollectionExtensions.cs
│   │   ├── ColorExtensions.cs
│   │   ├── DependencyObjectExtensions.cs
│   │   ├── EarTrumpetAddonExtensions.cs
│   │   ├── EventBinding/
│   │   │   ├── EventBindingExtension.cs
│   │   │   └── HandledEventBindingExtension.cs
│   │   ├── ExceptionExtensions.cs
│   │   ├── FloatExtensions.cs
│   │   ├── FrameworkElementExtensions.cs
│   │   ├── IEnumerableExtensions.cs
│   │   ├── IPropertyStoreExtensions.cs
│   │   ├── IconExtensions.cs
│   │   ├── ListExtensions.cs
│   │   ├── OperatingSystemExtensions.cs
│   │   ├── RegistryKeyExtensions.cs
│   │   ├── VisualExtensions.cs
│   │   └── WindowExtensions.cs
│   ├── Features.cs
│   ├── Interop/
│   │   ├── AppBarData.cs
│   │   ├── AppBarEdge.cs
│   │   ├── AppBarMessage.cs
│   │   ├── ApplicationResolver.cs
│   │   ├── CLSCTX.cs
│   │   ├── Combase.cs
│   │   ├── DwmApi.cs
│   │   ├── FolderIds.cs
│   │   ├── GPS.cs
│   │   ├── Gdi32.cs
│   │   ├── HRESULT.cs
│   │   ├── Helpers/
│   │   │   ├── AccentPolicyLibrary.cs
│   │   │   ├── AudioPolicyConfigFactory.cs
│   │   │   ├── AudioPolicyConfigFactoryImplFor21H2.cs
│   │   │   ├── AudioPolicyConfigFactoryImplForDownlevel.cs
│   │   │   ├── HotkeyData.cs
│   │   │   ├── HotkeyManager.cs
│   │   │   ├── IconHelper.cs
│   │   │   ├── ImmersiveSystemColors.cs
│   │   │   ├── InputHelper.cs
│   │   │   ├── Kernel32Helper.cs
│   │   │   ├── LegacyControlPanelHelper.cs
│   │   │   ├── MouseHook.cs
│   │   │   ├── PackageHelper.cs
│   │   │   ├── ProcessHelper.cs
│   │   │   ├── SettingsPageHelper.cs
│   │   │   ├── SingleInstanceAppMutex.cs
│   │   │   ├── Win32Window.cs
│   │   │   ├── WindowSizeHelper.cs
│   │   │   └── WindowsTaskbar.cs
│   │   ├── IPropertyStore.cs
│   │   ├── IShellItem.cs
│   │   ├── IShellItem2.cs
│   │   ├── IShellItemImageFactory.cs
│   │   ├── Kernel32.cs
│   │   ├── MMDeviceAPI/
│   │   │   ├── AUDIO_VOLUME_NOTIFICATION_DATA.cs
│   │   │   ├── AudioSessionDisconnectReason.cs
│   │   │   ├── AudioSessionState.cs
│   │   │   ├── DeviceState.cs
│   │   │   ├── EDataFlow.cs
│   │   │   ├── ERole.cs
│   │   │   ├── IAudioEndpointVolume.cs
│   │   │   ├── IAudioEndpointVolumeCallback.cs
│   │   │   ├── IAudioMeterInformation.cs
│   │   │   ├── IAudioPolicyConfigFactory.cs
│   │   │   ├── IAudioPolicyConfigFactoryVariantFor21H2.cs
│   │   │   ├── IAudioPolicyConfigFactoryVariantForDownlevel.cs
│   │   │   ├── IAudioSessionControl.cs
│   │   │   ├── IAudioSessionControl2.cs
│   │   │   ├── IAudioSessionEnumerator.cs
│   │   │   ├── IAudioSessionEvents.cs
│   │   │   ├── IAudioSessionManager.cs
│   │   │   ├── IAudioSessionManager2.cs
│   │   │   ├── IAudioSessionNotification.cs
│   │   │   ├── IAudioVolumeDuckNotification.cs
│   │   │   ├── IChannelAudioVolume.cs
│   │   │   ├── IDeviceTopology.cs
│   │   │   ├── IMMDevice.cs
│   │   │   ├── IMMDeviceCollection.cs
│   │   │   ├── IMMDeviceEnumerator.cs
│   │   │   ├── IMMEndpoint.cs
│   │   │   ├── IMMNotificationClient.cs
│   │   │   ├── IPolicyConfig.cs
│   │   │   ├── ISimpleAudioVolume.cs
│   │   │   ├── MMDeviceEnumerator.cs
│   │   │   └── PolicyConfigClient.cs
│   │   ├── NotifyIconData.cs
│   │   ├── Ntdll.cs
│   │   ├── Ole32.cs
│   │   ├── PropVariant.cs
│   │   ├── PropVariantUnion.cs
│   │   ├── PropertyKeys.cs
│   │   ├── RECT.cs
│   │   ├── SFGAO.cs
│   │   ├── SICHINT.cs
│   │   ├── SIGDN.cs
│   │   ├── SIZE.cs
│   │   ├── STGM.cs
│   │   ├── SafeHandles/
│   │   │   └── HMODULE.cs
│   │   ├── Shell32.cs
│   │   ├── SndVolSSO.cs
│   │   ├── User32.cs
│   │   ├── Uxtheme.cs
│   │   └── shlwapi.cs
│   ├── Properties/
│   │   ├── AssemblyInfo.cs
│   │   ├── Resources.Designer.cs
│   │   ├── Resources.af-ZA.resx
│   │   ├── Resources.ar-SA.resx
│   │   ├── Resources.bs-latn-ba.resx
│   │   ├── Resources.ca-ES.resx
│   │   ├── Resources.cs-CZ.resx
│   │   ├── Resources.da-DK.resx
│   │   ├── Resources.de-DE.resx
│   │   ├── Resources.el-GR.resx
│   │   ├── Resources.es-ES.resx
│   │   ├── Resources.fi-FI.resx
│   │   ├── Resources.fr-FR.resx
│   │   ├── Resources.he-IL.resx
│   │   ├── Resources.hr-HR.resx
│   │   ├── Resources.hu-HU.resx
│   │   ├── Resources.it-IT.resx
│   │   ├── Resources.ja-JP.resx
│   │   ├── Resources.ko-KR.resx
│   │   ├── Resources.nl-NL.resx
│   │   ├── Resources.no-NO.resx
│   │   ├── Resources.pl-PL.resx
│   │   ├── Resources.pt-BR.resx
│   │   ├── Resources.pt-PT.resx
│   │   ├── Resources.resx
│   │   ├── Resources.ro-RO.resx
│   │   ├── Resources.ru-RU.resx
│   │   ├── Resources.sl-SI.resx
│   │   ├── Resources.sv-SE.resx
│   │   ├── Resources.ta-IN.resx
│   │   ├── Resources.th-TH.resx
│   │   ├── Resources.tr-TR.resx
│   │   ├── Resources.uk-UA.resx
│   │   ├── Resources.vi-VN.resx
│   │   ├── Resources.zh-CN.resx
│   │   └── Resources.zh-TW.resx
│   ├── README.md
│   ├── UI/
│   │   ├── Behaviors/
│   │   │   ├── ButtonEx.cs
│   │   │   ├── ComboBoxEx.cs
│   │   │   ├── FrameworkElementEx.cs
│   │   │   ├── ScrollViewerEx.cs
│   │   │   └── TextBoxEx.cs
│   │   ├── Controls/
│   │   │   ├── AppPopup.cs
│   │   │   ├── ImageEx.cs
│   │   │   ├── ListView.cs
│   │   │   ├── ListViewItem.cs
│   │   │   ├── MenuItemTemplateSelector.cs
│   │   │   ├── SearchBox.xaml
│   │   │   └── VolumeSlider.cs
│   │   ├── Helpers/
│   │   │   ├── FlyoutViewState.cs
│   │   │   ├── IAppIconSource.cs
│   │   │   ├── IShellNotifyIconSource.cs
│   │   │   ├── NavigationCookie.cs
│   │   │   ├── RelayCommand.cs
│   │   │   ├── ShellNotifyIcon.cs
│   │   │   ├── SystemSoundsHelper.cs
│   │   │   ├── TaskbarIconSource.cs
│   │   │   ├── WindowAnimationLibrary.cs
│   │   │   ├── WindowHolder.cs
│   │   │   └── WindowViewState.cs
│   │   ├── Mutable.xaml
│   │   ├── Themes/
│   │   │   ├── AcrylicBrush.cs
│   │   │   ├── Brush.cs
│   │   │   ├── BrushValueParser.cs
│   │   │   ├── Manager.cs
│   │   │   ├── OS.cs
│   │   │   ├── Options.cs
│   │   │   ├── Ref.cs
│   │   │   ├── Rule.cs
│   │   │   └── ThemeBindingInfo.cs
│   │   ├── ViewModels/
│   │   │   ├── AddonAboutPageViewModel.cs
│   │   │   ├── AdvertisedCategorySettingsViewModel.cs
│   │   │   ├── AppItemViewModel.cs
│   │   │   ├── AudioSessionViewModel.cs
│   │   │   ├── BackstackViewModel.cs
│   │   │   ├── ContextMenuItem.cs
│   │   │   ├── DeviceCollectionViewModel.cs
│   │   │   ├── DeviceViewModel.cs
│   │   │   ├── EarTrumpetAboutPageViewModel.cs
│   │   │   ├── EarTrumpetCommunitySettingsPageViewModel.cs
│   │   │   ├── EarTrumpetLegacySettingsPageViewModel.cs
│   │   │   ├── EarTrumpetMouseSettingsPageViewModel.cs
│   │   │   ├── EarTrumpetShortcutsPageViewModel.cs
│   │   │   ├── FlyoutViewModel.cs
│   │   │   ├── FocusedAppItemViewModel.cs
│   │   │   ├── FocusedDeviceViewModel.cs
│   │   │   ├── FullWindowViewModel.cs
│   │   │   ├── HotkeyViewModel.cs
│   │   │   ├── IAppItemViewModel.cs
│   │   │   ├── IDeviceViewModel.cs
│   │   │   ├── IFlyoutViewModel.cs
│   │   │   ├── IFocusedViewModel.cs
│   │   │   ├── IPopupHostViewModel.cs
│   │   │   ├── ISettingsViewModel.cs
│   │   │   ├── ModalDialogViewModel.cs
│   │   │   ├── SettingsAppItemViewModel.cs
│   │   │   ├── SettingsCategoryViewModel.cs
│   │   │   ├── SettingsDialogViewModel.cs
│   │   │   ├── SettingsPageHeaderViewModel.cs
│   │   │   ├── SettingsPageViewModel.cs
│   │   │   ├── SettingsSearchItemViewModel.cs
│   │   │   ├── SettingsViewModel.cs
│   │   │   ├── TemporaryAppItemViewModel.cs
│   │   │   ├── ToolbarItemViewModel.cs
│   │   │   └── WelcomeViewModel.cs
│   │   └── Views/
│   │       ├── AppItemView.xaml
│   │       ├── AppItemView.xaml.cs
│   │       ├── DeviceView.xaml
│   │       ├── DeviceView.xaml.cs
│   │       ├── DialogWindow.xaml
│   │       ├── DialogWindow.xaml.cs
│   │       ├── FlyoutWindow.xaml
│   │       ├── FlyoutWindow.xaml.cs
│   │       ├── FullWindow.xaml
│   │       ├── FullWindow.xaml.cs
│   │       ├── SettingsWindow.xaml
│   │       └── SettingsWindow.xaml.cs
│   ├── packages.config
│   └── prebuild.ps1
├── EarTrumpet.ColorTool/
│   ├── App.config
│   ├── App.xaml
│   ├── App.xaml.cs
│   ├── ColorItemViewModel.cs
│   ├── ColorViewModel.cs
│   ├── EarTrumpet.ColorTool.csproj
│   ├── MainWindow.xaml
│   ├── MainWindow.xaml.cs
│   └── Properties/
│       └── AssemblyInfo.cs
├── EarTrumpet.Package/
│   ├── EarTrumpet.Package.wapproj
│   ├── Package.StoreAssociation.xml
│   ├── Package.appxmanifest
│   └── Package.xml
├── EarTrumpet.vs15.sln
├── GitVersion.yml
├── LICENSE
├── PRIVACY.md
├── Packaging/
│   └── MicrosoftStore/
│       ├── PDPs/
│       │   ├── ar-SA/
│       │   │   └── pdp.xml
│       │   ├── bs-latn-ba/
│       │   │   └── pdp.xml
│       │   ├── ca-ES/
│       │   │   └── pdp.xml
│       │   ├── cs-CZ/
│       │   │   └── pdp.xml
│       │   ├── da-DK/
│       │   │   └── pdp.xml
│       │   ├── de-DE/
│       │   │   └── pdp.xml
│       │   ├── el-GR/
│       │   │   └── pdp.xml
│       │   ├── en-us/
│       │   │   └── pdp.xml
│       │   ├── es-ES/
│       │   │   └── pdp.xml
│       │   ├── fr-FR/
│       │   │   └── pdp.xml
│       │   ├── he-IL/
│       │   │   └── pdp.xml
│       │   ├── hr-HR/
│       │   │   └── pdp.xml
│       │   ├── hu-HU/
│       │   │   └── pdp.xml
│       │   ├── it-IT/
│       │   │   └── pdp.xml
│       │   ├── ja-JP/
│       │   │   └── pdp.xml
│       │   ├── ko-KR/
│       │   │   └── pdp.xml
│       │   ├── nl-NL/
│       │   │   └── pdp.xml
│       │   ├── no-NO/
│       │   │   └── pdp.xml
│       │   ├── pl-PL/
│       │   │   └── pdp.xml
│       │   ├── pt-BR/
│       │   │   └── pdp.xml
│       │   ├── pt-PT/
│       │   │   └── pdp.xml
│       │   ├── ro-RO/
│       │   │   └── pdp.xml
│       │   ├── ru-RU/
│       │   │   └── pdp.xml
│       │   ├── sl-SI/
│       │   │   └── pdp.xml
│       │   ├── sv-SE/
│       │   │   └── pdp.xml
│       │   ├── th-TH/
│       │   │   └── pdp.xml
│       │   ├── tr-TR/
│       │   │   └── pdp.xml
│       │   ├── uk-UA/
│       │   │   └── pdp.xml
│       │   ├── vi-VN/
│       │   │   └── pdp.xml
│       │   ├── zh-CN/
│       │   │   └── pdp.xml
│       │   └── zh-TW/
│       │       └── pdp.xml
│       └── sbconfig.json
├── README.md
└── crowdin.yml
Download .txt
SYMBOL INDEX (1439 symbols across 308 files)

FILE: EarTrumpet.ColorTool/App.xaml.cs
  class App (line 5) | public partial class App : Application

FILE: EarTrumpet.ColorTool/ColorItemViewModel.cs
  class ColorItemViewModel (line 5) | public class ColorItemViewModel
    method ColorItemViewModel (line 7) | public ColorItemViewModel() { }

FILE: EarTrumpet.ColorTool/ColorViewModel.cs
  class ColorViewModel (line 11) | public class ColorViewModel : BindableBase
    method ColorViewModel (line 15) | public ColorViewModel()
    method OnTextChanged (line 20) | public void OnTextChanged(object sender, TextChangedEventArgs e)
    method Refresh (line 25) | public void Refresh(string search = null)

FILE: EarTrumpet.ColorTool/MainWindow.xaml.cs
  class MainWindow (line 5) | public partial class MainWindow : Window
    method MainWindow (line 7) | public MainWindow()

FILE: EarTrumpet/Addons/EarTrumpet.Actions/Controls/LinkedTextBlock.cs
  class LinkedTextBlock (line 17) | public class LinkedTextBlock : TextBlock
    method DataItemChanged (line 44) | private static void DataItemChanged(DependencyObject d, DependencyProp...
    method FormatTextChanged (line 54) | private static void FormatTextChanged(DependencyObject d, DependencyPr...
    method HyperlinkStyleChanged (line 73) | private static void HyperlinkStyleChanged(DependencyObject d, Dependen...
    method RunStyleChanged (line 74) | private static void RunStyleChanged(DependencyObject d, DependencyProp...
    method DataItemChanged (line 76) | private void DataItemChanged()
    method PropertiesChanged (line 81) | private void PropertiesChanged()
    method Popup_Loaded (line 159) | private void Popup_Loaded(object sender, RoutedEventArgs e)
    method ContextMenu_Loaded (line 167) | private void ContextMenu_Loaded(object sender, RoutedEventArgs e)
    method GetContextMenuFromOptionViewModel (line 174) | private List<ContextMenuItem> GetContextMenuFromOptionViewModel(IOptio...
    method ReadLinksAndText (line 184) | private void ReadLinksAndText(string text, Action<string, bool> callback)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/Controls/MenuButton.cs
  class MenuButton (line 6) | public class MenuButton : Button
    method MenuButton (line 8) | public MenuButton()
    method Button_Click (line 13) | private void Button_Click(object sender, System.Windows.RoutedEventArg...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/AudioAppEventKind.cs
  type AudioAppEventKind (line 3) | public enum AudioAppEventKind

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/AudioDeviceEventKind.cs
  type AudioDeviceEventKind (line 3) | public enum AudioDeviceEventKind

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/BoolValue.cs
  type BoolValue (line 3) | public enum BoolValue

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/ComparisonBoolKind.cs
  type ComparisonBoolKind (line 3) | public enum ComparisonBoolKind

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/EarTrumpetEventKind.cs
  type EarTrumpetEventKind (line 3) | public enum EarTrumpetEventKind

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/MuteKind.cs
  type MuteKind (line 3) | public enum MuteKind

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/ProcessEventKind.cs
  type ProcessEventKind (line 3) | public enum ProcessEventKind

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/ProcessStateKind.cs
  type ProcessStateKind (line 3) | public enum ProcessStateKind

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/SetVolumeKind.cs
  type SetVolumeKind (line 3) | public enum SetVolumeKind

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/IPartWithApp.cs
  type IPartWithApp (line 5) | interface IPartWithApp

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/IPartWithDevice.cs
  type IPartWithDevice (line 5) | public interface IPartWithDevice

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/IPartWithText.cs
  type IPartWithText (line 3) | interface IPartWithText

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/IPartWithVolume.cs
  type IPartWithVolume (line 3) | public interface IPartWithVolume

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/LocalVariablesContainer.cs
  class LocalVariablesContainer (line 5) | public class LocalVariablesContainer
    method LocalVariablesContainer (line 16) | public LocalVariablesContainer(ISettingsBag settings)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Part.cs
  class Part (line 3) | public abstract class Part { }

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/ProcessWatcher.cs
  class ProcessWatcher (line 11) | public class ProcessWatcher
    class ProcessInfo (line 13) | class ProcessInfo
    class WatcherInfo (line 18) | class WatcherInfo
    method ProcessWatcher (line 30) | public ProcessWatcher()
    method IsRunning (line 36) | public bool IsRunning(string procName)
    method OnWindowCreated (line 49) | private void OnWindowCreated(IntPtr hwnd)
    method FoundNewRelevantProcess (line 69) | bool FoundNewRelevantProcess(Process proc)
    method RegisterStop (line 95) | public void RegisterStop(string text, Action callback)
    method RegisterStart (line 116) | public void RegisterStart(string text, Action callback)
    method Clear (line 144) | public void Clear()

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Processing/ActionProcessor.cs
  class ActionProcessor (line 15) | class ActionProcessor
    method Invoke (line 17) | public static void Invoke(BaseAction a)
    method FindForegroundApp (line 117) | private static IAudioDeviceSession FindForegroundApp(ObservableCollect...
    method DoAudioAction (line 164) | private static void DoAudioAction(MuteKind action, IStreamWithVolumeCo...
    method DoAudioAction (line 180) | private static void DoAudioAction(SetVolumeKind action, IStreamWithVol...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Processing/AudioTriggerManager.cs
  class AudioTriggerManager (line 11) | class AudioTriggerManager
    method AudioTriggerManager (line 22) | public AudioTriggerManager()
    method Register (line 38) | public void Register(BaseTrigger trigger)
    method Clear (line 51) | public void Clear()
    method PlaybackDeviceManager_DefaultChanged (line 57) | private void PlaybackDeviceManager_DefaultChanged(object sender, EarTr...
    method RecordingMgr_DefaultChanged (line 66) | private void RecordingMgr_DefaultChanged(object sender, IAudioDevice n...
    method ProcessDefaultChanged (line 75) | private void ProcessDefaultChanged(IAudioDevice newDefault)
    method OnDeviceAddOrRemove (line 93) | private void OnDeviceAddOrRemove(IAudioDevice device, AudioDeviceEvent...
    method OnAppAddOrRemove (line 108) | private void OnAppAddOrRemove(IAudioDeviceSession app, AudioAppEventKi...
    method OnAppPropertyChanged (line 127) | private void OnAppPropertyChanged(IAudioDeviceSession app, string prop...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Processing/ConditionProcessor.cs
  class ConditionProcessor (line 8) | class ConditionProcessor
    method IsMet (line 10) | public static bool IsMet(BaseCondition condition)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Processing/TriggerManager.cs
  class TriggerManager (line 10) | class TriggerManager
    method TriggerManager (line 17) | public TriggerManager()
    method Clear (line 23) | public void Clear()
    method OnEvent (line 30) | public void OnEvent(AddonEventKind evt)
    method Register (line 42) | public void Register(BaseTrigger trig)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/Actions.cs
  class BaseAction (line 6) | [XmlInclude(typeof(SetAppVolumeAction))]
  class SetAppMuteAction (line 14) | public class SetAppMuteAction : BaseAction, IPartWithDevice, IPartWithApp
  class SetAppVolumeAction (line 21) | public class SetAppVolumeAction : BaseAction, IPartWithVolume, IPartWith...
  class SetDefaultDeviceAction (line 29) | public class SetDefaultDeviceAction : BaseAction, IPartWithDevice
  class SetDeviceMuteAction (line 34) | public class SetDeviceMuteAction : BaseAction, IPartWithDevice
  class SetDeviceVolumeAction (line 40) | public class SetDeviceVolumeAction : BaseAction, IPartWithDevice, IPartW...
  class SetVariableAction (line 47) | public class SetVariableAction : BaseAction, IPartWithText

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/App.cs
  class AppRef (line 3) | public class AppRef
    method GetHashCode (line 10) | public override int GetHashCode()
    method Equals (line 15) | public bool Equals(AppRef other)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/Conditions.cs
  class BaseCondition (line 6) | [XmlInclude(typeof(DefaultDeviceCondition))]
  class DefaultDeviceCondition (line 11) | public class DefaultDeviceCondition : BaseCondition, IPartWithDevice
  class ProcessCondition (line 17) | public class ProcessCondition : BaseCondition, IPartWithText
  class VariableCondition (line 23) | public class VariableCondition : BaseCondition, IPartWithText

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/Device.cs
  class Device (line 3) | public class Device
    method GetHashCode (line 9) | public override int GetHashCode()
    method Equals (line 14) | public bool Equals(Device other)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/EarTrumpetAction.cs
  class EarTrumpetAction (line 6) | public class EarTrumpetAction

FILE: EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/Triggers.cs
  class BaseTrigger (line 7) | [XmlInclude(typeof(EventTrigger))]
  class AppEventTrigger (line 15) | public class AppEventTrigger : BaseTrigger, IPartWithDevice, IPartWithApp
  class ContextMenuTrigger (line 22) | public class ContextMenuTrigger : BaseTrigger { }
  class DeviceEventTrigger (line 24) | public class DeviceEventTrigger : BaseTrigger, IPartWithDevice
  class EventTrigger (line 30) | public class EventTrigger : BaseTrigger
  class HotkeyTrigger (line 35) | public class HotkeyTrigger : BaseTrigger
  class ProcessTrigger (line 40) | public class ProcessTrigger : BaseTrigger, IPartWithText

FILE: EarTrumpet/Addons/EarTrumpet.Actions/EarTrumpetActionsAddon.cs
  class EarTrumpetActionsAddon (line 17) | [Export(typeof(EarTrumpetAddon))]
    method EarTrumpetActionsAddon (line 23) | public EarTrumpetActionsAddon() : base()
    method OnAddonEvent (line 42) | public void OnAddonEvent(AddonEventKind evt)
    method GetSettingsCategory (line 60) | public SettingsCategoryViewModel GetSettingsCategory()
    method LoadAndRegister (line 91) | private void LoadAndRegister()
    method Import (line 98) | public void Import(string fileName)
    method Export (line 109) | public string Export()
    method OnTriggered (line 114) | private void OnTriggered(BaseTrigger trigger)
    method TriggerAction (line 123) | public void TriggerAction(EarTrumpetAction action)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/Interop/Helpers/WindowWatcher.cs
  class WindowWatcher (line 8) | class WindowWatcher
    method WindowWatcher (line 15) | public WindowWatcher()
    method WndProc (line 26) | void WndProc(Message m)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/Interop/User32.cs
  class User32 (line 6) | class User32
    method RegisterShellHookWindow (line 12) | [DllImport("user32.dll", PreserveSig = true)]
    method RegisterWindowMessageW (line 16) | [DllImport("user32.dll", PreserveSig = true)]

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetAppMuteActionViewModel.cs
  class SetAppMuteActionViewModel (line 5) | class SetAppMuteActionViewModel : PartViewModel
    method SetAppMuteActionViewModel (line 13) | public SetAppMuteActionViewModel(SetAppMuteAction action) : base(action)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetAppVolumeActionViewModel.cs
  class SetAppVolumeActionViewModel (line 6) | class SetAppVolumeActionViewModel : PartViewModel
    method SetAppVolumeActionViewModel (line 15) | public SetAppVolumeActionViewModel(SetAppVolumeAction action) : base(a...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetDefaultDeviceActionViewModel.cs
  class SetDefaultDeviceActionViewModel (line 5) | class SetDefaultDeviceActionViewModel : PartViewModel
    method SetDefaultDeviceActionViewModel (line 9) | public SetDefaultDeviceActionViewModel(SetDefaultDeviceAction action) ...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetDeviceMuteActionViewModel.cs
  class SetDeviceMuteActionViewModel (line 5) | class SetDeviceMuteActionViewModel : PartViewModel
    method SetDeviceMuteActionViewModel (line 12) | public SetDeviceMuteActionViewModel(SetDeviceMuteAction action) : base...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetDeviceVolumeActionViewModel.cs
  class SetDeviceVolumeActionViewModel (line 6) | class SetDeviceVolumeActionViewModel : PartViewModel
    method SetDeviceVolumeActionViewModel (line 14) | public SetDeviceVolumeActionViewModel(SetDeviceVolumeAction action) : ...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetVariableActionViewModel.cs
  class SetVariableActionViewModel (line 5) | class SetVariableActionViewModel : PartViewModel
    method SetVariableActionViewModel (line 10) | public SetVariableActionViewModel(SetVariableAction action) : base(act...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/ActionsCategoryViewModel.cs
  class ActionsCategoryViewModel (line 11) | public class ActionsCategoryViewModel : SettingsCategoryViewModel
    method ActionsCategoryViewModel (line 13) | public ActionsCategoryViewModel()
    method ReloadSavedPages (line 52) | internal void ReloadSavedPages()
    method Delete (line 63) | public void Delete(EarTrumpetActionViewModel earTrumpetActionViewModel...
    method Save (line 91) | public void Save(EarTrumpetActionViewModel earTrumpetActionViewModel)
    method CompleteNavigation (line 110) | public void CompleteNavigation(NavigationCookie cookie)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/AppListViewModel.cs
  class AppListViewModel (line 15) | class AppListViewModel : BindableBase
    type AppKind (line 17) | [Flags]
    method AppListViewModel (line 29) | public AppListViewModel(IPartWithApp part, AppKind flags)
    method OnInvoked (line 42) | public void OnInvoked(object sender, IAppItemViewModel vivewModel)
    method ToString (line 51) | public override string ToString()
    method GetApps (line 61) | public void GetApps(AppKind flags)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Conditions/DefaultDeviceConditionViewModel.cs
  class DefaultDeviceConditionViewModel (line 5) | class DefaultDeviceConditionViewModel : PartViewModel
    method DefaultDeviceConditionViewModel (line 11) | public DefaultDeviceConditionViewModel(DefaultDeviceCondition conditio...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Conditions/ProcessConditionViewModel.cs
  class ProcessConditionViewModel (line 5) | class ProcessConditionViewModel : PartViewModel
    method ProcessConditionViewModel (line 11) | public ProcessConditionViewModel(ProcessCondition condition) : base(co...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Conditions/VariableConditionViewModel.cs
  class VariableConditionViewModel (line 5) | class VariableConditionViewModel : PartViewModel
    method VariableConditionViewModel (line 10) | public VariableConditionViewModel(VariableCondition condition) : base(...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/DefaultPlaybackDeviceViewModel.cs
  class DefaultPlaybackDeviceViewModel (line 5) | class DefaultPlaybackDeviceViewModel : DeviceViewModelBase
    method DefaultPlaybackDeviceViewModel (line 7) | public DefaultPlaybackDeviceViewModel()

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/DeviceListViewModel.cs
  class DeviceListViewModel (line 13) | public class DeviceListViewModel : BindableBase
    type DeviceListKind (line 15) | [Flags]
    method OnInvoked (line 25) | public void OnInvoked(object sender, DeviceViewModelBase vivewModel)
    method DeviceListViewModel (line 36) | public DeviceListViewModel(IPartWithDevice part, DeviceListKind flags)
    method ToString (line 48) | public override string ToString()
    method GetDevices (line 58) | void GetDevices(DeviceListKind flags)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/DeviceViewModel.cs
  class DeviceViewModel (line 7) | public class DeviceViewModel : DeviceViewModelBase, IAppIconSource
    method DeviceViewModel (line 17) | public DeviceViewModel(IAudioDevice device)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/DeviceViewModelBase.cs
  class DeviceViewModelBase (line 3) | public class DeviceViewModelBase : BindableBase

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/EarTrumpetActionPageHeaderViewModel.cs
  class EarTrumpetActionPageHeaderViewModel (line 6) | public class EarTrumpetActionPageHeaderViewModel : SettingsPageHeaderVie...
    method EarTrumpetActionPageHeaderViewModel (line 14) | public EarTrumpetActionPageHeaderViewModel(EarTrumpetActionViewModel p...
    method EarTrumpetActionPageHeaderViewModel_PropertyChanged (line 20) | private void EarTrumpetActionPageHeaderViewModel_PropertyChanged(objec...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/EarTrumpetActionViewModel.cs
  class EarTrumpetActionViewModel (line 13) | public class EarTrumpetActionViewModel : SettingsPageViewModel
    method EarTrumpetActionViewModel (line 80) | public EarTrumpetActionViewModel(ActionsCategoryViewModel parent, EarT...
    method Reset (line 115) | public void Reset(EarTrumpetAction action)
    method NavigatingFrom (line 139) | public override bool NavigatingFrom(NavigationCookie cookie)
    method GetAction (line 163) | public EarTrumpetAction GetAction()
    method Parts_CollectionChanged (line 172) | private void Parts_CollectionChanged(object sender, System.Collections...
    method MakeItem (line 184) | private ContextMenuItem MakeItem(PartViewModel part)
    method CreatePartViewModel (line 197) | private PartViewModel CreatePartViewModel(Part part)
    method InitializeViewModel (line 204) | private void InitializeViewModel(PartViewModel part)
    method GetListFromPart (line 210) | private ObservableCollection<PartViewModel> GetListFromPart(PartViewMo...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/EveryAppViewModel.cs
  class EveryAppViewModel (line 6) | class EveryAppViewModel : SettingsAppItemViewModel
    method EveryAppViewModel (line 8) | public EveryAppViewModel()

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/ForegroundAppViewModel.cs
  class ForegroundAppViewModel (line 6) | class ForegroundAppViewModel : SettingsAppItemViewModel
    method ForegroundAppViewModel (line 8) | public ForegroundAppViewModel()

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/HotkeyViewModel.cs
  class HotkeyViewModel (line 6) | public class HotkeyViewModel : BindableBase
    method HotkeyViewModel (line 12) | public HotkeyViewModel(HotkeyTrigger trigger)
    method ToString (line 22) | public override string ToString()
    method ResolveResource (line 34) | private string ResolveResource(string suffix)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/IOptionViewModel.cs
  type IOptionViewModel (line 5) | interface IOptionViewModel

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/ImportExportPageViewModel.cs
  class ImportExportPageViewModel (line 11) | public class ImportExportPageViewModel : SettingsPageViewModel
    method ImportExportPageViewModel (line 18) | public ImportExportPageViewModel(ActionsCategoryViewModel parent) : ba...
    method OnImport (line 28) | void OnImport()
    method OnExport (line 49) | void OnExport()

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Option.cs
  class Option (line 5) | public class Option : IEquatable<Option>
    method Option (line 10) | public Option(string displayName, object value)
    method Equals (line 16) | public bool Equals(Option other)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/OptionViewModel.cs
  class OptionViewModel (line 7) | class OptionViewModel : BindableBase, IOptionViewModel
    method OptionViewModel (line 31) | public OptionViewModel(object target, string property)
    method ToString (line 41) | public override string ToString()
    method GetLocalizedString (line 46) | private string GetLocalizedString(string name)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/PartViewModel.cs
  class PartViewModel (line 9) | public class PartViewModel : BindableBase
    method PartViewModel (line 55) | public PartViewModel(Part part)
    method Attach (line 60) | protected void Attach(INotifyPropertyChanged obj)
    method ResolveResource (line 69) | private string ResolveResource(string suffix)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/PartViewModelFactory.cs
  class PartViewModelFactory (line 8) | class PartViewModelFactory
    class TypeInfo (line 10) | class TypeInfo
    method Create (line 18) | public static PartViewModel Create(Part part)
    method Create (line 26) | public static IEnumerable<PartViewModel> Create<T>() where T : Part
    method Create (line 34) | private static PartViewModel Create(TypeInfo info)
    method PopulateCache (line 39) | private static void PopulateCache()

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/TextViewModel.cs
  class TextViewModel (line 6) | class TextViewModel : BindableBase
    method TextViewModel (line 22) | public TextViewModel(IPartWithText part)
    method ToString (line 27) | public override string ToString()
    method ResolveResource (line 39) | private string ResolveResource(string suffix)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/AppEventTriggerViewModel.cs
  class AppEventTriggerViewModel (line 5) | class AppEventTriggerViewModel : PartViewModel
    method AppEventTriggerViewModel (line 13) | public AppEventTriggerViewModel(AppEventTrigger trigger) : base(trigger)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/ContextMenuTriggerViewModel.cs
  class ContextMenuTriggerViewModel (line 5) | class ContextMenuTriggerViewModel : PartViewModel
    method ContextMenuTriggerViewModel (line 7) | public ContextMenuTriggerViewModel(ContextMenuTrigger trigger) : base(...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/DeviceEventTriggerViewModel.cs
  class DeviceEventTriggerViewModel (line 5) | class DeviceEventTriggerViewModel : PartViewModel
    method DeviceEventTriggerViewModel (line 11) | public DeviceEventTriggerViewModel(DeviceEventTrigger trigger) : base(...

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/EventTriggerViewModel.cs
  class EventTriggerViewModel (line 5) | class EventTriggerViewModel : PartViewModel
    method EventTriggerViewModel (line 9) | public EventTriggerViewModel(EventTrigger trigger) : base(trigger)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/HotkeyTriggerViewModel.cs
  class HotkeyTriggerViewModel (line 5) | class HotkeyTriggerViewModel : PartViewModel
    method HotkeyTriggerViewModel (line 11) | public HotkeyTriggerViewModel(HotkeyTrigger trigger) : base(trigger)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/ProcessTriggerViewModel.cs
  class ProcessTriggerViewModel (line 5) | class ProcessTriggerViewModel : PartViewModel
    method ProcessTriggerViewModel (line 10) | public ProcessTriggerViewModel(ProcessTrigger trigger) : base(trigger)

FILE: EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/VolumeViewModel.cs
  class VolumeViewModel (line 5) | public class VolumeViewModel : BindableBase
    method VolumeViewModel (line 18) | public VolumeViewModel(IPartWithVolume part)
    method ToString (line 23) | public override string ToString()

FILE: EarTrumpet/App.xaml.cs
  class App (line 23) | public partial class App
    method OnAppStartup (line 45) | private void OnAppStartup(object sender, StartupEventArgs e)
    method ContinueStartup (line 78) | private void ContinueStartup()
    method CompleteStartup (line 97) | private void CompleteStartup()
    method trayIconScrolled (line 124) | private void trayIconScrolled(object _, int wheelDelta)
    method DisplayFirstRunExperience (line 136) | private void DisplayFirstRunExperience()
    method IsCriticalFontLoadFailure (line 153) | private bool IsCriticalFontLoadFailure(Exception ex)
    method OnCriticalFontLoadFailure (line 159) | private void OnCriticalFontLoadFailure()
    method GetTrayContextMenuItems (line 182) | private IEnumerable<ContextMenuItem> GetTrayContextMenuItems()
    method CreateSettingsExperience (line 238) | private Window CreateSettingsExperience()
    method CreateAddonSettingsPage (line 266) | private SettingsCategoryViewModel CreateAddonSettingsPage(IEarTrumpetA...
    method CreateMixerExperience (line 278) | private Window CreateMixerExperience() => new FullWindow { DataContext...
    method AbsoluteVolumeIncrement (line 280) | private void AbsoluteVolumeIncrement()
    method AbsoluteVolumeDecrement (line 290) | private void AbsoluteVolumeDecrement()

FILE: EarTrumpet/AppSettings.cs
  class AppSettings (line 10) | public class AppSettings
    method RegisterHotkeys (line 21) | public void RegisterHotkeys()
    method IsTelemetryEnabledByDefault (line 181) | private bool IsTelemetryEnabledByDefault()

FILE: EarTrumpet/BindableBase.cs
  class BindableBase (line 5) | public class BindableBase : INotifyPropertyChanged
    method RaisePropertyChanged (line 9) | protected void RaisePropertyChanged(string name)

FILE: EarTrumpet/DataModel/AppInformation/AppInformationFactory.cs
  class AppInformationFactory (line 5) | public class AppInformationFactory
    method CreateForProcess (line 7) | public static IAppInfo CreateForProcess(int processId, bool trackProce...

FILE: EarTrumpet/DataModel/AppInformation/IAppInfo.cs
  type IAppInfo (line 5) | public interface IAppInfo

FILE: EarTrumpet/DataModel/AppInformation/Internal/DesktopAppInfo.cs
  class DesktopAppInfo (line 10) | class DesktopAppInfo : IAppInfo
    method DesktopAppInfo (line 22) | public DesktopAppInfo(int processId, bool trackProcess)
    method TryGetExecutableNameViaNtByPid (line 111) | private static bool TryGetExecutableNameViaNtByPid(int processId, out ...

FILE: EarTrumpet/DataModel/AppInformation/Internal/ModernAppInfo.cs
  class ModernAppInfo (line 9) | class ModernAppInfo : IAppInfo
    method ModernAppInfo (line 21) | public ModernAppInfo(int processId, bool trackProcess)
    method GetAppUserModelIdByPid (line 55) | private static string GetAppUserModelIdByPid(int processId)
    method CanResolveAppByApplicationUserModelId (line 149) | private static bool CanResolveAppByApplicationUserModelId(string aumid)

FILE: EarTrumpet/DataModel/AppInformation/Internal/SystemSoundsAppInfo.cs
  class SystemSoundsAppInfo (line 8) | class SystemSoundsAppInfo : IAppInfo
    method SystemSoundsAppInfo (line 18) | public SystemSoundsAppInfo()
    method Is64BitOperatingSystem (line 24) | private static bool Is64BitOperatingSystem()

FILE: EarTrumpet/DataModel/AppInformation/Internal/ZombieProcessException.cs
  class ZombieProcessException (line 6) | public class ZombieProcessException : Exception
    method ZombieProcessException (line 8) | public ZombieProcessException(int processId) : base($"Process is a zom...
    method ThrowIfZombie (line 10) | public static void ThrowIfZombie(int processId, IntPtr handle)

FILE: EarTrumpet/DataModel/Audio/IAudioDevice.cs
  type IAudioDevice (line 6) | public interface IAudioDevice : IStreamWithVolumeControl
    method AddFilter (line 12) | void AddFilter(Func<ObservableCollection<IAudioDeviceSession>, Observa...

FILE: EarTrumpet/DataModel/Audio/IAudioDeviceManager.cs
  type IAudioDeviceManager (line 6) | public interface IAudioDeviceManager
    method UpdatePeakValues (line 13) | void UpdatePeakValues();
    method AddFilter (line 14) | void AddFilter(Func<ObservableCollection<IAudioDevice>, ObservableColl...

FILE: EarTrumpet/DataModel/Audio/IAudioDeviceSession.cs
  type IAudioDeviceSession (line 7) | public interface IAudioDeviceSession : IStreamWithVolumeControl

FILE: EarTrumpet/DataModel/Audio/IAudioDeviceSessionComparer.cs
  class IAudioDeviceSessionComparer (line 5) | public class IAudioDeviceSessionComparer : IEqualityComparer<IAudioDevic...
    method Equals (line 9) | public bool Equals(IAudioDeviceSession x, IAudioDeviceSession y)
    method GetHashCode (line 14) | public int GetHashCode(IAudioDeviceSession obj)

FILE: EarTrumpet/DataModel/Audio/IStreamWithVolumeControl.cs
  type IStreamWithVolumeControl (line 5) | public interface IStreamWithVolumeControl : INotifyPropertyChanged

FILE: EarTrumpet/DataModel/Audio/Mocks/AudioDevice.cs
  class AudioDevice (line 11) | class AudioDevice : BindableBase, IAudioDevice, IAudioDeviceInternal, IA...
    method AudioDevice (line 13) | public AudioDevice(string id, IAudioDeviceManager parent)
    method AddFilter (line 72) | public void AddFilter(Func<ObservableCollection<IAudioDeviceSession>, ...
    method UpdatePeakValue (line 76) | public void UpdatePeakValue()
    method MoveHiddenAppsToDevice (line 80) | public void MoveHiddenAppsToDevice(string appId, string id)
    method UnhideSessionsForProcessId (line 84) | public void UnhideSessionsForProcessId(int processId)

FILE: EarTrumpet/DataModel/Audio/Mocks/AudioDeviceSession.cs
  class AudioDeviceSession (line 11) | class AudioDeviceSession : BindableBase, IAudioDeviceSessionInternal
    method AudioDeviceSession (line 80) | public AudioDeviceSession(IAudioDevice parent, string id, string displ...
    method Hide (line 90) | public void Hide()
    method UnHide (line 95) | public void UnHide()
    method MoveToDevice (line 100) | public void MoveToDevice(string id, bool hide)
    method UpdatePeakValueBackground (line 105) | public void UpdatePeakValueBackground()

FILE: EarTrumpet/DataModel/Audio/SessionState.cs
  type SessionState (line 3) | public enum SessionState

FILE: EarTrumpet/DataModel/FilteredCollectionChain.cs
  class FilteredCollectionChain (line 8) | public class FilteredCollectionChain<T>
    method FilteredCollectionChain (line 14) | public FilteredCollectionChain(ObservableCollection<T> items, Dispatch...
    method Listen (line 26) | void Listen()
    method Free (line 31) | void Free()
    method Sessions_CollectionChanged (line 36) | private void Sessions_CollectionChanged(object sender, System.Collecti...
    method AddFilter (line 50) | public void AddFilter(Func<ObservableCollection<T>, ObservableCollecti...
    method Populate (line 58) | private void Populate()

FILE: EarTrumpet/DataModel/ProcessWatcherService.cs
  class ProcessWatcherService (line 12) | public class ProcessWatcherService
    class ProcessWatcherData (line 14) | class ProcessWatcherData
    method WatchProcess (line 28) | public static void WatchProcess(int processId, Action<int> processQuit)
    method EnsureWatcherThreadRunning (line 62) | private static void EnsureWatcherThreadRunning()

FILE: EarTrumpet/DataModel/Storage/ISettingsBag.cs
  type ISettingsBag (line 5) | public interface ISettingsBag
    method HasKey (line 8) | bool HasKey(string key);
    method Get (line 9) | T Get<T>(string key, T defaultValue);
    method Set (line 10) | void Set<T>(string key, T value);

FILE: EarTrumpet/DataModel/Storage/Internal/NamespacedSettingsBag.cs
  class NamespacedSettingsBag (line 5) | class NamespacedSettingsBag : ISettingsBag
    method NamespacedSettingsBag (line 13) | public NamespacedSettingsBag(string nameSpace, ISettingsBag bag)
    method Get (line 20) | public T Get<T>(string key, T defaultValue)
    method HasKey (line 25) | public bool HasKey(string key)
    method Set (line 30) | public void Set<T>(string key, T value)

FILE: EarTrumpet/DataModel/Storage/Internal/RegistrySettingsBag.cs
  class RegistrySettingsBag (line 6) | class RegistrySettingsBag : ISettingsBag
    method HasKey (line 14) | public bool HasKey(string key)
    method Get (line 22) | public T Get<T>(string key, T defaultValue)
    method Set (line 38) | public void Set<T>(string key, T value)
    method ReadSetting (line 52) | static T ReadSetting<T>(string key, T defaultValue)
    method WriteSetting (line 69) | static void WriteSetting<T>(string key, T value)

FILE: EarTrumpet/DataModel/Storage/Internal/WindowsStorageSettingsBag.cs
  class WindowsStorageSettingsBag (line 8) | class WindowsStorageSettingsBag : ISettingsBag
    method HasKey (line 15) | public bool HasKey(string key)
    method Get (line 29) | public T Get<T>(string key, T defaultValue)
    method Set (line 50) | public void Set<T>(string key, T value)
    method ReadSetting (line 64) | static T ReadSetting<T>(string key, T defaultValue)
    method WriteSetting (line 78) | static void WriteSetting<T>(string key, T value)

FILE: EarTrumpet/DataModel/Storage/Serializer.cs
  class Serializer (line 7) | public class Serializer
    method FromString (line 9) | public static T FromString<T>(string data)
    method ToString (line 17) | public static string ToString<T>(string key, T value)

FILE: EarTrumpet/DataModel/Storage/StorageFactory.cs
  class StorageFactory (line 3) | public class StorageFactory
    method StorageFactory (line 7) | static StorageFactory()
    method GetSettings (line 12) | public static ISettingsBag GetSettings(string nameSpace = null)

FILE: EarTrumpet/DataModel/SystemSettings.cs
  class SystemSettings (line 8) | public static class SystemSettings
    method ReadDword (line 32) | private static bool ReadDword(string key, string valueName, int defaul...
    method LightThemeShim (line 41) | private static bool LightThemeShim(bool registryValue)

FILE: EarTrumpet/DataModel/WindowsAudio/AudioDeviceKind.cs
  type AudioDeviceKind (line 3) | public enum AudioDeviceKind

FILE: EarTrumpet/DataModel/WindowsAudio/IAudioDeviceChannel.cs
  type IAudioDeviceChannel (line 5) | public interface IAudioDeviceChannel : INotifyPropertyChanged

FILE: EarTrumpet/DataModel/WindowsAudio/IAudioDeviceManagerWindowsAudio.cs
  type IAudioDeviceManagerWindowsAudio (line 6) | public interface IAudioDeviceManagerWindowsAudio
    method SetDefaultDevice (line 8) | void SetDefaultDevice(IAudioDevice device, ERole role);
    method GetDefaultDevice (line 9) | IAudioDevice GetDefaultDevice(ERole role);
    method SetDefaultEndPoint (line 10) | void SetDefaultEndPoint(string id, int pid);
    method GetDefaultEndPoint (line 11) | string GetDefaultEndPoint(int processId);
    method MoveHiddenAppsToDevice (line 12) | void MoveHiddenAppsToDevice(string appId, string deviceId);
    method UnhideSessionsForProcessId (line 13) | void UnhideSessionsForProcessId(string deviceId, int processId);

FILE: EarTrumpet/DataModel/WindowsAudio/IAudioDeviceSessionChannel.cs
  type IAudioDeviceSessionChannel (line 5) | public interface IAudioDeviceSessionChannel : INotifyPropertyChanged

FILE: EarTrumpet/DataModel/WindowsAudio/IAudioDeviceWindowsAudio.cs
  type IAudioDeviceWindowsAudio (line 6) | public interface IAudioDeviceWindowsAudio : IAudioDevice

FILE: EarTrumpet/DataModel/WindowsAudio/Internal/AudioDevice.cs
  class AudioDevice (line 15) | public class AudioDevice : BindableBase, IAudioEndpointVolumeCallback, I...
    method AudioDevice (line 36) | public AudioDevice(IAudioDeviceManager deviceManager, IMMDevice device...
    method OnNotify (line 81) | void IAudioEndpointVolumeCallback.OnNotify(IntPtr pNotify)
    method UpdatePeakValue (line 176) | public void UpdatePeakValue()
    method UnhideSessionsForProcessId (line 188) | public void UnhideSessionsForProcessId(int processId)
    method MoveHiddenAppsToDevice (line 193) | public void MoveHiddenAppsToDevice(string appId, string id)
    method ReadProperties (line 198) | private void ReadProperties()
    method ReadSpeakerConfiguration (line 219) | private void ReadSpeakerConfiguration()
    method DevicePropertiesChanged (line 234) | public void DevicePropertiesChanged(IMMDevice dev)
    method AddFilter (line 247) | public void AddFilter(Func<ObservableCollection<IAudioDeviceSession>, ...

FILE: EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceChannel.cs
  class AudioDeviceChannel (line 7) | class AudioDeviceChannel : BindableBase, INotifyPropertyChanged, IAudioD...
    method AudioDeviceChannel (line 13) | public AudioDeviceChannel(IAudioEndpointVolume deviceVolume, uint index)
    method OnNotify (line 36) | internal void OnNotify(float newLevel)

FILE: EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceChannelCollection.cs
  class AudioDeviceChannelCollection (line 9) | class AudioDeviceChannelCollection
    method AudioDeviceChannelCollection (line 16) | public AudioDeviceChannelCollection(IAudioEndpointVolume deviceVolume,...
    method OnNotify (line 31) | public void OnNotify(IntPtr pNotify, AUDIO_VOLUME_NOTIFICATION_DATA data)

FILE: EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceManager.cs
  class AudioDeviceManager (line 15) | class AudioDeviceManager : IMMNotificationClient, IAudioDeviceManager, I...
    method AudioDeviceManager (line 50) | public AudioDeviceManager(AudioDeviceKind kind)
    method QueryDefaultDevice (line 107) | private void QueryDefaultDevice()
    method SetDefaultDevice (line 119) | public void SetDefaultDevice(IAudioDevice device, ERole role = ERole.e...
    method GetDefaultDevice (line 139) | public IAudioDevice GetDefaultDevice(ERole eRole = ERole.eMultimedia)
    method MoveHiddenAppsToDevice (line 154) | public void MoveHiddenAppsToDevice(string appId, string id)
    method UnhideSessionsForProcessId (line 162) | public void UnhideSessionsForProcessId(string deviceId, int processId)
    method UpdatePeakValues (line 170) | public void UpdatePeakValues()
    method OnDeviceAdded (line 178) | void IMMNotificationClient.OnDeviceAdded(string pwstrDeviceId)
    method OnDeviceRemoved (line 211) | void IMMNotificationClient.OnDeviceRemoved(string pwstrDeviceId)
    method OnDefaultDeviceChanged (line 224) | void IMMNotificationClient.OnDefaultDeviceChanged(EDataFlow flow, ERol...
    method OnDeviceStateChanged (line 237) | void IMMNotificationClient.OnDeviceStateChanged(string pwstrDeviceId, ...
    method OnPropertyValueChanged (line 256) | void IMMNotificationClient.OnPropertyValueChanged(string pwstrDeviceId...
    method SetDefaultEndPoint (line 276) | public void SetDefaultEndPoint(string id, int pid)
    method GetDefaultEndPoint (line 287) | public string GetDefaultEndPoint(int processId)
    method AddFilter (line 296) | public void AddFilter(Func<ObservableCollection<IAudioDevice>, Observa...
    method Add (line 301) | private void Add(IAudioDevice device)
    method Remove (line 309) | private void Remove(IAudioDevice device)
    method TryFind (line 317) | private bool TryFind(string deviceId, out IAudioDevice found)
    method TraceLine (line 328) | private void TraceLine(string message)

FILE: EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceSession.cs
  class AudioDeviceSession (line 17) | class AudioDeviceSession : BindableBase, IAudioSessionEvents, IAudioDevi...
    method AudioDeviceSession (line 145) | public AudioDeviceSession(IAudioDevice parent, IAudioSessionControl se...
    method Hide (line 201) | public void Hide()
    method UnHide (line 216) | public void UnHide()
    method MoveToDevice (line 226) | public void MoveToDevice(string id, bool hide)
    method UpdatePeakValueBackground (line 234) | public void UpdatePeakValueBackground()
    method ChooseDisplayName (line 241) | private void ChooseDisplayName(string displayNameFromSession)
    method ChooseIconPath (line 257) | private void ChooseIconPath(string iconPathFromSession)
    method ReadProcessId (line 273) | private int ReadProcessId()
    method SyncPersistedEndpoint (line 292) | private void SyncPersistedEndpoint(IAudioDevice parent)
    method ReadSessionDisplayName (line 346) | private string ReadSessionDisplayName()
    method DisconnectSession (line 369) | private void DisconnectSession()
    method OnSimpleVolumeChanged (line 380) | void IAudioSessionEvents.OnSimpleVolumeChanged(float NewVolume, int Ne...
    method OnGroupingParamChanged (line 392) | void IAudioSessionEvents.OnGroupingParamChanged(ref Guid NewGroupingPa...
    method OnStateChanged (line 402) | void IAudioSessionEvents.OnStateChanged(AudioSessionState NewState)
    method OnDisplayNameChanged (line 424) | void IAudioSessionEvents.OnDisplayNameChanged(string NewDisplayName, r...
    method OnSessionDisconnected (line 434) | void IAudioSessionEvents.OnSessionDisconnected(AudioSessionDisconnectR...
    method OnChannelVolumeChanged (line 436) | void IAudioSessionEvents.OnChannelVolumeChanged(uint ChannelCount, Int...
    method OnIconPathChanged (line 447) | void IAudioSessionEvents.OnIconPathChanged(string NewIconPath, ref Gui...

FILE: EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceSessionChannel.cs
  class AudioDeviceSessionChannel (line 8) | class AudioDeviceSessionChannel : BindableBase, INotifyPropertyChanged, ...
    method AudioDeviceSessionChannel (line 31) | public AudioDeviceSessionChannel(IChannelAudioVolume session, uint ind...
    method SetLevel (line 39) | internal void SetLevel(float newLevel)

FILE: EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceSessionChannelCollection.cs
  class AudioDeviceSessionChannelCollection (line 7) | class AudioDeviceSessionChannelCollection
    method AudioDeviceSessionChannelCollection (line 11) | public AudioDeviceSessionChannelCollection(IChannelAudioVolume session...

FILE: EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceSessionChannelMultiplexer.cs
  class AudioDeviceSessionChannelMultiplexer (line 5) | class AudioDeviceSessionChannelMultiplexer : BindableBase, IAudioDeviceS...
    method AudioDeviceSessionChannelMultiplexer (line 21) | public AudioDeviceSessionChannelMultiplexer(IAudioDeviceSessionChannel...
    method Channel_PropertyChanged (line 31) | private void Channel_PropertyChanged(object sender, PropertyChangedEve...

FILE: EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceSessionCollection.cs
  class AudioDeviceSessionCollection (line 12) | class AudioDeviceSessionCollection : IAudioSessionNotification
    method AudioDeviceSessionCollection (line 22) | public AudioDeviceSessionCollection(IAudioDevice parent, IMMDevice dev...
    method CreateAndAddSession (line 59) | private void CreateAndAddSession(IAudioSessionControl session)
    method OnSessionCreated (line 88) | void IAudioSessionNotification.OnSessionCreated(IAudioSessionControl N...
    method AddSession (line 94) | private void AddSession(IAudioDeviceSession session)
    method UnHideSessionsForProcessId (line 128) | internal void UnHideSessionsForProcessId(int processId)
    method MoveHiddenAppsToDevice (line 144) | public void MoveHiddenAppsToDevice(string appId, string id)
    method RemoveSession (line 155) | private void RemoveSession(IAudioDeviceSession session)
    method Session_PropertyChanged (line 187) | private void Session_PropertyChanged(object sender, System.ComponentMo...
    method MovedSession_PropertyChanged (line 206) | private void MovedSession_PropertyChanged(object sender, System.Compon...

FILE: EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceSessionGroup.cs
  class AudioDeviceSessionGroup (line 11) | class AudioDeviceSessionGroup : BindableBase, IAudioDeviceSession, IAudi...
    method Hide (line 112) | public void Hide()
    method UnHide (line 120) | public void UnHide()
    method MoveToDevice (line 128) | public void MoveToDevice(string id, bool hideExistingSessions)
    method UpdatePeakValueBackground (line 145) | public void UpdatePeakValueBackground()
    method AudioDeviceSessionGroup (line 158) | public AudioDeviceSessionGroup(IAudioDevice parent, IAudioDeviceSessio...
    method AddSession (line 175) | public void AddSession(IAudioDeviceSession session)
    method RemoveSession (line 190) | public void RemoveSession(IAudioDeviceSession session)
    method Session_PropertyChanged (line 196) | private void Session_PropertyChanged(object sender, PropertyChangedEve...

FILE: EarTrumpet/DataModel/WindowsAudio/Internal/AudioPolicyConfigService.cs
  class AudioPolicyConfig (line 9) | class AudioPolicyConfig
    method AudioPolicyConfig (line 18) | public AudioPolicyConfig(EDataFlow flow)
    method EnsurePolicyConfig (line 23) | private void EnsurePolicyConfig()
    method GenerateDeviceId (line 31) | private string GenerateDeviceId(string deviceId)
    method UnpackDeviceId (line 36) | private string UnpackDeviceId(string deviceId)
    method SetDefaultEndPoint (line 44) | public void SetDefaultEndPoint(string deviceId, int processId)
    method GetDefaultEndPoint (line 68) | public string GetDefaultEndPoint(int processId)

FILE: EarTrumpet/DataModel/WindowsAudio/Internal/Helpers.cs
  class Helpers (line 9) | class Helpers
    method ReadPeakValues (line 11) | public static float[] ReadPeakValues(IAudioMeterInformation meter)

FILE: EarTrumpet/DataModel/WindowsAudio/Internal/IAudioDeviceInternal.cs
  type IAudioDeviceInternal (line 3) | interface IAudioDeviceInternal
    method UpdatePeakValue (line 5) | void UpdatePeakValue();
    method MoveHiddenAppsToDevice (line 6) | void MoveHiddenAppsToDevice(string appId, string id);
    method UnhideSessionsForProcessId (line 7) | void UnhideSessionsForProcessId(int processId);

FILE: EarTrumpet/DataModel/WindowsAudio/Internal/IAudioDeviceSessionInternal.cs
  type IAudioDeviceSessionInternal (line 6) | interface IAudioDeviceSessionInternal : IAudioDeviceSession
    method Hide (line 9) | void Hide();
    method UnHide (line 10) | void UnHide();
    method MoveToDevice (line 11) | void MoveToDevice(string id, bool hide);
    method UpdatePeakValueBackground (line 12) | void UpdatePeakValueBackground();

FILE: EarTrumpet/DataModel/WindowsAudio/WindowsAudioFactory.cs
  class WindowsAudioFactory (line 6) | public class WindowsAudioFactory
    method Create (line 11) | public static IAudioDeviceManager Create(AudioDeviceKind kind)
    method CreateNonSharedDeviceManager (line 31) | public static IAudioDeviceManager CreateNonSharedDeviceManager(AudioDe...

FILE: EarTrumpet/DebugHelpers.cs
  class DebugHelpers (line 16) | class DebugHelpers
    class DebugContextMenuAddon (line 18) | class DebugContextMenuAddon : IEarTrumpetAddonNotificationAreaContextMenu
    method Add (line 60) | public static void Add()
    method DebugRemoveAllDevices (line 65) | private static void DebugRemoveAllDevices()
    method AddMockApp (line 77) | private static void AddMockApp(IAudioDevice mockDevice, string display...
    method MakeMockApp (line 89) | private static DataModel.Audio.Mocks.AudioDeviceSession MakeMockApp(IA...
    method DebugAddMockDevice (line 99) | private static void DebugAddMockDevice()

FILE: EarTrumpet/Diagnosis/CircularBufferTraceListener.cs
  class CircularBufferTraceListener (line 9) | class CircularBufferTraceListener : TraceListener
    method Write (line 15) | public override void Write(string message) => Debug.Assert(false);
    method WriteLine (line 17) | public override void WriteLine(string message)
    method GetLogText (line 33) | public string GetLogText()

FILE: EarTrumpet/Diagnosis/ErrorReporter.cs
  class ErrorReporter (line 8) | class ErrorReporter
    method ErrorReporter (line 15) | public ErrorReporter(AppSettings settings)
    method DisplayDiagnosticData (line 39) | public void DisplayDiagnosticData()
    method LogWarning (line 44) | public static void LogWarning(Exception ex) => s_instance.LogWarningIn...
    method LogWarningInstance (line 45) | private void LogWarningInstance(Exception ex)
    method OnBeforeNotify (line 51) | private void OnBeforeNotify(Bugsnag.Payload.Report error)
    method Fill (line 71) | private void Fill(Dictionary<string, object> dest, Dictionary<string, ...

FILE: EarTrumpet/Diagnosis/LocalDataExporter.cs
  class LocalDataExporter (line 14) | public class LocalDataExporter
    method DumpAndShowData (line 18) | public static void DumpAndShowData(string logText)
    method Populate (line 34) | private static void Populate(StringBuilder builder, Dictionary<string,...
    method DumpDeviceManager (line 42) | private static void DumpDeviceManager(StringBuilder builder, IAudioDev...
    method DumpDevice (line 50) | private static void DumpDevice(StringBuilder builder, IAudioDevice dev...
    method DumpSession (line 71) | private static void DumpSession(StringBuilder builder, string indent, ...
    method IsProcessAlive (line 88) | private static bool IsProcessAlive(int processId)

FILE: EarTrumpet/Diagnosis/SnapshotData.cs
  class SnapshotData (line 13) | class SnapshotData
    method InvokeNoThrow (line 15) | public static string InvokeNoThrow(Func<object> func)
    method GetProcessHandleCount (line 97) | private static uint GetProcessHandleCount()

FILE: EarTrumpet/Extensibility/EarTrumpetAddon.cs
  type IAddonInternal (line 9) | interface IAddonInternal
    method Initialize (line 11) | void Initialize();
    method InitializeInternal (line 12) | void InitializeInternal(AddonManifest manifest);
  class EarTrumpetAddon (line 16) | public class EarTrumpetAddon : IAddonInternal
    method Initialize (line 24) | void IAddonInternal.Initialize()
    method InitializeInternal (line 31) | void IAddonInternal.InitializeInternal(AddonManifest manifest)
    method LoadAddonResources (line 38) | protected void LoadAddonResources()

FILE: EarTrumpet/Extensibility/EarTrumpetAddonManifest.cs
  class AddonManifest (line 3) | public class AddonManifest

FILE: EarTrumpet/Extensibility/Hosting/AddonHost.cs
  class AddonHost (line 6) | public class AddonHost

FILE: EarTrumpet/Extensibility/Hosting/AddonManager.cs
  class AddonManager (line 10) | public class AddonManager
    method Load (line 18) | public static void Load(bool shouldLoadInternalAddons = false)
    method LoadInternalAddons (line 55) | private static void LoadInternalAddons()
    method Shutdown (line 62) | public static void Shutdown()
    method GetDiagnosticInfo (line 68) | public static string GetDiagnosticInfo() => string.Join(" ", s_loadedA...

FILE: EarTrumpet/Extensibility/Hosting/AddonResolver.cs
  class AddonResolver (line 12) | class AddonResolver
    method AddonResolver (line 16) | public AddonResolver()
    method Load (line 22) | public IEnumerable<DirectoryCatalog> Load(object target)
    method SelectAddon (line 53) | private DirectoryCatalog SelectAddon(string path)
    method SelectDevAddon (line 80) | private DirectoryCatalog SelectDevAddon(string path)
    method OnFinalAssemblyResolve (line 109) | private Assembly OnFinalAssemblyResolve(object sender, ResolveEventArg...

FILE: EarTrumpet/Extensibility/IEarTrumpetAddonAppContent.cs
  type IEarTrumpetAddonAppContent (line 7) | public interface IEarTrumpetAddonAppContent
    method GetContentForApp (line 9) | object GetContentForApp(string deviceId, string appId, Action requestC...
    method GetContextMenuItemsForApp (line 10) | IEnumerable<ContextMenuItem> GetContextMenuItemsForApp(string deviceId...

FILE: EarTrumpet/Extensibility/IEarTrumpetAddonDeviceContent.cs
  type IEarTrumpetAddonDeviceContent (line 7) | public interface IEarTrumpetAddonDeviceContent
    method GetContentForDevice (line 9) | object GetContentForDevice(string deviceId, Action requestClose);
    method GetContextMenuItemsForDevice (line 10) | IEnumerable<ContextMenuItem> GetContextMenuItemsForDevice(string devic...

FILE: EarTrumpet/Extensibility/IEarTrumpetAddonEvents.cs
  type AddonEventKind (line 3) | public enum AddonEventKind
  type IEarTrumpetAddonEvents (line 10) | public interface IEarTrumpetAddonEvents
    method OnAddonEvent (line 12) | void OnAddonEvent(AddonEventKind evt);

FILE: EarTrumpet/Extensibility/IEarTrumpetAddonNotificationAreaContextMenu.cs
  type IEarTrumpetAddonNotificationAreaContextMenu (line 6) | public interface IEarTrumpetAddonNotificationAreaContextMenu

FILE: EarTrumpet/Extensibility/IEarTrumpetAddonSettingsPage.cs
  type IEarTrumpetAddonSettingsPage (line 5) | public interface IEarTrumpetAddonSettingsPage
    method GetSettingsCategory (line 7) | SettingsCategoryViewModel GetSettingsCategory();

FILE: EarTrumpet/Extensibility/Shared/PlaybackDataModelHost.cs
  class PlaybackDataModelHost (line 7) | public class PlaybackDataModelHost
    method PlaybackDataModelHost (line 20) | private PlaybackDataModelHost()
    method Devices_CollectionChanged (line 30) | private void Devices_CollectionChanged(object sender, System.Collectio...
    method ListenToDevice (line 44) | private void ListenToDevice(IAudioDevice device)
    method ListenToApp (line 57) | private void ListenToApp(IAudioDeviceSession app)
    method App_PropertyChanged (line 63) | private void App_PropertyChanged(object sender, System.ComponentModel....
    method Groups_CollectionChanged (line 68) | private void Groups_CollectionChanged(object sender, System.Collection...
    method FreeApp (line 82) | private void FreeApp(IAudioDeviceSession app)
    method Device_PropertyChanged (line 88) | private void Device_PropertyChanged(object sender, System.ComponentMod...
    method FreeDevice (line 93) | private void FreeDevice(IAudioDevice device)

FILE: EarTrumpet/Extensibility/Shared/ResourceLoader.cs
  class ResourceLoader (line 7) | public class ResourceLoader
    method Load (line 11) | public static void Load(string addonNamespace, bool isInternal)

FILE: EarTrumpet/Extensibility/Shared/ServiceBus.cs
  class ServiceBus (line 5) | public static class ServiceBus
    method RegisterMany (line 9) | public static void RegisterMany(string name, object service)
    method GetMany (line 20) | public static List<object> GetMany(string name)

FILE: EarTrumpet/Extensions/CollectionExtensions.cs
  class CollectionExtensions (line 7) | public static class CollectionExtensions
    method AddSorted (line 9) | public static void AddSorted<T>(this ObservableCollection<T> collectio...
    method AddRange (line 20) | public static void AddRange<T>(this ObservableCollection<T> collection...
    method InsertRange (line 28) | public static void InsertRange<T>(this ObservableCollection<T> collect...

FILE: EarTrumpet/Extensions/ColorExtensions.cs
  class ColorExtensions (line 5) | public static class ColorExtensions
    method ToABGRColor (line 7) | public static Color ToABGRColor(this uint abgrValue)
    method ToABGR (line 18) | public static uint ToABGR(this Color abgrValue)

FILE: EarTrumpet/Extensions/DependencyObjectExtensions.cs
  class DependencyObjectExtensions (line 6) | public static class DependencyObjectExtensions
    method FindVisualParent (line 8) | public static T FindVisualParent<T>(this DependencyObject obj) where T...
    method GetParentObject (line 19) | public static DependencyObject GetParentObject(this DependencyObject c...
    method FindVisualChild (line 51) | public static childItem FindVisualChild<childItem>(this DependencyObje...

FILE: EarTrumpet/Extensions/EarTrumpetAddonExtensions.cs
  class EarTrumpetAddonExtensions (line 6) | public static class EarTrumpetAddonExtensions
    method IsInternal (line 8) | public static bool IsInternal(this EarTrumpetAddon addon)

FILE: EarTrumpet/Extensions/EventBinding/EventBindingExtension.cs
  class BindingExtension (line 10) | public class BindingExtension : MarkupExtension
    method BindingExtension (line 14) | public BindingExtension() { }
    method BindingExtension (line 15) | public BindingExtension(string path) { Path = path; }
    method ProvideValue (line 17) | public override object ProvideValue(IServiceProvider serviceProvider)
    method OnEvent (line 39) | protected virtual void OnEvent(object sender, object args)
    method ResolvePropertyPath (line 45) | private object ResolvePropertyPath(object target, string path, out str...

FILE: EarTrumpet/Extensions/EventBinding/HandledEventBindingExtension.cs
  class HandledBindingExtension (line 4) | public class HandledBindingExtension : BindingExtension
    method OnEvent (line 6) | protected override void OnEvent(object sender, object args)

FILE: EarTrumpet/Extensions/ExceptionExtensions.cs
  class ExceptionExtensions (line 7) | public static class ExceptionExtensions
    method Is (line 9) | public static bool Is(this Exception ex, HRESULT type)

FILE: EarTrumpet/Extensions/FloatExtensions.cs
  class FloatExtensions (line 5) | public static class FloatExtensions
    method ToVolumeInt (line 9) | public static int ToVolumeInt(this float val)
    method Bound (line 14) | public static float Bound(this float val, float min, float max)
    method ToLogVolume (line 19) | public static float ToLogVolume(this float val)
    method ToDisplayVolume (line 24) | public static float ToDisplayVolume(this float val)

FILE: EarTrumpet/Extensions/FrameworkElementExtensions.cs
  class FrameworkElementExtensions (line 7) | public static class FrameworkElementExtensions
    method WaitForKeyboardVisuals (line 9) | public static void WaitForKeyboardVisuals(this FrameworkElement elemen...

FILE: EarTrumpet/Extensions/IEnumerableExtensions.cs
  class IEnumerableExtensions (line 7) | public static class IEnumerableExtensions
    method ToSet (line 9) | public static HashSet<T> ToSet<T>(this IEnumerable<T> collection)
    method ForEachNoThrow (line 19) | public static void ForEachNoThrow<T>(this IEnumerable<T> list, Action<...

FILE: EarTrumpet/Extensions/IPropertyStoreExtensions.cs
  class IPropertyStoreExtensions (line 7) | public static class IPropertyStoreExtensions
    method GetValue (line 9) | public static T GetValue<T>(this IPropertyStore propStore, PROPERTYKEY...

FILE: EarTrumpet/Extensions/IconExtensions.cs
  class IconExtensions (line 6) | public static class IconExtensions
    method AsDisposableIcon (line 8) | public static Icon AsDisposableIcon(this Icon icon)

FILE: EarTrumpet/Extensions/ListExtensions.cs
  class ListExtensions (line 6) | public static class ListExtensions
    method Remove (line 8) | public static void Remove<T>(this List<T> list, Func<T,bool> shouldRem...

FILE: EarTrumpet/Extensions/OperatingSystemExtensions.cs
  type OSVersions (line 5) | public enum OSVersions : int
  class OperatingSystemExtensions (line 15) | public static class OperatingSystemExtensions
    method IsAtLeast (line 17) | public static bool IsAtLeast(this OperatingSystem os, OSVersions version)
    method IsGreaterThan (line 22) | public static bool IsGreaterThan(this OperatingSystem os, OSVersions v...
    method IsLessThan (line 27) | public static bool IsLessThan(this OperatingSystem os, OSVersions vers...

FILE: EarTrumpet/Extensions/RegistryKeyExtensions.cs
  class RegistryKeyExtensions (line 5) | public static class RegistryKeyExtensions
    method GetValue (line 7) | public static T GetValue<T>(this RegistryKey self, string valueName, T...

FILE: EarTrumpet/Extensions/VisualExtensions.cs
  class VisualExtensions (line 6) | public static class VisualExtensions
    method CalculateDpi (line 8) | private static Matrix CalculateDpi(this Visual visual)
    method DpiY (line 14) | public static double DpiY(this Visual visual) => CalculateDpi(visual)....
    method DpiX (line 15) | public static double DpiX(this Visual visual) => CalculateDpi(visual)....

FILE: EarTrumpet/Extensions/WindowExtensions.cs
  class WindowExtensions (line 10) | public static class WindowExtensions
    method SetWindowPos (line 12) | public static void SetWindowPos(this Window window, double top, double...
    method RaiseWindow (line 17) | public static void RaiseWindow(this Window window)
    method Cloak (line 24) | public static void Cloak(this Window window, bool hide = true)
    method EnableRoundedCornersIfApplicable (line 30) | public static void EnableRoundedCornersIfApplicable(this Window window)
    method RemoveWindowStyle (line 39) | public static void RemoveWindowStyle(this Window window, int styleToRe...
    method ApplyExtendedWindowStyle (line 51) | public static void ApplyExtendedWindowStyle(this Window window, int ne...
    method GetHandle (line 68) | public static IntPtr GetHandle(this Window window)

FILE: EarTrumpet/Features.cs
  class Features (line 3) | public class Features

FILE: EarTrumpet/Interop/AppBarData.cs
  type APPBARDATA (line 6) | [StructLayout(LayoutKind.Sequential)]

FILE: EarTrumpet/Interop/AppBarEdge.cs
  type AppBarEdge (line 3) | internal enum AppBarEdge : uint

FILE: EarTrumpet/Interop/AppBarMessage.cs
  type AppBarMessage (line 3) | internal enum AppBarMessage : uint

FILE: EarTrumpet/Interop/ApplicationResolver.cs
  class ApplicationResolver (line 6) | [ComImport]
  type IApplicationResolver (line 10) | [ComImport]
    method _ (line 15) | void _();
    method __ (line 16) | void __();
    method ___ (line 17) | void ___();
    method GetAppIDForProcess (line 18) | void GetAppIDForProcess(uint processId, [MarshalAs(UnmanagedType.LPWSt...

FILE: EarTrumpet/Interop/CLSCTX.cs
  type CLSCTX (line 3) | enum CLSCTX : int

FILE: EarTrumpet/Interop/Combase.cs
  class Combase (line 6) | static class Combase
    method RoGetActivationFactory (line 8) | [DllImport("combase.dll", PreserveSig = false)]
    method WindowsCreateString (line 14) | [DllImport("combase.dll", PreserveSig = false)]

FILE: EarTrumpet/Interop/DwmApi.cs
  class DwmApi (line 6) | class DwmApi
    type DWM_WINDOW_CORNER_PREFERENCE (line 11) | internal enum DWM_WINDOW_CORNER_PREFERENCE
    method DwmSetWindowAttribute (line 19) | [DllImport("dwmapi.dll", PreserveSig = false)]

FILE: EarTrumpet/Interop/FolderIds.cs
  class FolderIds (line 5) | static class FolderIds

FILE: EarTrumpet/Interop/GPS.cs
  type GPS (line 3) | enum GPS

FILE: EarTrumpet/Interop/Gdi32.cs
  class Gdi32 (line 6) | class Gdi32
    method DeleteObject (line 8) | [DllImport("gdi32.dll", PreserveSig = true)]

FILE: EarTrumpet/Interop/HRESULT.cs
  type HRESULT (line 3) | public enum HRESULT : uint

FILE: EarTrumpet/Interop/Helpers/AccentPolicyLibrary.cs
  class AccentPolicyLibrary (line 12) | public static class AccentPolicyLibrary
    method SetAccentPolicy (line 16) | private static void SetAccentPolicy(IntPtr handle, User32.AccentPolicy...
    method EnableAcrylic (line 33) | public static void EnableAcrylic(Visual target, Color color, User32.Ac...
    method DisableAcrylic (line 44) | public static void DisableAcrylic(Visual target)
    method HandleFromVisual (line 53) | private static IntPtr HandleFromVisual(Visual visual)

FILE: EarTrumpet/Interop/Helpers/AudioPolicyConfigFactory.cs
  class AudioPolicyConfigFactory (line 7) | public class AudioPolicyConfigFactory
    method Create (line 9) | public static IAudioPolicyConfigFactory Create()

FILE: EarTrumpet/Interop/Helpers/AudioPolicyConfigFactoryImplFor21H2.cs
  class AudioPolicyConfigFactoryImplFor21H2 (line 6) | class AudioPolicyConfigFactoryImplFor21H2 : IAudioPolicyConfigFactory
    method AudioPolicyConfigFactoryImplFor21H2 (line 10) | internal AudioPolicyConfigFactoryImplFor21H2()
    method ClearAllPersistedApplicationDefaultEndpoints (line 17) | public HRESULT ClearAllPersistedApplicationDefaultEndpoints()
    method GetPersistedDefaultAudioEndpoint (line 22) | public HRESULT GetPersistedDefaultAudioEndpoint(uint processId, EDataF...
    method SetPersistedDefaultAudioEndpoint (line 27) | public HRESULT SetPersistedDefaultAudioEndpoint(uint processId, EDataF...

FILE: EarTrumpet/Interop/Helpers/AudioPolicyConfigFactoryImplForDownlevel.cs
  class AudioPolicyConfigFactoryImplForDownlevel (line 6) | class AudioPolicyConfigFactoryImplForDownlevel : IAudioPolicyConfigFactory
    method AudioPolicyConfigFactoryImplForDownlevel (line 10) | internal AudioPolicyConfigFactoryImplForDownlevel()
    method ClearAllPersistedApplicationDefaultEndpoints (line 17) | public HRESULT ClearAllPersistedApplicationDefaultEndpoints()
    method GetPersistedDefaultAudioEndpoint (line 22) | public HRESULT GetPersistedDefaultAudioEndpoint(uint processId, EDataF...
    method SetPersistedDefaultAudioEndpoint (line 27) | public HRESULT SetPersistedDefaultAudioEndpoint(uint processId, EDataF...

FILE: EarTrumpet/Interop/Helpers/HotkeyData.cs
  class HotkeyData (line 6) | public class HotkeyData
    type ModifierKeys (line 8) | [Flags]
    method HotkeyData (line 21) | public HotkeyData(Message msg)
    method HotkeyData (line 27) | public HotkeyData() { }
    method ToString (line 29) | public override string ToString()
    method Equals (line 58) | public override bool Equals(object obj)
    method GetHashCode (line 64) | public override int GetHashCode()
    method ModifiersToKeys (line 72) | private static Keys ModifiersToKeys(ModifierKeys modifiers)
    method GetInteropModifiers (line 94) | public uint GetInteropModifiers()
    method KeysToModifiers (line 99) | private static ModifierKeys KeysToModifiers(Keys modifiers)

FILE: EarTrumpet/Interop/Helpers/HotkeyManager.cs
  class HotkeyManager (line 8) | public class HotkeyManager
    class Entry (line 10) | private class Entry
    method HotkeyManager (line 25) | public HotkeyManager()
    method WndProc (line 32) | private void WndProc(Message msg)
    method Register (line 42) | public void Register(HotkeyData hotkey)
    method Unregister (line 65) | public void Unregister(HotkeyData hotkey)
    method Pause (line 81) | public void Pause()
    method Resume (line 90) | public void Resume()

FILE: EarTrumpet/Interop/Helpers/IconHelper.cs
  class IconHelper (line 9) | public class IconHelper
    method LoadIconForTaskbar (line 11) | public static Icon LoadIconForTaskbar(string path, uint dpi)
    method LoadIconResource (line 35) | public static Icon LoadIconResource(string path, int iconOrdinal, int ...
    method ColorIcon (line 51) | public static Icon ColorIcon(Icon originalIcon, double fillPercent, Sy...

FILE: EarTrumpet/Interop/Helpers/ImmersiveSystemColors.cs
  class ImmersiveSystemColors (line 9) | public class ImmersiveSystemColors
    method Lookup (line 11) | public static Color Lookup(string name)
    method TryLookup (line 17) | public static bool TryLookup(string name, out Color color)
    method GetList (line 29) | public static IDictionary<string, Color> GetList()

FILE: EarTrumpet/Interop/Helpers/InputHelper.cs
  class InputHelper (line 8) | class InputHelper
    method RegisterForMouseInput (line 10) | public static void RegisterForMouseInput(IntPtr handle)
    method UnregisterForMouseInput (line 26) | public static void UnregisterForMouseInput()
    method RegisterRawInputDevices (line 41) | private static bool RegisterRawInputDevices(User32.RAWINPUTDEVICE data)
    method ProcessMouseInputMessage (line 50) | public static bool ProcessMouseInputMessage(IntPtr lParam, ref System....

FILE: EarTrumpet/Interop/Helpers/Kernel32Helper.cs
  class Kernel32Helper (line 6) | class Kernel32Helper
    method IsPackagedProcess (line 8) | public static bool IsPackagedProcess(int processId)

FILE: EarTrumpet/Interop/Helpers/LegacyControlPanelHelper.cs
  class LegacyControlPanelHelper (line 7) | class LegacyControlPanelHelper
    method Open (line 9) | public static void Open(string panel)
    method StartLegacyAudioMixer (line 26) | public static void StartLegacyAudioMixer()

FILE: EarTrumpet/Interop/Helpers/MouseHook.cs
  class MouseHook (line 7) | public class MouseHook
    type POINT (line 9) | [StructLayout(LayoutKind.Sequential)]
    type MouseLLHookStruct (line 16) | [StructLayout(LayoutKind.Sequential)]
    method SetHook (line 35) | public void SetHook()
    method UnHook (line 45) | public void UnHook()
    method MouseHookProc (line 54) | private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)

FILE: EarTrumpet/Interop/Helpers/PackageHelper.cs
  class PackageHelper (line 6) | class PackageHelper
    method GetVersion (line 8) | public static Version GetVersion(bool isPackaged)
    method GetFamilyName (line 21) | public static string GetFamilyName(bool isPackaged)
    method CheckHasIdentity (line 26) | public static bool CheckHasIdentity()
    method HasDevIdentity (line 52) | public static bool HasDevIdentity()

FILE: EarTrumpet/Interop/Helpers/ProcessHelper.cs
  class ProcessHelper (line 6) | public class ProcessHelper
    method StartNoThrow (line 8) | public  static void StartNoThrow(string fileName)

FILE: EarTrumpet/Interop/Helpers/SettingsPageHelper.cs
  class SettingsPageHelper (line 6) | class SettingsPageHelper
    method Open (line 8) | public static void Open(string page)

FILE: EarTrumpet/Interop/Helpers/SingleInstanceAppMutex.cs
  class SingleInstanceAppMutex (line 7) | class SingleInstanceAppMutex
    method TakeExclusivity (line 11) | public static bool TakeExclusivity()
    method ReleaseExclusivity (line 26) | public static void ReleaseExclusivity()

FILE: EarTrumpet/Interop/Helpers/Win32Window.cs
  class Win32Window (line 6) | public class Win32Window : NativeWindow, IDisposable
    method Initialize (line 10) | public void Initialize(Action<Message> wndProc)
    method WndProc (line 16) | protected override void WndProc(ref Message m)
    method Dispose (line 22) | public void Dispose()

FILE: EarTrumpet/Interop/Helpers/WindowSizeHelper.cs
  class WindowSizeHelper (line 7) | class WindowSizeHelper
    method RestrictMaximizedSizeToWorkArea (line 9) | public static void RestrictMaximizedSizeToWorkArea(Window window)

FILE: EarTrumpet/Interop/Helpers/WindowsTaskbar.cs
  class WindowsTaskbar (line 8) | public sealed class WindowsTaskbar
    type State (line 10) | public struct State
    type Position (line 24) | public enum Position
    method GetHwnd (line 82) | public static IntPtr GetHwnd() => User32.FindWindow("Shell_TrayWnd", n...
    method GetTrayToolbarWindowHwnd (line 84) | public static IntPtr GetTrayToolbarWindowHwnd()

FILE: EarTrumpet/Interop/IPropertyStore.cs
  type PROPERTYKEY (line 6) | [StructLayout(LayoutKind.Sequential)]
    method Equals (line 12) | public override bool Equals(object obj)
    method GetHashCode (line 23) | public override int GetHashCode()
  type IPropertyStore (line 29) | [ComImport]
    method GetCount (line 34) | [PreserveSig]
    method GetAt (line 36) | [PreserveSig]
    method GetValue (line 38) | PropVariant GetValue([In] ref PROPERTYKEY key);
    method SetValue (line 39) | [PreserveSig]
    method Commit (line 41) | [PreserveSig]

FILE: EarTrumpet/Interop/IShellItem.cs
  type IShellItem (line 6) | [Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")]
    method BindToHandler (line 10) | void BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc...
    method GetParent (line 11) | void GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
    method GetDisplayName (line 12) | void GetDisplayName([In] SIGDN sigdnName, [MarshalAs(UnmanagedType.LPW...
    method GetAttributes (line 13) | void GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs);
    method Compare (line 14) | void Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, ...

FILE: EarTrumpet/Interop/IShellItem2.cs
  type IShellItem2 (line 7) | [Guid("7E9FB0D3-919F-4307-AB2E-9B1860310C93")]
    method BindToHandler (line 11) | [return: MarshalAs(UnmanagedType.Interface)]
    method GetParent (line 13) | IShellItem GetParent();
    method GetDisplayName (line 14) | [return: MarshalAs(UnmanagedType.LPWStr)]
    method GetAttributes (line 16) | SFGAO GetAttributes(SFGAO sfgaoMask);
    method Compare (line 17) | int Compare(IShellItem psi, SICHINT hint);
    method GetPropertyStore (line 18) | [return: MarshalAs(UnmanagedType.Interface)]
    method GetPropertyStoreWithCreateObject (line 22) | [return: MarshalAs(UnmanagedType.Interface)]
    method GetPropertyStoreForKeys (line 27) | [return: MarshalAs(UnmanagedType.Interface)]
    method GetPropertyDescriptionList (line 33) | [return: MarshalAs(UnmanagedType.Interface)]
    method Update (line 37) | void Update(IBindCtx pbc);
    method GetProperty (line 38) | void GetProperty(ref PROPERTYKEY key, [In, Out] PropVariant pv);
    method GetCLSID (line 39) | Guid GetCLSID(ref PROPERTYKEY key);
    method GetFileTime (line 40) | System.Runtime.InteropServices.ComTypes.FILETIME GetFileTime(ref PROPE...
    method GetInt32 (line 41) | int GetInt32(ref PROPERTYKEY key);
    method GetString (line 42) | [return: MarshalAs(UnmanagedType.LPWStr)]
    method GetUInt32 (line 44) | uint GetUInt32(ref PROPERTYKEY key);
    method GetUInt64 (line 45) | ulong GetUInt64(ref PROPERTYKEY key);
    method GetBool (line 46) | [return: MarshalAs(UnmanagedType.Bool)]

FILE: EarTrumpet/Interop/IShellItemImageFactory.cs
  type SIIGBF (line 6) | enum SIIGBF : int
  type IShellItemImageFactory (line 20) | [Guid("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
    method GetImage (line 24) | void GetImage(SIZE size, SIIGBF flags, out IntPtr hBitmap);

FILE: EarTrumpet/Interop/Kernel32.cs
  class Kernel32 (line 8) | class Kernel32
    type ProcessFlags (line 18) | [Flags]
    type LoadLibraryFlags (line 25) | [Flags]
    type IMAGE_FILE_MACHINE (line 32) | [Flags]
    type PACKAGE_ID (line 42) | [StructLayout(LayoutKind.Sequential)]
    method LoadLibraryEx (line 59) | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, PreserveSig = tr...
    method FreeLibrary (line 65) | [DllImport("kernel32.dll", PreserveSig = true)]
    method OpenProcess (line 70) | [DllImport("kernel32.dll", PreserveSig = true)]
    method CloseHandle (line 76) | [DllImport("kernel32.dll", PreserveSig = true)]
    method GetApplicationUserModelId (line 80) | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, PreserveSig = tr...
    method ParseApplicationUserModelId (line 86) | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, PreserveSig = tr...
    method FindPackagesByPackageFamilyInitial (line 94) | [DllImport("kernel32.dll", EntryPoint = "FindPackagesByPackageFamily",...
    method FindPackagesByPackageFamily (line 104) | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, PreserveSig = tr...
    method OpenPackageInfoByFullName (line 114) | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, PreserveSig = tr...
    method GetPackageApplicationIds (line 120) | [DllImport("kernel32.dll", PreserveSig = true)]
    method ClosePackageInfo (line 127) | [DllImport("kernel32.dll", PreserveSig = true)]
    method QueryFullProcessImageName (line 131) | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, PreserveSig = tr...
    method WaitForMultipleObjects (line 138) | [DllImport("kernel32.dll", PreserveSig = true)]
    method WaitForSingleObject (line 145) | [DllImport("kernel32.dll", PreserveSig = true)]
    method IsWow64Process2 (line 150) | [DllImport("kernel32.dll", PreserveSig = true)]
    method FindResourceW (line 160) | [DllImport("kernel32.dll", PreserveSig = true)]
    method LoadResource (line 166) | [DllImport("kernel32.dll", PreserveSig = true)]
    method LockResource (line 171) | [DllImport("kernel32.dll", PreserveSig = true)]
    method SizeofResource (line 175) | [DllImport("kernel32.dll", PreserveSig = true)]
    method GetProcessHandleCount (line 180) | [DllImport("kernel32.dll", PreserveSig = true)]
    method GetCurrentProcess (line 186) | [DllImport("kernel32.dll", PreserveSig = true)]
    method GetPackageId (line 189) | [DllImport("kernel32.dll", PreserveSig = true)]

FILE: EarTrumpet/Interop/MMDeviceAPI/AUDIO_VOLUME_NOTIFICATION_DATA.cs
  type AUDIO_VOLUME_NOTIFICATION_DATA (line 6) | [StructLayout(LayoutKind.Sequential)]

FILE: EarTrumpet/Interop/MMDeviceAPI/AudioSessionDisconnectReason.cs
  type AudioSessionDisconnectReason (line 3) | enum AudioSessionDisconnectReason

FILE: EarTrumpet/Interop/MMDeviceAPI/AudioSessionState.cs
  type AudioSessionState (line 3) | enum AudioSessionState

FILE: EarTrumpet/Interop/MMDeviceAPI/DeviceState.cs
  type DeviceState (line 3) | public enum DeviceState : uint

FILE: EarTrumpet/Interop/MMDeviceAPI/EDataFlow.cs
  type EDataFlow (line 3) | public enum EDataFlow

FILE: EarTrumpet/Interop/MMDeviceAPI/ERole.cs
  type ERole (line 5) | [Flags]

FILE: EarTrumpet/Interop/MMDeviceAPI/IAudioEndpointVolume.cs
  type IAudioEndpointVolume (line 6) | [Guid("5CDF2C82-841E-4546-9722-0CF74078229A")]
    method RegisterControlChangeNotify (line 10) | void RegisterControlChangeNotify([MarshalAs(UnmanagedType.Interface)] ...
    method UnregisterControlChangeNotify (line 11) | void UnregisterControlChangeNotify([MarshalAs(UnmanagedType.Interface)...
    method GetChannelCount (line 12) | uint GetChannelCount();
    method SetMasterVolumeLevel (line 13) | void SetMasterVolumeLevel(float fLevelDB, ref Guid pguidEventContext);
    method SetMasterVolumeLevelScalar (line 14) | void SetMasterVolumeLevelScalar(float fLevel, ref Guid pguidEventConte...
    method GetMasterVolumeLevel (line 15) | void GetMasterVolumeLevel(out float pfLevelDB);
    method GetMasterVolumeLevelScalar (line 16) | void GetMasterVolumeLevelScalar(out float pfLevel);
    method SetChannelVolumeLevel (line 17) | void SetChannelVolumeLevel(uint nChannel, float fLevelDB, ref Guid pgu...
    method SetChannelVolumeLevelScalar (line 18) | void SetChannelVolumeLevelScalar(uint nChannel, float fLevel, ref Guid...
    method GetChannelVolumeLevel (line 19) | void GetChannelVolumeLevel(uint nChannel, out float pfLevelDB);
    method GetChannelVolumeLevelScalar (line 20) | float GetChannelVolumeLevelScalar(uint nChannel);
    method SetMute (line 21) | void SetMute(int bMute, ref Guid pguidEventContext);
    method GetMute (line 22) | int GetMute();
    method GetVolumeStepInfo (line 23) | void GetVolumeStepInfo(out uint pnStep, out uint pnStepCount);
    method VolumeStepUp (line 24) | void VolumeStepUp(ref Guid pguidEventContext);
    method VolumeStepDown (line 25) | void VolumeStepDown(ref Guid pguidEventContext);
    method QueryHardwareSupport (line 26) | void QueryHardwareSupport(out uint pdwHardwareSupportMask);
    method GetVolumeRange (line 27) | void GetVolumeRange(out float pflVolumeMindB, out float pflVolumeMaxdB...

FILE: EarTrumpet/Interop/MMDeviceAPI/IAudioEndpointVolumeCallback.cs
  type IAudioEndpointVolumeCallback (line 6) | [Guid("657804FA-D6AD-4496-8A60-352752AF4F89")]
    method OnNotify (line 10) | void OnNotify(IntPtr pNotify);

FILE: EarTrumpet/Interop/MMDeviceAPI/IAudioMeterInformation.cs
  type IAudioMeterInformation (line 6) | [Guid("C02216F6-8C67-4B5B-9D00-D008E73E0064")]
    method GetPeakValue (line 10) | float GetPeakValue();
    method GetMeteringChannelCount (line 11) | uint GetMeteringChannelCount();
    method GetChannelsPeakValues (line 12) | [PreserveSig]
    method QueryHardwareSupport (line 14) | void QueryHardwareSupport(out uint pdwHardwareSupportMask);

FILE: EarTrumpet/Interop/MMDeviceAPI/IAudioPolicyConfigFactory.cs
  type IAudioPolicyConfigFactory (line 5) | public interface IAudioPolicyConfigFactory
    method SetPersistedDefaultAudioEndpoint (line 7) | HRESULT SetPersistedDefaultAudioEndpoint(uint processId, EDataFlow flo...
    method GetPersistedDefaultAudioEndpoint (line 8) | HRESULT GetPersistedDefaultAudioEndpoint(uint processId, EDataFlow flo...
    method ClearAllPersistedApplicationDefaultEndpoints (line 9) | HRESULT ClearAllPersistedApplicationDefaultEndpoints();

FILE: EarTrumpet/Interop/MMDeviceAPI/IAudioPolicyConfigFactoryVariantFor21H2.cs
  type IAudioPolicyConfigFactoryVariantFor21H2 (line 6) | [Guid("ab3d4648-e242-459f-b02f-541c70306324")]
    method __incomplete__add_CtxVolumeChange (line 10) | int __incomplete__add_CtxVolumeChange();
    method __incomplete__remove_CtxVolumeChanged (line 11) | int __incomplete__remove_CtxVolumeChanged();
    method __incomplete__add_RingerVibrateStateChanged (line 12) | int __incomplete__add_RingerVibrateStateChanged();
    method __incomplete__remove_RingerVibrateStateChange (line 13) | int __incomplete__remove_RingerVibrateStateChange();
    method __incomplete__SetVolumeGroupGainForId (line 14) | int __incomplete__SetVolumeGroupGainForId();
    method __incomplete__GetVolumeGroupGainForId (line 15) | int __incomplete__GetVolumeGroupGainForId();
    method __incomplete__GetActiveVolumeGroupForEndpointId (line 16) | int __incomplete__GetActiveVolumeGroupForEndpointId();
    method __incomplete__GetVolumeGroupsForEndpoint (line 17) | int __incomplete__GetVolumeGroupsForEndpoint();
    method __incomplete__GetCurrentVolumeContext (line 18) | int __incomplete__GetCurrentVolumeContext();
    method __incomplete__SetVolumeGroupMuteForId (line 19) | int __incomplete__SetVolumeGroupMuteForId();
    method __incomplete__GetVolumeGroupMuteForId (line 20) | int __incomplete__GetVolumeGroupMuteForId();
    method __incomplete__SetRingerVibrateState (line 21) | int __incomplete__SetRingerVibrateState();
    method __incomplete__GetRingerVibrateState (line 22) | int __incomplete__GetRingerVibrateState();
    method __incomplete__SetPreferredChatApplication (line 23) | int __incomplete__SetPreferredChatApplication();
    method __incomplete__ResetPreferredChatApplication (line 24) | int __incomplete__ResetPreferredChatApplication();
    method __incomplete__GetPreferredChatApplication (line 25) | int __incomplete__GetPreferredChatApplication();
    method __incomplete__GetCurrentChatApplications (line 26) | int __incomplete__GetCurrentChatApplications();
    method __incomplete__add_ChatContextChanged (line 27) | int __incomplete__add_ChatContextChanged();
    method __incomplete__remove_ChatContextChanged (line 28) | int __incomplete__remove_ChatContextChanged();
    method SetPersistedDefaultAudioEndpoint (line 29) | [PreserveSig]
    method GetPersistedDefaultAudioEndpoint (line 31) | [PreserveSig]
    method ClearAllPersistedApplicationDefaultEndpoints (line 33) | [PreserveSig]

FILE: EarTrumpet/Interop/MMDeviceAPI/IAudioPolicyConfigFactoryVariantForDownlevel.cs
  type IAudioPolicyConfigFactoryVariantForDownlevel (line 6) | [Guid("2a59116d-6c4f-45e0-a74f-707e3fef9258")]
    method __incomplete__add_CtxVolumeChange (line 10) | int __incomplete__add_CtxVolumeChange();
    method __incomplete__remove_CtxVolumeChanged (line 11) | int __incomplete__remove_CtxVolumeChanged();
    method __incomplete__add_RingerVibrateStateChanged (line 12) | int __incomplete__add_RingerVibrateStateChanged();
    method __incomplete__remove_RingerVibrateStateChange (line 13) | int __incomplete__remove_RingerVibrateStateChange();
    method __incomplete__SetVolumeGroupGainForId (line 14) | int __incomplete__SetVolumeGroupGainForId();
    method __incomplete__GetVolumeGroupGainForId (line 15) | int __incomplete__GetVolumeGroupGainForId();
    method __incomplete__GetActiveVolumeGroupForEndpointId (line 16) | int __incomplete__GetActiveVolumeGroupForEndpointId();
    method __incomplete__GetVolumeGroupsForEndpoint (line 17) | int __incomplete__GetVolumeGroupsForEndpoint();
    method __incomplete__GetCurrentVolumeContext (line 18) | int __incomplete__GetCurrentVolumeContext();
    method __incomplete__SetVolumeGroupMuteForId (line 19) | int __incomplete__SetVolumeGroupMuteForId();
    method __incomplete__GetVolumeGroupMuteForId (line 20) | int __incomplete__GetVolumeGroupMuteForId();
    method __incomplete__SetRingerVibrateState (line 21) | int __incomplete__SetRingerVibrateState();
    method __incomplete__GetRingerVibrateState (line 22) | int __incomplete__GetRingerVibrateState();
    method __incomplete__SetPreferredChatApplication (line 23) | int __incomplete__SetPreferredChatApplication();
    method __incomplete__ResetPreferredChatApplication (line 24) | int __incomplete__ResetPreferredChatApplication();
    method __incomplete__GetPreferredChatApplication (line 25) | int __incomplete__GetPreferredChatApplication();
    method __incomplete__GetCurrentChatApplications (line 26) | int __incomplete__GetCurrentChatApplications();
    method __incomplete__add_ChatContextChanged (line 27) | int __incomplete__add_ChatContextChanged();
    method __incomplete__remove_ChatContextChanged (line 28) | int __incomplete__remove_ChatContextChanged();
    method SetPersistedDefaultAudioEndpoint (line 29) | [PreserveSig]
    method GetPersistedDefaultAudioEndpoint (line 31) | [PreserveSig]
    method ClearAllPersistedApplicationDefaultEndpoints (line 33) | [PreserveSig]

FILE: EarTrumpet/Interop/MMDeviceAPI/IAudioSessionControl.cs
  type IAudioSessionControl (line 6) | [Guid("F4B1A599-7266-4319-A8CA-E70ACB11E8CD")]
    method GetState (line 10) | AudioSessionState GetState();
    method GetDisplayName (line 11) | [return: MarshalAs(UnmanagedType.LPWStr)]
    method SetDisplayName (line 13) | void SetDisplayName([MarshalAs(UnmanagedType.LPWStr)]string Value, ref...
    method GetIconPath (line 14) | [return: MarshalAs(UnmanagedType.LPWStr)]
    method SetIconPath (line 16) | void SetIconPath([MarshalAs(UnmanagedType.LPWStr)]string Value, ref Gu...
    method GetGroupingParam (line 17) | Guid GetGroupingParam();
    method SetGroupingParam (line 18) | void SetGroupingParam(ref Guid Override, ref Guid EventContext);
    method RegisterAudioSessionNotification (line 19) | void RegisterAudioSessionNotification([MarshalAs(UnmanagedType.Interfa...
    method UnregisterAudioSessionNotification (line 20) | void UnregisterAudioSessionNotification([MarshalAs(UnmanagedType.Inter...

FILE: EarTrumpet/Interop/MMDeviceAPI/IAudioSessionControl2.cs
  type IAudioSessionControl2 (line 6) | [Guid("BFB7FF88-7239-4FC9-8FA2-07C950BE9C6D")]
    method GetState (line 10) | void GetState(out AudioSessionState pRetVal);
    method GetDisplayName (line 11) | void GetDisplayName([MarshalAs(UnmanagedType.LPWStr)]out string pRetVal);
    method SetDisplayName (line 12) | void SetDisplayName([MarshalAs(UnmanagedType.LPWStr)]string Value, ref...
    method GetIconPath (line 13) | void GetIconPath([MarshalAs(UnmanagedType.LPWStr)]out string pRetVal);
    method SetIconPath (line 14) | void SetIconPath([MarshalAs(UnmanagedType.LPWStr)]string Value, ref Gu...
    method GetGroupingParam (line 15) | void GetGroupingParam(out Guid pRetVal);
    method SetGroupingParam (line 16) | void SetGroupingParam(ref Guid Override, ref Guid EventContext);
    method RegisterAudioSessionNotification (line 17) | void RegisterAudioSessionNotification([MarshalAs(UnmanagedType.Interfa...
    method UnregisterAudioSessionNotification (line 18) | void UnregisterAudioSessionNotification([MarshalAs(UnmanagedType.Inter...
    method GetSessionIdentifier (line 19) | void GetSessionIdentifier([MarshalAs(UnmanagedType.LPWStr)]out string ...
    method GetSessionInstanceIdentifier (line 20) | void GetSessionInstanceIdentifier([MarshalAs(UnmanagedType.LPWStr)]out...
    method GetProcessId (line 21) | [PreserveSig]
    method IsSystemSoundsSession (line 23) | [PreserveSig]
    method SetDuckingPreference (line 25) | void SetDuckingPreference(int optOut);

FILE: EarTrumpet/Interop/MMDeviceAPI/IAudioSessionEnumerator.cs
  type IAudioSessionEnumerator (line 5) | [Guid("E2F5BB11-0570-40CA-ACDD-3AA01277DEE8")]
    method GetCount (line 9) | int GetCount();
    method GetSession (line 10) | [return: MarshalAs(UnmanagedType.Interface)]

FILE: EarTrumpet/Interop/MMDeviceAPI/IAudioSessionEvents.cs
  type IAudioSessionEvents (line 6) | [Guid("24918ACC-64B3-37C1-8CA9-74A66E9957A8")]
    method OnDisplayNameChanged (line 10) | void OnDisplayNameChanged([MarshalAs(UnmanagedType.LPWStr)]string NewD...
    method OnIconPathChanged (line 11) | void OnIconPathChanged([MarshalAs(UnmanagedType.LPWStr)]string NewIcon...
    method OnSimpleVolumeChanged (line 12) | void OnSimpleVolumeChanged(float NewVolume, int NewMute, ref Guid Even...
    method OnChannelVolumeChanged (line 13) | void OnChannelVolumeChanged(uint ChannelCount, IntPtr afNewChannelVolu...
    method OnGroupingParamChanged (line 14) | void OnGroupingParamChanged(ref Guid NewGroupingParam, ref Guid EventC...
    method OnStateChanged (line 15) | void OnStateChanged(AudioSessionState NewState);
    method OnSessionDisconnected (line 16) | void OnSessionDisconnected(AudioSessionDisconnectReason DisconnectReas...

FILE: EarTrumpet/Interop/MMDeviceAPI/IAudioSessionManager.cs
  type IAudioSessionManager (line 6) | [Guid("BFA971F1-4D5E-40BB-935E-967039BFBEE4")]
    method GetAudioSessionControl (line 10) | void GetAudioSessionControl(ref Guid AudioSessionGuid, uint StreamFlag...
    method GetSimpleAudioVolume (line 11) | void GetSimpleAudioVolume(ref Guid AudioSessionGuid, uint StreamFlags,...

FILE: EarTrumpet/Interop/MMDeviceAPI/IAudioSessionManager2.cs
  type IAudioSessionManager2 (line 6) | [Guid("77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F")]
    method GetAudioSessionControl (line 10) | void GetAudioSessionControl(ref Guid AudioSessionGuid, uint StreamFlag...
    method GetSimpleAudioVolume (line 11) | void GetSimpleAudioVolume(ref Guid AudioSessionGuid, uint StreamFlags,...
    method GetSessionEnumerator (line 12) | [return: MarshalAs(UnmanagedType.Interface)]
    method RegisterSessionNotification (line 14) | void RegisterSessionNotification([MarshalAs(UnmanagedType.Interface)] ...
    method UnregisterSessionNotification (line 15) | void UnregisterSessionNotification([MarshalAs(UnmanagedType.Interface)...
    method RegisterDuckNotification (line 16) | void RegisterDuckNotification([MarshalAs(UnmanagedType.LPWStr)]string ...
    method UnregisterDuckNotification (line 17) | void UnregisterDuckNotification([MarshalAs(UnmanagedType.Interface)] I...

FILE: EarTrumpet/Interop/MMDeviceAPI/IAudioSessionNotification.cs
  type IAudioSessionNotification (line 5) | [Guid("641DD20B-4D41-49CC-ABA3-174B9477BB08")]
    method OnSessionCreated (line 9) | void OnSessionCreated([MarshalAs(UnmanagedType.Interface)] IAudioSessi...

FILE: EarTrumpet/Interop/MMDeviceAPI/IAudioVolumeDuckNotification.cs
  type IAudioVolumeDuckNotification (line 5) | [Guid("C3B284D4-6D39-4359-B3CF-B56DDB3BB39C")]
    method OnVolumeDuckNotification (line 9) | void OnVolumeDuckNotification([MarshalAs(UnmanagedType.LPWStr)]string ...
    method OnVolumeUnduckNotification (line 10) | void OnVolumeUnduckNotification([MarshalAs(UnmanagedType.LPWStr)]strin...

FILE: EarTrumpet/Interop/MMDeviceAPI/IChannelAudioVolume.cs
  type IChannelAudioVolume (line 6) | [Guid("1C158861-B533-4B30-B1CF-E853E51C59B8")]
    method GetChannelCount (line 10) | uint GetChannelCount();
    method SetChannelVolume (line 11) | [PreserveSig]
    method GetChannelVolume (line 13) | [PreserveSig]
    method SetAllVolumes (line 15) | [PreserveSig]
    method GetAllVolumes (line 17) | [PreserveSig]

FILE: EarTrumpet/Interop/MMDeviceAPI/IDeviceTopology.cs
  type IConnector (line 6) | public interface IConnector { }
  type ISubunit (line 8) | [Guid("82149A85-DBA6-4487-86BB-EA8F7FEFCC71")]
  type IDeviceTopology (line 12) | [Guid("2A07407E-6497-4A18-9787-32F79BD0D98F")]
    method GetConnectorCount (line 16) | uint GetConnectorCount();
    method GetConnector (line 17) | object GetConnector(uint index);
    method GetSubunitCount (line 18) | uint GetSubunitCount();
    method GetSubunit (line 19) | ISubunit GetSubunit(uint index);
    method GetPartById (line 20) | object GetPartById(uint id);
    method GetDeviceId (line 21) | void GetDeviceId([MarshalAs(UnmanagedType.LPWStr)] out string ppwstrDe...
    method GetSignalPath (line 22) | int GetSignalPath();

FILE: EarTrumpet/Interop/MMDeviceAPI/IMMDevice.cs
  type IMMDevice (line 6) | [Guid("D666063F-1587-4E43-81F1-B948E807363F")]
    method Activate (line 10) | void Activate(ref Guid iid, uint dwClsCtx, IntPtr pActivationParams, [...
    method OpenPropertyStore (line 11) | [return: MarshalAs(UnmanagedType.Interface)]
    method GetId (line 13) | [return: MarshalAs(UnmanagedType.LPWStr)]
    method GetState (line 15) | DeviceState GetState();
  class IMMDeviceExtensions (line 18) | public static class IMMDeviceExtensions
    method Activate (line 20) | public static T Activate<T>(this IMMDevice device)

FILE: EarTrumpet/Interop/MMDeviceAPI/IMMDeviceCollection.cs
  type IMMDeviceCollection (line 5) | [Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E")]
    method GetCount (line 9) | uint GetCount();
    method Item (line 10) | [return: MarshalAs(UnmanagedType.Interface)]

FILE: EarTrumpet/Interop/MMDeviceAPI/IMMDeviceEnumerator.cs
  type IMMDeviceEnumerator (line 5) | [Guid("A95664D2-9614-4F35-A746-DE8DB63617E6")]
    method EnumAudioEndpoints (line 9) | [return: MarshalAs(UnmanagedType.Interface)]
    method GetDefaultAudioEndpoint (line 11) | [return: MarshalAs(UnmanagedType.Interface)]
    method GetDevice (line 13) | [return: MarshalAs(UnmanagedType.Interface)]
    method RegisterEndpointNotificationCallback (line 15) | void RegisterEndpointNotificationCallback([MarshalAs(UnmanagedType.Int...
    method UnregisterEndpointNotificationCallback (line 16) | void UnregisterEndpointNotificationCallback([MarshalAs(UnmanagedType.I...

FILE: EarTrumpet/Interop/MMDeviceAPI/IMMEndpoint.cs
  type IMMEndpoint (line 6) | [Guid("1BE09788-6894-4089-8586-9A2A6C265AC5")]
    method GetDataFlow (line 10) | EDataFlow GetDataFlow();

FILE: EarTrumpet/Interop/MMDeviceAPI/IMMNotificationClient.cs
  type IMMNotificationClient (line 5) | [Guid("7991EEC9-7E89-4D85-8390-6C703CEC60C0")]
    method OnDeviceStateChanged (line 9) | void OnDeviceStateChanged([MarshalAs(UnmanagedType.LPWStr)]string pwst...
    method OnDeviceAdded (line 10) | void OnDeviceAdded([MarshalAs(UnmanagedType.LPWStr)]string pwstrDevice...
    method OnDeviceRemoved (line 11) | void OnDeviceRemoved([MarshalAs(UnmanagedType.LPWStr)]string pwstrDevi...
    method OnDefaultDeviceChanged (line 12) | void OnDefaultDeviceChanged(EDataFlow flow, ERole role, [MarshalAs(Unm...
    method OnPropertyValueChanged (line 13) | void OnPropertyValueChanged([MarshalAs(UnmanagedType.LPWStr)]string pw...

FILE: EarTrumpet/Interop/MMDeviceAPI/IPolicyConfig.cs
  type IPolicyConfigWin7 (line 9) | [Guid("F8679F50-850A-41CF-9C72-430F290290C8")]
    method Unused1 (line 13) | void Unused1();
    method Unused2 (line 14) | void Unused2();
    method Unused3 (line 15) | void Unused3();
    method Unused4 (line 16) | void Unused4();
    method Unused5 (line 17) | void Unused5();
    method Unused6 (line 18) | void Unused6();
    method Unused7 (line 19) | void Unused7();
    method Unused8 (line 20) | void Unused8();
    method GetPropertyValue (line 21) | void GetPropertyValue([MarshalAs(UnmanagedType.LPWStr)]string wszDevic...
    method SetPropertyValue (line 22) | void SetPropertyValue([MarshalAs(UnmanagedType.LPWStr)]string wszDevic...
    method SetDefaultEndpoint (line 23) | void SetDefaultEndpoint([MarshalAs(UnmanagedType.LPWStr)]string wszDev...
    method SetEndpointVisibility (line 24) | void SetEndpointVisibility([MarshalAs(UnmanagedType.LPWStr)]string wsz...

FILE: EarTrumpet/Interop/MMDeviceAPI/ISimpleAudioVolume.cs
  type ISimpleAudioVolume (line 6) | [Guid("87CE5498-68D6-44E5-9215-6DA47EF883D8")]
    method SetMasterVolume (line 10) | void SetMasterVolume(float fLevel, ref Guid EventContext);
    method GetMasterVolume (line 11) | void GetMasterVolume(out float pfLevel);
    method SetMute (line 12) | void SetMute(int bMute, ref Guid EventContext);
    method GetMute (line 13) | int GetMute();

FILE: EarTrumpet/Interop/MMDeviceAPI/MMDeviceEnumerator.cs
  class MMDeviceEnumerator (line 5) | [ComImport]

FILE: EarTrumpet/Interop/MMDeviceAPI/PolicyConfigClient.cs
  class PolicyConfigClient (line 6) | [ComImport]
  class AutoPolicyConfigClientWin7 (line 10) | public class AutoPolicyConfigClientWin7
    method SetEndpointVisibility (line 14) | public void SetEndpointVisibility(string deviceId, bool isVisible)
    method SetDefaultEndpoint (line 19) | public void SetDefaultEndpoint(string deviceId, ERole role = ERole.eMu...

FILE: EarTrumpet/Interop/NotifyIconData.cs
  type NotifyIconFlags (line 6) | public enum NotifyIconFlags : int
  type NOTIFYICONDATAW (line 17) | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
  type NOTIFYICONIDENTIFIER (line 40) | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]

FILE: EarTrumpet/Interop/Ntdll.cs
  class Ntdll (line 6) | class Ntdll
    type SYSTEM_INFORMATION_CLASS (line 8) | public enum SYSTEM_INFORMATION_CLASS
    type SYSTEM_PROCESS_INFORMATION (line 16) | [StructLayout(LayoutKind.Explicit)]
    type LARGE_INTEGER (line 33) | [StructLayout(LayoutKind.Explicit, Size = 8)]
    type UNICODE_STRING (line 44) | [StructLayout(LayoutKind.Sequential, Size = 8)]
    type NTSTATUS (line 52) | public enum NTSTATUS : uint
    method NtQuerySystemInformationInitial (line 58) | [DllImport("ntdll.dll", PreserveSig = true, EntryPoint = "NtQuerySyste...
    method NtQuerySystemInformation (line 65) | [DllImport("ntdll.dll", PreserveSig = true)]

FILE: EarTrumpet/Interop/Ole32.cs
  class Ole32 (line 5) | static class Ole32
    method PropVariantClear (line 7) | [DllImport("ole32.dll", PreserveSig = false)]

FILE: EarTrumpet/Interop/PropVariant.cs
  type PropArray (line 6) | [StructLayout(LayoutKind.Sequential, Pack = 0)]
  type PropVariant (line 13) | [StructLayout(LayoutKind.Explicit, Pack = 1)]

FILE: EarTrumpet/Interop/PropVariantUnion.cs
  type CY (line 18) | [StructLayout(LayoutKind.Sequential, Pack = 0)]
  type BSTRBLOB (line 28) | [StructLayout(LayoutKind.Sequential, Pack = 0)]
  type BLOB (line 38) | [StructLayout(LayoutKind.Sequential, Pack = 0)]
  type CArray (line 48) | [StructLayout(LayoutKind.Sequential, Pack = 0)]
  type PropVariantUnion (line 74) | [StructLayout(LayoutKind.Explicit)]

FILE: EarTrumpet/Interop/PropertyKeys.cs
  class PropertyKeys (line 5) | public static class PropertyKeys

FILE: EarTrumpet/Interop/RECT.cs
  type RECT (line 6) | [Serializable]
    method ToString (line 15) | public override string ToString() => $"[Left={Left},Top={Top},Right={R...
    method Contains (line 16) | public bool Contains(System.Drawing.Point pt) => pt.X >= Left && pt.X ...

FILE: EarTrumpet/Interop/SFGAO.cs
  type SFGAO (line 5) | [Flags]

FILE: EarTrumpet/Interop/SICHINT.cs
  type SICHINT (line 5) | [Flags]

FILE: EarTrumpet/Interop/SIGDN.cs
  type SIGDN (line 3) | enum SIGDN : uint

FILE: EarTrumpet/Interop/SIZE.cs
  type SIZE (line 5) | [StructLayout(LayoutKind.Sequential)]

FILE: EarTrumpet/Interop/STGM.cs
  type STGM (line 3) | public enum STGM

FILE: EarTrumpet/Interop/SafeHandles/HMODULE.cs
  class HMODULE (line 5) | public class HMODULE : SafeHandleZeroOrMinusOneIsInvalid
    method HMODULE (line 7) | private HMODULE() : base(ownsHandle: true)
    method ReleaseHandle (line 11) | protected override bool ReleaseHandle()

FILE: EarTrumpet/Interop/Shell32.cs
  class Shell32 (line 6) | class Shell32
    type AppBarState (line 12) | [Flags]
    method SHCreateItemInKnownFolder (line 18) | [DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = fal...
    method SHCreateItemFromParsingName (line 26) | [DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = fal...
    method SHAppBarMessage (line 33) | [DllImport("shell32.dll", PreserveSig = true)]
    type NotifyIconMessage (line 38) | public enum NotifyIconMessage : int
    type NotifyIconNotification (line 47) | public enum NotifyIconNotification : int
    method Shell_NotifyIconW (line 61) | [DllImport("shell32.dll", PreserveSig = true, SetLastError = true)]
    method Shell_NotifyIconGetRect (line 67) | [DllImport("shell32.dll", PreserveSig = true)]

FILE: EarTrumpet/Interop/SndVolSSO.cs
  class SndVolSSO (line 5) | public class SndVolSSO
    type IconId (line 7) | public enum IconId
    method GetPath (line 19) | public static string GetPath(IconId icon)

FILE: EarTrumpet/Interop/User32.cs
  class User32 (line 7) | public class User32
    method MAKEWPARAM (line 21) | public static uint MAKEWPARAM(ushort low, ushort high) => ((uint)high ...
    method RegisterHotKey (line 23) | [DllImport("user32.dll", PreserveSig = true)]
    method UnregisterHotKey (line 30) | [DllImport("user32.dll", PreserveSig = true)]
    type WindowPosFlags (line 35) | [Flags]
    method SetWindowPos (line 44) | [DllImport("user32.dll", PreserveSig = true)]
    method SetWindowCompositionAttribute (line 54) | [DllImport("user32.dll", PreserveSig = true)]
    method FindWindow (line 59) | [DllImport("user32.dll", CharSet = CharSet.Unicode, PreserveSig = true)]
    method GetWindowRect (line 64) | [DllImport("user32.dll", PreserveSig = true)]
    method IsImmersiveProcess (line 69) | [DllImport("user32.dll", PreserveSig = true)]
    type WindowCompositionAttribData (line 73) | [StructLayout(LayoutKind.Sequential)]
    type AccentPolicy (line 81) | [StructLayout(LayoutKind.Sequential)]
    type AccentFlags (line 90) | [Flags]
    type WindowCompositionAttribute (line 103) | internal enum WindowCompositionAttribute
    type AccentState (line 111) | internal enum AccentState
    type RAWINPUTDEVICE (line 124) | [StructLayout(LayoutKind.Sequential)]
    type RAWINPUTHEADER (line 133) | [StructLayout(LayoutKind.Sequential)]
    type RAWMOUSE_FLAGS (line 142) | [Flags]
    type RAWMOUSE (line 151) | [StructLayout(LayoutKind.Explicit)]
    type RAWINPUT (line 176) | [StructLayout(LayoutKind.Explicit)]
    type HidUsagePage (line 188) | public enum HidUsagePage : ushort
    type HidUsage (line 199) | public enum HidUsage : ushort
    type GWL (line 213) | public enum GWL : int
    type WINDOWPLACEMENT (line 221) | [Serializable]
    type POINT (line 233) | [Serializable]
    method RegisterRawInputDevices (line 241) | [DllImport("user32.dll", SetLastError = true, PreserveSig = true)]
    method GetRawInputData (line 248) | [DllImport("user32.dll", SetLastError = true, PreserveSig = true)]
    method SetForegroundWindow (line 265) | [DllImport("user32.dll", PreserveSig = true)]
    method GetForegroundWindow (line 269) | [DllImport("user32.dll", PreserveSig = true)]
    method GetWindowThreadProcessId (line 272) | [DllImport("user32.dll", PreserveSig = true)]
    method GetClassName (line 275) | [DllImport("user32.dll", PreserveSig = true, CharSet = CharSet.Unicode)]
    method FindWindowEx (line 280) | [DllImport("user32.dll", CharSet = CharSet.Unicode, PreserveSig = true)]
    method GetWindowLong (line 288) | [DllImport("user32.dll", CharSet = CharSet.Unicode, PreserveSig = true)]
    method SetWindowLong (line 293) | [DllImport("user32.dll", CharSet = CharSet.Unicode, PreserveSig = true)]
    method RegisterWindowMessage (line 302) | [DllImport("user32.dll", CharSet = CharSet.Unicode, PreserveSig = true)]
    method GetDpiForWindow (line 305) | [DllImport("user32.dll", PreserveSig = true)]
    method GetDpiForSystem (line 308) | [DllImport("user32.dll", PreserveSig = true)]
    type SystemMetrics (line 311) | public enum SystemMetrics : int
    method GetSystemMetricsForDpi (line 323) | [DllImport("user32.dll", PreserveSig = true)]
    type LoadImageFlags (line 326) | public enum LoadImageFlags : uint
    type IconCursorVersion (line 334) | public enum IconCursorVersion : int
    method CreateIconFromResourceEx (line 339) | [DllImport("user32.dll", PreserveSig = true, SetLastError = true)]
    method LookupIconIdFromDirectoryEx (line 349) | [DllImport("user32.dll", PreserveSig = true)]
    type GR_FLAGS (line 357) | [Flags]
    method GetGuiResources (line 368) | [DllImport("user32.dll", PreserveSig = true)]
    method SendMessage (line 373) | [DllImport("user32.dll", PreserveSig = true)]
    method SetWindowsHookEx (line 378) | [DllImport("user32.dll", PreserveSig = true)]
    method UnhookWindowsHookEx (line 385) | [DllImport("user32.dll", PreserveSig = true)]
    method CallNextHookEx (line 388) | [DllImport("user32.dll", PreserveSig = true)]
    method SetWindowPlacement (line 395) | [DllImport("user32.dll", PreserveSig = true)]
    method GetWindowPlacement (line 401) | [DllImport("user32.dll", PreserveSig = true)]

FILE: EarTrumpet/Interop/Uxtheme.cs
  class Uxtheme (line 6) | class Uxtheme
    method GetImmersiveColorSetCount (line 8) | [DllImport("uxtheme.dll", EntryPoint = "#94", CharSet = CharSet.Unicod...
    method GetImmersiveColorFromColorSetEx (line 11) | [DllImport("uxtheme.dll", EntryPoint = "#95", CharSet = CharSet.Unicod...
    method GetImmersiveColorTypeFromName (line 18) | [DllImport("uxtheme.dll", EntryPoint = "#96", CharSet = CharSet.Unicod...
    method GetImmersiveUserColorSetPreference (line 22) | [DllImport("uxtheme.dll", EntryPoint = "#98", CharSet = CharSet.Unicod...
    method GetImmersiveColorNamedTypeByIndex (line 27) | [DllImport("uxtheme.dll", EntryPoint = "#100", CharSet = CharSet.Unico...

FILE: EarTrumpet/Interop/shlwapi.cs
  class Shlwapi (line 7) | class Shlwapi
    method SHLoadIndirectString (line 9) | [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = t...
    method PathParseIconLocationW (line 16) | [DllImport("shlwapi.dll", ExactSpelling = true, PreserveSig = true)]

FILE: EarTrumpet/Properties/Resources.Designer.cs
  class Resources (line 22) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resource...
    method Resources (line 31) | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Mic...

FILE: EarTrumpet/UI/Behaviors/ButtonEx.cs
  class ButtonEx (line 12) | public class ButtonEx
    type ClickActionKind (line 14) | public enum ClickActionKind
    method GetClickAction (line 23) | public static ClickActionKind GetClickAction(DependencyObject obj) => ...
    method SetClickAction (line 24) | public static void SetClickAction(DependencyObject obj, ClickActionKin...
    method ClickActionChanged (line 27) | private static void ClickActionChanged(DependencyObject dependencyObje...
    method GetClickPopup (line 54) | public static Popup GetClickPopup(DependencyObject obj) => (Popup)obj....
    method SetClickPopup (line 55) | public static void SetClickPopup(DependencyObject obj, Popup value) =>...
    method ClickPopupChanged (line 58) | private static void ClickPopupChanged(DependencyObject dependencyObjec...
    method GetIsToolBarButton (line 85) | public static bool GetIsToolBarButton(DependencyObject obj) => (bool)o...
    method SetIsToolBarButton (line 86) | public static void SetIsToolBarButton(DependencyObject obj, bool value...
    method IsToolBarButtonChanged (line 89) | private static void IsToolBarButtonChanged(DependencyObject dependency...

FILE: EarTrumpet/UI/Behaviors/ComboBoxEx.cs
  class ComboBoxEx (line 12) | public class ComboBoxEx
    method GetItemClickEnabled (line 17) | public static bool GetItemClickEnabled(DependencyObject obj) => (bool)...
    method SetItemClickEnabled (line 18) | public static void SetItemClickEnabled(DependencyObject obj, bool valu...
    method ItemClickEnabledChanged (line 22) | private static void ItemClickEnabledChanged(DependencyObject dependenc...
    method OnComboBoxItemPreviewMouseLeftButtonDown (line 29) | private static void OnComboBoxItemPreviewMouseLeftButtonDown(object se...
    method GetSearchItemsSource (line 38) | public static object GetSearchItemsSource(DependencyObject obj) => (ob...
    method SetSearchItemsSource (line 39) | public static void SetSearchItemsSource(DependencyObject obj, object v...
    method SearchItemsSourceChanged (line 43) | private static void SearchItemsSourceChanged(DependencyObject dependen...
    method OnPreviewKeyUp (line 50) | private static void OnPreviewKeyUp(object sender, System.Windows.Input...
    method OnTextChanged (line 67) | private static void OnTextChanged(object sender, TextChangedEventArgs e)
    method DoSearch (line 90) | private static IEnumerable<SettingsSearchItemViewModel> DoSearch(Setti...
    method InvokeSearchItem (line 127) | private static void InvokeSearchItem(SettingsSearchItemViewModel item,...
    method ClearComboBox (line 133) | private static void ClearComboBox(ComboBox comboBox)

FILE: EarTrumpet/UI/Behaviors/FrameworkElementEx.cs
  class FrameworkElementEx (line 9) | public class FrameworkElementEx
    type FlowDirectionKind (line 11) | public enum FlowDirectionKind
    method GetFlowDirection (line 18) | public static FlowDirectionKind GetFlowDirection(DependencyObject obj)...
    method SetFlowDirection (line 19) | public static void SetFlowDirection(DependencyObject obj, FlowDirectio...
    method OnFlowDirectionChanged (line 23) | private static void OnFlowDirectionChanged(DependencyObject dependency...
    method GetDisplaySettingsChanged (line 30) | public static ICommand GetDisplaySettingsChanged(DependencyObject obj)...
    method SetDisplaySettingsChanged (line 31) | public static void SetDisplaySettingsChanged(DependencyObject obj, ICo...
    method OnDisplaySettingsChangedChanged (line 35) | private static void OnDisplaySettingsChangedChanged(DependencyObject d...

FILE: EarTrumpet/UI/Behaviors/ScrollViewerEx.cs
  class ScrollViewerEx (line 6) | public static class ScrollViewerEx
    method GetScrollToTopOnChanged (line 9) | public static object GetScrollToTopOnChanged(DependencyObject obj) => ...
    method SetScrollToTopOnChanged (line 10) | public static void SetScrollToTopOnChanged(DependencyObject obj, objec...
    method ScrollToTopOnChanged (line 13) | private static void ScrollToTopOnChanged(DependencyObject dependencyOb...

FILE: EarTrumpet/UI/Behaviors/TextBoxEx.cs
  class TextBoxEx (line 7) | public class TextBoxEx
    method GetClearText (line 10) | public static bool GetClearText(DependencyObject obj) => (bool)obj.Get...
    method SetClearText (line 11) | public static void SetClearText(DependencyObject obj, bool value) => o...
    method ClearTextChanged (line 15) | private static void ClearTextChanged(DependencyObject dependencyObject...

FILE: EarTrumpet/UI/Controls/AppPopup.cs
  class AppPopup (line 10) | public class AppPopup : Popup
    method AppPopup (line 12) | public AppPopup()
    method OnOpened (line 21) | private void OnOpened(object sender, EventArgs e)

FILE: EarTrumpet/UI/Controls/ImageEx.cs
  class ImageEx (line 16) | public class ImageEx : Image
    method ImageEx (line 26) | public ImageEx()
    method OnDpiChanged (line 32) | private void OnDpiChanged(object sender, DpiChangedEventArgs e)
    method OnSourceExChanged (line 45) | private void OnSourceExChanged()
    method LoadImage (line 53) | private ImageSource LoadImage(string path, bool isDesktopApp)
    method LoadShellIcon (line 106) | public static ImageSource LoadShellIcon(string path, bool isDesktopApp...
    method CanonicalizePath (line 137) | private static string CanonicalizePath(string path)
    method GetWindowDpi (line 158) | private uint GetWindowDpi() => User32.GetDpiForWindow(((HwndSource)Pre...
    method OnSourceExChanged (line 159) | private static void OnSourceExChanged(DependencyObject d, DependencyPr...

FILE: EarTrumpet/UI/Controls/ListView.cs
  class ListView (line 6) | public class ListView : System.Windows.Controls.ListView
    method GetContainerForItemOverride (line 10) | protected override DependencyObject GetContainerForItemOverride() => n...
    method InvokeItem (line 12) | public void InvokeItem(ListViewItem listViewItem)

FILE: EarTrumpet/UI/Controls/ListViewItem.cs
  class ListViewItem (line 5) | public class ListViewItem : System.Windows.Controls.ListViewItem
    method ListViewItem (line 9) | public ListViewItem(ListView parent)
    method OnMouseUp (line 14) | protected override void OnMouseUp(MouseButtonEventArgs e)
    method OnKeyDown (line 20) | protected override void OnKeyDown(KeyEventArgs e)

FILE: EarTrumpet/UI/Controls/MenuItemTemplateSelector.cs
  class MenuItemTemplateSelector (line 8) | public class MenuItemTemplateSelector : ItemContainerTemplateSelector
    method SelectTemplate (line 10) | public override DataTemplate SelectTemplate(object item, ItemsControl ...

FILE: EarTrumpet/UI/Controls/VolumeSlider.cs
  class VolumeSlider (line 9) | public class VolumeSlider : Slider
    method VolumeSlider (line 32) | public VolumeSlider() : base()
    method OnLoaded (line 44) | private void OnLoaded(object sender, RoutedEventArgs e)
    method ArrangeOverride (line 51) | protected override Size ArrangeOverride(Size arrangeBounds)
    method PeakValueChanged (line 58) | private static void PeakValueChanged(DependencyObject d, DependencyPro...
    method SizeOrVolumeOrPeakValueChanged (line 63) | private void SizeOrVolumeOrPeakValueChanged()
    method OnTouchDown (line 76) | private void OnTouchDown(object sender, TouchEventArgs e)
    method OnMouseDown (line 86) | private void OnMouseDown(object sender, MouseButtonEventArgs e)
    method OnTouchUp (line 103) | private void OnTouchUp(object sender, TouchEventArgs e)
    method OnMouseUp (line 111) | private void OnMouseUp(object sender, MouseButtonEventArgs e)
    method OnTouchMove (line 127) | private void OnTouchMove(object sender, TouchEventArgs e)
    method OnMouseMove (line 136) | private void OnMouseMove(object sender, MouseEventArgs e)
    method OnMouseWheel (line 146) | private void OnMouseWheel(object sender, MouseWheelEventArgs e)
    method SetPositionByControlPoint (line 153) | public void SetPositionByControlPoint(Point point)
    method ChangePositionByAmount (line 159) | public void ChangePositionByAmount(double amount)
    method Bound (line 164) | public double Bound(double val)

FILE: EarTrumpet/UI/Helpers/FlyoutViewState.cs
  type FlyoutViewState (line 3) | public enum FlyoutViewState

FILE: EarTrumpet/UI/Helpers/IAppIconSource.cs
  type IAppIconSource (line 3) | public interface IAppIconSource

FILE: EarTrumpet/UI/Helpers/IShellNotifyIconSource.cs
  type IShellNotifyIconSource (line 5) | public interface IShellNotifyIconSource
    method OnMouseOverChanged (line 9) | void OnMouseOverChanged(bool isMouseOver);
    method CheckForUpdate (line 10) | void CheckForUpdate();

FILE: EarTrumpet/UI/Helpers/NavigationCookie.cs
  class NavigationCookie (line 5) | public class NavigationCookie
    method NavigationCookie (line 8) | public NavigationCookie(Action action)
    method Execute (line 13) | public void Execute()

FILE: EarTrumpet/UI/Helpers/RelayCommand.cs
  class RelayCommand (line 6) | public class RelayCommand : ICommand
    method RelayCommand (line 12) | public RelayCommand(Action actionToExecute)
    method CanExecute (line 17) | public bool CanExecute(object parameter = null)
    method Execute (line 22) | public void Execute(object parameter = null)
    method RaiseCanExecuteChanged (line 32) | public void RaiseCanExecuteChanged()
    method RelayCommand (line 47) | public RelayCommand(Action<T> actionToExecute)
    method CanExecute (line 52) | public bool CanExecute(object parameter = null)
    method Execute (line 57) | public void Execute(object parameter = null)
    method RaiseCanExecuteChanged (line 67) | public void RaiseCanExecuteChanged()
  class RelayCommand (line 41) | public class RelayCommand<T> : ICommand
    method RelayCommand (line 12) | public RelayCommand(Action actionToExecute)
    method CanExecute (line 17) | public bool CanExecute(object parameter = null)
    method Execute (line 22) | public void Execute(object parameter = null)
    method RaiseCanExecuteChanged (line 32) | public void RaiseCanExecuteChanged()
    method RelayCommand (line 47) | public RelayCommand(Action<T> actionToExecute)
    method CanExecute (line 52) | public bool CanExecute(object parameter = null)
    method Execute (line 57) | public void Execute(object parameter = null)
    method RaiseCanExecuteChanged (line 67) | public void RaiseCanExecuteChanged()

FILE: EarTrumpet/UI/Helpers/ShellNotifyIcon.cs
  class ShellNotifyIcon (line 18) | public class ShellNotifyIcon
    class SecondaryInvokeArgs (line 20) | public class SecondaryInvokeArgs
    method ShellNotifyIcon (line 75) | public ShellNotifyIcon(IShellNotifyIconSource icon)
    method SetFocus (line 87) | public void SetFocus()
    method SetTooltip (line 97) | public void SetTooltip(string text)
    method MakeData (line 103) | private NOTIFYICONDATAW MakeData()
    method Update (line 116) | private void Update()
    method WndProc (line 156) | private void WndProc(System.Windows.Forms.Message msg)
    method CallbackMsgWndProc (line 178) | private void CallbackMsgWndProc(System.Windows.Forms.Message msg)
    method CreateSecondaryInvokeArgs (line 212) | private SecondaryInvokeArgs CreateSecondaryInvokeArgs(InputType type, ...
    method OnNotifyIconMouseMove (line 218) | private void OnNotifyIconMouseMove()
    method IsCursorWithinNotifyIconBounds (line 238) | private bool IsCursorWithinNotifyIconBounds()
    method ScheduleDelayedIconInvalidation (line 268) | private void ScheduleDelayedIconInvalidation()
    method OnDelayedIconCheckForUpdate (line 276) | private void OnDelayedIconCheckForUpdate()
    method ShowContextMenu (line 289) | public void ShowContextMenu(IEnumerable itemsSource, Point point)

FILE: EarTrumpet/UI/Helpers/SystemSoundsHelper.cs
  class SystemSoundsHelper (line 5) | public class SystemSoundsHelper
    method SystemSoundsHelper (line 9) | static SystemSoundsHelper()

FILE: EarTrumpet/UI/Helpers/TaskbarIconSource.cs
  class TaskbarIconSource (line 11) | public class TaskbarIconSource : IShellNotifyIconSource
    type IconKind (line 13) | enum IconKind
    method TaskbarIconSource (line 35) | public TaskbarIconSource(DeviceCollectionViewModel collection, AppSett...
    method OnMouseOverChanged (line 46) | public void OnMouseOverChanged(bool isMouseOver)
    method CheckForUpdate (line 52) | public void CheckForUpdate()
    method OnTrayPropertyChanged (line 67) | private void OnTrayPropertyChanged()
    method SelectAndLoadIcon (line 73) | private Icon SelectAndLoadIcon(IconKind kind)
    method LoadIcon (line 116) | private static Icon LoadIcon(IconKind kind)
    method GetHash (line 141) | private string GetHash() =>
    method GetIconFillPercent (line 149) | private static double GetIconFillPercent(IconKind kind) => kind == Ico...
    method ColorIconForLightTheme (line 151) | private static Icon ColorIconForLightTheme(Icon darkIcon, IconKind kind)
    method ColorIconForHighContrast (line 156) | private static Icon ColorIconForHighContrast(Icon darkIcon, IconKind k...
    method IconKindFromDeviceCollection (line 162) | private static IconKind IconKindFromDeviceCollection(DeviceCollectionV...

FILE: EarTrumpet/UI/Helpers/WindowAnimationLibrary.cs
  class WindowAnimationLibrary (line 12) | public class WindowAnimationLibrary
    method BeginFlyoutEntranceAnimation (line 16) | public static void BeginFlyoutEntranceAnimation(Window window, Windows...
    method BeginFlyoutExitanimation (line 124) | public static void BeginFlyoutExitanimation(Window window, Action comp...
    method BeginWindowExitAnimation (line 205) | public static void BeginWindowExitAnimation(Window window, Action comp...
    method BeginWindowEntranceAnimation (line 243) | public static void BeginWindowEntranceAnimation(Window window, Action ...
    method BringTaskbarToFront (line 280) | public static void BringTaskbarToFront()

FILE: EarTrumpet/UI/Helpers/WindowHolder.cs
  class WindowHolder (line 7) | public class WindowHolder
    method WindowHolder (line 12) | public WindowHolder(Func<Window> create)
    method OpenOrClose (line 17) | public void OpenOrClose()
    method OpenOrBringToFront (line 30) | public void OpenOrBringToFront()
    method CreateWindow (line 42) | private void CreateWindow()

FILE: EarTrumpet/UI/Helpers/WindowViewState.cs
  type WindowViewState (line 3) | public enum WindowViewState

FILE: EarTrumpet/UI/Themes/AcrylicBrush.cs
  class AcrylicBrush (line 10) | class AcrylicBrush
    method GetBackground (line 12) | public static string GetBackground(DependencyObject obj) => (string)ob...
    method SetBackground (line 13) | public static void SetBackground(DependencyObject obj, string value) =...
    method GetIsSuppressed (line 17) | public static bool GetIsSuppressed(DependencyObject obj) => (bool)obj....
    method SetIsSuppressed (line 18) | public static void SetIsSuppressed(DependencyObject obj, bool value) =...
    method BackgroundChanged (line 22) | private static void BackgroundChanged(DependencyObject dependencyObjec...
    method SuppressAryclic (line 52) | private static void SuppressAryclic(Window window, DispatcherTimer timer)
    method ApplyAcrylicToWindow (line 80) | private static void ApplyAcrylicToWindow(Window window, string refValue)
    method UpdateWindowAcrylic (line 90) | private static void UpdateWindowAcrylic(Window window)

FILE: EarTrumpet/UI/Themes/Brush.cs
  class Brush (line 6) | public static class Brush
    method ImplementPropertyChanged (line 11) | private static void ImplementPropertyChanged(string propertyName, Depe...
    method GetForeground (line 33) | public static string GetForeground(DependencyObject obj) => (string)ob...
    method SetForeground (line 34) | public static void SetForeground(DependencyObject obj, string value) =...
    method ForegroundChanged (line 37) | private static void ForegroundChanged(DependencyObject d, DependencyPr...
    method GetBackground (line 39) | public static string GetBackground(DependencyObject obj) => (string)ob...
    method SetBackground (line 40) | public static void SetBackground(DependencyObject obj, string value) =...
    method BackgroundChanged (line 43) | private static void BackgroundChanged(DependencyObject d, DependencyPr...
    method GetBorderBrush (line 45) | public static string GetBorderBrush(DependencyObject obj) => (string)o...
    method SetBorderBrush (line 46) | public static void SetBorderBrush(DependencyObject obj, string value) ...
    method BorderBrushChanged (line 49) | private static void BorderBrushChanged(DependencyObject d, DependencyP...
    method GetStroke (line 51) | public static string GetStroke(DependencyObject obj) => (string)obj.Ge...
    method SetStroke (line 52) | public static void SetStroke(DependencyObject obj, string value) => ob...
    method StrokeChanged (line 55) | private static void StrokeChanged(DependencyObject d, DependencyProper...
    method GetFill (line 57) | public static string GetFill(DependencyObject obj) => (string)obj.GetV...
    method SetFill (line 58) | public static void SetFill(DependencyObject obj, string value) => obj....
    method FillChanged (line 61) | private static void FillChanged(DependencyObject d, DependencyProperty...
    method GetSelectionBrush (line 63) | public static string GetSelectionBrush(DependencyObject obj) => (strin...
    method SetSelectionBrush (line 64) | public static void SetSelectionBrush(DependencyObject obj, string valu...
    method SelectionBrushChanged (line 67) | private static void SelectionBrushChanged(DependencyObject d, Dependen...
    method GetCaretBrush (line 69) | public static string GetCaretBrush(DependencyObject obj) => (string)ob...
    method SetCaretBrush (line 70) | public static void SetCaretBrush(DependencyObject obj, string value) =...
    method CaretBrushChanged (line 73) | private static void CaretBrushChanged(DependencyObject d, DependencyPr...

FILE: EarTrumpet/UI/Themes/BrushValueParser.cs
  class BrushValueParser (line 13) | class BrushValueParser
    method Parse (line 15) | public static SolidColorBrush Parse(DependencyObject element, string v...
    method FindReference (line 176) | private static bool FindReference(DependencyObject element, string sea...
    method ParseOpacityFromColor (line 232) | private static string ParseOpacityFromColor(string colorName, out doub...

FILE: EarTrumpet/UI/Themes/Manager.cs
  class Manager (line 15) | public class Manager : BindableBase, INotifyPropertyChanged
    method Manager (line 52) | public Manager()
    method Load (line 67) | public void Load()
    method ResolveRef (line 72) | public Color ResolveRef(DependencyObject target, string key)
    method WndProc (line 77) | private void WndProc(int msg, IntPtr wParam, IntPtr lParam)
    method OnThemeColorsChanged (line 107) | private void OnThemeColorsChanged()
    method ThemeChangeTimer_Tick (line 116) | private void ThemeChangeTimer_Tick(object sender, EventArgs e)

FILE: EarTrumpet/UI/Themes/OS.cs
  class OS (line 7) | public class OS : DependencyObject

FILE: EarTrumpet/UI/Themes/Options.cs
  class Options (line 5) | public class Options
    type SourceKind (line 7) | public enum SourceKind
    method GetSource (line 12) | public static SourceKind? GetSource(DependencyObject obj) => (SourceKi...
    method SetSource (line 13) | public static void SetSource(DependencyObject obj, SourceKind? value) ...
    method GetScope (line 17) | public static string GetScope(DependencyObject obj) => (string)obj.Get...
    method SetScope (line 18) | public static void SetScope(DependencyObject obj, string value) => obj...

FILE: EarTrumpet/UI/Themes/Ref.cs
  class Ref (line 5) | public class Ref
    method Ref (line 11) | public Ref() { }

FILE: EarTrumpet/UI/Themes/Rule.cs
  class Rule (line 5) | public class Rule
    type Kind (line 7) | public enum Kind

FILE: EarTrumpet/UI/Themes/ThemeBindingInfo.cs
  class ThemeBindingInfo (line 7) | class ThemeBindingInfo<T>
    method ThemeBindingInfo (line 16) | public ThemeBindingInfo(DependencyObject element, string value, string...
    method Leaving (line 35) | public void Leaving()
    method Element_Loaded (line 53) | private void Element_Loaded(object sender, RoutedEventArgs e)
    method UnregisterLoaded (line 62) | private void UnregisterLoaded(DependencyObject element)
    method ApplyValue (line 74) | public void ApplyValue(DependencyObject element)
    method ThemeChanged (line 86) | private void ThemeChanged()
    method GetProperty (line 94) | private PropertyInfo GetProperty(DependencyObject element) => element....
    method ReadPropertyValue (line 95) | private object ReadPropertyValue(DependencyObject element) => GetPrope...
    method WritePropertyValue (line 96) | private void WritePropertyValue(DependencyObject element, object value...

FILE: EarTrumpet/UI/ViewModels/AddonAboutPageViewModel.cs
  class AddonAboutPageViewModel (line 8) | internal class AddonAboutPageViewModel : SettingsPageViewModel
    method AddonAboutPageViewModel (line 17) | public AddonAboutPageViewModel(EarTrumpetAddon addon) : base(DefaultMa...

FILE: EarTrumpet/UI/ViewModels/AdvertisedCategorySettingsViewModel.cs
  class AdvertisedCategorySettingsViewModel (line 5) | public class AdvertisedCategorySettingsViewModel : SettingsCategoryViewM...
    method AdvertisedCategorySettingsViewModel (line 9) | public AdvertisedCategorySettingsViewModel(string title, string glyph,...
    method Activate (line 16) | public void Activate() => ProcessHelper.StartNoThrow(_link);

FILE: EarTrumpet/UI/ViewModels/AppItemViewModel.cs
  class AppItemViewModel (line 16) | public class AppItemViewModel : AudioSessionViewModel, IAppItemViewModel
    class ExeNameComparer (line 18) | public class ExeNameComparer : IComparer<IAppItemViewModel>
      method Compare (line 20) | public int Compare(IAppItemViewModel one, IAppItemViewModel two)
    method AppItemViewModel (line 59) | internal AppItemViewModel(DeviceViewModel parent, IAudioDeviceSession ...
    method Session_PropertyChanged (line 78) | private void Session_PropertyChanged(object sender, PropertyChangedEve...
    method Children_CollectionChanged (line 91) | private void Children_CollectionChanged(object sender, NotifyCollectio...
    method MoveToDevice (line 112) | public void MoveToDevice(string id, bool hide)
    method UpdatePeakValueForeground (line 117) | public override void UpdatePeakValueForeground()
    method UpdatePeakValueBackground (line 130) | public void UpdatePeakValueBackground()
    method DoesGroupWith (line 143) | public bool DoesGroupWith(IAppItemViewModel app) => (AppId == app.AppId);
    method ToString (line 145) | public override string ToString() => IsMuted ? Properties.Resources.Ap...

FILE: EarTrumpet/UI/ViewModels/AudioSessionViewModel.cs
  class AudioSessionViewModel (line 8) | public class AudioSessionViewModel : BindableBase
    method AudioSessionViewModel (line 13) | public AudioSessionViewModel(IStreamWithVolumeControl stream)
    method Stream_PropertyChanged (line 28) | private void Stream_PropertyChanged(object sender, System.ComponentMod...
    method UpdatePeakValueForeground (line 55) | public virtual void UpdatePeakValueForeground()

FILE: EarTrumpet/UI/ViewModels/BackstackViewModel.cs
  class BackstackViewModel (line 8) | class BackstackViewModel : BindableBase
    method BackstackViewModel (line 16) | public BackstackViewModel()
    method Add (line 28) | public void Add(Action action)

FILE: EarTrumpet/UI/ViewModels/ContextMenuItem.cs
  class ContextMenuItem (line 6) | public class ContextMenuItem
  class ContextMenuSeparator (line 16) | public class ContextMenuSeparator : ContextMenuItem

FILE: EarTrumpet/UI/ViewModels/DeviceCollectionViewModel.cs
  class DeviceCollectionViewModel (line 16) | public class DeviceCollectionViewModel : BindableBase
    method DeviceCollectionViewModel (line 33) | public DeviceCollectionViewModel(IAudioDeviceManager deviceManager, Ap...
    method OnDefaultChanged (line 46) | private void OnDefaultChanged(object sender, IAudioDevice newDevice)
    method SetDefault (line 64) | private void SetDefault(DeviceViewModel device)
    method OnDefaultDevicePropertyChanged (line 83) | private void OnDefaultDevicePropertyChanged(object sender, PropertyCha...
    method AddDevice (line 94) | protected virtual void AddDevice(IAudioDevice device)
    method OnCollectionChanged (line 100) | private void OnCollectionChanged(object sender, NotifyCollectionChange...
    method PeakMeterTimer_Elapsed (line 135) | private void PeakMeterTimer_Elapsed(object sender, ElapsedEventArgs e)
    method MoveAppToDevice (line 148) | public void MoveAppToDevice(IAppItemViewModel app, DeviceViewModel dev)
    method MoveAppToDeviceInternal (line 178) | private void MoveAppToDeviceInternal(IAppItemViewModel app, DeviceView...
    method StartOrStopPeakTimer (line 210) | private void StartOrStopPeakTimer()
    method OnTrayFlyoutShown (line 215) | public void OnTrayFlyoutShown()
    method OnTrayFlyoutHidden (line 221) | public void OnTrayFlyoutHidden()
    method OnFullWindowClosed (line 227) | public void OnFullWindowClosed()
    method OnFullWindowOpened (line 233) | public void OnFullWindowOpened()
    method GetTrayToolTip (line 239) | public string GetTrayToolTip()

FILE: EarTrumpet/UI/ViewModels/DeviceViewModel.cs
  class DeviceViewModel (line 12) | public class DeviceViewModel : AudioSessionViewModel, IDeviceViewModel
    class DisplayNameComparer (line 14) | public class DisplayNameComparer : IComparer<DeviceViewModel>
      method Compare (line 16) | public int Compare(DeviceViewModel one, DeviceViewModel two)
    type DeviceIconKind (line 24) | public enum DeviceIconKind
    method DeviceViewModel (line 74) | public DeviceViewModel(DeviceCollectionViewModel parent, IAudioDeviceM...
    method OnPropertyChanged (line 98) | private void OnPropertyChanged(object sender, System.ComponentModel.Pr...
    method UpdatePeakValueForeground (line 113) | public override void UpdatePeakValueForeground()
    method UpdateMasterVolumeIcon (line 123) | private void UpdateMasterVolumeIcon()
    method OnCollectionChanged (line 163) | private void OnCollectionChanged(object sender, System.Collections.Spe...
    method AddSession (line 186) | private void AddSession(IAudioDeviceSession session)
    method AppMovingToThisDevice (line 205) | public void AppMovingToThisDevice(TemporaryAppItemViewModel app)
    method OnAppExpired (line 230) | private void OnAppExpired(object sender, EventArgs e)
    method AppLeavingFromThisDevice (line 240) | internal void AppLeavingFromThisDevice(IAppItemViewModel app)
    method MakeDefaultDevice (line 248) | public void MakeDefaultDevice() => _deviceManager.Default = _device;
    method IncrementVolume (line 249) | public void IncrementVolume(int delta) => Volume += delta;
    method ToString (line 250) | public override string ToString() => AccessibleName;

FILE: EarTrumpet/UI/ViewModels/EarTrumpetAboutPageViewModel.cs
  class EarTrumpetAboutPageViewModel (line 9) | class EarTrumpetAboutPageViewModel : SettingsPageViewModel
    method EarTrumpetAboutPageViewModel (line 26) | public EarTrumpetAboutPageViewModel(Action openDiagnostics, AppSetting...
    method OpenDiagnostics (line 40) | private void OpenDiagnostics()
    method OpenGitHubIssueChooser (line 51) | private void OpenGitHubIssueChooser() => ProcessHelper.StartNoThrow("h...
    method OpenAbout (line 52) | private void OpenAbout() => ProcessHelper.StartNoThrow("https://github...
    method OpenPrivacyPolicy (line 53) | private void OpenPrivacyPolicy() => ProcessHelper.StartNoThrow("https:...

FILE: EarTrumpet/UI/ViewModels/EarTrumpetCommunitySettingsPageViewModel.cs
  class EarTrumpetCommunitySettingsPageViewModel (line 3) | public class EarTrumpetCommunitySettingsPageViewModel : SettingsPageView...
    method EarTrumpetCommunitySettingsPageViewModel (line 12) | public EarTrumpetCommunitySettingsPageViewModel(AppSettings settings) ...

FILE: EarTrumpet/UI/ViewModels/EarTrumpetLegacySettingsPageViewModel.cs
  class EarTrumpetLegacySettingsPageViewModel (line 5) | public class EarTrumpetLegacySettingsPageViewModel : SettingsPageViewModel
    method EarTrumpetLegacySettingsPageViewModel (line 15) | public EarTrumpetLegacySettingsPageViewModel(AppSettings settings) : b...

FILE: EarTrumpet/UI/ViewModels/EarTrumpetMouseSettingsPageViewModel.cs
  class EarTrumpetMouseSettingsPageViewModel (line 5) | public class EarTrumpetMouseSettingsPageViewModel : SettingsPageViewModel
    method EarTrumpetMouseSettingsPageViewModel (line 21) | public EarTrumpetMouseSettingsPageViewModel(AppSettings settings) : ba...

FILE: EarTrumpet/UI/ViewModels/EarTrumpetShortcutsPageViewModel.cs
  class EarTrumpetShortcutsPageViewModel (line 5) | internal class EarTrumpetShortcutsPageViewModel : SettingsPageViewModel
    method EarTrumpetShortcutsPageViewModel (line 24) | public EarTrumpetShortcutsPageViewModel(AppSettings settings) : base(n...

FILE: EarTrumpet/UI/ViewModels/FlyoutViewModel.cs
  class FlyoutViewModel (line 14) | public class FlyoutViewModel : BindableBase, IPopupHostViewModel, IFlyou...
    method FlyoutViewModel (line 39) | public FlyoutViewModel(DeviceCollectionViewModel mainViewModel, Action...
    method UpdateWindowPos (line 67) | public void UpdateWindowPos(double top, double left, double height, do...
    method OnDeBounceTimerTick (line 72) | private void OnDeBounceTimerTick(object sender, EventArgs e)
    method AddDevice (line 79) | private void AddDevice(DeviceViewModel device)
    method Apps_CollectionChanged (line 88) | private void Apps_CollectionChanged(object sender, NotifyCollectionCha...
    method RemoveDevice (line 104) | private void RemoveDevice(string id)
    method AllDevices_CollectionChanged (line 114) | private void AllDevices_CollectionChanged(object sender, System.Collec...
    method RaiseDevicesChanged (line 148) | private void RaiseDevicesChanged()
    method OnDefaultPlaybackDeviceChanged (line 156) | private void OnDefaultPlaybackDeviceChanged(object sender, DeviceViewM...
    method UpdateTextVisibility (line 183) | private void UpdateTextVisibility()
    method DoExpandCollapse (line 192) | public void DoExpandCollapse()
    method InvalidateWindowSize (line 226) | private void InvalidateWindowSize()
    method ChangeState (line 235) | public void ChangeState(FlyoutViewState state)
    method ValidateStateChange (line 276) | private void ValidateStateChange(FlyoutViewState newState)
    method OpenPopup (line 290) | public void OpenPopup(object vm, FrameworkElement container)
    method OnMouseWheelEvent (line 319) | private int OnMouseWheelEvent(object sender, System.Windows.Forms.Mous...
    method BeginOpen (line 333) | public void BeginOpen(InputType inputType)
    method BeginClose (line 347) | public void BeginClose(InputType inputType)
    method OpenFlyout (line 362) | public void OpenFlyout(InputType inputType)
    method OnDeactivated (line 375) | public void OnDeactivated(object sender, EventArgs e)
    method OnPreviewKeyDown (line 384) | public void OnPreviewKeyDown(object sender, KeyEventArgs e)
    method OnClosing (line 404) | public void OnClosing(object sender, System.ComponentModel.CancelEvent...
    method OnLightDismissBorderPreviewMouseDown (line 410) | public void OnLightDismissBorderPreviewMouseDown(object sender, MouseB...

FILE: EarTrumpet/UI/ViewModels/FocusedAppItemViewModel.cs
  class FocusedAppItemViewModel (line 9) | public class FocusedAppItemViewModel : IFocusedViewModel
    method FocusedAppItemViewModel (line 18) | public FocusedAppItemViewModel(DeviceCollectionViewModel parent, IAppI...
    method Closing (line 85) | public void Closing()

FILE: EarTrumpet/UI/ViewModels/FocusedDeviceViewModel.cs
  class FocusedDeviceViewModel (line 9) | class FocusedDeviceViewModel : IFocusedViewModel
    method FocusedDeviceViewModel (line 20) | public FocusedDeviceViewModel(DeviceCollectionViewModel mainViewModel,...
    method Closing (line 51) | public void Closing() { }

FILE: EarTrumpet/UI/ViewModels/FullWindowViewModel.cs
  class FullWindowViewModel (line 9) | public class FullWindowViewModel : BindableBase, IPopupHostViewModel
    method FullWindowViewModel (line 21) | public FullWindowViewModel(DeviceCollectionViewModel mainViewModel)
    method OnDevicesChanged (line 31) | private void OnDevicesChanged(object sender, System.Collections.Specia...
    method OpenPopup (line 36) | public void OpenPopup(object vm, FrameworkElement container)
    method OnClosing (line 61) | public void OnClosing(object sender, System.ComponentModel.CancelEvent...
    method OnPreviewKeyDown (line 89) | public void OnPreviewKeyDown(object sender, KeyEventArgs e)
    method OnSizeChanged (line 104) | public void OnSizeChanged(object sender, SizeChangedEventArgs e)
    method OnLocationChanged (line 109) | public void OnLocationChanged(object sender, EventArgs e)
    method OnLightDismissBorderPreviewMouseDown (line 114) | public void OnLightDismissBorderPreviewMouseDown(object sender, MouseB...

FILE: EarTrumpet/UI/ViewModels/HotkeyViewModel.cs
  class HotkeyViewModel (line 8) | public class HotkeyViewModel : BindableBase
    method HotkeyViewModel (line 34) | public HotkeyViewModel(HotkeyData hotkey, Action<HotkeyData> save)
    method OnPreviewKeyDown (line 43) | public void OnPreviewKeyDown(object sender, KeyEventArgs e)
    method OnLostFocus (line 103) | public void OnLostFocus(object sender, RoutedEventArgs e)
    method OnGotFocus (line 121) | public void OnGotFocus(object sender, RoutedEventArgs e)
    method SetHotkeyText (line 126) | private void SetHotkeyText()

FILE: EarTrumpet/UI/ViewModels/IAppItemViewModel.cs
  type IAppItemViewModel (line 8) | public interface IAppItemViewModel : IAppIconSource, INotifyPropertyChanged
    method DoesGroupWith (line 25) | bool DoesGroupWith(IAppItemViewModel app);
    method MoveToDevice (line 26) | void MoveToDevice(string id, bool hide);
    method UpdatePeakValueForeground (line 27) | void UpdatePeakValueForeground();
    method UpdatePeakValueBackground (line 28) | void UpdatePeakValueBackground();

FILE: EarTrumpet/UI/ViewModels/IDeviceViewModel.cs
  type IDeviceViewModel (line 3) | public interface IDeviceViewModel

FILE: EarTrumpet/UI/ViewModels/IFlyoutViewModel.cs
  type IFlyoutViewModel (line 6) | public interface IFlyoutViewModel
    method ChangeState (line 14) | void ChangeState(FlyoutViewState state);
    method UpdateWindowPos (line 15) | void UpdateWindowPos(double top, double left, double height, double wi...

FILE: EarTrumpet/UI/ViewModels/IFocusedViewModel.cs
  type IFocusedViewModel (line 6) | public interface IFocusedViewModel
    method Closing (line 11) | void Closing();

FILE: EarTrumpet/UI/ViewModels/IPopupHostViewModel.cs
  type IPopupHostViewModel (line 5) | public interface IPopupHostViewModel
    method OpenPopup (line 7) | void OpenPopup(object vm, FrameworkElement container);

FILE: EarTrumpet/UI/ViewModels/ISettingsViewModel.cs
  type ISettingsViewModel (line 6) | public interface ISettingsViewModel
    method ShowDialog (line 8) | void ShowDialog(string title, string description, string btn1, string ...
    method CompleteNavigation (line 9) | void CompleteNavigation(NavigationCookie cookie);

FILE: EarTrumpet/UI/ViewModels/ModalDialogViewModel.cs
  class ModalDialogViewModel (line 5) | public class ModalDialogViewModel : BindableBase

FILE: EarTrumpet/UI/ViewModels/SettingsAppItemViewModel.cs
  class SettingsAppItemViewModel (line 11) | public class SettingsAppItemViewModel : BindableBase, IAppItemViewModel
    method SettingsAppItemViewModel (line 61) | public SettingsAppItemViewModel(IAudioDeviceSession session)
    method SettingsAppItemViewModel (line 70) | public SettingsAppItemViewModel()
    method DoesGroupWith (line 74) | public bool DoesGroupWith(IAppItemViewModel app)
    method MoveToDevice (line 79) | public void MoveToDevice(string id, bool hide)
    method OpenPopup (line 84) | public void OpenPopup(FrameworkElement uIElement)
    method UpdatePeakValueBackground (line 89) | public void UpdatePeakValueBackground()
    method UpdatePeakValueForeground (line 94) | public void UpdatePeakValueForeground()

FILE: EarTrumpet/UI/ViewModels/SettingsCategoryViewModel.cs
  class SettingsCategoryViewModel (line 8) | public class SettingsCategoryViewModel : BindableBase
    method SelectImpl (line 37) | private void SelectImpl(SettingsPageViewModel page)
    method SettingsCategoryViewModel (line 60) | public SettingsCategoryViewModel(string title, string glyph, string de...
    method NavigatedTo (line 69) | public void NavigatedTo(ISettingsViewModel settingsViewModel)
    method NavigatingFrom (line 74) | public bool NavigatingFrom(NavigationCookie cookie)
    method ShowDialog (line 83) | public void ShowDialog(string title, string description, string btn1, ...
    method ToString (line 88) | public override string ToString() => $"{Title}\n{Description}";

FILE: EarTrumpet/UI/ViewModels/SettingsDialogViewModel.cs
  class SettingsDialogViewModel (line 5) | class SettingsDialogViewModel

FILE: EarTrumpet/UI/ViewModels/SettingsPageHeaderViewModel.cs
  class SettingsPageHeaderViewModel (line 3) | public class SettingsPageHeaderViewModel : BindableBase
    method SettingsPageHeaderViewModel (line 9) | public SettingsPageHeaderViewModel(SettingsPageViewModel settingsPageV...

FILE: EarTrumpet/UI/ViewModels/SettingsPageViewModel.cs
  class SettingsPageViewModel (line 7) | public class SettingsPageViewModel : BindableBase
    method NavigatingFrom (line 45) | public virtual bool NavigatingFrom(NavigationCookie cookie)
    method SettingsPageViewModel (line 50) | public SettingsPageViewModel(string groupName)
    method NavigatedTo (line 56) | public void NavigatedTo()
    method ToString (line 61) | public override string ToString() => Title;

FILE: EarTrumpet/UI/ViewModels/SettingsSearchItemViewModel.cs
  class SettingsSearchItemViewModel (line 5) | class SettingsSearchItemViewModel
    method ToString (line 15) | public override string ToString() => SearchText;

FILE: EarTrumpet/UI/ViewModels/SettingsViewModel.cs
  class SettingsViewModel (line 10) | class SettingsViewModel : BindableBase, ISettingsViewModel
    method OnInvoked (line 31) | public void OnInvoked(object sender, SettingsCategoryViewModel toSelect)
    method SettingsViewModel (line 67) | public SettingsViewModel(string title, IEnumerable<SettingsCategoryVie...
    method InvokeSearchResult (line 74) | public void InvokeSearchResult(SettingsCategoryViewModel cat, Settings...
    method SelectImpl (line 89) | private void SelectImpl(SettingsCategoryViewModel categoryToSelect)
    method OnClosing (line 121) | public void OnClosing(object sender, System.ComponentModel.CancelEvent...
    method ShowDialog (line 150) | public void ShowDialog(string title, string description, string btn1, ...
    method CompleteNavigation (line 171) | public void CompleteNavigation(NavigationCookie cookie)

FILE: EarTrumpet/UI/ViewModels/TemporaryAppItemViewModel.cs
  class TemporaryAppItemViewModel (line 16) | public class TemporaryAppItemViewModel : BindableBase, IAppItemViewModel
    method TemporaryAppItemViewModel (line 76) | internal TemporaryAppItemViewModel(DeviceCollectionViewModel parent, I...
    method ChildApp_PropertyChanged (line 144) | private void ChildApp_PropertyChanged(object sender, PropertyChangedEv...
    method DoesGroupWith (line 149) | public bool DoesGroupWith(IAppItemViewModel app)
    method MoveToDevice (line 154) | public void MoveToDevice(string id, bool hide)
    method Expire (line 168) | private void Expire()
    method UpdatePeakValueBackground (line 173) | public void UpdatePeakValueBackground() { }
    method UpdatePeakValueForeground (line 174) | public void UpdatePeakValueForeground() { }

FILE: EarTrumpet/UI/ViewModels/ToolbarItemViewModel.cs
  class ToolbarItemViewModel (line 6) | public class ToolbarItemViewModel

FILE: EarTrumpet/UI/ViewModels/WelcomeViewModel.cs
  class WelcomeViewModel (line 8) | class WelcomeViewModel
    method WelcomeViewModel (line 25) | public WelcomeViewModel(AppSettings settings)
    method OnClosing (line 33) | public void OnClosing(object sender, System.ComponentModel.CancelEvent...

FILE: EarTrumpet/UI/Views/AppItemView.xaml.cs
  class AppItemView (line 9) | public partial class AppItemView : UserControl
    method AppItemView (line 13) | public AppItemView()
    method OnPreviewKeyDown (line 28) | private void OnPreviewKeyDown(object sender, KeyEventArgs e)
    method OpenPopup (line 54) | private void OpenPopup()

FILE: EarTrumpet/UI/Views/DeviceView.xaml.cs
  class DeviceView (line 10) | public partial class DeviceView : UserControl
    method DeviceView (line 26) | public DeviceView()
    method FocusAndRemoveFocusVisual (line 34) | public void FocusAndRemoveFocusVisual()
    method RemoveFocusVisual (line 40) | private void RemoveFocusVisual(UIElement element)
    method OnPreviewKeyDown (line 53) | private void OnPreviewKeyDown(object sender, KeyEventArgs e)
    method DeviceChanged (line 79) | private static void DeviceChanged(DependencyObject d, DependencyProper...
    method TouchSlider_TouchUp (line 85) | private void TouchSlider_TouchUp(object sender, TouchEventArgs e)
    method TouchSlider_MouseUp (line 90) | private void TouchSlider_MouseUp(object sender, MouseButtonEventArgs e)
    method OpenPopup (line 98) | private void OpenPopup()

FILE: EarTrumpet/UI/Views/DialogWindow.xaml.cs
  class DialogWindow (line 6) | public partial class DialogWindow : Window
    method DialogWindow (line 8) | public DialogWindow()

FILE: EarTrumpet/UI/Views/FlyoutWindow.xaml.cs
  class FlyoutWindow (line 11) | public partial class FlyoutWindow
    method FlyoutWindow (line 15) | public FlyoutWindow(IFlyoutViewModel viewModel)
    method Initialize (line 32) | public void Initialize()
    method OnStateChanged (line 42) | private void OnStateChanged(object sender, object e)
    method OnWindowsSizeInvalidated (line 98) | private void OnWindowsSizeInvalidated(object sender, object e)
    method PositionWindowRelativeToTaskbar (line 110) | private void PositionWindowRelativeToTaskbar(WindowsTaskbar.State task...
    method EnableAcrylicIfApplicable (line 206) | private void EnableAcrylicIfApplicable(WindowsTaskbar.State taskbar)
    method GetAccentFlags (line 220) | private User32.AccentFlags GetAccentFlags(WindowsTaskbar.State taskbar)

FILE: EarTrumpet/UI/Views/FullWindow.xaml.cs
  class FullWindow (line 10) | public partial class FullWindow : Window
    method FullWindow (line 15) | public FullWindow()
    method OnDevicesChanged (line 53) | private void OnDevicesChanged(object sender, System.Collections.Specia...

FILE: EarTrumpet/UI/Views/SettingsWindow.xaml.cs
  class SettingsWindow (line 11) | public partial class SettingsWindow : Window
    method SettingsWindow (line 13) | public SettingsWindow()
    method OnWindowStateChanged (line 42) | private void OnWindowStateChanged(object sender, EventArgs e)
Condensed preview — 424 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,297K chars).
[
  {
    "path": ".azure-pipelines.yml",
    "chars": 6764,
    "preview": "trigger:\r\n  branches:\r\n    include:\r\n      - master\r\n      - review/*\r\n      - experiment/*\r\n      - dev\r\n  paths:\r\n    "
  },
  {
    "path": ".chocolatey/eartrumpet.nuspec",
    "chars": 1212,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<package xmlns=\"http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd\">\r\n  "
  },
  {
    "path": ".chocolatey/tools/LICENSE.txt",
    "chars": 1173,
    "preview": "From: https://github.com/File-New-Project/EarTrumpet/blob/master/LICENSE\r\n\r\nLICENSE\r\n\r\nThe MIT License (MIT)\r\n\r\nCopyrig"
  },
  {
    "path": ".chocolatey/tools/VERIFICATION.txt",
    "chars": 240,
    "preview": "VERIFICATION\r\nVerification is intended to assist the Chocolatey moderators and community\r\nin verifying that this packag"
  },
  {
    "path": ".chocolatey/tools/chocolateybeforemodify.ps1",
    "chars": 124,
    "preview": "$process = Get-Process -Name EarTrumpet -ErrorAction SilentlyContinue\r\nif ($process) {\r\n  $process | Stop-Process -Forc"
  },
  {
    "path": ".chocolatey/tools/chocolateyinstall.ps1",
    "chars": 870,
    "preview": "$ErrorActionPreference = 'Stop'\r\n$toolsDir   = \"$(Split-Path -parent $MyInvocation.MyCommand.Definition)\"\r\n$installPath"
  },
  {
    "path": ".chocolatey/tools/chocolateyuninstall.ps1",
    "chars": 203,
    "preview": "Remove-Item \"C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\EarTrumpet.lnk\" -ErrorAction Continue\r\nRemove-ItemProp"
  },
  {
    "path": ".gitattributes",
    "chars": 348,
    "preview": "[core]\r\n* text eol=crlf\r\n\r\n*.png binary\r\n*.jpg binary\r\n*.jpeg binary\r\n*.gif binary\r\n*.ico binary\r\n*.mov binary\r\n*.mp4 bi"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 245,
    "preview": "# These are supported funding model platforms\r\n\r\n## Supported\r\ngithub: File-New-Project\r\n\r\n## Currently unsupported\r\npat"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "chars": 1056,
    "preview": "name: Bug report\r\ndescription: Report a problem with EarTrumpet or related add-on\r\nbody:\r\n  - type: textarea\r\n    id: su"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 413,
    "preview": "blank_issues_enabled: true\r\ncontact_links:\r\n  - name: Request a feature\r\n    url: https://github.com/File-New-Project/Ea"
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 23437,
    "preview": "name: EarTrumpet-CI\r\non:\r\n  push:\r\n    branches:\r\n      - master\r\n      - dev\r\n      - rafael/*\r\n      - dave/*\r\n      -"
  },
  {
    "path": ".github/workflows/sponsors.yml",
    "chars": 756,
    "preview": "name: Generate Sponsors\r\non:\r\n  workflow_dispatch:\r\n  schedule:\r\n    - cron: 0 12 1-31 * *\r\njobs:\r\n  deploy:\r\n    runs-o"
  },
  {
    "path": ".github/workflows/translators.yml",
    "chars": 1823,
    "preview": "name: Update Translators List\r\n\r\non:\r\n  schedule:\r\n    - cron: '0 0 * * 0' # Run weekly on Sunday at 00:00\r\n  workflow_d"
  },
  {
    "path": ".gitignore",
    "chars": 3408,
    "preview": "## Ignore Visual Studio temporary files, build results, and\r\n## files generated by popular Visual Studio add-ons.\r\n\r\n# U"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 11404,
    "preview": "# Changelog\r\n\r\n## 2.3.0.0\r\n- Added setting to turn on/off ability to change volume with the scroll wheel anywhere (thank"
  },
  {
    "path": "COMPILING.md",
    "chars": 1266,
    "preview": "# Compiling EarTrumpet\r\n\r\n## Requirements\r\n* [Visual Studio 2017](https://visualstudio.microsoft.com/vs/community/) (or "
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1695,
    "preview": "# Contributing to EarTrumpet\r\nThanks for your interest in contributing to EarTrumpet!\r\n\r\nYou can contribute to EarTrumpe"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/AddonResources.xaml",
    "chars": 30186,
    "preview": "<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\r\n                    xmlns:x=\"htt"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/Controls/LinkedTextBlock.cs",
    "chars": 9520,
    "preview": "using EarTrumpet.Extensions;\r\nusing EarTrumpet.UI.Helpers;\r\nusing EarTrumpet.UI.ViewModels;\r\nusing EarTrumpet.Actions.V"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/Controls/MenuButton.cs",
    "chars": 740,
    "preview": "using System.Windows.Controls;\r\nusing System.Windows.Controls.Primitives;\r\n\r\nnamespace EarTrumpet.Actions.Controls\r\n{\r\n"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/AudioAppEventKind.cs",
    "chars": 218,
    "preview": "namespace EarTrumpet.Actions.DataModel.Enum\r\n{\r\n    public enum AudioAppEventKind\r\n    {\r\n        Added,\r\n        Remov"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/AudioDeviceEventKind.cs",
    "chars": 189,
    "preview": "namespace EarTrumpet.Actions.DataModel.Enum\r\n{\r\n    public enum AudioDeviceEventKind\r\n    {\r\n        Added,\r\n        Re"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/BoolValue.cs",
    "chars": 124,
    "preview": "namespace EarTrumpet.Actions.DataModel.Enum\r\n{\r\n    public enum BoolValue\r\n    {\r\n        True,\r\n        False,\r\n    }\r"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/ComparisonBoolKind.cs",
    "chars": 131,
    "preview": "namespace EarTrumpet.Actions.DataModel.Enum\r\n{\r\n    public enum ComparisonBoolKind\r\n    {\r\n        Is,\r\n        IsNot,\r"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/EarTrumpetEventKind.cs",
    "chars": 141,
    "preview": "namespace EarTrumpet.Actions.DataModel.Enum\r\n{\r\n    public enum EarTrumpetEventKind\r\n    {\r\n        Startup,\r\n        S"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/MuteKind.cs",
    "chars": 145,
    "preview": "namespace EarTrumpet.Actions.DataModel.Enum\r\n{\r\n    public enum MuteKind\r\n    {\r\n        Mute,\r\n        Unmute,\r\n      "
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/ProcessEventKind.cs",
    "chars": 131,
    "preview": "namespace EarTrumpet.Actions.DataModel.Enum\r\n{\r\n    public enum ProcessEventKind\r\n    {\r\n        Start,\r\n        Stop,\r"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/ProcessStateKind.cs",
    "chars": 138,
    "preview": "namespace EarTrumpet.Actions.DataModel.Enum\r\n{\r\n    public enum ProcessStateKind\r\n    {\r\n        Running,\r\n        NotR"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Enum/SetVolumeKind.cs",
    "chars": 151,
    "preview": "namespace EarTrumpet.Actions.DataModel.Enum\r\n{\r\n    public enum SetVolumeKind\r\n    {\r\n        Set,\r\n        Increment,\r"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/IPartWithApp.cs",
    "chars": 176,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.DataModel\r\n{\r\n    interface IPartWith"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/IPartWithDevice.cs",
    "chars": 189,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.DataModel\r\n{\r\n    public interface IP"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/IPartWithText.cs",
    "chars": 125,
    "preview": "namespace EarTrumpet.Actions.DataModel\r\n{\r\n    interface IPartWithText\r\n    {\r\n        string Text { get; set; }\r\n    }"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/IPartWithVolume.cs",
    "chars": 136,
    "preview": "namespace EarTrumpet.Actions.DataModel\r\n{\r\n    public interface IPartWithVolume\r\n    {\r\n        double Volume { get; se"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/LocalVariablesContainer.cs",
    "chars": 598,
    "preview": "using EarTrumpet.DataModel.Storage;\r\n\r\nnamespace EarTrumpet.Actions.DataModel\r\n{\r\n    public class LocalVariablesContai"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Part.cs",
    "chars": 83,
    "preview": "namespace EarTrumpet.Actions.DataModel\r\n{\r\n    public abstract class Part { }\r\n}\r\n"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/ProcessWatcher.cs",
    "chars": 4792,
    "preview": "using EarTrumpet.Interop;\r\nusing EarTrumpet.Actions.Interop.Helpers;\r\nusing System;\r\nusing System.Collections.Generic;\r"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Processing/ActionProcessor.cs",
    "chars": 7887,
    "preview": "using EarTrumpet.Interop;\r\nusing EarTrumpet.Actions.DataModel.Serialization;\r\nusing EarTrumpet.Actions.DataModel.Enum;\r"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Processing/AudioTriggerManager.cs",
    "chars": 6777,
    "preview": "using EarTrumpet.Actions.DataModel.Enum;\r\nusing EarTrumpet.Actions.DataModel.Serialization;\r\nusing System;\r\nusing Syste"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Processing/ConditionProcessor.cs",
    "chars": 2016,
    "preview": "using EarTrumpet.Actions.DataModel.Enum;\r\nusing EarTrumpet.Actions.DataModel.Serialization;\r\nusing System;\r\nusing EarTr"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Processing/TriggerManager.cs",
    "chars": 3013,
    "preview": "using EarTrumpet.Extensibility;\r\nusing EarTrumpet.Interop.Helpers;\r\nusing EarTrumpet.Actions.DataModel.Enum;\r\nusing Ear"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/Actions.cs",
    "chars": 1703,
    "preview": "using EarTrumpet.Actions.DataModel.Enum;\r\nusing System.Xml.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.DataModel.Ser"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/App.cs",
    "chars": 524,
    "preview": "namespace EarTrumpet.Actions.DataModel.Serialization\r\n{\r\n    public class AppRef\r\n    {\r\n        public static readonly"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/Conditions.cs",
    "chars": 868,
    "preview": "using EarTrumpet.Actions.DataModel.Enum;\r\nusing System.Xml.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.DataModel.Ser"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/Device.cs",
    "chars": 408,
    "preview": "namespace EarTrumpet.Actions.DataModel.Serialization\r\n{\r\n    public class Device\r\n    {\r\n        public string Id { get"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/EarTrumpetAction.cs",
    "chars": 622,
    "preview": "using System;\r\nusing System.Collections.ObjectModel;\r\n\r\nnamespace EarTrumpet.Actions.DataModel.Serialization\r\n{\r\n    pu"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/DataModel/Serialization/Triggers.cs",
    "chars": 1381,
    "preview": "using EarTrumpet.Interop.Helpers;\r\nusing EarTrumpet.Actions.DataModel.Enum;\r\nusing System.Xml.Serialization;\r\n\r\nnamespa"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/EarTrumpetActionsAddon.cs",
    "chars": 4400,
    "preview": "using EarTrumpet.Actions.DataModel;\r\nusing EarTrumpet.Actions.DataModel.Processing;\r\nusing EarTrumpet.Actions.DataModel"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/Interop/Helpers/WindowWatcher.cs",
    "chars": 1242,
    "preview": "using EarTrumpet.Interop.Helpers;\r\nusing System;\r\nusing System.Diagnostics;\r\nusing System.Windows.Forms;\r\n\r\nnamespace E"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/Interop/User32.cs",
    "chars": 644,
    "preview": "using System;\r\nusing System.Runtime.InteropServices;\r\n\r\nnamespace EarTrumpet.Actions.Interop\r\n{\r\n    class User32\r\n    "
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetAppMuteActionViewModel.cs",
    "chars": 897,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel.Actions\r\n{\r\n    class SetAp"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetAppVolumeActionViewModel.cs",
    "chars": 1473,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\nusing EarTrumpet.Actions.DataModel.Enum;\r\n\r\nnamespace EarTrumpet.Act"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetDefaultDeviceActionViewModel.cs",
    "chars": 481,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel.Actions\r\n{\r\n    class SetDe"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetDeviceMuteActionViewModel.cs",
    "chars": 1170,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel.Actions\r\n{\r\n    class SetDe"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetDeviceVolumeActionViewModel.cs",
    "chars": 1336,
    "preview": "using EarTrumpet.Actions.DataModel.Enum;\r\nusing EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Act"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Actions/SetVariableActionViewModel.cs",
    "chars": 554,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel.Actions\r\n{\r\n    class SetVa"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/ActionsCategoryViewModel.cs",
    "chars": 4687,
    "preview": "using EarTrumpet.Extensions;\r\nusing EarTrumpet.UI.Helpers;\r\nusing EarTrumpet.UI.ViewModels;\r\nusing EarTrumpet.Actions.D"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/AppListViewModel.cs",
    "chars": 2425,
    "preview": "using EarTrumpet.Extensions;\r\nusing EarTrumpet.UI.ViewModels;\r\nusing EarTrumpet.Actions.DataModel;\r\nusing EarTrumpet.Ac"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Conditions/DefaultDeviceConditionViewModel.cs",
    "chars": 654,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel.Conditions\r\n{\r\n    class De"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Conditions/ProcessConditionViewModel.cs",
    "chars": 572,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel.Conditions\r\n{\r\n    class Pr"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Conditions/VariableConditionViewModel.cs",
    "chars": 572,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel.Conditions\r\n{\r\n    class Va"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/DefaultPlaybackDeviceViewModel.cs",
    "chars": 443,
    "preview": "using EarTrumpet.DataModel.WindowsAudio;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel\r\n{\r\n    class DefaultPlaybackDeviceV"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/DeviceListViewModel.cs",
    "chars": 2621,
    "preview": "using EarTrumpet.Extensions;\r\nusing EarTrumpet.Actions.DataModel;\r\nusing EarTrumpet.Actions.DataModel.Serialization;\r\nu"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/DeviceViewModel.cs",
    "chars": 1114,
    "preview": "using EarTrumpet.DataModel.Audio;\r\nusing EarTrumpet.DataModel.WindowsAudio;\r\nusing EarTrumpet.UI.Helpers;\r\n\r\nnamespace "
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/DeviceViewModelBase.cs",
    "chars": 294,
    "preview": "namespace EarTrumpet.Actions.ViewModel\r\n{\r\n    public class DeviceViewModelBase : BindableBase\r\n    {\r\n        public s"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/EarTrumpetActionPageHeaderViewModel.cs",
    "chars": 1053,
    "preview": "using EarTrumpet.UI.ViewModels;\r\nusing System.ComponentModel;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel\r\n{\r\n    public "
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/EarTrumpetActionViewModel.cs",
    "chars": 8570,
    "preview": "using EarTrumpet.UI.Helpers;\r\nusing EarTrumpet.UI.ViewModels;\r\nusing EarTrumpet.Actions.DataModel;\r\nusing EarTrumpet.Ac"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/EveryAppViewModel.cs",
    "chars": 360,
    "preview": "using EarTrumpet.UI.ViewModels;\r\nusing EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.View"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/ForegroundAppViewModel.cs",
    "chars": 380,
    "preview": "using EarTrumpet.UI.ViewModels;\r\nusing EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.View"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/HotkeyViewModel.cs",
    "chars": 1332,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\nusing System;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel\r\n{\r\n    publ"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/IOptionViewModel.cs",
    "chars": 222,
    "preview": "using System.Collections.ObjectModel;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel\r\n{\r\n    interface IOptionViewModel\r\n   "
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/ImportExportPageViewModel.cs",
    "chars": 2072,
    "preview": "using EarTrumpet.UI.Helpers;\r\nusing EarTrumpet.UI.ViewModels;\r\nusing System;\r\nusing System.Diagnostics;\r\nusing System.I"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Option.cs",
    "chars": 490,
    "preview": "using System;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel\r\n{\r\n    public class Option : IEquatable<Option>\r\n    {\r\n      "
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/OptionViewModel.cs",
    "chars": 1886,
    "preview": "using System;\r\nusing System.Collections.ObjectModel;\r\nusing System.Linq;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel\r\n{\r\n"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/PartViewModel.cs",
    "chars": 2412,
    "preview": "using EarTrumpet.Actions.DataModel;\r\nusing EarTrumpet.Actions.DataModel.Serialization;\r\nusing System;\r\nusing System.Com"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/PartViewModelFactory.cs",
    "chars": 1759,
    "preview": "using EarTrumpet.Actions.DataModel;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\n\r\nnamespace "
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/TextViewModel.cs",
    "chars": 1275,
    "preview": "using EarTrumpet.Actions.DataModel;\r\nusing System;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel\r\n{\r\n    class TextViewMode"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/AppEventTriggerViewModel.cs",
    "chars": 785,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel.Triggers\r\n{\r\n    class AppE"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/ContextMenuTriggerViewModel.cs",
    "chars": 270,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel.Triggers\r\n{\r\n    class Cont"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/DeviceEventTriggerViewModel.cs",
    "chars": 683,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel.Triggers\r\n{\r\n    class Devi"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/EventTriggerViewModel.cs",
    "chars": 425,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel.Triggers\r\n{\r\n    class Even"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/HotkeyTriggerViewModel.cs",
    "chars": 482,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel.Triggers\r\n{\r\n    class Hotk"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/Triggers/ProcessTriggerViewModel.cs",
    "chars": 552,
    "preview": "using EarTrumpet.Actions.DataModel.Serialization;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel.Triggers\r\n{\r\n    class Proc"
  },
  {
    "path": "EarTrumpet/Addons/EarTrumpet.Actions/ViewModel/VolumeViewModel.cs",
    "chars": 624,
    "preview": "using EarTrumpet.Actions.DataModel;\r\n\r\nnamespace EarTrumpet.Actions.ViewModel\r\n{\r\n    public class VolumeViewModel : Bi"
  },
  {
    "path": "EarTrumpet/App.config",
    "chars": 880,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<configuration>\r\n    <configSections>\r\n\t\t<section name=\"bugsnag\" type=\"Bugsnag."
  },
  {
    "path": "EarTrumpet/App.manifest",
    "chars": 1349,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<assembly manifestVersion=\"1.0\" xmlns=\"urn:schemas-microsoft-com:asm.v1\" xmlns:"
  },
  {
    "path": "EarTrumpet/App.xaml",
    "chars": 157827,
    "preview": "<Application x:Class=\"EarTrumpet.App\"\r\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\r\n"
  },
  {
    "path": "EarTrumpet/App.xaml.cs",
    "chars": 14243,
    "preview": "using EarTrumpet.DataModel.WindowsAudio;\r\nusing EarTrumpet.Diagnosis;\r\nusing EarTrumpet.Extensibility;\r\nusing EarTrumpet"
  },
  {
    "path": "EarTrumpet/AppSettings.cs",
    "chars": 9579,
    "preview": "using EarTrumpet.DataModel.Storage;\r\nusing EarTrumpet.Interop.Helpers;\r\nusing System;\r\nusing System.Diagnostics;\r\nusing"
  },
  {
    "path": "EarTrumpet/BindableBase.cs",
    "chars": 360,
    "preview": "using System.ComponentModel;\r\n\r\nnamespace EarTrumpet\r\n{\r\n    public class BindableBase : INotifyPropertyChanged\r\n    {\r"
  },
  {
    "path": "EarTrumpet/DataModel/AppInformation/AppInformationFactory.cs",
    "chars": 678,
    "preview": "using EarTrumpet.Interop.Helpers;\r\n\r\nnamespace EarTrumpet.DataModel.AppInformation\r\n{\r\n    public class AppInformationF"
  },
  {
    "path": "EarTrumpet/DataModel/AppInformation/IAppInfo.cs",
    "chars": 346,
    "preview": "using System;\r\n\r\nnamespace EarTrumpet.DataModel.AppInformation\r\n{\r\n    public interface IAppInfo\r\n    {\r\n        event "
  },
  {
    "path": "EarTrumpet/DataModel/AppInformation/Internal/DesktopAppInfo.cs",
    "chars": 5892,
    "preview": "using EarTrumpet.Interop;\r\nusing System;\r\nusing System.Diagnostics;\r\nusing System.IO;\r\nusing System.Runtime.InteropServ"
  },
  {
    "path": "EarTrumpet/DataModel/AppInformation/Internal/ModernAppInfo.cs",
    "chars": 6858,
    "preview": "using EarTrumpet.Interop;\r\nusing System;\r\nusing System.Diagnostics;\r\nusing System.Runtime.InteropServices;\r\nusing Syste"
  },
  {
    "path": "EarTrumpet/DataModel/AppInformation/Internal/SystemSoundsAppInfo.cs",
    "chars": 1729,
    "preview": "using EarTrumpet.Extensions;\r\nusing EarTrumpet.Interop;\r\nusing System;\r\nusing System.Diagnostics;\r\n\r\nnamespace EarTrump"
  },
  {
    "path": "EarTrumpet/DataModel/AppInformation/Internal/ZombieProcessException.cs",
    "chars": 547,
    "preview": "using EarTrumpet.Interop;\r\nusing System;\r\n\r\nnamespace EarTrumpet.DataModel.AppInformation.Internal\r\n{\r\n    public class"
  },
  {
    "path": "EarTrumpet/DataModel/Audio/IAudioDevice.cs",
    "chars": 482,
    "preview": "using System;\r\nusing System.Collections.ObjectModel;\r\n\r\nnamespace EarTrumpet.DataModel.Audio\r\n{\r\n    public interface I"
  },
  {
    "path": "EarTrumpet/DataModel/Audio/IAudioDeviceManager.cs",
    "chars": 528,
    "preview": "using System;\r\nusing System.Collections.ObjectModel;\r\n\r\nnamespace EarTrumpet.DataModel.Audio\r\n{\r\n    public interface I"
  },
  {
    "path": "EarTrumpet/DataModel/Audio/IAudioDeviceSession.cs",
    "chars": 703,
    "preview": "using EarTrumpet.DataModel.WindowsAudio;\r\nusing System.Collections.Generic;\r\nusing System.Collections.ObjectModel;\r\n\r\nn"
  },
  {
    "path": "EarTrumpet/DataModel/Audio/IAudioDeviceSessionComparer.cs",
    "chars": 558,
    "preview": "using System.Collections.Generic;\r\n\r\nnamespace EarTrumpet.DataModel.Audio\r\n{\r\n    public class IAudioDeviceSessionCompa"
  },
  {
    "path": "EarTrumpet/DataModel/Audio/IStreamWithVolumeControl.cs",
    "chars": 333,
    "preview": "using System.ComponentModel;\r\n\r\nnamespace EarTrumpet.DataModel.Audio\r\n{\r\n    public interface IStreamWithVolumeControl "
  },
  {
    "path": "EarTrumpet/DataModel/Audio/Mocks/AudioDevice.cs",
    "chars": 2558,
    "preview": "using EarTrumpet.DataModel.WindowsAudio;\r\nusing EarTrumpet.DataModel.WindowsAudio.Internal;\r\nusing EarTrumpet.Extension"
  },
  {
    "path": "EarTrumpet/DataModel/Audio/Mocks/AudioDeviceSession.cs",
    "chars": 2846,
    "preview": "using EarTrumpet.DataModel.WindowsAudio;\r\nusing EarTrumpet.DataModel.WindowsAudio.Internal;\r\nusing EarTrumpet.Extension"
  },
  {
    "path": "EarTrumpet/DataModel/Audio/SessionState.cs",
    "chars": 197,
    "preview": "namespace EarTrumpet.DataModel.Audio\r\n{\r\n    public enum SessionState\r\n    {\r\n        Invalid = 0,\r\n        Expired = 1"
  },
  {
    "path": "EarTrumpet/DataModel/FilteredCollectionChain.cs",
    "chars": 2155,
    "preview": "using System;\r\nusing System.Collections.ObjectModel;\r\nusing System.Linq;\r\nusing System.Windows.Threading;\r\n\r\nnamespace "
  },
  {
    "path": "EarTrumpet/DataModel/ProcessWatcherService.cs",
    "chars": 5142,
    "preview": "using EarTrumpet.Interop;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Diagnostics;\r\nusing System.Li"
  },
  {
    "path": "EarTrumpet/DataModel/Storage/ISettingsBag.cs",
    "chars": 326,
    "preview": "using System;\r\n\r\nnamespace EarTrumpet.DataModel.Storage\r\n{\r\n    public interface ISettingsBag\r\n    {\r\n        string Na"
  },
  {
    "path": "EarTrumpet/DataModel/Storage/Internal/NamespacedSettingsBag.cs",
    "chars": 912,
    "preview": "using System;\r\n\r\nnamespace EarTrumpet.DataModel.Storage.Internal\r\n{\r\n    class NamespacedSettingsBag : ISettingsBag\r\n  "
  },
  {
    "path": "EarTrumpet/DataModel/Storage/Internal/RegistrySettingsBag.cs",
    "chars": 2116,
    "preview": "using Microsoft.Win32;\r\nusing System;\r\n\r\nnamespace EarTrumpet.DataModel.Storage.Internal\r\n{\r\n    class RegistrySettings"
  },
  {
    "path": "EarTrumpet/DataModel/Storage/Internal/WindowsStorageSettingsBag.cs",
    "chars": 2420,
    "preview": "using EarTrumpet.Diagnosis;\r\nusing System;\r\nusing Windows.Management.Core;\r\nusing Windows.Storage;\r\n\r\nnamespace EarTrum"
  },
  {
    "path": "EarTrumpet/DataModel/Storage/Serializer.cs",
    "chars": 860,
    "preview": "using System.IO;\r\nusing System.Xml;\r\nusing System.Xml.Serialization;\r\n\r\nnamespace EarTrumpet.DataModel.Storage\r\n{\r\n    "
  },
  {
    "path": "EarTrumpet/DataModel/Storage/StorageFactory.cs",
    "chars": 589,
    "preview": "namespace EarTrumpet.DataModel.Storage\r\n{\r\n    public class StorageFactory\r\n    {\r\n        private static ISettingsBag "
  },
  {
    "path": "EarTrumpet/DataModel/SystemSettings.cs",
    "chars": 2204,
    "preview": "using Microsoft.Win32;\r\nusing System.Globalization;\r\nusing EarTrumpet.Extensions;\r\nusing System;\r\n\r\nnamespace EarTrumpe"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/AudioDeviceKind.cs",
    "chars": 137,
    "preview": "namespace EarTrumpet.DataModel.WindowsAudio\r\n{\r\n    public enum AudioDeviceKind\r\n    {\r\n        Playback,\r\n        Reco"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/IAudioDeviceChannel.cs",
    "chars": 198,
    "preview": "using System.ComponentModel;\r\n\r\nnamespace EarTrumpet.DataModel.WindowsAudio\r\n{\r\n    public interface IAudioDeviceChanne"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/IAudioDeviceManagerWindowsAudio.cs",
    "chars": 561,
    "preview": "using EarTrumpet.DataModel.Audio;\r\nusing EarTrumpet.Interop.MMDeviceAPI;\r\n\r\nnamespace EarTrumpet.DataModel.WindowsAudio"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/IAudioDeviceSessionChannel.cs",
    "chars": 205,
    "preview": "using System.ComponentModel;\r\n\r\nnamespace EarTrumpet.DataModel.WindowsAudio\r\n{\r\n    public interface IAudioDeviceSessio"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/IAudioDeviceWindowsAudio.cs",
    "chars": 382,
    "preview": "using EarTrumpet.DataModel.Audio;\r\nusing System.Collections.Generic;\r\n\r\nnamespace EarTrumpet.DataModel.WindowsAudio\r\n{\r"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/Internal/AudioDevice.cs",
    "chars": 9006,
    "preview": "using EarTrumpet.DataModel.Audio;\r\nusing EarTrumpet.Extensions;\r\nusing EarTrumpet.Interop;\r\nusing EarTrumpet.Interop.MM"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceChannel.cs",
    "chars": 1280,
    "preview": "using System;\r\nusing System.ComponentModel;\r\nusing EarTrumpet.Interop.MMDeviceAPI;\r\n\r\nnamespace EarTrumpet.DataModel.Wi"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceChannelCollection.cs",
    "chars": 1491,
    "preview": "using EarTrumpet.Interop.MMDeviceAPI;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Runtime.InteropSe"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceManager.cs",
    "chars": 11756,
    "preview": "using EarTrumpet.DataModel.Audio;\r\nusing EarTrumpet.Diagnosis;\r\nusing EarTrumpet.Extensions;\r\nusing EarTrumpet.Interop;"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceSession.cs",
    "chars": 16947,
    "preview": "using EarTrumpet.DataModel.AppInformation;\r\nusing EarTrumpet.DataModel.Audio;\r\nusing EarTrumpet.Extensions;\r\nusing EarT"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceSessionChannel.cs",
    "chars": 1428,
    "preview": "using EarTrumpet.Interop.MMDeviceAPI;\r\nusing System;\r\nusing System.ComponentModel;\r\nusing System.Windows.Threading;\r\n\r\n"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceSessionChannelCollection.cs",
    "chars": 692,
    "preview": "using EarTrumpet.Interop.MMDeviceAPI;\r\nusing System.Collections.Generic;\r\nusing System.Windows.Threading;\r\n\r\nnamespace "
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceSessionChannelMultiplexer.cs",
    "chars": 990,
    "preview": "using System.ComponentModel;\r\n\r\nnamespace EarTrumpet.DataModel.WindowsAudio.Internal\r\n{\r\n    class AudioDeviceSessionCh"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceSessionCollection.cs",
    "chars": 8459,
    "preview": "using EarTrumpet.DataModel.Audio;\r\nusing EarTrumpet.Interop.MMDeviceAPI;\r\nusing System;\r\nusing System.Collections.Gener"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/Internal/AudioDeviceSessionGroup.cs",
    "chars": 6716,
    "preview": "using EarTrumpet.DataModel.Audio;\r\nusing EarTrumpet.Extensions;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusin"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/Internal/AudioPolicyConfigService.cs",
    "chars": 3099,
    "preview": "using EarTrumpet.Interop;\r\nusing EarTrumpet.Interop.Helpers;\r\nusing EarTrumpet.Interop.MMDeviceAPI;\r\nusing System;\r\nusi"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/Internal/Helpers.cs",
    "chars": 1505,
    "preview": "using EarTrumpet.Extensions;\r\nusing EarTrumpet.Interop;\r\nusing EarTrumpet.Interop.MMDeviceAPI;\r\nusing System;\r\nusing Sy"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/Internal/IAudioDeviceInternal.cs",
    "chars": 264,
    "preview": "namespace EarTrumpet.DataModel.WindowsAudio.Internal\r\n{\r\n    interface IAudioDeviceInternal\r\n    {\r\n        void Update"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/Internal/IAudioDeviceSessionInternal.cs",
    "chars": 368,
    "preview": "using EarTrumpet.DataModel.Audio;\r\nusing System;\r\n\r\nnamespace EarTrumpet.DataModel.WindowsAudio.Internal\r\n{\r\n    interf"
  },
  {
    "path": "EarTrumpet/DataModel/WindowsAudio/WindowsAudioFactory.cs",
    "chars": 1140,
    "preview": "using EarTrumpet.DataModel.Audio;\r\nusing EarTrumpet.DataModel.WindowsAudio.Internal;\r\n\r\nnamespace EarTrumpet.DataModel."
  },
  {
    "path": "EarTrumpet/DebugHelpers.cs",
    "chars": 5510,
    "preview": "using EarTrumpet.DataModel.AppInformation;\r\nusing EarTrumpet.DataModel.Audio;\r\nusing EarTrumpet.DataModel.WindowsAudio;"
  },
  {
    "path": "EarTrumpet/Diagnosis/CircularBufferTraceListener.cs",
    "chars": 1365,
    "preview": "using System;\r\nusing System.Collections.Concurrent;\r\nusing System.Diagnostics;\r\nusing System.Text;\r\nusing System.Thread"
  },
  {
    "path": "EarTrumpet/Diagnosis/ErrorReporter.cs",
    "chars": 2614,
    "preview": "using Bugsnag;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Diagnostics;\r\n\r\nnamespace EarTrumpet.Dia"
  },
  {
    "path": "EarTrumpet/Diagnosis/LocalDataExporter.cs",
    "chars": 4207,
    "preview": "using EarTrumpet.DataModel.Audio;\r\nusing EarTrumpet.DataModel.WindowsAudio;\r\nusing EarTrumpet.DataModel.WindowsAudio.In"
  },
  {
    "path": "EarTrumpet/Diagnosis/SnapshotData.cs",
    "chars": 4144,
    "preview": "using EarTrumpet.DataModel;\r\nusing EarTrumpet.Extensibility.Hosting;\r\nusing EarTrumpet.Interop;\r\nusing EarTrumpet.Inter"
  },
  {
    "path": "EarTrumpet/EarTrumpet.csproj",
    "chars": 32801,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"14.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.micro"
  },
  {
    "path": "EarTrumpet/Extensibility/EarTrumpetAddon.cs",
    "chars": 1404,
    "preview": "using EarTrumpet.DataModel.Storage;\r\nusing EarTrumpet.Extensibility.Shared;\r\nusing EarTrumpet.Extensions;\r\nusing Newton"
  },
  {
    "path": "EarTrumpet/Extensibility/EarTrumpetAddonManifest.cs",
    "chars": 271,
    "preview": "namespace EarTrumpet.Extensibility\r\n{\r\n    public class AddonManifest\r\n    {\r\n        public string Id { get; set; }\r\n "
  },
  {
    "path": "EarTrumpet/Extensibility/Hosting/AddonHost.cs",
    "chars": 737,
    "preview": "using System.Collections.Generic;\r\nusing System.ComponentModel.Composition;\r\n\r\nnamespace EarTrumpet.Extensibility.Hosti"
  },
  {
    "path": "EarTrumpet/Extensibility/Hosting/AddonManager.cs",
    "chars": 3082,
    "preview": "using EarTrumpet.Actions;\r\nusing EarTrumpet.Extensions;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System"
  },
  {
    "path": "EarTrumpet/Extensibility/Hosting/AddonResolver.cs",
    "chars": 4732,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.ComponentModel.Composition;\r\nusing System.ComponentModel"
  },
  {
    "path": "EarTrumpet/Extensibility/IEarTrumpetAddonAppContent.cs",
    "chars": 373,
    "preview": "using System;\r\nusing EarTrumpet.UI.ViewModels;\r\nusing System.Collections.Generic;\r\n\r\nnamespace EarTrumpet.Extensibility"
  },
  {
    "path": "EarTrumpet/Extensibility/IEarTrumpetAddonDeviceContent.cs",
    "chars": 354,
    "preview": "using System;\r\nusing EarTrumpet.UI.ViewModels;\r\nusing System.Collections.Generic;\r\n\r\nnamespace EarTrumpet.Extensibility"
  },
  {
    "path": "EarTrumpet/Extensibility/IEarTrumpetAddonEvents.cs",
    "chars": 276,
    "preview": "namespace EarTrumpet.Extensibility\r\n{\r\n    public enum AddonEventKind\r\n    {\r\n        InitializeAddon,\r\n        AddonsI"
  },
  {
    "path": "EarTrumpet/Extensibility/IEarTrumpetAddonNotificationAreaContextMenu.cs",
    "chars": 271,
    "preview": "using EarTrumpet.UI.ViewModels;\r\nusing System.Collections.Generic;\r\n\r\nnamespace EarTrumpet.Extensibility\r\n{\r\n    public"
  },
  {
    "path": "EarTrumpet/Extensibility/IEarTrumpetAddonSettingsPage.cs",
    "chars": 201,
    "preview": "using EarTrumpet.UI.ViewModels;\r\n\r\nnamespace EarTrumpet.Extensibility\r\n{\r\n    public interface IEarTrumpetAddonSettings"
  },
  {
    "path": "EarTrumpet/Extensibility/Shared/PlaybackDataModelHost.cs",
    "chars": 3766,
    "preview": "using EarTrumpet.DataModel.Audio;\r\nusing EarTrumpet.DataModel.WindowsAudio;\r\nusing System;\r\n\r\nnamespace EarTrumpet.Exte"
  },
  {
    "path": "EarTrumpet/Extensibility/Shared/ResourceLoader.cs",
    "chars": 1153,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Windows;\r\n\r\nnamespace EarTrumpet.Extensibility.Shared\r\n{"
  },
  {
    "path": "EarTrumpet/Extensibility/Shared/ServiceBus.cs",
    "chars": 839,
    "preview": "using System.Collections.Generic;\r\n\r\nnamespace EarTrumpet.Extensibility.Shared\r\n{\r\n    public static class ServiceBus\r\n"
  },
  {
    "path": "EarTrumpet/Extensions/CollectionExtensions.cs",
    "chars": 1059,
    "preview": "using System.Collections.Generic;\r\nusing System.Collections.ObjectModel;\r\nusing System.Linq;\r\n\r\nnamespace EarTrumpet.Ex"
  },
  {
    "path": "EarTrumpet/Extensions/ColorExtensions.cs",
    "chars": 913,
    "preview": "using System.Windows.Media;\r\n\r\nnamespace EarTrumpet.Extensions\r\n{\r\n    public static class ColorExtensions\r\n    {\r\n    "
  },
  {
    "path": "EarTrumpet/Extensions/DependencyObjectExtensions.cs",
    "chars": 2358,
    "preview": "using System.Windows;\r\nusing System.Windows.Media;\r\n\r\nnamespace EarTrumpet.Extensions\r\n{\r\n    public static class Depen"
  },
  {
    "path": "EarTrumpet/Extensions/EarTrumpetAddonExtensions.cs",
    "chars": 309,
    "preview": "using EarTrumpet.Actions;\r\nusing EarTrumpet.Extensibility;\r\n\r\nnamespace EarTrumpet.Extensions\r\n{\r\n    public static cla"
  },
  {
    "path": "EarTrumpet/Extensions/EventBinding/EventBindingExtension.cs",
    "chars": 2118,
    "preview": "using System;\r\nusing System.Linq;\r\nusing System.Reflection;\r\nusing System.Windows;\r\nusing System.Windows.Markup;\r\n\r\nnam"
  },
  {
    "path": "EarTrumpet/Extensions/EventBinding/HandledEventBindingExtension.cs",
    "chars": 321,
    "preview": "namespace EarTrumpet.Extensions.EventBinding\r\n{\r\n    // {Event:HandledBinding}\r\n    public class HandledBindingExtensio"
  },
  {
    "path": "EarTrumpet/Extensions/ExceptionExtensions.cs",
    "chars": 653,
    "preview": "using EarTrumpet.Interop;\r\nusing System;\r\nusing System.Runtime.InteropServices;\r\n\r\nnamespace EarTrumpet.Extensions\r\n{\r\n"
  },
  {
    "path": "EarTrumpet/Extensions/FloatExtensions.cs",
    "chars": 850,
    "preview": "using System;\r\n\r\nnamespace EarTrumpet.Extensions\r\n{\r\n    public static class FloatExtensions\r\n    {\r\n        private co"
  },
  {
    "path": "EarTrumpet/Extensions/FrameworkElementExtensions.cs",
    "chars": 675,
    "preview": "using System;\r\nusing System.Windows;\r\nusing System.Windows.Threading;\r\n\r\nnamespace EarTrumpet.Extensions\r\n{\r\n    public"
  },
  {
    "path": "EarTrumpet/Extensions/IEnumerableExtensions.cs",
    "chars": 874,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Diagnostics;\r\n\r\nnamespace EarTrumpet.Extensions\r\n{\r\n    "
  },
  {
    "path": "EarTrumpet/Extensions/IPropertyStoreExtensions.cs",
    "chars": 918,
    "preview": "using EarTrumpet.Interop;\r\nusing System;\r\nusing System.Runtime.InteropServices;\r\n\r\nnamespace EarTrumpet.Extensions\r\n{\r\n"
  },
  {
    "path": "EarTrumpet/Extensions/IconExtensions.cs",
    "chars": 664,
    "preview": "using System.Drawing;\r\nusing System.Reflection;\r\n\r\nnamespace EarTrumpet.Extensions\r\n{\r\n    public static class IconExte"
  },
  {
    "path": "EarTrumpet/Extensions/ListExtensions.cs",
    "chars": 600,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\n\r\nnamespace EarTrumpet.Extensions\r\n{\r\n    public static class ListExt"
  },
  {
    "path": "EarTrumpet/Extensions/OperatingSystemExtensions.cs",
    "chars": 815,
    "preview": "using System;\r\n\r\nnamespace EarTrumpet.Extensions\r\n{\r\n    public enum OSVersions : int\r\n    {\r\n        RS3 = 16299,\r\n   "
  },
  {
    "path": "EarTrumpet/Extensions/RegistryKeyExtensions.cs",
    "chars": 563,
    "preview": "using Microsoft.Win32;\r\n\r\nnamespace EarTrumpet.Extensions\r\n{\r\n    public static class RegistryKeyExtensions\r\n    {\r\n   "
  },
  {
    "path": "EarTrumpet/Extensions/VisualExtensions.cs",
    "chars": 588,
    "preview": "using System.Windows;\r\nusing System.Windows.Media;\r\n\r\nnamespace EarTrumpet.Extensions\r\n{\r\n    public static class Visua"
  },
  {
    "path": "EarTrumpet/Extensions/WindowExtensions.cs",
    "chars": 2958,
    "preview": "using EarTrumpet.Interop;\r\nusing System;\r\nusing System.Diagnostics;\r\nusing System.Runtime.InteropServices;\r\nusing Syste"
  },
  {
    "path": "EarTrumpet/Features.cs",
    "chars": 70,
    "preview": "namespace EarTrumpet\r\n{\r\n    public class Features\r\n    {\r\n    }\r\n}\r\n"
  },
  {
    "path": "EarTrumpet/Interop/AppBarData.cs",
    "chars": 359,
    "preview": "using System;\r\nusing System.Runtime.InteropServices;\r\n\r\nnamespace EarTrumpet.Interop\r\n{\r\n    [StructLayout(LayoutKind.S"
  },
  {
    "path": "EarTrumpet/Interop/AppBarEdge.cs",
    "chars": 165,
    "preview": "namespace EarTrumpet.Interop\r\n{\r\n    internal enum AppBarEdge : uint\r\n    {\r\n        Left = 0,\r\n        Top = 1,\r\n     "
  },
  {
    "path": "EarTrumpet/Interop/AppBarMessage.cs",
    "chars": 191,
    "preview": "namespace EarTrumpet.Interop\r\n{\r\n    internal enum AppBarMessage : uint\r\n    {\r\n        // ...\r\n        GetState = 0x00"
  },
  {
    "path": "EarTrumpet/Interop/ApplicationResolver.cs",
    "chars": 585,
    "preview": "using System;\r\nusing System.Runtime.InteropServices;\r\n\r\nnamespace EarTrumpet.Interop\r\n{\r\n    [ComImport]\r\n    [Guid(\"66"
  },
  {
    "path": "EarTrumpet/Interop/CLSCTX.cs",
    "chars": 111,
    "preview": "namespace EarTrumpet.Interop\r\n{\r\n    enum CLSCTX : int\r\n    {\r\n        CLSCTX_INPROC_SERVER = 0x1,\r\n    }\r\n}\r\n"
  },
  {
    "path": "EarTrumpet/Interop/Combase.cs",
    "chars": 680,
    "preview": "using System;\r\nusing System.Runtime.InteropServices;\r\n\r\nnamespace EarTrumpet.Interop\r\n{\r\n    static class Combase\r\n    "
  },
  {
    "path": "EarTrumpet/Interop/DwmApi.cs",
    "chars": 673,
    "preview": "using System;\r\nusing System.Runtime.InteropServices;\r\n\r\nnamespace EarTrumpet.Interop\r\n{\r\n    class DwmApi\r\n    {\r\n     "
  },
  {
    "path": "EarTrumpet/Interop/FolderIds.cs",
    "chars": 191,
    "preview": "using System;\r\n\r\nnamespace EarTrumpet.Interop\r\n{\r\n    static class FolderIds\r\n    {\r\n        public static Guid AppsFol"
  },
  {
    "path": "EarTrumpet/Interop/GPS.cs",
    "chars": 2023,
    "preview": "namespace EarTrumpet.Interop\r\n{\r\n    enum GPS\r\n    {\r\n        // If no flags are specified (GPS_DEFAULT), a read-only p"
  },
  {
    "path": "EarTrumpet/Interop/Gdi32.cs",
    "chars": 250,
    "preview": "using System;\r\nusing System.Runtime.InteropServices;\r\n\r\nnamespace EarTrumpet.Interop\r\n{\r\n    class Gdi32\r\n    {\r\n      "
  },
  {
    "path": "EarTrumpet/Interop/HRESULT.cs",
    "chars": 309,
    "preview": "namespace EarTrumpet.Interop\r\n{\r\n    public enum HRESULT : uint\r\n    {\r\n        S_OK = 0x0,\r\n        S_FALSE = 0x1,\r\n  "
  },
  {
    "path": "EarTrumpet/Interop/Helpers/AccentPolicyLibrary.cs",
    "chars": 2421,
    "preview": "using EarTrumpet.Extensions;\r\nusing System;\r\nusing System.Diagnostics;\r\nusing System.Runtime.InteropServices;\r\nusing Sy"
  },
  {
    "path": "EarTrumpet/Interop/Helpers/AudioPolicyConfigFactory.cs",
    "chars": 559,
    "preview": "using EarTrumpet.Extensions;\r\nusing EarTrumpet.Interop.MMDeviceAPI;\r\nusing System;\r\n\r\nnamespace EarTrumpet.Interop.Help"
  },
  {
    "path": "EarTrumpet/Interop/Helpers/AudioPolicyConfigFactoryImplFor21H2.cs",
    "chars": 1271,
    "preview": "using EarTrumpet.Interop.MMDeviceAPI;\r\nusing System;\r\n\r\nnamespace EarTrumpet.Interop.Helpers\r\n{\r\n    class AudioPolicyC"
  },
  {
    "path": "EarTrumpet/Interop/Helpers/AudioPolicyConfigFactoryImplForDownlevel.cs",
    "chars": 1296,
    "preview": "using EarTrumpet.Interop.MMDeviceAPI;\r\nusing System;\r\n\r\nnamespace EarTrumpet.Interop.Helpers\r\n{\r\n    class AudioPolicyC"
  },
  {
    "path": "EarTrumpet/Interop/Helpers/HotkeyData.cs",
    "chars": 3602,
    "preview": "using System;\r\nusing System.Windows.Forms;\r\n\r\nnamespace EarTrumpet.Interop.Helpers\r\n{\r\n    public class HotkeyData\r\n   "
  },
  {
    "path": "EarTrumpet/Interop/Helpers/HotkeyManager.cs",
    "chars": 2819,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Diagnostics;\r\nusing System.Windows.Forms;\r\n\r\nnamespace E"
  },
  {
    "path": "EarTrumpet/Interop/Helpers/IconHelper.cs",
    "chars": 3380,
    "preview": "using EarTrumpet.Extensions;\r\nusing System;\r\nusing System.Diagnostics;\r\nusing System.Drawing;\r\nusing System.Text;\r\n\r\nna"
  },
  {
    "path": "EarTrumpet/Interop/Helpers/ImmersiveSystemColors.cs",
    "chars": 1562,
    "preview": "using EarTrumpet.Extensions;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Runtime.InteropServices;\r\n"
  },
  {
    "path": "EarTrumpet/Interop/Helpers/InputHelper.cs",
    "chars": 4390,
    "preview": "using System;\r\nusing System.Diagnostics;\r\nusing System.Runtime.InteropServices;\r\nusing System.Windows.Forms;\r\n\r\nnamespa"
  },
  {
    "path": "EarTrumpet/Interop/Helpers/Kernel32Helper.cs",
    "chars": 1360,
    "preview": "using System;\r\nusing System.Runtime.InteropServices;\r\n\r\nnamespace EarTrumpet.Interop.Helpers\r\n{\r\n    class Kernel32Help"
  },
  {
    "path": "EarTrumpet/Interop/Helpers/LegacyControlPanelHelper.cs",
    "chars": 1257,
    "preview": "using System;\r\nusing System.Diagnostics;\r\nusing System.IO;\r\n\r\nnamespace EarTrumpet.Interop.Helpers\r\n{\r\n    class Legacy"
  },
  {
    "path": "EarTrumpet/Interop/Helpers/MouseHook.cs",
    "chars": 2222,
    "preview": "using System;\r\nusing System.Windows.Forms;\r\nusing System.Runtime.InteropServices;\r\n\r\nnamespace EarTrumpet.Interop.Helper"
  },
  {
    "path": "EarTrumpet/Interop/Helpers/PackageHelper.cs",
    "chars": 1949,
    "preview": "using System;\r\nusing Windows.ApplicationModel;\r\n\r\nnamespace EarTrumpet.Interop.Helpers\r\n{\r\n    class PackageHelper\r\n   "
  },
  {
    "path": "EarTrumpet/Interop/Helpers/ProcessHelper.cs",
    "chars": 568,
    "preview": "using System;\r\nusing System.Diagnostics;\r\n\r\nnamespace EarTrumpet.Interop.Helpers\r\n{\r\n    public class ProcessHelper\r\n  "
  },
  {
    "path": "EarTrumpet/Interop/Helpers/SettingsPageHelper.cs",
    "chars": 530,
    "preview": "using System;\r\nusing System.Diagnostics;\r\n\r\nnamespace EarTrumpet.Interop.Helpers\r\n{\r\n    class SettingsPageHelper\r\n    "
  },
  {
    "path": "EarTrumpet/Interop/Helpers/SingleInstanceAppMutex.cs",
    "chars": 929,
    "preview": "using System.Diagnostics;\r\nusing System.Reflection;\r\nusing System.Threading;\r\n\r\nnamespace EarTrumpet.Interop.Helpers\r\n{"
  },
  {
    "path": "EarTrumpet/Interop/Helpers/Win32Window.cs",
    "chars": 584,
    "preview": "using System;\r\nusing System.Windows.Forms;\r\n\r\nnamespace EarTrumpet.Interop.Helpers\r\n{\r\n    public class Win32Window : N"
  },
  {
    "path": "EarTrumpet/Interop/Helpers/WindowSizeHelper.cs",
    "chars": 735,
    "preview": "using System;\r\nusing System.Windows;\r\nusing System.Windows.Interop;\r\n\r\nnamespace EarTrumpet.Interop.Helpers\r\n{\r\n    cla"
  },
  {
    "path": "EarTrumpet/Interop/Helpers/WindowsTaskbar.cs",
    "chars": 3789,
    "preview": "using System;\r\nusing System.Diagnostics;\r\nusing System.Runtime.InteropServices;\r\nusing System.Windows.Forms;\r\n\r\nnamespa"
  }
]

// ... and 224 more files (download for full content)

About this extraction

This page contains the full source code of the File-New-Project/EarTrumpet GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 424 files (2.0 MB), approximately 552.2k tokens, and a symbol index with 1439 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!