From 5c1cd1410e5dcae34d9c47f7a9f0d48570c6c3e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20St=C3=B8dle?= Date: Mon, 7 Sep 2015 09:58:20 +0200 Subject: [PATCH 01/34] =?UTF-8?q?Add=20translation=20for=20Norwegian=20Bok?= =?UTF-8?q?m=C3=A5l?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- EarTrumpet/EarTrumpet.csproj | 9 ++ .../Properties/Resources.nb-no.Designer.cs | 0 EarTrumpet/Properties/Resources.nb-no.resx | 135 ++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 EarTrumpet/Properties/Resources.nb-no.Designer.cs create mode 100644 EarTrumpet/Properties/Resources.nb-no.resx diff --git a/EarTrumpet/EarTrumpet.csproj b/EarTrumpet/EarTrumpet.csproj index ff97fde56..f81276f1d 100644 --- a/EarTrumpet/EarTrumpet.csproj +++ b/EarTrumpet/EarTrumpet.csproj @@ -62,6 +62,11 @@ + + Resources.nb-no.resx + True + True + True True @@ -111,6 +116,10 @@ + + PublicResXFileCodeGenerator + Resources.nb-no.Designer.cs + PublicResXFileCodeGenerator Resources.Designer.cs diff --git a/EarTrumpet/Properties/Resources.nb-no.Designer.cs b/EarTrumpet/Properties/Resources.nb-no.Designer.cs new file mode 100644 index 000000000..e69de29bb diff --git a/EarTrumpet/Properties/Resources.nb-no.resx b/EarTrumpet/Properties/Resources.nb-no.resx new file mode 100644 index 000000000..c70792816 --- /dev/null +++ b/EarTrumpet/Properties/Resources.nb-no.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Om + + + Avslutt + + + Vis skrivebordsapplikasjoner + + + Det ser ikke ut som du har noen applikasjoner åpne. + + + Systemlyder + + \ No newline at end of file From 592f1168c8b6f8327852d9bc1fcf4151af57a50d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20St=C3=B8dle?= Date: Mon, 7 Sep 2015 09:59:36 +0200 Subject: [PATCH 02/34] Add translation for Norwegian Nynorsk --- EarTrumpet/EarTrumpet.csproj | 9 ++ .../Properties/Resources.nn-no.Designer.cs | 0 EarTrumpet/Properties/Resources.nn-no.resx | 135 ++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 EarTrumpet/Properties/Resources.nn-no.Designer.cs create mode 100644 EarTrumpet/Properties/Resources.nn-no.resx diff --git a/EarTrumpet/EarTrumpet.csproj b/EarTrumpet/EarTrumpet.csproj index f81276f1d..c94f4f1c3 100644 --- a/EarTrumpet/EarTrumpet.csproj +++ b/EarTrumpet/EarTrumpet.csproj @@ -62,6 +62,11 @@ + + Resources.nn-no.resx + True + True + Resources.nb-no.resx True @@ -116,6 +121,10 @@ + + PublicResXFileCodeGenerator + Resources.nn-no.Designer.cs + PublicResXFileCodeGenerator Resources.nb-no.Designer.cs diff --git a/EarTrumpet/Properties/Resources.nn-no.Designer.cs b/EarTrumpet/Properties/Resources.nn-no.Designer.cs new file mode 100644 index 000000000..e69de29bb diff --git a/EarTrumpet/Properties/Resources.nn-no.resx b/EarTrumpet/Properties/Resources.nn-no.resx new file mode 100644 index 000000000..59a133334 --- /dev/null +++ b/EarTrumpet/Properties/Resources.nn-no.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Om + + + Avslutt + + + Vis skrivebordsapplikasjonar + + + Det ser ikkje ut som du har nokon applikasjonar opne. + + + Systemlydar + + \ No newline at end of file From ef7fea8a9406bcce6da7e770d8745fcb700df888 Mon Sep 17 00:00:00 2001 From: actionthomas Date: Mon, 7 Sep 2015 20:48:52 +0200 Subject: [PATCH 03/34] French translation Added translation for tray icon tooltip --- EarTrumpet/EarTrumpet.csproj | 241 ++++++++--------- EarTrumpet/Properties/Resources.Designer.cs | 225 ++++++++-------- EarTrumpet/Properties/Resources.fr.resx | 138 ++++++++++ EarTrumpet/Properties/Resources.resx | 271 ++++++++++---------- EarTrumpet/TrayIcon.cs | 2 +- 5 files changed, 514 insertions(+), 363 deletions(-) create mode 100644 EarTrumpet/Properties/Resources.fr.resx diff --git a/EarTrumpet/EarTrumpet.csproj b/EarTrumpet/EarTrumpet.csproj index ff97fde56..e73dbe1aa 100644 --- a/EarTrumpet/EarTrumpet.csproj +++ b/EarTrumpet/EarTrumpet.csproj @@ -1,127 +1,128 @@ - - - - - Debug - AnyCPU - {BA3C7B42-84B0-468C-8640-217E2A24CF81} - WinExe - Properties - EarTrumpet - EarTrumpet - v4.5 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - - - Application.ico - - - true - ..\Build\Debug\ - DEBUG;TRACE - full - x86 - prompt - MinimumRecommendedRules.ruleset - true - 4 - - - true - - - ..\Build\Release\ - TRACE - true - pdbonly - x86 - prompt - MinimumRecommendedRules.ruleset - true - - - - - - - - 4.0 - - - - - - - - MSBuild:Compile - Designer - - - - - - - True - True - Resources.resx - - - - - - - - - - - - - - - - - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - MainWindow.xaml - Code - - - - - Code - - - - - - - - - - - - - - PublicResXFileCodeGenerator - Resources.Designer.cs - - - + + + + + Debug + AnyCPU + {BA3C7B42-84B0-468C-8640-217E2A24CF81} + WinExe + Properties + EarTrumpet + EarTrumpet + v4.5 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + Application.ico + + + true + ..\Build\Debug\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + true + 4 + + + true + + + ..\Build\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + true + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + + + + True + True + Resources.resx + + + + + + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + Code + + + + + + + + + + + + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + + + + --> \ No newline at end of file diff --git a/EarTrumpet/Properties/Resources.Designer.cs b/EarTrumpet/Properties/Resources.Designer.cs index abcdf2821..fec63046f 100644 --- a/EarTrumpet/Properties/Resources.Designer.cs +++ b/EarTrumpet/Properties/Resources.Designer.cs @@ -1,108 +1,117 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace EarTrumpet.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("EarTrumpet.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to About. - /// - public static string ContextMenuAboutTitle { - get { - return ResourceManager.GetString("ContextMenuAboutTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Exit. - /// - public static string ContextMenuExitTitle { - get { - return ResourceManager.GetString("ContextMenuExitTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Show Desktop Apps. - /// - public static string ContextMenuShowDesktopAppsTitle { - get { - return ResourceManager.GetString("ContextMenuShowDesktopAppsTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to It doesn't look like you have any apps open.. - /// - public static string NoAppsPanelContent { - get { - return ResourceManager.GetString("NoAppsPanelContent", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to System Sounds. - /// - public static string SystemSoundsDisplayName { - get { - return ResourceManager.GetString("SystemSoundsDisplayName", resourceCulture); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace EarTrumpet.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("EarTrumpet.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to About. + /// + public static string ContextMenuAboutTitle { + get { + return ResourceManager.GetString("ContextMenuAboutTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exit. + /// + public static string ContextMenuExitTitle { + get { + return ResourceManager.GetString("ContextMenuExitTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Show Desktop Apps. + /// + public static string ContextMenuShowDesktopAppsTitle { + get { + return ResourceManager.GetString("ContextMenuShowDesktopAppsTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It doesn't look like you have any apps open.. + /// + public static string NoAppsPanelContent { + get { + return ResourceManager.GetString("NoAppsPanelContent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System Sounds. + /// + public static string SystemSoundsDisplayName { + get { + return ResourceManager.GetString("SystemSoundsDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume Control for Windows. + /// + public static string TrayIconTooltipText { + get { + return ResourceManager.GetString("TrayIconTooltipText", resourceCulture); + } + } + } +} diff --git a/EarTrumpet/Properties/Resources.fr.resx b/EarTrumpet/Properties/Resources.fr.resx new file mode 100644 index 000000000..34cbbeb28 --- /dev/null +++ b/EarTrumpet/Properties/Resources.fr.resx @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + A propos + + + Quitter + + + Afficher les applications classiques du bureau + + + Il semble que vous n'ayez aucune application ouverte. + + + Sons système + + + Contrôle du volume pour Windows + + \ No newline at end of file diff --git a/EarTrumpet/Properties/Resources.resx b/EarTrumpet/Properties/Resources.resx index b8538f337..b0bf94045 100644 --- a/EarTrumpet/Properties/Resources.resx +++ b/EarTrumpet/Properties/Resources.resx @@ -1,135 +1,138 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - About - - - Exit - - - Show Desktop Apps - - - It doesn't look like you have any apps open. - - - System Sounds - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + About + + + Exit + + + Show Desktop Apps + + + It doesn't look like you have any apps open. + + + System Sounds + + + Volume Control for Windows + \ No newline at end of file diff --git a/EarTrumpet/TrayIcon.cs b/EarTrumpet/TrayIcon.cs index c45212ea5..a096c9035 100644 --- a/EarTrumpet/TrayIcon.cs +++ b/EarTrumpet/TrayIcon.cs @@ -33,7 +33,7 @@ public TrayIcon() _trayIcon.MouseClick += TrayIcon_MouseClick; _trayIcon.Icon = new System.Drawing.Icon(Application.GetResourceStream(new Uri("pack://application:,,,/EarTrumpet;component/Tray.ico")).Stream); - _trayIcon.Text = "Ear Trumpet - Volume Control for Windows"; + _trayIcon.Text = string.Concat("Ear Trumpet - ", EarTrumpet.Properties.Resources.TrayIconTooltipText); _trayIcon.Visible = true; } From badc7e4eebcf09ebdfe1c4a3b816093f9bae1bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20St=C3=B8dle?= Date: Mon, 7 Sep 2015 23:17:36 +0200 Subject: [PATCH 04/34] Add tray tooltip translation --- EarTrumpet/Properties/Resources.nb-no.resx | 3 +++ EarTrumpet/Properties/Resources.nn-no.resx | 3 +++ 2 files changed, 6 insertions(+) diff --git a/EarTrumpet/Properties/Resources.nb-no.resx b/EarTrumpet/Properties/Resources.nb-no.resx index c70792816..856e71f91 100644 --- a/EarTrumpet/Properties/Resources.nb-no.resx +++ b/EarTrumpet/Properties/Resources.nb-no.resx @@ -132,4 +132,7 @@ Systemlyder + + Volumkontroll for Windows + \ No newline at end of file diff --git a/EarTrumpet/Properties/Resources.nn-no.resx b/EarTrumpet/Properties/Resources.nn-no.resx index 59a133334..de303b9d5 100644 --- a/EarTrumpet/Properties/Resources.nn-no.resx +++ b/EarTrumpet/Properties/Resources.nn-no.resx @@ -132,4 +132,7 @@ Systemlydar + + Volumkontroll for Windows + \ No newline at end of file From f9517d39e6d7138499b0b373f29679597b8dbb5d Mon Sep 17 00:00:00 2001 From: dAr2q Date: Fri, 18 Sep 2015 05:10:54 +0200 Subject: [PATCH 05/34] German Translation --- EarTrumpet/EarTrumpet.csproj | 9 ++ .../Properties/Resources.de.Designer.cs | 0 EarTrumpet/Properties/Resources.de.resx | 138 ++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 EarTrumpet/Properties/Resources.de.Designer.cs create mode 100644 EarTrumpet/Properties/Resources.de.resx diff --git a/EarTrumpet/EarTrumpet.csproj b/EarTrumpet/EarTrumpet.csproj index ccfbe79d2..ca480bb26 100644 --- a/EarTrumpet/EarTrumpet.csproj +++ b/EarTrumpet/EarTrumpet.csproj @@ -62,6 +62,11 @@ + + Resources.de.resx + True + True + Resources.nn-no.resx True @@ -121,6 +126,10 @@ + + PublicResXFileCodeGenerator + Resources.de.Designer.cs + PublicResXFileCodeGenerator Resources.nn-no.Designer.cs diff --git a/EarTrumpet/Properties/Resources.de.Designer.cs b/EarTrumpet/Properties/Resources.de.Designer.cs new file mode 100644 index 000000000..e69de29bb diff --git a/EarTrumpet/Properties/Resources.de.resx b/EarTrumpet/Properties/Resources.de.resx new file mode 100644 index 000000000..881ee49df --- /dev/null +++ b/EarTrumpet/Properties/Resources.de.resx @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Über + + + Beenden + + + Desktop Apps anzeigen + + + Es sieht so aus als währen keine Apps offen + + + Sytemklänge + + + Lautstärkesteuerung für Windows + + \ No newline at end of file From 69ee8248b0111099a9657dfb5448a5c648082542 Mon Sep 17 00:00:00 2001 From: dAr2q Date: Fri, 18 Sep 2015 06:14:06 +0200 Subject: [PATCH 06/34] Fixed a Typo --- EarTrumpet/Properties/Resources.de.resx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EarTrumpet/Properties/Resources.de.resx b/EarTrumpet/Properties/Resources.de.resx index 881ee49df..9f1c5eeb5 100644 --- a/EarTrumpet/Properties/Resources.de.resx +++ b/EarTrumpet/Properties/Resources.de.resx @@ -127,12 +127,12 @@ Desktop Apps anzeigen - Es sieht so aus als währen keine Apps offen + Es sieht so aus als sind keine Apps geöffnet - Sytemklänge + Systemklänge Lautstärkesteuerung für Windows - \ No newline at end of file + From 4f533230aa6a0f053fd1e17fee33b14faa55f4db Mon Sep 17 00:00:00 2001 From: Rafael Rivera Date: Fri, 8 Apr 2016 23:53:52 -0700 Subject: [PATCH 07/34] Upgraded project, desktop apps always show --- EarTrumpet.Interop/EarTrumpet.Interop.vcxproj | 228 +++++++++--------- EarTrumpet.sln | 62 ++--- EarTrumpet/Services/UserPreferencesService.cs | 21 +- EarTrumpet/TrayIcon.cs | 18 +- EarTrumpet/ViewModels/AudioMixerViewModel.cs | 7 +- 5 files changed, 151 insertions(+), 185 deletions(-) diff --git a/EarTrumpet.Interop/EarTrumpet.Interop.vcxproj b/EarTrumpet.Interop/EarTrumpet.Interop.vcxproj index 5f3d2044b..00563abb3 100644 --- a/EarTrumpet.Interop/EarTrumpet.Interop.vcxproj +++ b/EarTrumpet.Interop/EarTrumpet.Interop.vcxproj @@ -1,115 +1,115 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {73FA0BF9-96FE-4C5B-89B2-00B861F3F778} - Win32Proj - EarTrumpetInterop - EarTrumpet.Interop - - - - DynamicLibrary - true - v120 - Unicode - - - DynamicLibrary - false - v120 - true - Unicode - - - - - - - - - - - - - true - $(SolutionDir)Build\$(Configuration)\ - $(ProjectDir)int\$(Configuration)\ - - - false - $(SolutionDir)Build\$(Configuration)\ - $(ProjectDir)int\$(Configuration)\ - false - - - - Level4 - Disabled - WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) - - true - ProgramDatabase - StdCall - - - Windows - true - - - pathcch.lib;kernel32.lib;ntdll.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - - - Level4 - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - - false - true - StdCall - - - Windows - true - true - true - - - pathcch.lib;kernel32.lib;ntdll.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - true - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + + {73FA0BF9-96FE-4C5B-89B2-00B861F3F778} + Win32Proj + EarTrumpetInterop + EarTrumpet.Interop + + + + DynamicLibrary + true + v140 + Unicode + + + DynamicLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + true + $(SolutionDir)Build\$(Configuration)\ + $(ProjectDir)int\$(Configuration)\ + + + false + $(SolutionDir)Build\$(Configuration)\ + $(ProjectDir)int\$(Configuration)\ + false + + + + Level4 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + true + ProgramDatabase + StdCall + + + Windows + true + + + pathcch.lib;kernel32.lib;ntdll.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + Level4 + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + false + true + StdCall + + + Windows + true + true + true + + + pathcch.lib;kernel32.lib;ntdll.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + true + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EarTrumpet.sln b/EarTrumpet.sln index 0cb072013..8fcdb9aa7 100644 --- a/EarTrumpet.sln +++ b/EarTrumpet.sln @@ -1,31 +1,31 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EarTrumpet", "EarTrumpet\EarTrumpet.csproj", "{BA3C7B42-84B0-468C-8640-217E2A24CF81}" - ProjectSection(ProjectDependencies) = postProject - {73FA0BF9-96FE-4C5B-89B2-00B861F3F778} = {73FA0BF9-96FE-4C5B-89B2-00B861F3F778} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EarTrumpet.Interop", "EarTrumpet.Interop\EarTrumpet.Interop.vcxproj", "{73FA0BF9-96FE-4C5B-89B2-00B861F3F778}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {BA3C7B42-84B0-468C-8640-217E2A24CF81}.Debug|x86.ActiveCfg = Debug|x86 - {BA3C7B42-84B0-468C-8640-217E2A24CF81}.Debug|x86.Build.0 = Debug|x86 - {BA3C7B42-84B0-468C-8640-217E2A24CF81}.Release|x86.ActiveCfg = Release|x86 - {BA3C7B42-84B0-468C-8640-217E2A24CF81}.Release|x86.Build.0 = Release|x86 - {73FA0BF9-96FE-4C5B-89B2-00B861F3F778}.Debug|x86.ActiveCfg = Debug|Win32 - {73FA0BF9-96FE-4C5B-89B2-00B861F3F778}.Debug|x86.Build.0 = Debug|Win32 - {73FA0BF9-96FE-4C5B-89B2-00B861F3F778}.Release|x86.ActiveCfg = Release|Win32 - {73FA0BF9-96FE-4C5B-89B2-00B861F3F778}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EarTrumpet", "EarTrumpet\EarTrumpet.csproj", "{BA3C7B42-84B0-468C-8640-217E2A24CF81}" + ProjectSection(ProjectDependencies) = postProject + {73FA0BF9-96FE-4C5B-89B2-00B861F3F778} = {73FA0BF9-96FE-4C5B-89B2-00B861F3F778} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EarTrumpet.Interop", "EarTrumpet.Interop\EarTrumpet.Interop.vcxproj", "{73FA0BF9-96FE-4C5B-89B2-00B861F3F778}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BA3C7B42-84B0-468C-8640-217E2A24CF81}.Debug|x86.ActiveCfg = Debug|x86 + {BA3C7B42-84B0-468C-8640-217E2A24CF81}.Debug|x86.Build.0 = Debug|x86 + {BA3C7B42-84B0-468C-8640-217E2A24CF81}.Release|x86.ActiveCfg = Release|x86 + {BA3C7B42-84B0-468C-8640-217E2A24CF81}.Release|x86.Build.0 = Release|x86 + {73FA0BF9-96FE-4C5B-89B2-00B861F3F778}.Debug|x86.ActiveCfg = Debug|Win32 + {73FA0BF9-96FE-4C5B-89B2-00B861F3F778}.Debug|x86.Build.0 = Debug|Win32 + {73FA0BF9-96FE-4C5B-89B2-00B861F3F778}.Release|x86.ActiveCfg = Release|Win32 + {73FA0BF9-96FE-4C5B-89B2-00B861F3F778}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/EarTrumpet/Services/UserPreferencesService.cs b/EarTrumpet/Services/UserPreferencesService.cs index 0c1baed90..cdf6a9e89 100644 --- a/EarTrumpet/Services/UserPreferencesService.cs +++ b/EarTrumpet/Services/UserPreferencesService.cs @@ -6,25 +6,6 @@ namespace EarTrumpet.Services { public static class UserPreferencesService { - public static bool ShowDesktopApps - { - get - { - try - { - return 1 == (int) Registry.CurrentUser.CreateSubKey(@"Software\EarTrumpet").GetValue("ShowDesktopApps"); - } - catch (Exception e) - { - Debug.WriteLine("Failed to get ShowDektopApps: " + e.Message); - return false; - } - } - - set - { - Registry.CurrentUser.CreateSubKey(@"Software\EarTrumpet").SetValue("ShowDesktopApps", value ? 1 : 0); - } - } + // It's quiet in here. } } \ No newline at end of file diff --git a/EarTrumpet/TrayIcon.cs b/EarTrumpet/TrayIcon.cs index a096c9035..e57a80863 100644 --- a/EarTrumpet/TrayIcon.cs +++ b/EarTrumpet/TrayIcon.cs @@ -1,5 +1,4 @@ -using EarTrumpet.Services; -using System; +using System; using System.Diagnostics; using System.Reflection; using System.Windows; @@ -21,15 +20,11 @@ public TrayIcon() var version = Assembly.GetEntryAssembly().GetName().Version; _trayIcon.ContextMenu.MenuItems.Add(String.Format("{0} Ear Trumpet {1} ...", aboutString, version)); _trayIcon.ContextMenu.MenuItems[0].Click += About_Click; - - _trayIcon.ContextMenu.MenuItems.Add(EarTrumpet.Properties.Resources.ContextMenuShowDesktopAppsTitle); - _trayIcon.ContextMenu.MenuItems[1].Checked = UserPreferencesService.ShowDesktopApps; - _trayIcon.ContextMenu.MenuItems[1].Click += ShowDesktopApps_Click; - + _trayIcon.ContextMenu.MenuItems.Add("-"); _trayIcon.ContextMenu.MenuItems.Add(EarTrumpet.Properties.Resources.ContextMenuExitTitle); - _trayIcon.ContextMenu.MenuItems[3].Click += Exit_Click; + _trayIcon.ContextMenu.MenuItems[2].Click += Exit_Click; _trayIcon.MouseClick += TrayIcon_MouseClick; _trayIcon.Icon = new System.Drawing.Icon(Application.GetResourceStream(new Uri("pack://application:,,,/EarTrumpet;component/Tray.ico")).Stream); @@ -50,13 +45,6 @@ void About_Click(object sender, EventArgs e) Process.Start("http://github.com/File-New-Project/EarTrumpet"); } - void ShowDesktopApps_Click(object sender, EventArgs e) - { - var menuItem = (System.Windows.Forms.MenuItem)sender; - menuItem.Checked = !menuItem.Checked; - UserPreferencesService.ShowDesktopApps = menuItem.Checked; - } - void Exit_Click(object sender, EventArgs e) { _trayIcon.Visible = false; diff --git a/EarTrumpet/ViewModels/AudioMixerViewModel.cs b/EarTrumpet/ViewModels/AudioMixerViewModel.cs index 85bd368ce..fa2504691 100644 --- a/EarTrumpet/ViewModels/AudioMixerViewModel.cs +++ b/EarTrumpet/ViewModels/AudioMixerViewModel.cs @@ -53,7 +53,7 @@ public void Refresh() // remove stale apps foreach (var app in Apps) { - if (!sessions.Where(x => (x.IsSame(app) && (!app.IsDesktop || UserPreferencesService.ShowDesktopApps))).Any()) + if (!sessions.Where(x => (x.IsSame(app))).Any()) { staleSessionsToRemove.Add(app); } @@ -66,10 +66,7 @@ public void Refresh() var findApp = Apps.FirstOrDefault(x => x.IsSame(session)); if (findApp == null) { - if (!session.IsDesktop || UserPreferencesService.ShowDesktopApps) - { - Apps.AddSorted(session, AppItemViewModelComparer.Instance); - } + Apps.AddSorted(session, AppItemViewModelComparer.Instance); } else { From 77247944c855671188bd3a0c102cbeea78373a5f Mon Sep 17 00:00:00 2001 From: Rafael Rivera Date: Fri, 8 Apr 2016 23:54:29 -0700 Subject: [PATCH 08/34] Fixed line endings --- EarTrumpet.Interop/AudioSessionService.cpp | 614 ++++++++++----------- 1 file changed, 307 insertions(+), 307 deletions(-) diff --git a/EarTrumpet.Interop/AudioSessionService.cpp b/EarTrumpet.Interop/AudioSessionService.cpp index d9632ae47..6368bc053 100644 --- a/EarTrumpet.Interop/AudioSessionService.cpp +++ b/EarTrumpet.Interop/AudioSessionService.cpp @@ -1,310 +1,310 @@ -#include "common.h" -#include -#include -#include -#include -#include -#include -#include "AudioSessionService.h" -#include "ShellProperties.h" -#include "MrtResourceManager.h" - -using namespace std; -using namespace std::tr1; -using namespace EarTrumpet::Interop; - -AudioSessionService* AudioSessionService::__instance = nullptr; - -struct PackageInfoReferenceDeleter -{ - void operator()(PACKAGE_INFO_REFERENCE* reference) - { - ClosePackageInfo(*reference); - } -}; - -typedef unique_ptr PackageInfoReference; - -void AudioSessionService::CleanUpAudioSessions() -{ - for (auto session = _sessions.begin(); session != _sessions.end(); session++) - { - CoTaskMemFree(session->DisplayName); - CoTaskMemFree(session->IconPath); - } - - _sessions.clear(); - _sessionMap.clear(); -} - -int AudioSessionService::GetAudioSessionCount() -{ - return _sessions.size(); -} - -HRESULT AudioSessionService::RefreshAudioSessions() -{ - CleanUpAudioSessions(); - - CComPtr deviceEnumerator; - FAST_FAIL(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&deviceEnumerator))); - - // TIP: Role parameter is not actually used https://msdn.microsoft.com/en-us/library/windows/desktop/dd371401.aspx - CComPtr device; - FAST_FAIL(deviceEnumerator->GetDefaultAudioEndpoint(EDataFlow::eRender, ERole::eMultimedia, &device)); - - CComPtr audioSessionManager; - FAST_FAIL(device->Activate(__uuidof(IAudioSessionManager2), CLSCTX_INPROC, nullptr, (void**)&audioSessionManager)); - - CComPtr audioSessionEnumerator; - FAST_FAIL(audioSessionManager->GetSessionEnumerator(&audioSessionEnumerator)); - - int sessionCount; - FAST_FAIL(audioSessionEnumerator->GetCount(&sessionCount)); - - for (int i = 0; i < sessionCount; i++) - { - EarTrumpetAudioSession audioSession; - if (SUCCEEDED(CreateEtAudioSessionFromAudioSession(audioSessionEnumerator, i, &audioSession))) - { - _sessions.push_back(audioSession); - } - } - - return S_OK; -} - -HRESULT AudioSessionService::CreateEtAudioSessionFromAudioSession(CComPtr audioSessionEnumerator, int sessionCount, EarTrumpetAudioSession* etAudioSession) -{ - CComPtr audioSessionControl; - FAST_FAIL(audioSessionEnumerator->GetSession(sessionCount, &audioSessionControl)); - - CComPtr audioSessionControl2; - FAST_FAIL(audioSessionControl->QueryInterface(IID_PPV_ARGS(&audioSessionControl2))); - - DWORD pid; - FAST_FAIL(audioSessionControl2->GetProcessId(&pid)); - - etAudioSession->ProcessId = pid; - - FAST_FAIL(audioSessionControl2->GetGroupingParam(&etAudioSession->GroupingId)); - - CComHeapPtr sessionIdString; - FAST_FAIL(audioSessionControl2->GetSessionIdentifier(&sessionIdString)); - - hash stringHash; - etAudioSession->SessionId = stringHash(static_cast(sessionIdString)); - - _sessionMap[etAudioSession->SessionId] = audioSessionControl2; - - CComPtr simpleAudioVolume; - FAST_FAIL(audioSessionControl->QueryInterface(IID_PPV_ARGS(&simpleAudioVolume))); - FAST_FAIL(simpleAudioVolume->GetMasterVolume(&etAudioSession->Volume)); - - HRESULT hr = IsImmersiveProcess(pid); - if (hr == S_OK) - { - PWSTR appUserModelId; - FAST_FAIL(GetAppUserModelIdFromPid(pid, &appUserModelId)); - - FAST_FAIL(GetAppProperties(appUserModelId, &etAudioSession->DisplayName, &etAudioSession->IconPath, &etAudioSession->BackgroundColor)); - - etAudioSession->IsDesktopApp = false; - } - else if (hr == S_FALSE) - { - bool isSystemSoundsSession = (S_OK == audioSessionControl2->IsSystemSoundsSession()); - - AudioSessionState state; - FAST_FAIL(audioSessionControl2->GetState(&state)); - if (!isSystemSoundsSession && (state == AudioSessionState::AudioSessionStateExpired)) - { - return E_NOT_VALID_STATE; - } - - if (isSystemSoundsSession) - { - PCWSTR pszDllPath; - BOOL isWow64Process; - if (!IsWow64Process(GetCurrentProcess(), &isWow64Process) || isWow64Process) - { - pszDllPath = L"%windir%\\sysnative\\audiosrv.dll"; - } - else - { - pszDllPath = L"%windir%\\system32\\audiosrv.dll"; - } - - wchar_t szPath[MAX_PATH] = {}; - if (0 == ExpandEnvironmentStrings(pszDllPath, szPath, ARRAYSIZE(szPath))) - { - return E_FAIL; - } - - FAST_FAIL(SHStrDup(pszDllPath, &etAudioSession->IconPath)); - FAST_FAIL(SHStrDup(L"System Sounds", &etAudioSession->DisplayName)); - } - else - { - shared_ptr processHandle(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid), CloseHandle); - FAST_FAIL_HANDLE(processHandle.get()); - - wchar_t imagePath[MAX_PATH] = {}; - DWORD dwCch = ARRAYSIZE(imagePath); - FAST_FAIL(QueryFullProcessImageName(processHandle.get(), 0, imagePath, &dwCch) == 0 ? E_FAIL : S_OK); - - FAST_FAIL(SHStrDup(imagePath, &etAudioSession->IconPath)); - FAST_FAIL(SHStrDup(PathFindFileName(imagePath), &etAudioSession->DisplayName)); - } - - etAudioSession->IsDesktopApp = true; - etAudioSession->BackgroundColor = 0x00000000; - } - - return S_OK; -} - -HRESULT AudioSessionService::GetAudioSessions(void** audioSessions) -{ - if (_sessions.size() == 0) - { - return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS); - } - - *audioSessions = &_sessions[0]; - return S_OK; -} - -HRESULT AudioSessionService::IsImmersiveProcess(DWORD pid) -{ - shared_ptr processHandle(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid), CloseHandle); - FAST_FAIL_HANDLE(processHandle.get()); - return (::IsImmersiveProcess(processHandle.get()) ? S_OK : S_FALSE); -} - -HRESULT AudioSessionService::CanResolveAppByApplicationUserModelId(LPCWSTR applicationUserModelId) -{ - CComPtr item; - return SUCCEEDED(SHCreateItemInKnownFolder(FOLDERID_AppsFolder, KF_FLAG_DONT_VERIFY, applicationUserModelId, IID_PPV_ARGS(&item))); -} - -HRESULT AudioSessionService::GetAppUserModelIdFromPid(DWORD pid, LPWSTR* applicationUserModelId) -{ - shared_ptr processHandle(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid), CloseHandle); - FAST_FAIL_HANDLE(processHandle.get()); - - unsigned int appUserModelIdLength = 0; - long returnCode = GetApplicationUserModelId(processHandle.get(), &appUserModelIdLength, nullptr); - if (returnCode != ERROR_INSUFFICIENT_BUFFER) - { - return HRESULT_FROM_WIN32(returnCode); - } - - unique_ptr appUserModelId(new wchar_t[appUserModelIdLength]); - returnCode = GetApplicationUserModelId(processHandle.get(), &appUserModelIdLength, appUserModelId.get()); - if (returnCode != ERROR_SUCCESS) - { - return HRESULT_FROM_WIN32(returnCode); - } - - if (CanResolveAppByApplicationUserModelId(appUserModelId.get())) - { - FAST_FAIL(SHStrDup(appUserModelId.get(), applicationUserModelId)); - } - else - { - wchar_t packageFamilyName[PACKAGE_FAMILY_NAME_MAX_LENGTH]; - UINT32 packageFamilyNameLength = ARRAYSIZE(packageFamilyName); - wchar_t packageRelativeAppId[PACKAGE_RELATIVE_APPLICATION_ID_MAX_LENGTH]; - UINT32 packageRelativeAppIdLength = ARRAYSIZE(packageRelativeAppId); - - FAST_FAIL_WIN32(ParseApplicationUserModelId(appUserModelId.get(), &packageFamilyNameLength, packageFamilyName, &packageRelativeAppIdLength, packageRelativeAppId)); - - UINT32 packageCount = 0; - UINT32 packageNamesBufferLength = 0; - FAST_FAIL_BUFFER(FindPackagesByPackageFamily(packageFamilyName, PACKAGE_FILTER_HEAD | PACKAGE_INFORMATION_BASIC, &packageCount, nullptr, &packageNamesBufferLength, nullptr, nullptr)); - - if (packageCount <= 0) - { - return E_NOTFOUND; - } - - unique_ptr packageNames(new PWSTR[packageCount]); - unique_ptr buffer(new wchar_t[packageNamesBufferLength]); - FAST_FAIL_WIN32(FindPackagesByPackageFamily(packageFamilyName, PACKAGE_FILTER_HEAD | PACKAGE_INFORMATION_BASIC, &packageCount, packageNames.get(), &packageNamesBufferLength, buffer.get(), nullptr)); - - PackageInfoReference packageInfoRef; - PACKAGE_INFO_REFERENCE rawPackageInfoRef; - FAST_FAIL_WIN32(OpenPackageInfoByFullName(packageNames[0], 0, &rawPackageInfoRef)); - packageInfoRef.reset(&rawPackageInfoRef); - - UINT32 packageIdsLength = 0; - UINT32 packageIdCount = 0; - FAST_FAIL_BUFFER(GetPackageApplicationIds(*packageInfoRef.get(), &packageIdsLength, nullptr, &packageIdCount)); - - if (packageIdCount <= 0) - { - return E_NOTFOUND; - } - - unique_ptr packageIdsRaw(new BYTE[packageIdsLength]); - FAST_FAIL_WIN32(GetPackageApplicationIds(*packageInfoRef.get(), &packageIdsLength, packageIdsRaw.get(), &packageIdCount)); - - PCWSTR* packageIds = reinterpret_cast(packageIdsRaw.get()); - FAST_FAIL(SHStrDup(packageIds[0], applicationUserModelId)); - } - - return S_OK; -} - -HRESULT AudioSessionService::SetAudioSessionVolume(unsigned long sessionId, float volume) -{ - if (!_sessionMap[sessionId]) - { - return E_INVALIDARG; - } - - CComPtr simpleAudioVolume; - FAST_FAIL(_sessionMap[sessionId]->QueryInterface(IID_PPV_ARGS(&simpleAudioVolume))); - - FAST_FAIL(simpleAudioVolume->SetMasterVolume(volume, nullptr)); - - return S_OK; -} - -HRESULT AudioSessionService::GetAppProperties(PCWSTR pszAppId, PWSTR* ppszName, PWSTR* ppszIcon, ULONG *background) -{ - *ppszIcon = nullptr; - *ppszName = nullptr; - *background = 0; - - CComPtr item; - FAST_FAIL(SHCreateItemInKnownFolder(FOLDERID_AppsFolder, KF_FLAG_DONT_VERIFY, pszAppId, IID_PPV_ARGS(&item))); - - CComHeapPtr itemName; - FAST_FAIL(item->GetString(PKEY_ItemNameDisplay, &itemName)); - FAST_FAIL(item->GetUInt32(PKEY_AppUserModel_Background, background)); - - CComHeapPtr installPath; - FAST_FAIL(item->GetString(PKEY_AppUserModel_PackageInstallPath, &installPath)); - - CComHeapPtr iconPath; - FAST_FAIL(item->GetString(PKEY_AppUserModel_Icon, &iconPath)); - - CComHeapPtr fullPackagePath; - FAST_FAIL(item->GetString(PKEY_AppUserModel_PackageFullName, &fullPackagePath)); - - CComPtr mrtResMgr; - FAST_FAIL(CoCreateInstance(__uuidof(MrtResourceManager), nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&mrtResMgr))); - FAST_FAIL(mrtResMgr->InitializeForPackage(fullPackagePath)); - +#include "common.h" +#include +#include +#include +#include +#include +#include +#include "AudioSessionService.h" +#include "ShellProperties.h" +#include "MrtResourceManager.h" + +using namespace std; +using namespace std::tr1; +using namespace EarTrumpet::Interop; + +AudioSessionService* AudioSessionService::__instance = nullptr; + +struct PackageInfoReferenceDeleter +{ + void operator()(PACKAGE_INFO_REFERENCE* reference) + { + ClosePackageInfo(*reference); + } +}; + +typedef unique_ptr PackageInfoReference; + +void AudioSessionService::CleanUpAudioSessions() +{ + for (auto session = _sessions.begin(); session != _sessions.end(); session++) + { + CoTaskMemFree(session->DisplayName); + CoTaskMemFree(session->IconPath); + } + + _sessions.clear(); + _sessionMap.clear(); +} + +int AudioSessionService::GetAudioSessionCount() +{ + return _sessions.size(); +} + +HRESULT AudioSessionService::RefreshAudioSessions() +{ + CleanUpAudioSessions(); + + CComPtr deviceEnumerator; + FAST_FAIL(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&deviceEnumerator))); + + // TIP: Role parameter is not actually used https://msdn.microsoft.com/en-us/library/windows/desktop/dd371401.aspx + CComPtr device; + FAST_FAIL(deviceEnumerator->GetDefaultAudioEndpoint(EDataFlow::eRender, ERole::eMultimedia, &device)); + + CComPtr audioSessionManager; + FAST_FAIL(device->Activate(__uuidof(IAudioSessionManager2), CLSCTX_INPROC, nullptr, (void**)&audioSessionManager)); + + CComPtr audioSessionEnumerator; + FAST_FAIL(audioSessionManager->GetSessionEnumerator(&audioSessionEnumerator)); + + int sessionCount; + FAST_FAIL(audioSessionEnumerator->GetCount(&sessionCount)); + + for (int i = 0; i < sessionCount; i++) + { + EarTrumpetAudioSession audioSession; + if (SUCCEEDED(CreateEtAudioSessionFromAudioSession(audioSessionEnumerator, i, &audioSession))) + { + _sessions.push_back(audioSession); + } + } + + return S_OK; +} + +HRESULT AudioSessionService::CreateEtAudioSessionFromAudioSession(CComPtr audioSessionEnumerator, int sessionCount, EarTrumpetAudioSession* etAudioSession) +{ + CComPtr audioSessionControl; + FAST_FAIL(audioSessionEnumerator->GetSession(sessionCount, &audioSessionControl)); + + CComPtr audioSessionControl2; + FAST_FAIL(audioSessionControl->QueryInterface(IID_PPV_ARGS(&audioSessionControl2))); + + DWORD pid; + FAST_FAIL(audioSessionControl2->GetProcessId(&pid)); + + etAudioSession->ProcessId = pid; + + FAST_FAIL(audioSessionControl2->GetGroupingParam(&etAudioSession->GroupingId)); + + CComHeapPtr sessionIdString; + FAST_FAIL(audioSessionControl2->GetSessionIdentifier(&sessionIdString)); + + hash stringHash; + etAudioSession->SessionId = stringHash(static_cast(sessionIdString)); + + _sessionMap[etAudioSession->SessionId] = audioSessionControl2; + + CComPtr simpleAudioVolume; + FAST_FAIL(audioSessionControl->QueryInterface(IID_PPV_ARGS(&simpleAudioVolume))); + FAST_FAIL(simpleAudioVolume->GetMasterVolume(&etAudioSession->Volume)); + + HRESULT hr = IsImmersiveProcess(pid); + if (hr == S_OK) + { + PWSTR appUserModelId; + FAST_FAIL(GetAppUserModelIdFromPid(pid, &appUserModelId)); + + FAST_FAIL(GetAppProperties(appUserModelId, &etAudioSession->DisplayName, &etAudioSession->IconPath, &etAudioSession->BackgroundColor)); + + etAudioSession->IsDesktopApp = false; + } + else if (hr == S_FALSE) + { + bool isSystemSoundsSession = (S_OK == audioSessionControl2->IsSystemSoundsSession()); + + AudioSessionState state; + FAST_FAIL(audioSessionControl2->GetState(&state)); + if (!isSystemSoundsSession && (state == AudioSessionState::AudioSessionStateExpired)) + { + return E_NOT_VALID_STATE; + } + + if (isSystemSoundsSession) + { + PCWSTR pszDllPath; + BOOL isWow64Process; + if (!IsWow64Process(GetCurrentProcess(), &isWow64Process) || isWow64Process) + { + pszDllPath = L"%windir%\\sysnative\\audiosrv.dll"; + } + else + { + pszDllPath = L"%windir%\\system32\\audiosrv.dll"; + } + + wchar_t szPath[MAX_PATH] = {}; + if (0 == ExpandEnvironmentStrings(pszDllPath, szPath, ARRAYSIZE(szPath))) + { + return E_FAIL; + } + + FAST_FAIL(SHStrDup(pszDllPath, &etAudioSession->IconPath)); + FAST_FAIL(SHStrDup(L"System Sounds", &etAudioSession->DisplayName)); + } + else + { + shared_ptr processHandle(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid), CloseHandle); + FAST_FAIL_HANDLE(processHandle.get()); + + wchar_t imagePath[MAX_PATH] = {}; + DWORD dwCch = ARRAYSIZE(imagePath); + FAST_FAIL(QueryFullProcessImageName(processHandle.get(), 0, imagePath, &dwCch) == 0 ? E_FAIL : S_OK); + + FAST_FAIL(SHStrDup(imagePath, &etAudioSession->IconPath)); + FAST_FAIL(SHStrDup(PathFindFileName(imagePath), &etAudioSession->DisplayName)); + } + + etAudioSession->IsDesktopApp = true; + etAudioSession->BackgroundColor = 0x00000000; + } + + return S_OK; +} + +HRESULT AudioSessionService::GetAudioSessions(void** audioSessions) +{ + if (_sessions.size() == 0) + { + return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS); + } + + *audioSessions = &_sessions[0]; + return S_OK; +} + +HRESULT AudioSessionService::IsImmersiveProcess(DWORD pid) +{ + shared_ptr processHandle(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid), CloseHandle); + FAST_FAIL_HANDLE(processHandle.get()); + return (::IsImmersiveProcess(processHandle.get()) ? S_OK : S_FALSE); +} + +HRESULT AudioSessionService::CanResolveAppByApplicationUserModelId(LPCWSTR applicationUserModelId) +{ + CComPtr item; + return SUCCEEDED(SHCreateItemInKnownFolder(FOLDERID_AppsFolder, KF_FLAG_DONT_VERIFY, applicationUserModelId, IID_PPV_ARGS(&item))); +} + +HRESULT AudioSessionService::GetAppUserModelIdFromPid(DWORD pid, LPWSTR* applicationUserModelId) +{ + shared_ptr processHandle(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid), CloseHandle); + FAST_FAIL_HANDLE(processHandle.get()); + + unsigned int appUserModelIdLength = 0; + long returnCode = GetApplicationUserModelId(processHandle.get(), &appUserModelIdLength, nullptr); + if (returnCode != ERROR_INSUFFICIENT_BUFFER) + { + return HRESULT_FROM_WIN32(returnCode); + } + + unique_ptr appUserModelId(new wchar_t[appUserModelIdLength]); + returnCode = GetApplicationUserModelId(processHandle.get(), &appUserModelIdLength, appUserModelId.get()); + if (returnCode != ERROR_SUCCESS) + { + return HRESULT_FROM_WIN32(returnCode); + } + + if (CanResolveAppByApplicationUserModelId(appUserModelId.get())) + { + FAST_FAIL(SHStrDup(appUserModelId.get(), applicationUserModelId)); + } + else + { + wchar_t packageFamilyName[PACKAGE_FAMILY_NAME_MAX_LENGTH]; + UINT32 packageFamilyNameLength = ARRAYSIZE(packageFamilyName); + wchar_t packageRelativeAppId[PACKAGE_RELATIVE_APPLICATION_ID_MAX_LENGTH]; + UINT32 packageRelativeAppIdLength = ARRAYSIZE(packageRelativeAppId); + + FAST_FAIL_WIN32(ParseApplicationUserModelId(appUserModelId.get(), &packageFamilyNameLength, packageFamilyName, &packageRelativeAppIdLength, packageRelativeAppId)); + + UINT32 packageCount = 0; + UINT32 packageNamesBufferLength = 0; + FAST_FAIL_BUFFER(FindPackagesByPackageFamily(packageFamilyName, PACKAGE_FILTER_HEAD | PACKAGE_INFORMATION_BASIC, &packageCount, nullptr, &packageNamesBufferLength, nullptr, nullptr)); + + if (packageCount <= 0) + { + return E_NOTFOUND; + } + + unique_ptr packageNames(new PWSTR[packageCount]); + unique_ptr buffer(new wchar_t[packageNamesBufferLength]); + FAST_FAIL_WIN32(FindPackagesByPackageFamily(packageFamilyName, PACKAGE_FILTER_HEAD | PACKAGE_INFORMATION_BASIC, &packageCount, packageNames.get(), &packageNamesBufferLength, buffer.get(), nullptr)); + + PackageInfoReference packageInfoRef; + PACKAGE_INFO_REFERENCE rawPackageInfoRef; + FAST_FAIL_WIN32(OpenPackageInfoByFullName(packageNames[0], 0, &rawPackageInfoRef)); + packageInfoRef.reset(&rawPackageInfoRef); + + UINT32 packageIdsLength = 0; + UINT32 packageIdCount = 0; + FAST_FAIL_BUFFER(GetPackageApplicationIds(*packageInfoRef.get(), &packageIdsLength, nullptr, &packageIdCount)); + + if (packageIdCount <= 0) + { + return E_NOTFOUND; + } + + unique_ptr packageIdsRaw(new BYTE[packageIdsLength]); + FAST_FAIL_WIN32(GetPackageApplicationIds(*packageInfoRef.get(), &packageIdsLength, packageIdsRaw.get(), &packageIdCount)); + + PCWSTR* packageIds = reinterpret_cast(packageIdsRaw.get()); + FAST_FAIL(SHStrDup(packageIds[0], applicationUserModelId)); + } + + return S_OK; +} + +HRESULT AudioSessionService::SetAudioSessionVolume(unsigned long sessionId, float volume) +{ + if (!_sessionMap[sessionId]) + { + return E_INVALIDARG; + } + + CComPtr simpleAudioVolume; + FAST_FAIL(_sessionMap[sessionId]->QueryInterface(IID_PPV_ARGS(&simpleAudioVolume))); + + FAST_FAIL(simpleAudioVolume->SetMasterVolume(volume, nullptr)); + + return S_OK; +} + +HRESULT AudioSessionService::GetAppProperties(PCWSTR pszAppId, PWSTR* ppszName, PWSTR* ppszIcon, ULONG *background) +{ + *ppszIcon = nullptr; + *ppszName = nullptr; + *background = 0; + + CComPtr item; + FAST_FAIL(SHCreateItemInKnownFolder(FOLDERID_AppsFolder, KF_FLAG_DONT_VERIFY, pszAppId, IID_PPV_ARGS(&item))); + + CComHeapPtr itemName; + FAST_FAIL(item->GetString(PKEY_ItemNameDisplay, &itemName)); + FAST_FAIL(item->GetUInt32(PKEY_AppUserModel_Background, background)); + + CComHeapPtr installPath; + FAST_FAIL(item->GetString(PKEY_AppUserModel_PackageInstallPath, &installPath)); + + CComHeapPtr iconPath; + FAST_FAIL(item->GetString(PKEY_AppUserModel_Icon, &iconPath)); + + CComHeapPtr fullPackagePath; + FAST_FAIL(item->GetString(PKEY_AppUserModel_PackageFullName, &fullPackagePath)); + + CComPtr mrtResMgr; + FAST_FAIL(CoCreateInstance(__uuidof(MrtResourceManager), nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&mrtResMgr))); + FAST_FAIL(mrtResMgr->InitializeForPackage(fullPackagePath)); + CComPtr resourceMap; - FAST_FAIL(mrtResMgr->GetMainResourceMap(IID_PPV_ARGS(&resourceMap))); - + FAST_FAIL(mrtResMgr->GetMainResourceMap(IID_PPV_ARGS(&resourceMap))); + CComHeapPtr resolvedIconPath; - FAST_FAIL(resourceMap->GetFilePath(iconPath, &resolvedIconPath)); - - *ppszIcon = resolvedIconPath.Detach(); - *ppszName = itemName.Detach(); - return S_OK; + FAST_FAIL(resourceMap->GetFilePath(iconPath, &resolvedIconPath)); + + *ppszIcon = resolvedIconPath.Detach(); + *ppszName = itemName.Detach(); + return S_OK; } \ No newline at end of file From 93a3854267b7726980fe0112d6b62bdbb7773b73 Mon Sep 17 00:00:00 2001 From: GoldenTao Date: Sat, 9 Apr 2016 17:44:57 +1000 Subject: [PATCH 09/34] Improve Window Show Time #50 --- EarTrumpet/MainWindow.xaml | 6 +-- EarTrumpet/ViewModels/AppItemViewModel.cs | 47 +++++++++++++------ .../ViewModels/AppItemViewModelComparer.cs | 2 +- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/EarTrumpet/MainWindow.xaml b/EarTrumpet/MainWindow.xaml index 949beb8ec..ed36c0cef 100644 --- a/EarTrumpet/MainWindow.xaml +++ b/EarTrumpet/MainWindow.xaml @@ -189,14 +189,14 @@ - - diff --git a/EarTrumpet/ViewModels/AppItemViewModel.cs b/EarTrumpet/ViewModels/AppItemViewModel.cs index 580f8c838..6423bc2d5 100644 --- a/EarTrumpet/ViewModels/AppItemViewModel.cs +++ b/EarTrumpet/ViewModels/AppItemViewModel.cs @@ -5,8 +5,11 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using System.Windows.Media; using System.Windows.Media.Imaging; +using System.Windows.Threading; namespace EarTrumpet.ViewModels { @@ -15,8 +18,34 @@ public class AppItemViewModel : BindableBase private readonly IAudioMixerViewModelCallback _callback; private EarTrumpetAudioSessionModelGroup _sessions; - public string DisplayName { get; set; } - public uint SessionId { get; set; } + private string displayName; + public string DisplayName + { + get + { + if (string.IsNullOrEmpty(displayName)) + { + Task.Factory.StartNew(() => + { + try + { + var proc = Process.GetProcessById((int)ProcessId); + if (!string.IsNullOrWhiteSpace(proc.MainWindowTitle)) + { + displayName = proc.MainWindowTitle; + App.Current.Dispatcher.BeginInvoke((Action)delegate { RaisePropertyChanged("DisplayName"); }, DispatcherPriority.Background); + } + } + catch { } // we fallback to exe name if DisplayName is not set in the try above. + }); + return ExeName; + } + return displayName; + } + } + public string ExeName { get; private set; } + public uint SessionId { get; private set; } + public uint ProcessId { get; set; } public ImageSource Icon { get; set; } public double IconHeight { get; set; } public double IconWidth { get; set; } @@ -51,7 +80,8 @@ public AppItemViewModel(IAudioMixerViewModelCallback callback, EarTrumpetAudioSe IconHeight = IconWidth = 32; SessionId = session.SessionId; - DisplayName = session.DisplayName.Equals("System Sounds") ? EarTrumpet.Properties.Resources.SystemSoundsDisplayName : session.DisplayName; + ProcessId = session.ProcessId; + ExeName = session.DisplayName.Equals("System Sounds") ? EarTrumpet.Properties.Resources.SystemSoundsDisplayName : session.DisplayName; IsDesktop = session.IsDesktop; _volume = Convert.ToInt32(Math.Round((session.Volume * 100), @@ -68,18 +98,7 @@ public AppItemViewModel(IAudioMixerViewModelCallback callback, EarTrumpetAudioSe { // ignored } - Background = new SolidColorBrush(Colors.Transparent); - - try - { - var proc = Process.GetProcessById((int)session.ProcessId); - if (!string.IsNullOrWhiteSpace(proc.MainWindowTitle)) - { - DisplayName = proc.MainWindowTitle; - } - } - catch { } // we fallback to exe name if DisplayName is not set in the try above. } else { diff --git a/EarTrumpet/ViewModels/AppItemViewModelComparer.cs b/EarTrumpet/ViewModels/AppItemViewModelComparer.cs index 61150e42d..00c72bcf4 100644 --- a/EarTrumpet/ViewModels/AppItemViewModelComparer.cs +++ b/EarTrumpet/ViewModels/AppItemViewModelComparer.cs @@ -9,7 +9,7 @@ public class AppItemViewModelComparer : IComparer public int Compare(AppItemViewModel one, AppItemViewModel two) { - return string.Compare(one.DisplayName, two.DisplayName, StringComparison.Ordinal); + return string.Compare(one.ExeName, two.ExeName, StringComparison.Ordinal); } } } From 0a842720cb519a0d1e0fcfe0c0e9d44e27d1665b Mon Sep 17 00:00:00 2001 From: GoldenTao Date: Sat, 9 Apr 2016 18:15:18 +1000 Subject: [PATCH 10/34] Display name for #40 --- EarTrumpet/Properties/Resources.Designer.cs | 9 +++++++++ EarTrumpet/Properties/Resources.de.resx | 5 ++++- EarTrumpet/Properties/Resources.fr.resx | 3 +++ EarTrumpet/Properties/Resources.nb-no.resx | 3 +++ EarTrumpet/Properties/Resources.nn-no.resx | 3 +++ EarTrumpet/Properties/Resources.resx | 3 +++ EarTrumpet/ViewModels/AppItemViewModel.cs | 12 +++++++++++- 7 files changed, 36 insertions(+), 2 deletions(-) diff --git a/EarTrumpet/Properties/Resources.Designer.cs b/EarTrumpet/Properties/Resources.Designer.cs index fec63046f..87b1c9424 100644 --- a/EarTrumpet/Properties/Resources.Designer.cs +++ b/EarTrumpet/Properties/Resources.Designer.cs @@ -96,6 +96,15 @@ public class Resources { } } + /// + /// Looks up a localized string similar to Speech Runtime. + /// + public static string SpeechRuntimeDisplayName { + get { + return ResourceManager.GetString("SpeechRuntimeDisplayName", resourceCulture); + } + } + /// /// Looks up a localized string similar to System Sounds. /// diff --git a/EarTrumpet/Properties/Resources.de.resx b/EarTrumpet/Properties/Resources.de.resx index 9f1c5eeb5..a7719db08 100644 --- a/EarTrumpet/Properties/Resources.de.resx +++ b/EarTrumpet/Properties/Resources.de.resx @@ -129,10 +129,13 @@ Es sieht so aus als sind keine Apps geöffnet + + Speech Runtime + Systemklänge Lautstärkesteuerung für Windows - + \ No newline at end of file diff --git a/EarTrumpet/Properties/Resources.fr.resx b/EarTrumpet/Properties/Resources.fr.resx index 34cbbeb28..3ee44ecda 100644 --- a/EarTrumpet/Properties/Resources.fr.resx +++ b/EarTrumpet/Properties/Resources.fr.resx @@ -129,6 +129,9 @@ Il semble que vous n'ayez aucune application ouverte. + + Speech Runtime + Sons système diff --git a/EarTrumpet/Properties/Resources.nb-no.resx b/EarTrumpet/Properties/Resources.nb-no.resx index 856e71f91..a8e75f370 100644 --- a/EarTrumpet/Properties/Resources.nb-no.resx +++ b/EarTrumpet/Properties/Resources.nb-no.resx @@ -129,6 +129,9 @@ Det ser ikke ut som du har noen applikasjoner åpne. + + Speech Runtime + Systemlyder diff --git a/EarTrumpet/Properties/Resources.nn-no.resx b/EarTrumpet/Properties/Resources.nn-no.resx index de303b9d5..9640d9194 100644 --- a/EarTrumpet/Properties/Resources.nn-no.resx +++ b/EarTrumpet/Properties/Resources.nn-no.resx @@ -129,6 +129,9 @@ Det ser ikkje ut som du har nokon applikasjonar opne. + + Speech Runtime + Systemlydar diff --git a/EarTrumpet/Properties/Resources.resx b/EarTrumpet/Properties/Resources.resx index b0bf94045..57cbd0fdd 100644 --- a/EarTrumpet/Properties/Resources.resx +++ b/EarTrumpet/Properties/Resources.resx @@ -129,6 +129,9 @@ It doesn't look like you have any apps open. + + Speech Runtime + System Sounds diff --git a/EarTrumpet/ViewModels/AppItemViewModel.cs b/EarTrumpet/ViewModels/AppItemViewModel.cs index 6423bc2d5..a1ccfce1a 100644 --- a/EarTrumpet/ViewModels/AppItemViewModel.cs +++ b/EarTrumpet/ViewModels/AppItemViewModel.cs @@ -81,7 +81,7 @@ public AppItemViewModel(IAudioMixerViewModelCallback callback, EarTrumpetAudioSe IconHeight = IconWidth = 32; SessionId = session.SessionId; ProcessId = session.ProcessId; - ExeName = session.DisplayName.Equals("System Sounds") ? EarTrumpet.Properties.Resources.SystemSoundsDisplayName : session.DisplayName; + ExeName = GetExeName(session.DisplayName); IsDesktop = session.IsDesktop; _volume = Convert.ToInt32(Math.Round((session.Volume * 100), @@ -110,6 +110,16 @@ public AppItemViewModel(IAudioMixerViewModelCallback callback, EarTrumpetAudioSe } } + private string GetExeName(string displayName) + { + switch (displayName.ToLowerInvariant()) + { + case "system sounds": return Properties.Resources.SystemSoundsDisplayName; + case "speechruntime.exe": return Properties.Resources.SpeechRuntimeDisplayName; + default: return displayName; + } + } + public void UpdateFromOther(AppItemViewModel other) { if (_volume == other.Volume) return; From feb4b710d495ee7ebdf7ae43c7e3ebf4ce026681 Mon Sep 17 00:00:00 2001 From: GoldenTao Date: Sat, 9 Apr 2016 19:02:53 +1000 Subject: [PATCH 11/34] #40 Speech Runtime handling. --- EarTrumpet/Extensions/IconExtensions.cs | 4 ++-- EarTrumpet/ViewModels/AppItemViewModel.cs | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/EarTrumpet/Extensions/IconExtensions.cs b/EarTrumpet/Extensions/IconExtensions.cs index cb17f310a..cd99cb1fb 100644 --- a/EarTrumpet/Extensions/IconExtensions.cs +++ b/EarTrumpet/Extensions/IconExtensions.cs @@ -35,9 +35,9 @@ public static ImageSource ToImageSource(this Icon icon) return bitmapSource; } - public static ImageSource ExtractIconFromDll(this string path) + public static ImageSource ExtractIconFromDll(this string path, int iconIndex = 0) { - var iconPtr = ExtractIcon(Process.GetCurrentProcess().Handle, path, 0); + var iconPtr = ExtractIcon(Process.GetCurrentProcess().Handle, path, iconIndex); var image = Imaging.CreateBitmapSourceFromHIcon(iconPtr, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); DestroyIcon(iconPtr); return image; diff --git a/EarTrumpet/ViewModels/AppItemViewModel.cs b/EarTrumpet/ViewModels/AppItemViewModel.cs index a1ccfce1a..1b7fc1878 100644 --- a/EarTrumpet/ViewModels/AppItemViewModel.cs +++ b/EarTrumpet/ViewModels/AppItemViewModel.cs @@ -92,7 +92,23 @@ public AppItemViewModel(IAudioMixerViewModelCallback callback, EarTrumpetAudioSe { try { - Icon = Path.GetExtension(session.IconPath) == ".dll" ? IconExtensions.ExtractIconFromDll(session.IconPath) : System.Drawing.Icon.ExtractAssociatedIcon(session.IconPath).ToImageSource(); + if (Path.GetExtension(session.IconPath) == ".dll") + { + Icon = IconExtensions.ExtractIconFromDll(session.IconPath); + } + else + { + // override for SpeechRuntime.exe (Repo -> HEY CORTANA) + if (session.IconPath.ToLowerInvariant().Contains("speechruntime.exe")) + { + var sysType = Environment.Is64BitOperatingSystem ? "SysNative" : "System32"; + Icon = IconExtensions.ExtractIconFromDll(Path.Combine("%windir%", sysType, "Speech\\SpeechUX\\SpeechUXWiz.exe"), 0); + } + else + { + Icon = System.Drawing.Icon.ExtractAssociatedIcon(session.IconPath).ToImageSource(); + } + } } catch { From 6b69add4940c10816fed4c40d09093e8ded8a545 Mon Sep 17 00:00:00 2001 From: GoldenTao Date: Sat, 9 Apr 2016 19:44:53 +1000 Subject: [PATCH 12/34] #36 Notification overlaps autohide taskbar. --- EarTrumpet/MainWindow.xaml.cs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/EarTrumpet/MainWindow.xaml.cs b/EarTrumpet/MainWindow.xaml.cs index b2dfed822..968673fdf 100644 --- a/EarTrumpet/MainWindow.xaml.cs +++ b/EarTrumpet/MainWindow.xaml.cs @@ -168,8 +168,26 @@ private void UpdateWindowPosition() var taskbarScreenWorkArea = TaskbarService.TaskbarScreen.WorkingArea; var taskbarPosition = TaskbarService.TaskbarPosition; - Left = (taskbarPosition == TaskbarPosition.Left) ? (taskbarScreenWorkArea.Left / this.DpiWidthFactor()) : (taskbarScreenWorkArea.Right / this.DpiWidthFactor()) - Width; - Top = (taskbarPosition == TaskbarPosition.Top) ? (taskbarScreenWorkArea.Top / this.DpiHeightFactor()) : (taskbarScreenWorkArea.Bottom / this.DpiHeightFactor()) - Height; + var taskbarRect = TaskbarService.TaskbarPostionRect; + switch(taskbarPosition) + { + case TaskbarPosition.Left: + Left = (taskbarScreenWorkArea.Left / this.DpiWidthFactor()) + taskbarRect.Width; + Top = (taskbarScreenWorkArea.Bottom / this.DpiHeightFactor()) - Height; + break; + case TaskbarPosition.Right: + Left = (taskbarScreenWorkArea.Right / this.DpiWidthFactor()) - taskbarRect.Width - Width; + Top = (taskbarScreenWorkArea.Bottom / this.DpiHeightFactor()) - Height; + break; + case TaskbarPosition.Top: + Left = (taskbarScreenWorkArea.Right / this.DpiWidthFactor()) - Width; + Top = (taskbarScreenWorkArea.Top / this.DpiHeightFactor()) + taskbarRect.Height; + break; + case TaskbarPosition.Bottom: + Left = (taskbarScreenWorkArea.Right / this.DpiWidthFactor())- Width; + Top = (taskbarScreenWorkArea.Bottom / this.DpiHeightFactor()) - taskbarRect.Height - Height; + break; + } } } } From 42b59af96a4076e4a467a297913e994e2455fa50 Mon Sep 17 00:00:00 2001 From: GoldenTao Date: Sun, 10 Apr 2016 01:27:30 +1000 Subject: [PATCH 13/34] #36 Better taskbar handling. --- EarTrumpet/Extensions/BlurWindowExtensions.cs | 2 +- EarTrumpet/Extensions/WindowExtensions.cs | 4 +- EarTrumpet/MainWindow.xaml.cs | 22 ++-- EarTrumpet/Services/TaskbarService.cs | 108 ++++++++++++------ 4 files changed, 86 insertions(+), 50 deletions(-) diff --git a/EarTrumpet/Extensions/BlurWindowExtensions.cs b/EarTrumpet/Extensions/BlurWindowExtensions.cs index 130d960a4..3b2da4bad 100644 --- a/EarTrumpet/Extensions/BlurWindowExtensions.cs +++ b/EarTrumpet/Extensions/BlurWindowExtensions.cs @@ -101,7 +101,7 @@ private static Interop.AccentFlags GetAccentFlagsForTaskbarPosition() { var flags = Interop.AccentFlags.DrawAllBorders; - switch(TaskbarService.TaskbarPosition) + switch(TaskbarService.GetWinTaskbarState().TaskbarPosition) { case TaskbarPosition.Top: flags &= ~Interop.AccentFlags.DrawTopBorder; diff --git a/EarTrumpet/Extensions/WindowExtensions.cs b/EarTrumpet/Extensions/WindowExtensions.cs index a4fdae40f..1fd756705 100644 --- a/EarTrumpet/Extensions/WindowExtensions.cs +++ b/EarTrumpet/Extensions/WindowExtensions.cs @@ -23,7 +23,7 @@ public static void HideWithAnimation(this Window window) FillBehavior = FillBehavior.Stop, EasingFunction = new ExponentialEase {EasingMode = EasingMode.EaseIn} }; - var taskbarPosition = TaskbarService.TaskbarPosition; + var taskbarPosition = TaskbarService.GetWinTaskbarState().TaskbarPosition; switch (taskbarPosition) { case TaskbarPosition.Left: @@ -64,7 +64,7 @@ public static void ShowwithAnimation(this Window window) FillBehavior = FillBehavior.Stop, EasingFunction = new ExponentialEase { EasingMode = EasingMode.EaseOut } }; - var taskbarPosition = TaskbarService.TaskbarPosition; + var taskbarPosition = TaskbarService.GetWinTaskbarState().TaskbarPosition; switch (taskbarPosition) { case TaskbarPosition.Left: diff --git a/EarTrumpet/MainWindow.xaml.cs b/EarTrumpet/MainWindow.xaml.cs index 968673fdf..02048f4e9 100644 --- a/EarTrumpet/MainWindow.xaml.cs +++ b/EarTrumpet/MainWindow.xaml.cs @@ -166,26 +166,24 @@ private void UpdateWindowPosition() LayoutRoot.Measure(new Size(double.PositiveInfinity, MaxHeight)); Height = LayoutRoot.DesiredSize.Height; - var taskbarScreenWorkArea = TaskbarService.TaskbarScreen.WorkingArea; - var taskbarPosition = TaskbarService.TaskbarPosition; - var taskbarRect = TaskbarService.TaskbarPostionRect; - switch(taskbarPosition) + var taskbarState = TaskbarService.GetWinTaskbarState(); + switch(taskbarState.TaskbarPosition) { case TaskbarPosition.Left: - Left = (taskbarScreenWorkArea.Left / this.DpiWidthFactor()) + taskbarRect.Width; - Top = (taskbarScreenWorkArea.Bottom / this.DpiHeightFactor()) - Height; + Left = (taskbarState.TaskbarSize.right / this.DpiWidthFactor()); + Top = (taskbarState.TaskbarSize.bottom / this.DpiHeightFactor()) - Height; break; case TaskbarPosition.Right: - Left = (taskbarScreenWorkArea.Right / this.DpiWidthFactor()) - taskbarRect.Width - Width; - Top = (taskbarScreenWorkArea.Bottom / this.DpiHeightFactor()) - Height; + Left = (taskbarState.TaskbarSize.left / this.DpiWidthFactor()) - Width; + Top = (taskbarState.TaskbarSize.bottom / this.DpiHeightFactor()) - Height; break; case TaskbarPosition.Top: - Left = (taskbarScreenWorkArea.Right / this.DpiWidthFactor()) - Width; - Top = (taskbarScreenWorkArea.Top / this.DpiHeightFactor()) + taskbarRect.Height; + Left = (taskbarState.TaskbarSize.right / this.DpiWidthFactor()) - Width; + Top = (taskbarState.TaskbarSize.bottom / this.DpiHeightFactor()); break; case TaskbarPosition.Bottom: - Left = (taskbarScreenWorkArea.Right / this.DpiWidthFactor())- Width; - Top = (taskbarScreenWorkArea.Bottom / this.DpiHeightFactor()) - taskbarRect.Height - Height; + Left = (taskbarState.TaskbarSize.right / this.DpiWidthFactor()) - Width; + Top = (taskbarState.TaskbarSize.top / this.DpiHeightFactor()) - Height; break; } } diff --git a/EarTrumpet/Services/TaskbarService.cs b/EarTrumpet/Services/TaskbarService.cs index 3324e6720..cebe8d351 100644 --- a/EarTrumpet/Services/TaskbarService.cs +++ b/EarTrumpet/Services/TaskbarService.cs @@ -2,7 +2,6 @@ using System.Drawing; using System.Linq; using System.Runtime.InteropServices; -using System.Windows; using System.Windows.Forms; namespace EarTrumpet.Services @@ -11,46 +10,42 @@ public sealed class TaskbarService { private const string ClassName = "Shell_TrayWnd"; - public static Rectangle TaskbarPostionRect + public static TaskbarState GetWinTaskbarState() { - get - { - var taskbarHandle = User32.FindWindow(ClassName, null); + APPBARDATA ABD = new APPBARDATA(); + TaskbarState retState = new TaskbarState(); - var r = new RECT(); - User32.GetWindowRect(taskbarHandle, ref r); + ABD.cbSize = Marshal.SizeOf(ABD); + ABD.uEdge = 0; + ABD.hWnd = User32.FindWindow(ClassName, null); + ABD.lParam = 1; - return Rectangle.FromLTRB(r.left, r.top, r.right, r.bottom); - } - } + var tsize = Shell32.SHAppBarMessage((int)ABMsg.ABM_GETTASKBARPOS, ref ABD); + retState.TaskbarSize = ABD.rc; - public static TaskbarPosition TaskbarPosition - { - get - { - var rect = TaskbarPostionRect; - var screen = TaskbarScreen; - if (screen == null) return TaskbarPosition.Bottom; + var screen = Screen.AllScreens.FirstOrDefault(x => x.Bounds.Contains( + new Rectangle( + retState.TaskbarSize.left, + retState.TaskbarSize.top, + retState.TaskbarSize.right - retState.TaskbarSize.left, + retState.TaskbarSize.bottom - retState.TaskbarSize.top) + )); - if (rect.Bottom == screen.Bounds.Bottom && rect.Top == screen.Bounds.Top) + retState.TaskbarPosition = TaskbarPosition.Bottom; + + if (screen != null) + { + if (retState.TaskbarSize.bottom == screen.Bounds.Bottom && retState.TaskbarSize.top == screen.Bounds.Top) { - return (rect.Left == screen.Bounds.Left) ? TaskbarPosition.Left : TaskbarPosition.Right; + retState.TaskbarPosition = (retState.TaskbarSize.left == screen.Bounds.Left) ? TaskbarPosition.Left : TaskbarPosition.Right; } - if (rect.Right == screen.Bounds.Right && rect.Left == screen.Bounds.Left) + if (retState.TaskbarSize.right == screen.Bounds.Right && retState.TaskbarSize.left == screen.Bounds.Left) { - return (rect.Top == screen.Bounds.Top) ? TaskbarPosition.Top : TaskbarPosition.Bottom; + retState.TaskbarPosition = (retState.TaskbarSize.top == screen.Bounds.Top) ? TaskbarPosition.Top : TaskbarPosition.Bottom; } - return TaskbarPosition.Bottom; - } - } + } - public static Screen TaskbarScreen - { - get - { - var rect = TaskbarPostionRect; - return Screen.AllScreens.FirstOrDefault(x => x.Bounds.Contains(rect)); - } + return retState; } } @@ -58,10 +53,6 @@ public static class User32 { [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect); } [StructLayout(LayoutKind.Sequential)] @@ -73,6 +64,53 @@ public struct RECT public int bottom; } + public static class Shell32 + { + [DllImport("shell32.dll")] + public static extern IntPtr SHAppBarMessage(uint dwMessage, [In] ref APPBARDATA pData); + } + + [StructLayout(LayoutKind.Sequential)] + public struct APPBARDATA + { + public int cbSize; // initialize this field using: Marshal.SizeOf(typeof(APPBARDATA)); + public IntPtr hWnd; + public uint uCallbackMessage; + public uint uEdge; + public RECT rc; + public int lParam; + } + + public enum ABMsg + { + ABM_NEW = 0, + ABM_REMOVE, + ABM_QUERYPOS, + ABM_SETPOS, + ABM_GETSTATE, + ABM_GETTASKBARPOS, + ABM_ACTIVATE, + ABM_GETAUTOHIDEBAR, + ABM_SETAUTOHIDEBAR, + ABM_WINDOWPOSCHANGED, + ABM_SETSTATE + } + + public enum ABEdge + { + ABE_LEFT = 0, + ABE_TOP = 1, + ABE_RIGHT = 2, + ABE_BOTTOM = 3 + } + + [StructLayout(LayoutKind.Sequential)] + public struct TaskbarState + { + public TaskbarPosition TaskbarPosition; + public RECT TaskbarSize; + } + public enum TaskbarPosition { Top, From ff0080ed0e5445b3ad7bdb57729c04ccdf3e38aa Mon Sep 17 00:00:00 2001 From: GoldenTao Date: Sun, 10 Apr 2016 11:41:55 +1000 Subject: [PATCH 14/34] #20 Installer/Uninstaller check for App running. --- EarTrumpet/EarTrumpet.iss | 1 + 1 file changed, 1 insertion(+) diff --git a/EarTrumpet/EarTrumpet.iss b/EarTrumpet/EarTrumpet.iss index 3e63bf729..e2eb5184b 100644 --- a/EarTrumpet/EarTrumpet.iss +++ b/EarTrumpet/EarTrumpet.iss @@ -23,6 +23,7 @@ DisableStartupPrompt=yes DisableWelcomePage=yes MinVersion=10.0 SetupMutex=EarTrumpetSetup +AppMutex="Local\{{02639d71-0935-35e8-9d1b-9dd1a2a34627}{{EarTrumpet}" [Files] Source: "EarTrumpet.exe"; DestDir: "{app}"; Flags: replacesameversion From 10b579edd9773da1373b8183c0500062ee0a4830 Mon Sep 17 00:00:00 2001 From: GoldenTao Date: Sun, 10 Apr 2016 18:17:20 +1000 Subject: [PATCH 15/34] #3 Fast mute support --- EarTrumpet.Interop/AudioSessionService.cpp | 18 +++++++ EarTrumpet.Interop/AudioSessionService.h | 2 + EarTrumpet.Interop/exports.cpp | 7 ++- EarTrumpet/MainWindow.xaml | 52 ++++++++++++++++--- EarTrumpet/MainWindow.xaml.cs | 33 ++++++++++++ .../Models/EarTrumpetAudioSessionModel.cs | 3 ++ .../Services/EarTrumpetAudioSessionService.cs | 17 ++++-- EarTrumpet/ViewModels/AppItemViewModel.cs | 26 ++++++++++ EarTrumpet/ViewModels/AudioMixerViewModel.cs | 9 +++- .../IAudioMixerViewModelCallback.cs | 1 + 10 files changed, 155 insertions(+), 13 deletions(-) diff --git a/EarTrumpet.Interop/AudioSessionService.cpp b/EarTrumpet.Interop/AudioSessionService.cpp index 6368bc053..f6fbd1705 100644 --- a/EarTrumpet.Interop/AudioSessionService.cpp +++ b/EarTrumpet.Interop/AudioSessionService.cpp @@ -101,6 +101,10 @@ HRESULT AudioSessionService::CreateEtAudioSessionFromAudioSession(CComPtrQueryInterface(IID_PPV_ARGS(&simpleAudioVolume))); FAST_FAIL(simpleAudioVolume->GetMasterVolume(&etAudioSession->Volume)); + BOOL isMuted; + FAST_FAIL(simpleAudioVolume->GetMute(&isMuted)); + etAudioSession->IsMuted = !!isMuted; + HRESULT hr = IsImmersiveProcess(pid); if (hr == S_OK) { @@ -272,6 +276,20 @@ HRESULT AudioSessionService::SetAudioSessionVolume(unsigned long sessionId, floa return S_OK; } +HRESULT AudioSessionService::SetAudioSessionMute(unsigned long sessionId, bool isMuted) +{ + if (!_sessionMap[sessionId]) + { + return E_INVALIDARG; + } + + CComPtr simpleAudioVolume; + FAST_FAIL(_sessionMap[sessionId]->QueryInterface(IID_PPV_ARGS(&simpleAudioVolume))); + + FAST_FAIL(simpleAudioVolume->SetMute(isMuted, nullptr)); + return S_OK; +} + HRESULT AudioSessionService::GetAppProperties(PCWSTR pszAppId, PWSTR* ppszName, PWSTR* ppszIcon, ULONG *background) { *ppszIcon = nullptr; diff --git a/EarTrumpet.Interop/AudioSessionService.h b/EarTrumpet.Interop/AudioSessionService.h index 6f358e858..53bc5c328 100644 --- a/EarTrumpet.Interop/AudioSessionService.h +++ b/EarTrumpet.Interop/AudioSessionService.h @@ -14,6 +14,7 @@ namespace EarTrumpet unsigned long BackgroundColor; float Volume; bool IsDesktopApp; + bool IsMuted; }; class AudioSessionService @@ -45,6 +46,7 @@ namespace EarTrumpet HRESULT GetAudioSessions(void** audioSessions); HRESULT RefreshAudioSessions(); HRESULT SetAudioSessionVolume(unsigned long sessionId, float volume); + HRESULT SetAudioSessionMute(unsigned long sessionId, bool isMuted); }; } } \ No newline at end of file diff --git a/EarTrumpet.Interop/exports.cpp b/EarTrumpet.Interop/exports.cpp index 2142a02d3..076fb9b70 100644 --- a/EarTrumpet.Interop/exports.cpp +++ b/EarTrumpet.Interop/exports.cpp @@ -22,4 +22,9 @@ extern "C" __declspec(dllexport) HRESULT GetAudioSessions(void** audioSessions) extern "C" __declspec(dllexport) HRESULT SetAudioSessionVolume(unsigned long sessionId, float volume) { return AudioSessionService::instance()->SetAudioSessionVolume(sessionId, volume); -} \ No newline at end of file +} + +extern "C" __declspec(dllexport) HRESULT SetAudioSessionMute(unsigned long sessionId, bool isMuted) +{ + return AudioSessionService::instance()->SetAudioSessionMute(sessionId, isMuted); +} diff --git a/EarTrumpet/MainWindow.xaml b/EarTrumpet/MainWindow.xaml index ed36c0cef..cd1d71ede 100644 --- a/EarTrumpet/MainWindow.xaml +++ b/EarTrumpet/MainWindow.xaml @@ -183,24 +183,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + Margin="4,0" + MouseDown="Icon_MouseDown" x:Name="AppIcon"> + + + + + GetAudioSessions() { Interop.RefreshAudioSessions(); - + var sessionCount = Interop.GetAudioSessionCount(); var sessions = new List(); @@ -34,10 +38,10 @@ public IEnumerable GetAudioSessions() Interop.GetAudioSessions(ref rawSessionsPtr); var sizeOfAudioSessionStruct = Marshal.SizeOf(typeof(EarTrumpetAudioSessionModel)); - for(var i = 0; i < sessionCount; i++) + for (var i = 0; i < sessionCount; i++) { var window = new IntPtr(rawSessionsPtr.ToInt64() + (sizeOfAudioSessionStruct * i)); - + var session = (EarTrumpetAudioSessionModel)Marshal.PtrToStructure(window, typeof(EarTrumpetAudioSessionModel)); sessions.Add(session); } @@ -47,7 +51,7 @@ public IEnumerable GetAudioSessions() public IEnumerable GetAudioSessionGroups() { return GetAudioSessions().GroupBy( - x => x.GroupingId, + x => x.GroupingId, x => x, (key, result) => new EarTrumpetAudioSessionModelGroup(result.ToList())); } @@ -55,5 +59,10 @@ public void SetAudioSessionVolume(uint sessionId, float volume) { Interop.SetAudioSessionVolume(sessionId, volume); } + + public void SetAudioSessionMute(uint sessionId, bool isMuted) + { + Interop.SetAudioSessionMute(sessionId, isMuted); + } } } diff --git a/EarTrumpet/ViewModels/AppItemViewModel.cs b/EarTrumpet/ViewModels/AppItemViewModel.cs index 1b7fc1878..df61d1704 100644 --- a/EarTrumpet/ViewModels/AppItemViewModel.cs +++ b/EarTrumpet/ViewModels/AppItemViewModel.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Threading; @@ -72,6 +73,28 @@ public int Volume public SolidColorBrush Background { get; set; } public bool IsDesktop { get; set; } + private bool _isMuted = false; + public bool IsMuted + { + get + { + return _isMuted; + } + set + { + if (_isMuted != value) + { + _isMuted = value; + + foreach (var session in _sessions.Sessions) + { + _callback.SetMute(session, _isMuted); + } + RaisePropertyChanged("IsMuted"); + } + } + } + public AppItemViewModel(IAudioMixerViewModelCallback callback, EarTrumpetAudioSessionModelGroup sessions) { _sessions = sessions; @@ -86,6 +109,7 @@ public AppItemViewModel(IAudioMixerViewModelCallback callback, EarTrumpetAudioSe _volume = Convert.ToInt32(Math.Round((session.Volume * 100), MidpointRounding.AwayFromZero)); + _isMuted = session.IsMuted; _callback = callback; if (session.IsDesktop) @@ -141,7 +165,9 @@ public void UpdateFromOther(AppItemViewModel other) if (_volume == other.Volume) return; _sessions = other._sessions; _volume = other.Volume; + _isMuted = other.IsMuted; RaisePropertyChanged("Volume"); + RaisePropertyChanged("IsMuted"); } public bool IsSame(AppItemViewModel other) diff --git a/EarTrumpet/ViewModels/AudioMixerViewModel.cs b/EarTrumpet/ViewModels/AudioMixerViewModel.cs index fa2504691..3ea89b005 100644 --- a/EarTrumpet/ViewModels/AudioMixerViewModel.cs +++ b/EarTrumpet/ViewModels/AudioMixerViewModel.cs @@ -25,9 +25,14 @@ public void SetVolume(EarTrumpetAudioSessionModel item, float volume) { _service.SetAudioSessionVolume(item.SessionId, volume); } - } - public ObservableCollection Apps { get; private set; } + public void SetMute(EarTrumpetAudioSessionModel item, bool isMuted) + { + _service.SetAudioSessionMute(item.SessionId, isMuted); + } + } + + public ObservableCollection Apps { get; private set; } public Visibility ListVisibility { get; private set; } public Visibility NoAppsPaneVisibility { get; private set; } diff --git a/EarTrumpet/ViewModels/IAudioMixerViewModelCallback.cs b/EarTrumpet/ViewModels/IAudioMixerViewModelCallback.cs index 43eaac167..9a5fb7c7a 100644 --- a/EarTrumpet/ViewModels/IAudioMixerViewModelCallback.cs +++ b/EarTrumpet/ViewModels/IAudioMixerViewModelCallback.cs @@ -5,5 +5,6 @@ namespace EarTrumpet.ViewModels public interface IAudioMixerViewModelCallback { void SetVolume(EarTrumpetAudioSessionModel session, float volume); + void SetMute(EarTrumpetAudioSessionModel session, bool isMuted); } } From 3c50a456dfa7c867708e5075f13337c91674a837 Mon Sep 17 00:00:00 2001 From: GoldenTao Date: Sun, 10 Apr 2016 18:19:54 +1000 Subject: [PATCH 16/34] Slider design changes --- EarTrumpet/MainWindow.xaml | 16 +--------------- EarTrumpet/Services/ThemeService.cs | 3 --- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/EarTrumpet/MainWindow.xaml b/EarTrumpet/MainWindow.xaml index cd1d71ede..4dff3ef7d 100644 --- a/EarTrumpet/MainWindow.xaml +++ b/EarTrumpet/MainWindow.xaml @@ -23,11 +23,7 @@ - - + Color="#39FFFFFF" /> - - - @@ -134,11 +125,6 @@ - - - diff --git a/EarTrumpet/Services/ThemeService.cs b/EarTrumpet/Services/ThemeService.cs index 0c8f4396e..69e4b358d 100644 --- a/EarTrumpet/Services/ThemeService.cs +++ b/EarTrumpet/Services/ThemeService.cs @@ -16,9 +16,6 @@ public static void UpdateThemeResources(ResourceDictionary dictionary) SetBrush(dictionary, "WindowForeground", "ImmersiveApplicationTextDarkTheme"); ReplaceBrush(dictionary, "CottonSwabSliderThumb", "ImmersiveSystemAccent"); - ReplaceBrush(dictionary, "CottonSwabSliderTrackBackground", SystemParameters.HighContrast ? "ImmersiveSystemAccentLight1" : "ImmersiveControlDarkSliderTrackBackgroundRest"); - SetBrushWithOpacity(dictionary, "CottonSwabSliderTrackBackgroundHover", SystemParameters.HighContrast ? "ImmersiveSystemAccentLight1" : "ImmersiveDarkBaseMediumHigh", SystemParameters.HighContrast ? 1.0 : 0.25); - SetBrush(dictionary, "CottonSwabSliderTrackBackgroundPressed", "ImmersiveControlDarkSliderTrackBackgroundRest"); ReplaceBrush(dictionary, "CottonSwabSliderTrackFill", "ImmersiveSystemAccentLight1"); SetBrush(dictionary, "CottonSwabSliderThumbHover", "ImmersiveControlDarkSliderThumbHover"); SetBrush(dictionary, "CottonSwabSliderThumbPressed", "ImmersiveControlDarkSliderThumbHover"); From 46ed7130fd0e5f42a46b6dba530ec4bafbd2a0e6 Mon Sep 17 00:00:00 2001 From: GoldenTao Date: Sun, 10 Apr 2016 21:20:50 +1000 Subject: [PATCH 17/34] Better animation handling --- EarTrumpet/Extensions/WindowExtensions.cs | 158 ++++++++++++---------- EarTrumpet/MainWindow.xaml.cs | 2 +- 2 files changed, 88 insertions(+), 72 deletions(-) diff --git a/EarTrumpet/Extensions/WindowExtensions.cs b/EarTrumpet/Extensions/WindowExtensions.cs index 1fd756705..65c9d9415 100644 --- a/EarTrumpet/Extensions/WindowExtensions.cs +++ b/EarTrumpet/Extensions/WindowExtensions.cs @@ -8,90 +8,106 @@ namespace EarTrumpet.Extensions { internal static class WindowExtensions { - private static bool _windowVisible; - - public static bool IsWindowVisible(this Window window) - { - return _windowVisible; - } - + private static bool hideAnimationInProgress = false; public static void HideWithAnimation(this Window window) { - var hideAnimation = new DoubleAnimation - { - Duration = new Duration(TimeSpan.FromSeconds(0.2)), - FillBehavior = FillBehavior.Stop, - EasingFunction = new ExponentialEase {EasingMode = EasingMode.EaseIn} - }; - var taskbarPosition = TaskbarService.GetWinTaskbarState().TaskbarPosition; - switch (taskbarPosition) - { - case TaskbarPosition.Left: - case TaskbarPosition.Right: - hideAnimation.From = window.Left; - break; - default: - hideAnimation.From = window.Top; - break; - } - hideAnimation.To = (taskbarPosition == TaskbarPosition.Top || taskbarPosition == TaskbarPosition.Left) ? hideAnimation.From - 10 : hideAnimation.From + 10; - hideAnimation.Completed += (s, e) => + if (hideAnimationInProgress) return; + + try { - window.Visibility = Visibility.Hidden; - }; + hideAnimationInProgress = true; + + var hideAnimation = new DoubleAnimation + { + Duration = new Duration(TimeSpan.FromSeconds(0.2)), + FillBehavior = FillBehavior.Stop, + EasingFunction = new ExponentialEase { EasingMode = EasingMode.EaseIn } + }; + var taskbarPosition = TaskbarService.GetWinTaskbarState().TaskbarPosition; + switch (taskbarPosition) + { + case TaskbarPosition.Left: + case TaskbarPosition.Right: + hideAnimation.From = window.Left; + break; + default: + hideAnimation.From = window.Top; + break; + } + hideAnimation.To = (taskbarPosition == TaskbarPosition.Top || taskbarPosition == TaskbarPosition.Left) ? hideAnimation.From - 10 : hideAnimation.From + 10; + hideAnimation.Completed += (s, e) => + { + window.Visibility = Visibility.Hidden; + hideAnimationInProgress = false; + }; - switch (taskbarPosition) + switch (taskbarPosition) + { + case TaskbarPosition.Left: + case TaskbarPosition.Right: + window.ApplyAnimationClock(Window.LeftProperty, hideAnimation.CreateClock()); + break; + default: + window.ApplyAnimationClock(Window.TopProperty, hideAnimation.CreateClock()); + break; + } + } + catch { - case TaskbarPosition.Left: - case TaskbarPosition.Right: - window.ApplyAnimationClock(Window.LeftProperty, hideAnimation.CreateClock()); - break; - default: - window.ApplyAnimationClock(Window.TopProperty, hideAnimation.CreateClock()); - break; + hideAnimationInProgress = false; } - _windowVisible = false; } + private static bool showAnimationInProgress = false; public static void ShowwithAnimation(this Window window) - { - window.Visibility = Visibility.Visible; - window.Topmost = false; - window.Activate(); - var showAnimation = new DoubleAnimation - { - Duration = new Duration(TimeSpan.FromSeconds(0.3)), - FillBehavior = FillBehavior.Stop, - EasingFunction = new ExponentialEase { EasingMode = EasingMode.EaseOut } - }; - var taskbarPosition = TaskbarService.GetWinTaskbarState().TaskbarPosition; - switch (taskbarPosition) + { + if (showAnimationInProgress) return; + + try { - case TaskbarPosition.Left: - case TaskbarPosition.Right: - showAnimation.To = window.Left; - break; - default: - showAnimation.To = window.Top; - break; + showAnimationInProgress = true; + window.Visibility = Visibility.Visible; + window.Topmost = false; + window.Activate(); + var showAnimation = new DoubleAnimation + { + Duration = new Duration(TimeSpan.FromSeconds(0.3)), + FillBehavior = FillBehavior.Stop, + EasingFunction = new ExponentialEase { EasingMode = EasingMode.EaseOut } + }; + var taskbarPosition = TaskbarService.GetWinTaskbarState().TaskbarPosition; + switch (taskbarPosition) + { + case TaskbarPosition.Left: + case TaskbarPosition.Right: + showAnimation.To = window.Left; + break; + default: + showAnimation.To = window.Top; + break; + } + showAnimation.From = (taskbarPosition == TaskbarPosition.Top || taskbarPosition == TaskbarPosition.Left) ? showAnimation.To - 25 : showAnimation.To + 25; + showAnimation.Completed += (s, e) => + { + window.Topmost = true; + showAnimationInProgress = false; + window.Focus(); + }; + switch (taskbarPosition) + { + case TaskbarPosition.Left: + case TaskbarPosition.Right: + window.ApplyAnimationClock(Window.LeftProperty, showAnimation.CreateClock()); + break; + default: + window.ApplyAnimationClock(Window.TopProperty, showAnimation.CreateClock()); + break; + } } - showAnimation.From = (taskbarPosition == TaskbarPosition.Top || taskbarPosition == TaskbarPosition.Left) ? showAnimation.To - 25 : showAnimation.To + 25; - showAnimation.Completed += (s, e) => - { - window.Topmost = true; - window.Focus(); - }; - switch (taskbarPosition) + catch { - case TaskbarPosition.Left: - case TaskbarPosition.Right: - window.ApplyAnimationClock(Window.LeftProperty, showAnimation.CreateClock()); - break; - default: - window.ApplyAnimationClock(Window.TopProperty, showAnimation.CreateClock()); - break; + showAnimationInProgress = false; } - _windowVisible = true; } public static Matrix CalculateDpiFactors(this Window window) diff --git a/EarTrumpet/MainWindow.xaml.cs b/EarTrumpet/MainWindow.xaml.cs index eddc3d7cb..5ed4191f5 100644 --- a/EarTrumpet/MainWindow.xaml.cs +++ b/EarTrumpet/MainWindow.xaml.cs @@ -44,7 +44,7 @@ private void CreateAndHideWindow() void TrayIcon_Invoked() { - if (this.IsWindowVisible()) + if (this.Visibility == Visibility.Visible) { this.HideWithAnimation(); } From e3940c1c800f86da08d7e9622845e7f28961726a Mon Sep 17 00:00:00 2001 From: GoldenTao Date: Mon, 11 Apr 2016 08:51:28 +1000 Subject: [PATCH 18/34] #3 Drop VSM to converter, fixes startup state of mute. --- EarTrumpet/EarTrumpet.csproj | 1 + EarTrumpet/Extensions/OpacityConverter.cs | 23 ++++++++++++++ EarTrumpet/MainWindow.xaml | 37 ++++------------------- EarTrumpet/MainWindow.xaml.cs | 2 -- 4 files changed, 30 insertions(+), 33 deletions(-) create mode 100644 EarTrumpet/Extensions/OpacityConverter.cs diff --git a/EarTrumpet/EarTrumpet.csproj b/EarTrumpet/EarTrumpet.csproj index ca480bb26..91ea80de2 100644 --- a/EarTrumpet/EarTrumpet.csproj +++ b/EarTrumpet/EarTrumpet.csproj @@ -61,6 +61,7 @@ + Resources.de.resx diff --git a/EarTrumpet/Extensions/OpacityConverter.cs b/EarTrumpet/Extensions/OpacityConverter.cs new file mode 100644 index 000000000..88d00d98d --- /dev/null +++ b/EarTrumpet/Extensions/OpacityConverter.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace EarTrumpet.Extensions +{ + public class OpacityConverter: IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return (bool)value ? 0.4 : 1.0; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/EarTrumpet/MainWindow.xaml b/EarTrumpet/MainWindow.xaml index 4dff3ef7d..332c31881 100644 --- a/EarTrumpet/MainWindow.xaml +++ b/EarTrumpet/MainWindow.xaml @@ -3,6 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:p="clr-namespace:EarTrumpet.Properties" xmlns:viewModels="clr-namespace:EarTrumpet.ViewModels" + xmlns:ext="clr-namespace:EarTrumpet.Extensions" Title="Ear Trumpet" MaxHeight="600" Width="360" @@ -32,6 +33,8 @@ Color="Yellow" /> + +