├── docs
├── SBOutputController_Main.png
└── SBOutputController_Setup.png
├── SBOutputController
├── output_toggle_icon.ico
├── Resources
│ ├── output_toggle_icon.ico
│ ├── baseline_error_black_36dp.png
│ ├── baseline_error_white_36dp.png
│ ├── baseline_headset_black_36dp.png
│ ├── baseline_headset_white_36dp.png
│ ├── baseline_speaker_black_36dp.png
│ ├── baseline_speaker_white_36dp.png
│ ├── headphones_speaker_toggle_black_36p.png
│ └── headphones_speaker_toggle_white_36p.png
├── App.xaml.cs
├── App.xaml
├── EqualizerAPO.cs
├── HotKeyEditorControl.xaml
├── FileBrowseControl.xaml
├── SBOutputController.csproj.user
├── Properties
│ ├── Settings.settings
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── app.manifest
│ ├── Resources.resx
│ └── Settings.Designer.cs
├── App.config
├── HotKeyEditorControl.xaml.cs
├── DependenciesSetup.xaml.cs
├── FileBrowseControl.xaml.cs
├── KeyboardHook.cs
├── HotKey.cs
├── DependenciesSetup.xaml
├── MainWindow.xaml
├── SBOutputController.csproj
├── SBController.cs
└── MainWindow.xaml.cs
├── appveyor.yml
├── LICENSE
├── README.md
├── SBOutputController.sln
└── .gitignore
/docs/SBOutputController_Main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/heftyy/sb-output-controller/HEAD/docs/SBOutputController_Main.png
--------------------------------------------------------------------------------
/docs/SBOutputController_Setup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/heftyy/sb-output-controller/HEAD/docs/SBOutputController_Setup.png
--------------------------------------------------------------------------------
/SBOutputController/output_toggle_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/heftyy/sb-output-controller/HEAD/SBOutputController/output_toggle_icon.ico
--------------------------------------------------------------------------------
/SBOutputController/Resources/output_toggle_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/heftyy/sb-output-controller/HEAD/SBOutputController/Resources/output_toggle_icon.ico
--------------------------------------------------------------------------------
/SBOutputController/Resources/baseline_error_black_36dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/heftyy/sb-output-controller/HEAD/SBOutputController/Resources/baseline_error_black_36dp.png
--------------------------------------------------------------------------------
/SBOutputController/Resources/baseline_error_white_36dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/heftyy/sb-output-controller/HEAD/SBOutputController/Resources/baseline_error_white_36dp.png
--------------------------------------------------------------------------------
/SBOutputController/Resources/baseline_headset_black_36dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/heftyy/sb-output-controller/HEAD/SBOutputController/Resources/baseline_headset_black_36dp.png
--------------------------------------------------------------------------------
/SBOutputController/Resources/baseline_headset_white_36dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/heftyy/sb-output-controller/HEAD/SBOutputController/Resources/baseline_headset_white_36dp.png
--------------------------------------------------------------------------------
/SBOutputController/Resources/baseline_speaker_black_36dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/heftyy/sb-output-controller/HEAD/SBOutputController/Resources/baseline_speaker_black_36dp.png
--------------------------------------------------------------------------------
/SBOutputController/Resources/baseline_speaker_white_36dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/heftyy/sb-output-controller/HEAD/SBOutputController/Resources/baseline_speaker_white_36dp.png
--------------------------------------------------------------------------------
/SBOutputController/Resources/headphones_speaker_toggle_black_36p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/heftyy/sb-output-controller/HEAD/SBOutputController/Resources/headphones_speaker_toggle_black_36p.png
--------------------------------------------------------------------------------
/SBOutputController/Resources/headphones_speaker_toggle_white_36p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/heftyy/sb-output-controller/HEAD/SBOutputController/Resources/headphones_speaker_toggle_white_36p.png
--------------------------------------------------------------------------------
/SBOutputController/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace SBOutputController
4 | {
5 | public partial class App : Application
6 | {
7 | public App()
8 | {
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/SBOutputController/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/SBOutputController/EqualizerAPO.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace SBOutputController
4 | {
5 | class EqualizerAPO
6 | {
7 | public static void UpdateEqualizer(DeviceOutputModes output_mode)
8 | {
9 | string source_path = output_mode == DeviceOutputModes.Headphones ? Properties.Settings.Default.EqualizerFilePathHeadphones : Properties.Settings.Default.EqualizerFilePathSpeakers;
10 | string target_path = Properties.Settings.Default.EqualizerFilePathConfig;
11 |
12 | string source_content = File.ReadAllText(source_path);
13 | File.WriteAllText(target_path, source_content);
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: build-{build}
2 | configuration: Release
3 | skip_non_tags: true
4 | platform: x86
5 | before_build:
6 | - cmd: echo %APPVEYOR_REPO_TAG_NAME% > SBOutputController\version.txt
7 | build:
8 | verbosity: minimal
9 | after_build:
10 | - cmd: 7z a sb_output_controller_%APPVEYOR_REPO_TAG_NAME%.zip %APPVEYOR_BUILD_FOLDER%\SBOutputController\bin\x86\Release\*
11 | artifacts:
12 | - path: sb_output_controller_%APPVEYOR_REPO_TAG_NAME%.zip
13 | name: sb_output_controller
14 | deploy:
15 | - provider: GitHub
16 | auth_token:
17 | secure: NmYiWU0cS/AkZpWQ9O12oJsMbB30T0fpylZlc3yK60Lbn+ZIpaPDAsDIZ4QAFqY/
18 | artifact: sb_output_controller
19 | on:
20 | branch: main
21 |
--------------------------------------------------------------------------------
/SBOutputController/HotKeyEditorControl.xaml:
--------------------------------------------------------------------------------
1 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Szymon Nowik
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/SBOutputController/FileBrowseControl.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/SBOutputController/SBOutputController.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Project
5 | C:\Program Files %28x86%29\Creative\Sound Blaster Connect 2\Creative.SBConnect.exe
6 | C:\Program Files %28x86%29\Creative\Sound Blaster Connect 2\
7 | true
8 |
9 |
10 | E:\SBOutputController\|publish\
11 |
12 |
13 |
14 |
15 |
16 | en-US
17 | false
18 |
19 |
20 | C:\Program Files %28x86%29\Creative\Sound Blaster Command\Creative.SBCommand.exe
21 |
22 |
23 | true
24 | Project
25 |
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SBOutputController for Sound BlasterX G6
2 | What it can do:
3 | * Assign global hotkeys to switch between sound outputs
4 | * Keep your EqualizerAPO config.txt up to date depending on the sound output
5 | * Run on windows startup
6 |
7 | 
8 |
9 | ## How to use:
10 | 1. Install Sound Blaster Command
11 | 2. Download latest version of SBOutputController from https://github.com/heftyy/sb-output-controller/releases
12 | 3. After starting the application you will be asked to go through the initial setup
13 |
14 | 
15 |
16 | 4. Browse to the directory where Sound Blaster Command is installed and find Creative.SBCommand.exe
17 | (SBOutputController uses the .dlls that are installed with Sound Blaster Command to do the actual output switching and monitoring which output is currently active)
18 | 5. Register SndCrUSB.DLL by clicking the Register button in the setup window.
19 | This will require admin privileges to run the windows utility regsvr32 that adds the dll to the registery. This is the easiest way I found to make my application recognize that dll.
20 | 6. Click finish in the setup window.
21 | 7. Assign hotkeys.
22 | 8. (Optional) Enable the EqualizerAPO checkbox and browse for config files.
23 | 9. Press the hotkey :)
24 |
--------------------------------------------------------------------------------
/SBOutputController.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30413.136
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SBOutputController", "SBOutputController\SBOutputController.csproj", "{BEE89AB0-22F1-432C-8A11-16251BF2686F}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Debug|x86 = Debug|x86
12 | Release|Any CPU = Release|Any CPU
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {BEE89AB0-22F1-432C-8A11-16251BF2686F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {BEE89AB0-22F1-432C-8A11-16251BF2686F}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {BEE89AB0-22F1-432C-8A11-16251BF2686F}.Debug|x86.ActiveCfg = Debug|x86
19 | {BEE89AB0-22F1-432C-8A11-16251BF2686F}.Debug|x86.Build.0 = Debug|x86
20 | {BEE89AB0-22F1-432C-8A11-16251BF2686F}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {BEE89AB0-22F1-432C-8A11-16251BF2686F}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {BEE89AB0-22F1-432C-8A11-16251BF2686F}.Release|x86.ActiveCfg = Release|x86
23 | {BEE89AB0-22F1-432C-8A11-16251BF2686F}.Release|x86.Build.0 = Release|x86
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {BE12F71D-DDD4-46D0-B073-E822E9533D58}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/SBOutputController/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | C:\Program Files (x86)\Creative\Sound Blaster Command\Creative.SBCommand.exe
7 |
8 |
9 | G6
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Ctrl + Shift + D0
19 |
20 |
21 | C:\Program Files\EqualizerAPO\config\headphones.txt
22 |
23 |
24 | C:\Program Files\EqualizerAPO\config\speakers.txt
25 |
26 |
27 | C:\Program Files\EqualizerAPO\config\config.txt
28 |
29 |
30 | False
31 |
32 |
33 | False
34 |
35 |
36 | False
37 |
38 |
39 | False
40 |
41 |
42 |
--------------------------------------------------------------------------------
/SBOutputController/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("SBConnectController")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("SBConnectController")]
15 | [assembly: AssemblyCopyright("Copyright © 2020")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | //In order to begin building localizable applications, set
25 | //CultureYouAreCodingWith in your .csproj file
26 | //inside a . For example, if you are using US english
27 | //in your source files, set the to en-US. Then uncomment
28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
29 | //the line below to match the UICulture setting in the project file.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
36 | //(used if a resource is not found in the page,
37 | // or application resource dictionaries)
38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
39 | //(used if a resource is not found in the page,
40 | // app, or any theme specific resource dictionaries)
41 | )]
42 |
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/SBOutputController/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | C:\Program Files (x86)\Creative\Sound Blaster Command\Creative.SBCommand.exe
17 |
18 |
19 | G6
20 |
21 |
22 | Ctrl + Shift + D0
23 |
24 |
25 | C:\Program Files\EqualizerAPO\config\headphones.txt
26 |
27 |
28 | C:\Program Files\EqualizerAPO\config\speakers.txt
29 |
30 |
31 | C:\Program Files\EqualizerAPO\config\config.txt
32 |
33 |
34 | False
35 |
36 |
37 | False
38 |
39 |
40 | False
41 |
42 |
43 | False
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/SBOutputController/HotKeyEditorControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Input;
3 |
4 | namespace SBOutputController
5 | {
6 | public partial class HotKeyEditorControl
7 | {
8 | public static readonly DependencyProperty HotKeyProperty =
9 | DependencyProperty.Register(nameof(HotKey), typeof(HotKey),
10 | typeof(HotKeyEditorControl),
11 | new FrameworkPropertyMetadata(default(HotKey),
12 | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
13 |
14 | public HotKey HotKey
15 | {
16 | get => (HotKey)GetValue(HotKeyProperty);
17 | set
18 | {
19 | SetValue(HotKeyProperty, value);
20 | RaiseEvent(new RoutedEventArgs(HotKeyChangedEvent));
21 | }
22 | }
23 |
24 | public static readonly RoutedEvent HotKeyChangedEvent = EventManager.RegisterRoutedEvent("HotKeyChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(HotKeyEditorControl));
25 |
26 | public event RoutedEventHandler HotKeyChanged
27 | {
28 | add { AddHandler(HotKeyChangedEvent, value); }
29 | remove { RemoveHandler(HotKeyChangedEvent, value); }
30 | }
31 |
32 | public HotKeyEditorControl()
33 | {
34 | InitializeComponent();
35 |
36 | GotKeyboardFocus += HotKeyEditorControl_GotKeyboardFocus;
37 | }
38 |
39 | private void HotKeyEditorControl_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
40 | {
41 | HotKeyTextBox.Text = "Recording...";
42 | }
43 |
44 | private void HotKeyTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
45 | {
46 | // Don't let the event pass further
47 | // because we don't want standard textbox shortcuts working
48 | e.Handled = true;
49 |
50 | // Get modifiers and key data
51 | var modifiers = Keyboard.Modifiers;
52 | var key = e.Key;
53 |
54 | // When Alt is pressed, SystemKey is used instead
55 | if (key == Key.System)
56 | {
57 | key = e.SystemKey;
58 | }
59 |
60 | // Pressing delete, backspace or escape without modifiers clears the current value
61 | if (modifiers == ModifierKeys.None && (key == Key.Delete || key == Key.Back || key == Key.Escape))
62 | {
63 | HotKey = null;
64 | return;
65 | }
66 |
67 | // If no actual key was pressed or no modifiers were held - return
68 | if (key == Key.LeftCtrl ||
69 | key == Key.RightCtrl ||
70 | key == Key.LeftAlt ||
71 | key == Key.RightAlt ||
72 | key == Key.LeftShift ||
73 | key == Key.RightShift ||
74 | key == Key.LWin ||
75 | key == Key.RWin ||
76 | key == Key.Clear ||
77 | key == Key.OemClear ||
78 | key == Key.Apps ||
79 | modifiers == ModifierKeys.None)
80 | {
81 | return;
82 | }
83 |
84 | // Update the value
85 | HotKey = new HotKey(key, modifiers);
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # exclude the generated version file
10 | SBOutputController/version.txt
11 |
12 | # Build results
13 |
14 | [Dd]ebug/
15 | [Rr]elease/
16 | x64/
17 | build/
18 | build_debug/
19 | build_release/
20 | out/
21 | [Bb]in/
22 | [Oo]bj/
23 | enc_temp_folder/
24 |
25 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
26 | !packages/*/build/
27 |
28 | # MSTest test Results
29 | [Tt]est[Rr]esult*/
30 | [Bb]uild[Ll]og.*
31 |
32 | *_i.c
33 | *_p.c
34 | *.ilk
35 | *.meta
36 | *.obj
37 | *.pch
38 | *.pdb
39 | *.pgc
40 | *.pgd
41 | *.rsp
42 | *.sbr
43 | *.tlb
44 | *.tli
45 | *.tlh
46 | *.tmp
47 | *.tmp_proj
48 | *.log
49 | *.vspscc
50 | *.vssscc
51 | .builds
52 | *.pidb
53 | *.log
54 | *.scc
55 |
56 | # Visual C++ cache files
57 | ipch/
58 | *.aps
59 | *.ncb
60 | *.opensdf
61 | *.sdf
62 | *.cachefile
63 |
64 | # Visual Studio profiler
65 | *.psess
66 | *.vsp
67 | *.vspx
68 |
69 | # Guidance Automation Toolkit
70 | *.gpState
71 |
72 | # ReSharper is a .NET coding add-in
73 | _ReSharper*/
74 | *.[Rr]e[Ss]harper
75 |
76 | # TeamCity is a build add-in
77 | _TeamCity*
78 |
79 | # DotCover is a Code Coverage Tool
80 | *.dotCover
81 |
82 | # NCrunch
83 | *.ncrunch*
84 | .*crunch*.local.xml
85 |
86 | # Installshield output folder
87 | [Ee]xpress/
88 |
89 | # DocProject is a documentation generator add-in
90 | DocProject/buildhelp/
91 | DocProject/Help/*.HxT
92 | DocProject/Help/*.HxC
93 | DocProject/Help/*.hhc
94 | DocProject/Help/*.hhk
95 | DocProject/Help/*.hhp
96 | DocProject/Help/Html2
97 | DocProject/Help/html
98 |
99 | # Click-Once directory
100 | publish/
101 |
102 | # Publish Web Output
103 | *.Publish.xml
104 |
105 | # NuGet Packages Directory
106 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
107 | #packages/
108 |
109 | # Windows Azure Build Output
110 | csx
111 | *.build.csdef
112 |
113 | # Windows Store app package directory
114 | AppPackages/
115 |
116 | # Others
117 | sql/
118 | *.Cache
119 | ClientBin/
120 | [Ss]tyle[Cc]op.*
121 | ~$*
122 | *~
123 | *.dbmdl
124 | *.[Pp]ublish.xml
125 | *.pfx
126 | *.publishsettings
127 |
128 | # RIA/Silverlight projects
129 | Generated_Code/
130 |
131 | # Backup & report files from converting an old project file to a newer
132 | # Visual Studio version. Backup files are not needed, because we have git ;-)
133 | _UpgradeReport_Files/
134 | Backup*/
135 | UpgradeLog*.XML
136 | UpgradeLog*.htm
137 |
138 | # SQL Server files
139 | App_Data/*.mdf
140 | App_Data/*.ldf
141 |
142 |
143 | #LightSwitch generated files
144 | GeneratedArtifacts/
145 | _Pvt_Extensions/
146 | ModelManifest.xml
147 |
148 | # =========================
149 | # Windows detritus
150 | # =========================
151 |
152 | # Windows image file caches
153 | Thumbs.db
154 | ehthumbs.db
155 |
156 | # Folder config file
157 | Desktop.ini
158 |
159 | # Recycle Bin used on file shares
160 | $RECYCLE.BIN/
161 |
162 | # Mac desktop service store files
163 | .DS_Store
164 |
165 | .idea/
166 | .vs/
167 | .vscode/
168 | _build/
169 | Testing/
170 | testBin/
171 | CMakeFiles/
172 | Makefile
173 | CTestTestfile.cmake
174 | CMakeCache.txt
175 | cmake_install.cmake
176 |
--------------------------------------------------------------------------------
/SBOutputController/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace SBOutputController.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SBOutputController.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
65 | ///
66 | internal static System.Drawing.Icon output_toggle_icon {
67 | get {
68 | object obj = ResourceManager.GetObject("output_toggle_icon", resourceCulture);
69 | return ((System.Drawing.Icon)(obj));
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/SBOutputController/Properties/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
48 |
55 |
56 |
70 |
--------------------------------------------------------------------------------
/SBOutputController/DependenciesSetup.xaml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Win32;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.IO;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace SBOutputController
10 | {
11 | public partial class DependenciesSetup
12 | {
13 | public DependenciesSetup(string sb_exe_path)
14 | {
15 | InitializeComponent();
16 |
17 | GridRequiredDll.IsEnabled = false;
18 | FileBrowserSBExecutablePath.FilePath = sb_exe_path;
19 | }
20 |
21 | private async void ListLoadedDlls_RegisterRequiredDll(object sender, RoutedEventArgs e)
22 | {
23 | SBRequiredDLL required_dll = (SBRequiredDLL)GridRequiredDll.SelectedItem;
24 | if (required_dll.Status == DLLLoadedStatus.Registered)
25 | {
26 | return;
27 | }
28 |
29 | string quoted_dll_path = String.Format("\"{0}\"", required_dll.FullPath);
30 | ProcessStartInfo start_info = new ProcessStartInfo("regsvr32.exe", quoted_dll_path)
31 | {
32 | UseShellExecute = true,
33 | Verb = "runas"
34 | };
35 | Process.Start(start_info);
36 |
37 | await Task.Delay(2000);
38 |
39 | GridRequiredDll.ItemsSource = SBController.GetRequiredDLLs(Path.GetDirectoryName(FileBrowserSBExecutablePath.FilePath));
40 | ButtonSetupFinish.IsEnabled = SBController.VerifySetup(FileBrowserSBExecutablePath.FilePath);
41 | }
42 |
43 | private void FileBrowserSBExecutablePath_FilePathChanged(object sender, RoutedEventArgs e)
44 | {
45 | string path = FileBrowserSBExecutablePath.FilePath;
46 | if (SBController.VerifyExecutablePath(path))
47 | {
48 | LabelExecutableNotLoaded.Visibility = Visibility.Collapsed;
49 | GridRequiredDll.IsEnabled = true;
50 |
51 | string sb_directory = Path.GetDirectoryName(path);
52 | GridRequiredDll.ItemsSource = SBController.GetRequiredDLLs(sb_directory);
53 | ButtonSetupFinish.IsEnabled = SBController.VerifySetup(FileBrowserSBExecutablePath.FilePath);
54 | }
55 | else
56 | {
57 | LabelExecutableNotLoaded.Visibility = Visibility.Visible;
58 | GridRequiredDll.IsEnabled = false;
59 | GridRequiredDll.ItemsSource = new List();
60 | ButtonSetupFinish.IsEnabled = false;
61 | }
62 | }
63 |
64 | private void ButtonSetupFinish_Click(object sender, RoutedEventArgs e)
65 | {
66 | Close();
67 | }
68 |
69 | private void CheckboxRunOnStartup_Changed(object sender, RoutedEventArgs e)
70 | {
71 | if (!IsInitialized)
72 | return;
73 |
74 | #if DEBUG
75 | string application_name = "SBOutputController (Debug)";
76 | #else
77 | string application_name = "SBOutputController";
78 | #endif
79 |
80 | var path = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run";
81 | RegistryKey key = Registry.CurrentUser.OpenSubKey(path, true);
82 |
83 | if (Properties.Settings.Default.RunOnStartup)
84 | {
85 | key.SetValue(application_name, System.Reflection.Assembly.GetExecutingAssembly().Location);
86 | }
87 | else
88 | {
89 | key.DeleteValue(application_name, false);
90 | }
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/SBOutputController/FileBrowseControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 |
4 | namespace SBOutputController
5 | {
6 | public partial class FileBrowseControl : UserControl
7 | {
8 | public static readonly DependencyProperty FilePathProperty =
9 | DependencyProperty.Register(nameof(FilePath), typeof(string),
10 | typeof(FileBrowseControl),
11 | new FrameworkPropertyMetadata(default(string),
12 | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
13 |
14 | public static readonly DependencyProperty InitialDirectoryProperty =
15 | DependencyProperty.Register(nameof(InitialDirectory), typeof(string),
16 | typeof(FileBrowseControl), new FrameworkPropertyMetadata(""));
17 |
18 | public static readonly DependencyProperty InitialFilenameProperty =
19 | DependencyProperty.Register(nameof(InitialFilename), typeof(string),
20 | typeof(FileBrowseControl), new FrameworkPropertyMetadata(""));
21 |
22 | public static readonly DependencyProperty DefaultExtProperty =
23 | DependencyProperty.Register(nameof(DefaultExt), typeof(string),
24 | typeof(FileBrowseControl), new FrameworkPropertyMetadata(""));
25 |
26 | public static readonly DependencyProperty FilterProperty =
27 | DependencyProperty.Register(nameof(Filter), typeof(string),
28 | typeof(FileBrowseControl), new FrameworkPropertyMetadata(""));
29 |
30 | public string FilePath
31 | {
32 | get => (string)GetValue(FilePathProperty);
33 | set
34 | {
35 | SetValue(FilePathProperty, value);
36 | RaiseEvent(new RoutedEventArgs(FilePathChangedEvent));
37 | }
38 | }
39 |
40 | public string InitialDirectory
41 | {
42 | get => (string)GetValue(InitialDirectoryProperty);
43 | set => SetValue(InitialDirectoryProperty, value);
44 | }
45 |
46 | public string InitialFilename
47 | {
48 | get => (string)GetValue(InitialFilenameProperty);
49 | set => SetValue(InitialFilenameProperty, value);
50 | }
51 |
52 | public string DefaultExt
53 | {
54 | get => (string)GetValue(DefaultExtProperty);
55 | set => SetValue(DefaultExtProperty, value);
56 | }
57 |
58 | public string Filter
59 | {
60 | get => (string)GetValue(FilterProperty);
61 | set => SetValue(FilterProperty, value);
62 | }
63 |
64 | public static readonly RoutedEvent FilePathChangedEvent = EventManager.RegisterRoutedEvent("FilePathChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(FileBrowseControl));
65 |
66 | public event RoutedEventHandler FilePathChanged
67 | {
68 | add { AddHandler(FilePathChangedEvent, value); }
69 | remove { RemoveHandler(FilePathChangedEvent, value); }
70 | }
71 |
72 | public FileBrowseControl()
73 | {
74 | InitializeComponent();
75 | }
76 |
77 | private void ButtonBrowseFilePath_Click(object sender, RoutedEventArgs e)
78 | {
79 | Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog
80 | {
81 | InitialDirectory = InitialDirectory,
82 | FileName = InitialFilename,
83 | DefaultExt = DefaultExt,
84 | Filter = Filter,
85 | CheckFileExists = true
86 | };
87 |
88 | bool? result = dlg.ShowDialog();
89 | if (result == true)
90 | {
91 | FilePath = dlg.FileName;
92 | }
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/SBOutputController/KeyboardHook.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.InteropServices;
4 | using System.Windows.Forms;
5 | using System.Windows.Input;
6 |
7 | namespace SBOutputController
8 | {
9 | public sealed class KeyboardHook : IDisposable
10 | {
11 | [DllImport("user32.dll")]
12 | private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
13 | [DllImport("user32.dll")]
14 | private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
15 |
16 | private class Window : NativeWindow, IDisposable
17 | {
18 | private static readonly int WM_HOTKEY = 0x0312;
19 |
20 | public Window()
21 | {
22 | // create the handle for the window.
23 | this.CreateHandle(new CreateParams());
24 | }
25 |
26 | protected override void WndProc(ref Message m)
27 | {
28 | base.WndProc(ref m);
29 |
30 | // check if we got a hot key pressed.
31 | if (m.Msg == WM_HOTKEY)
32 | {
33 | // get the keys.
34 | Key key = KeyInterop.KeyFromVirtualKey(((int)m.LParam >> 16) & 0xFFFF);
35 | ModifierKeys modifier = (ModifierKeys)((int)m.LParam & 0xFFFF);
36 |
37 | // invoke the event to notify the parent.
38 | KeyPressedNative?.Invoke(this, new KeyPressedEventArgs(new HotKey(key, modifier)));
39 | }
40 | }
41 |
42 | public event EventHandler KeyPressedNative;
43 |
44 | public void Dispose()
45 | {
46 | this.DestroyHandle();
47 | }
48 | }
49 |
50 | private readonly Window _window = new Window();
51 | private readonly Dictionary _registeredHotKeys = new Dictionary();
52 | private int _currentId;
53 |
54 | public KeyboardHook()
55 | {
56 | // register the event of the inner native window.
57 | _window.KeyPressedNative += delegate (object sender, KeyPressedEventArgs args)
58 | {
59 | KeyPressed(this, args);
60 | };
61 | }
62 |
63 | public void RegisterHotKey(HotKey hotkey)
64 | {
65 | if (hotkey == null || hotkey.Key == Key.None)
66 | return;
67 |
68 | // increment the counter.
69 | _currentId += 1;
70 |
71 | // register the hot key.
72 | if (!RegisterHotKey(_window.Handle, _currentId, (uint)hotkey.Modifiers, (uint)KeyInterop.VirtualKeyFromKey(hotkey.Key)))
73 | throw new InvalidOperationException("Couldn’t register the hot key.");
74 |
75 | _registeredHotKeys[hotkey] = _currentId;
76 | }
77 |
78 | public void UnregisterHotKey(HotKey hotkey)
79 | {
80 | int id_to_unregister;
81 | if (hotkey != null && _registeredHotKeys.TryGetValue(hotkey, out id_to_unregister))
82 | {
83 | UnregisterHotKey(_window.Handle, id_to_unregister);
84 | _registeredHotKeys.Remove(hotkey);
85 | }
86 | }
87 |
88 | public event EventHandler KeyPressed;
89 |
90 | public void Dispose()
91 | {
92 | // unregister all the registered hot keys.
93 | foreach(int id in _registeredHotKeys.Values)
94 | {
95 | UnregisterHotKey(_window.Handle, id);
96 | }
97 |
98 | // dispose the inner native window.
99 | _window.Dispose();
100 | }
101 | }
102 |
103 | public class KeyPressedEventArgs : EventArgs
104 | {
105 | internal KeyPressedEventArgs(HotKey hotkey)
106 | {
107 | HotKey = hotkey;
108 | }
109 |
110 | public HotKey HotKey { get; }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/SBOutputController/HotKey.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Text;
4 | using System.Windows.Input;
5 |
6 | namespace SBOutputController
7 | {
8 | [TypeConverter(typeof(HotKeyConverter))]
9 | public class HotKey
10 | {
11 | public Key Key { get; } = Key.None;
12 |
13 | public ModifierKeys Modifiers { get; } = ModifierKeys.None;
14 |
15 | public HotKey(Key key, ModifierKeys modifiers)
16 | {
17 | Key = key;
18 | Modifiers = modifiers;
19 | }
20 |
21 | public HotKey(string hotkey)
22 | {
23 | Modifiers = ModifiersFromString(hotkey);
24 | Key = KeyFromString(hotkey);
25 | }
26 |
27 | private ModifierKeys ModifiersFromString(string hotkey)
28 | {
29 | ModifierKeys modifiers = ModifierKeys.None;
30 |
31 | if (hotkey.Contains("Ctrl"))
32 | modifiers |= ModifierKeys.Control;
33 | if (hotkey.Contains("Shift"))
34 | modifiers |= ModifierKeys.Shift;
35 | if (hotkey.Contains("Alt"))
36 | modifiers |= ModifierKeys.Alt;
37 | if (hotkey.Contains("Win"))
38 | modifiers |= ModifierKeys.Windows;
39 |
40 | return modifiers;
41 | }
42 |
43 | private Key KeyFromString(string hotkey)
44 | {
45 | hotkey = hotkey.Replace("Ctrl", "").Replace("Shift", "").Replace("Alt", "").Replace("Win", "").Replace(" ", "").Replace("+", "");
46 | foreach (Key key in Enum.GetValues(typeof(Key)))
47 | {
48 | if (hotkey == key.ToString())
49 | {
50 | return key;
51 | }
52 | }
53 | return Key.None;
54 | }
55 |
56 | public override string ToString()
57 | {
58 | if (Key == Key.None)
59 | return "Unassigned";
60 |
61 | var str = new StringBuilder();
62 |
63 | if (Modifiers.HasFlag(ModifierKeys.Control))
64 | str.Append("Ctrl + ");
65 | if (Modifiers.HasFlag(ModifierKeys.Shift))
66 | str.Append("Shift + ");
67 | if (Modifiers.HasFlag(ModifierKeys.Alt))
68 | str.Append("Alt + ");
69 | if (Modifiers.HasFlag(ModifierKeys.Windows))
70 | str.Append("Win + ");
71 |
72 | str.Append(Key);
73 |
74 | return str.ToString();
75 | }
76 |
77 | public override bool Equals(object obj)
78 | {
79 | return obj is HotKey key &&
80 | Key == key.Key &&
81 | Modifiers == key.Modifiers;
82 | }
83 |
84 | public static bool operator==(HotKey lhs, HotKey rhs)
85 | {
86 | if (lhs is null)
87 | {
88 | if (rhs is null)
89 | {
90 | return true;
91 | }
92 | return false;
93 | }
94 | return lhs.Equals(rhs);
95 | }
96 |
97 | public static bool operator!=(HotKey lhs, HotKey rhs)
98 | {
99 | return !(lhs == rhs);
100 | }
101 |
102 | public override int GetHashCode()
103 | {
104 | int hashCode = 34518437;
105 | hashCode = hashCode * -1521134295 + Key.GetHashCode();
106 | hashCode = hashCode * -1521134295 + Modifiers.GetHashCode();
107 | return hashCode;
108 | }
109 | }
110 |
111 | public class HotKeyConverter : TypeConverter
112 | {
113 | public override bool CanConvertFrom(ITypeDescriptorContext context, Type source_type)
114 | {
115 | return source_type == typeof(string) || base.CanConvertFrom(context, source_type);
116 | }
117 |
118 | public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
119 | {
120 | if (value is string string_value && !string.IsNullOrWhiteSpace(string_value))
121 | {
122 | return new HotKey(string_value);
123 | }
124 | return base.ConvertFrom(context, culture, value);
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/SBOutputController/DependenciesSetup.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
47 |
48 |
49 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/SBOutputController/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
122 | ..\Resources\output_toggle_icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
123 |
124 |
--------------------------------------------------------------------------------
/SBOutputController/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace SBOutputController.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 |
26 | [global::System.Configuration.UserScopedSettingAttribute()]
27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
28 | [global::System.Configuration.DefaultSettingValueAttribute("C:\\Program Files (x86)\\Creative\\Sound Blaster Command\\Creative.SBCommand.exe")]
29 | public string SBExecutablePath {
30 | get {
31 | return ((string)(this["SBExecutablePath"]));
32 | }
33 | set {
34 | this["SBExecutablePath"] = value;
35 | }
36 | }
37 |
38 | [global::System.Configuration.UserScopedSettingAttribute()]
39 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
40 | [global::System.Configuration.DefaultSettingValueAttribute("G6")]
41 | public string LastSelectedDevice {
42 | get {
43 | return ((string)(this["LastSelectedDevice"]));
44 | }
45 | set {
46 | this["LastSelectedDevice"] = value;
47 | }
48 | }
49 |
50 | [global::System.Configuration.UserScopedSettingAttribute()]
51 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
52 | public global::SBOutputController.HotKey HotKeyOutputHeadphones {
53 | get {
54 | return ((global::SBOutputController.HotKey)(this["HotKeyOutputHeadphones"]));
55 | }
56 | set {
57 | this["HotKeyOutputHeadphones"] = value;
58 | }
59 | }
60 |
61 | [global::System.Configuration.UserScopedSettingAttribute()]
62 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
63 | public global::SBOutputController.HotKey HotKeyOutputSpeakers {
64 | get {
65 | return ((global::SBOutputController.HotKey)(this["HotKeyOutputSpeakers"]));
66 | }
67 | set {
68 | this["HotKeyOutputSpeakers"] = value;
69 | }
70 | }
71 |
72 | [global::System.Configuration.UserScopedSettingAttribute()]
73 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
74 | [global::System.Configuration.DefaultSettingValueAttribute("Ctrl + Shift + D0")]
75 | public global::SBOutputController.HotKey HotKeyOutputToggle {
76 | get {
77 | return ((global::SBOutputController.HotKey)(this["HotKeyOutputToggle"]));
78 | }
79 | set {
80 | this["HotKeyOutputToggle"] = value;
81 | }
82 | }
83 |
84 | [global::System.Configuration.UserScopedSettingAttribute()]
85 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
86 | [global::System.Configuration.DefaultSettingValueAttribute("C:\\Program Files\\EqualizerAPO\\config\\headphones.txt")]
87 | public string EqualizerFilePathHeadphones {
88 | get {
89 | return ((string)(this["EqualizerFilePathHeadphones"]));
90 | }
91 | set {
92 | this["EqualizerFilePathHeadphones"] = value;
93 | }
94 | }
95 |
96 | [global::System.Configuration.UserScopedSettingAttribute()]
97 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
98 | [global::System.Configuration.DefaultSettingValueAttribute("C:\\Program Files\\EqualizerAPO\\config\\speakers.txt")]
99 | public string EqualizerFilePathSpeakers {
100 | get {
101 | return ((string)(this["EqualizerFilePathSpeakers"]));
102 | }
103 | set {
104 | this["EqualizerFilePathSpeakers"] = value;
105 | }
106 | }
107 |
108 | [global::System.Configuration.UserScopedSettingAttribute()]
109 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
110 | [global::System.Configuration.DefaultSettingValueAttribute("C:\\Program Files\\EqualizerAPO\\config\\config.txt")]
111 | public string EqualizerFilePathConfig {
112 | get {
113 | return ((string)(this["EqualizerFilePathConfig"]));
114 | }
115 | set {
116 | this["EqualizerFilePathConfig"] = value;
117 | }
118 | }
119 |
120 | [global::System.Configuration.UserScopedSettingAttribute()]
121 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
122 | [global::System.Configuration.DefaultSettingValueAttribute("False")]
123 | public bool EqualizerEnabled {
124 | get {
125 | return ((bool)(this["EqualizerEnabled"]));
126 | }
127 | set {
128 | this["EqualizerEnabled"] = value;
129 | }
130 | }
131 |
132 | [global::System.Configuration.UserScopedSettingAttribute()]
133 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
134 | [global::System.Configuration.DefaultSettingValueAttribute("False")]
135 | public bool RunOnStartup {
136 | get {
137 | return ((bool)(this["RunOnStartup"]));
138 | }
139 | set {
140 | this["RunOnStartup"] = value;
141 | }
142 | }
143 |
144 | [global::System.Configuration.UserScopedSettingAttribute()]
145 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
146 | [global::System.Configuration.DefaultSettingValueAttribute("False")]
147 | public bool HeadphonesDirectMode {
148 | get {
149 | return ((bool)(this["HeadphonesDirectMode"]));
150 | }
151 | set {
152 | this["HeadphonesDirectMode"] = value;
153 | }
154 | }
155 |
156 | [global::System.Configuration.UserScopedSettingAttribute()]
157 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
158 | [global::System.Configuration.DefaultSettingValueAttribute("False")]
159 | public bool SpeakersDirectMode {
160 | get {
161 | return ((bool)(this["SpeakersDirectMode"]));
162 | }
163 | set {
164 | this["SpeakersDirectMode"] = value;
165 | }
166 | }
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/SBOutputController/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
78 |
79 |
80 |
85 |
90 |
95 |
96 |
97 |
98 |
99 |
100 |
102 |
103 |
105 |
106 |
109 |
112 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/SBOutputController/SBOutputController.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {BEE89AB0-22F1-432C-8A11-16251BF2686F}
8 | WinExe
9 | SBOutputController
10 | SBOutputController
11 | v4.7.2
12 | 512
13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 4
15 | true
16 | true
17 | false
18 | E:\SBOutputController\
19 | true
20 | Disk
21 | false
22 | Foreground
23 | 7
24 | Days
25 | false
26 | false
27 | true
28 | en-001
29 | SBOutputController
30 | SZNO
31 | SBOutputController
32 | true
33 | 0
34 | 1.0.0.%2a
35 | false
36 | true
37 |
38 |
39 | AnyCPU
40 | true
41 | full
42 | false
43 | bin\Debug\
44 | DEBUG;TRACE
45 | prompt
46 | 4
47 |
48 |
49 | false
50 | true
51 |
52 |
53 | AnyCPU
54 | pdbonly
55 | true
56 | bin\Release\
57 | TRACE
58 | prompt
59 | 4
60 |
61 |
62 | true
63 | bin\x86\Debug\
64 | DEBUG;TRACE
65 | full
66 | x86
67 | 7.3
68 | prompt
69 | MinimumRecommendedRules.ruleset
70 | true
71 |
72 |
73 | bin\x86\Release\
74 | TRACE
75 | true
76 | pdbonly
77 | x86
78 | 7.3
79 | prompt
80 | MinimumRecommendedRules.ruleset
81 | true
82 |
83 |
84 | false
85 |
86 |
87 | true
88 |
89 |
90 | false
91 |
92 |
93 | SBOutputController.App
94 |
95 |
96 | output_toggle_icon.ico
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | 4.0
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | MSBuild:Compile
123 | Designer
124 |
125 |
126 |
127 | FileBrowseControl.xaml
128 |
129 |
130 |
131 | HotKeyEditorControl.xaml
132 |
133 |
134 |
135 | True
136 | True
137 | Resources.resx
138 |
139 |
140 |
141 | DependenciesSetup.xaml
142 |
143 |
144 | Designer
145 | MSBuild:Compile
146 |
147 |
148 | Designer
149 | MSBuild:Compile
150 |
151 |
152 | MSBuild:Compile
153 | Designer
154 |
155 |
156 | App.xaml
157 | Code
158 |
159 |
160 | MainWindow.xaml
161 | Code
162 |
163 |
164 | Designer
165 | MSBuild:Compile
166 |
167 |
168 |
169 |
170 | Code
171 |
172 |
173 | True
174 | Settings.settings
175 | True
176 |
177 |
178 | SettingsSingleFileGenerator
179 | Settings.Designer.cs
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 | False
188 | Microsoft .NET Framework 4.7.2 %28x86 and x64%29
189 | true
190 |
191 |
192 | False
193 | .NET Framework 3.5 SP1
194 | false
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 | PreserveNewest
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 | ResXFileCodeGenerator
222 | Resources.Designer.cs
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
--------------------------------------------------------------------------------
/SBOutputController/SBController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Reflection;
6 |
7 | namespace SBOutputController
8 | {
9 | public class DeviceWrapper
10 | {
11 | public DeviceWrapper(dynamic device)
12 | {
13 | NativeDevice = device;
14 | DeviceName = device.DeviceName;
15 | }
16 |
17 | public string DeviceName { get; }
18 | public dynamic NativeDevice { get; }
19 | }
20 |
21 | class NoDevicesFound : Exception
22 | {
23 | public NoDevicesFound(string message)
24 | : base(message)
25 | { }
26 | }
27 |
28 | class MethodNotFound : Exception
29 | {
30 | public MethodNotFound(string message)
31 | : base(message)
32 | { }
33 | }
34 |
35 | enum DeviceOutputModes : uint
36 | {
37 | Speakers = 2U,
38 | Headphones = 4U
39 | }
40 |
41 | enum DirectModeStates : uint
42 | {
43 | Off = 0U,
44 | On = 1U
45 | }
46 |
47 | class OutputModeChangedEventArgs : EventArgs
48 | {
49 | public OutputModeChangedEventArgs(DeviceOutputModes output_mode)
50 | {
51 | OutputMode = output_mode;
52 | }
53 |
54 | public DeviceOutputModes OutputMode { get; }
55 | }
56 |
57 | public enum DLLLoadedStatus
58 | {
59 | Missing,
60 | Registered
61 | }
62 |
63 | public readonly struct SBRequiredDLL
64 | {
65 | public SBRequiredDLL(string cls_id, string relative_path, string full_path, DLLLoadedStatus dll_status)
66 | {
67 | ClsId = cls_id;
68 | RelativePath = relative_path;
69 | FullPath = full_path;
70 | Status = dll_status;
71 | }
72 |
73 | public string ClsId { get; }
74 | public string RelativePath { get; }
75 | public string FullPath { get; }
76 | public DLLLoadedStatus Status { get; }
77 | }
78 |
79 | class SBController
80 | {
81 | public static readonly Dictionary RequiredDllsList = new Dictionary()
82 | {
83 | { "{495E4C24-85ED-4f19-885E-C2D01D7EA26C}", @"Platform\SndCrUSB.dll" }
84 | };
85 |
86 | public static string SbConnectExecutable = @"Creative.SBCommand.exe";
87 | public static string SbConnectPath = @"C:\Program Files (x86)\Creative\Sound Blaster Command\";
88 |
89 | public event EventHandler OutputModeChangedEvent;
90 |
91 | public SBController(string sb_directory)
92 | {
93 | _sbDirectory = sb_directory;
94 | _activeDevice = null;
95 |
96 | Initialize();
97 | }
98 |
99 | private void Initialize()
100 | {
101 | string log4net_dll_path = Path.Combine(_sbDirectory, "Package", "log4net.dll");
102 | string devices_dll_path = Path.Combine(_sbDirectory, "Platform", "Creative.Platform.Devices.dll");
103 |
104 | Assembly.LoadFrom(log4net_dll_path);
105 | _sbDevicesDLL = Assembly.LoadFrom(devices_dll_path);
106 | Type device_manager_type = _sbDevicesDLL.GetType("Creative.Platform.Devices.Models.DeviceManager", true);
107 | Type device_endpoint_selection_service_type = _sbDevicesDLL.GetType("Creative.Platform.Devices.Selections.DeviceEndpointSelectionService", true);
108 |
109 | MethodInfo device_manager_instance_method = device_manager_type.GetMethod("get_Instance");
110 | if (device_manager_instance_method == null)
111 | {
112 | throw new MethodNotFound("Failed to find DeviceManager.Instance");
113 | }
114 | _deviceManager = device_manager_instance_method.Invoke(null, null);
115 | _deviceManager.Initialize();
116 |
117 | if (_deviceManager.DiscoveredDevices.Count == 0)
118 | {
119 | throw new NoDevicesFound("No devices found");
120 | }
121 |
122 | MethodInfo endpoint_service_instance_method = device_endpoint_selection_service_type.GetMethod("get_Instance");
123 | if (endpoint_service_instance_method == null)
124 | {
125 | throw new MethodNotFound("Failed to find DeviceEndpointSelectionService.Instance");
126 | }
127 | _deviceEndpointSelectionService = endpoint_service_instance_method.Invoke(null, null);
128 | }
129 |
130 | public static bool VerifySetup(string exe_path)
131 | {
132 | if (!VerifyExecutablePath(exe_path))
133 | return false;
134 |
135 | string sb_directory = Path.GetDirectoryName(exe_path);
136 | List required_dll_status = GetRequiredDLLs(sb_directory);
137 |
138 | return required_dll_status.All(dll => dll.Status == DLLLoadedStatus.Registered);
139 | }
140 |
141 | public static bool VerifyExecutablePath(string exe_path)
142 | {
143 | return exe_path != null && exe_path.EndsWith(SbConnectExecutable) && File.Exists(exe_path);
144 | }
145 |
146 | public static List GetRequiredDLLs(string sb_directory)
147 | {
148 | var result = new List();
149 |
150 | foreach(var item in RequiredDllsList)
151 | {
152 | using (var classes_root_key = Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.ClassesRoot, Microsoft.Win32.RegistryView.Default))
153 | {
154 | string cls_id = item.Key;
155 |
156 | var cls_id_key =
157 | classes_root_key.OpenSubKey(@"Wow6432Node\CLSID\" + cls_id) ??
158 | classes_root_key.OpenSubKey(@"CLSID\" + cls_id);
159 |
160 | string expected_dll_full_path = Path.Combine(sb_directory, item.Value);
161 |
162 | if (cls_id_key == null)
163 | {
164 | result.Add(new SBRequiredDLL(cls_id, item.Value, expected_dll_full_path, DLLLoadedStatus.Missing));
165 | continue;
166 | }
167 |
168 | var inproc_key = cls_id_key.OpenSubKey("InprocServer32");
169 | cls_id_key.Dispose();
170 | if (inproc_key == null)
171 | {
172 | result.Add(new SBRequiredDLL(cls_id, item.Value, expected_dll_full_path, DLLLoadedStatus.Missing));
173 | continue;
174 | }
175 |
176 | string reg_dll_full_path = inproc_key.GetValue(null).ToString();
177 | inproc_key.Dispose();
178 |
179 | if (reg_dll_full_path != null && string.Compare(reg_dll_full_path, expected_dll_full_path, true) == 0)
180 | {
181 | result.Add(new SBRequiredDLL(cls_id, item.Value, expected_dll_full_path, DLLLoadedStatus.Registered));
182 | }
183 | else
184 | {
185 | result.Add(new SBRequiredDLL(cls_id, item.Value, expected_dll_full_path, DLLLoadedStatus.Missing));
186 | }
187 | }
188 | }
189 |
190 | return result;
191 | }
192 |
193 | public void SetActiveDevice(DeviceWrapper device_wrapper)
194 | {
195 | if (_activeDevice == null || _activeDevice.NativeDevice != device_wrapper.NativeDevice)
196 | {
197 | _activeDevice = device_wrapper;
198 | _outputModeFeature = _deviceEndpointSelectionService.GetAggregatedFeature(device_wrapper.NativeDevice, "MultiplexOutputFeatureId");
199 | _stereoDirectFeature = _deviceEndpointSelectionService.GetAggregatedFeature(device_wrapper.NativeDevice, "StereoDirectFeatureId");
200 |
201 | Type value_changed_delegate_type = _sbDevicesDLL.GetType("Creative.Platform.Devices.Selections.EffectParameterValueChangedDelegate");
202 | dynamic value_changed_delegate = Delegate.CreateDelegate(value_changed_delegate_type, this, "OnOutputModeChanged");
203 | // EffectParameterValueChangedHanlder is the "correct" spelling.... Thanks Creative
204 | _outputModeFeature.EffectParameterValueChangedHanlder += value_changed_delegate;
205 | }
206 | }
207 |
208 | public List GetDevices()
209 | {
210 | List devices = new List();
211 |
212 | foreach (var device in _deviceManager.DiscoveredDevices)
213 | {
214 | devices.Add(new DeviceWrapper(device));
215 | }
216 |
217 | return devices;
218 | }
219 |
220 | public void OnOutputModeChanged(object parameters)
221 | {
222 | if (_activeDevice != null)
223 | {
224 | DeviceOutputModes output_mode = GetOutputModeForDevice(_activeDevice);
225 | OutputModeChangedEvent(this, new OutputModeChangedEventArgs(output_mode));
226 | }
227 | }
228 |
229 | public DeviceOutputModes GetOutputModeForDevice(DeviceWrapper device_wrapper)
230 | {
231 | SetActiveDevice(device_wrapper);
232 |
233 | uint output_mode_value = _outputModeFeature.GetValue("MultiplexOutputParameterId");
234 | return (DeviceOutputModes)output_mode_value;
235 | }
236 |
237 | public void SwitchToOutputMode(DeviceWrapper device_wrapper, DeviceOutputModes requested_output_mode_enum)
238 | {
239 | SetActiveDevice(device_wrapper);
240 |
241 | uint requested_output_mode = (uint)requested_output_mode_enum;
242 | uint output_mode_value = _outputModeFeature.GetValue("MultiplexOutputParameterId");
243 | if (output_mode_value != requested_output_mode)
244 | {
245 | _outputModeFeature.SetValue(requested_output_mode, "MultiplexOutputParameterId");
246 | }
247 | }
248 |
249 | public void SwitchDirectMode(DeviceWrapper device_wrapper, DirectModeStates requested_direct_mode_enum)
250 | {
251 | SetActiveDevice(device_wrapper);
252 |
253 | uint requested_direct_mode = (uint)requested_direct_mode_enum;
254 | uint direct_mode_value = _stereoDirectFeature.GetValue("StereoDirectParameterId");
255 | if (direct_mode_value != requested_direct_mode)
256 | {
257 | _stereoDirectFeature.SetValue(requested_direct_mode, "StereoDirectParameterId");
258 | }
259 | }
260 |
261 | private Assembly _sbDevicesDLL;
262 |
263 | private dynamic _deviceManager;
264 | private dynamic _deviceEndpointSelectionService;
265 | private dynamic _outputModeFeature;
266 | private dynamic _stereoDirectFeature;
267 |
268 | private readonly string _sbDirectory;
269 |
270 | private DeviceWrapper _activeDevice;
271 | }
272 | }
273 |
--------------------------------------------------------------------------------
/SBOutputController/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.IO;
5 | using System.Reflection;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Forms;
9 | using System.Windows.Media;
10 | using ContextMenu = System.Windows.Forms.ContextMenu;
11 |
12 | namespace SBOutputController
13 | {
14 | public partial class MainWindow
15 | {
16 | private SBController _sbConnectApi = null;
17 | private readonly KeyboardHook _keyboardHook = new KeyboardHook();
18 | private readonly NotifyIcon _notifyIcon = new NotifyIcon();
19 | private readonly ContextMenu _notifyIconContextMenu = new ContextMenu();
20 |
21 | private string SBDirectory
22 | {
23 | get => Path.GetDirectoryName(Properties.Settings.Default.SBExecutablePath);
24 | }
25 |
26 | static readonly private Color StatusSuccess = Color.FromRgb(85, 189, 90);
27 | static readonly private Color StatusFailure = Color.FromRgb(189, 92, 92);
28 |
29 | public MainWindow()
30 | {
31 | InitializeComponent();
32 |
33 | string version = "Version unknown";
34 | Assembly this_assembly = Assembly.GetExecutingAssembly();
35 | Stream stream = this_assembly.GetManifestResourceStream(this_assembly.GetName().Name + ".version.txt");
36 | if (stream != null)
37 | {
38 | using (stream)
39 | using (StreamReader reader = new StreamReader(stream))
40 | {
41 | version = reader.ReadToEnd();
42 | }
43 | }
44 |
45 | Title += " - " + version;
46 |
47 | _keyboardHook.KeyPressed += KeyboardHook_HotKeyPressed;
48 | Microsoft.Win32.SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
49 |
50 | HotKeyOutputHeadphones.HotKey = Properties.Settings.Default.HotKeyOutputHeadphones;
51 | HotKeyOutputSpeakers.HotKey = Properties.Settings.Default.HotKeyOutputSpeakers;
52 | HotKeyOutputToggle.HotKey = Properties.Settings.Default.HotKeyOutputToggle;
53 |
54 | var show_menu_item = new System.Windows.Forms.MenuItem
55 | {
56 | Index = 0,
57 | Text = "&Show",
58 | };
59 | show_menu_item.Click += Window_Show;
60 |
61 | var exit_menu_item = new System.Windows.Forms.MenuItem
62 | {
63 | Index = 0,
64 | Text = "E&xit"
65 | };
66 | exit_menu_item.Click += Window_Shutdown;
67 |
68 | _notifyIconContextMenu.MenuItems.Add(show_menu_item);
69 | _notifyIconContextMenu.MenuItems.Add(exit_menu_item);
70 |
71 | _notifyIcon.Icon = Properties.Resources.output_toggle_icon;
72 | _notifyIcon.Visible = false;
73 | _notifyIcon.Text = "SB Output Controller";
74 | _notifyIcon.DoubleClick += Window_Show;
75 | _notifyIcon.ContextMenu = _notifyIconContextMenu;
76 |
77 | CheckboxEqualizerAPO_Changed(this, null);
78 | }
79 |
80 | private void InitializeSBConnect()
81 | {
82 | Directory.SetCurrentDirectory(SBDirectory);
83 |
84 | _sbConnectApi = new SBController(SBDirectory);
85 | _sbConnectApi.OutputModeChangedEvent += SBConnect_OutputModeChanged;
86 |
87 | ListDevices.Items.Clear();
88 | foreach (DeviceWrapper device_wrapper in _sbConnectApi.GetDevices())
89 | {
90 | ListDevices.Items.Add(device_wrapper);
91 | if (device_wrapper.DeviceName == Properties.Settings.Default.LastSelectedDevice)
92 | {
93 | ListDevices.SelectedItem = device_wrapper;
94 | }
95 | }
96 | }
97 |
98 | private void Window_ContentRendered(object sender, EventArgs e)
99 | {
100 | if (!SBController.VerifySetup(Properties.Settings.Default.SBExecutablePath))
101 | {
102 | ButtonOpenSetup_Click(this, null);
103 | }
104 | else
105 | {
106 | SetupChanged(Properties.Settings.Default.SBExecutablePath);
107 | }
108 | }
109 |
110 | private void Window_Show(object sender, EventArgs args)
111 | {
112 | _notifyIcon.Visible = false;
113 |
114 | Show();
115 | Activate();
116 | WindowState = WindowState.Normal;
117 | }
118 |
119 | private void Window_Closing(object sender, CancelEventArgs e)
120 | {
121 | _notifyIcon.Visible = true;
122 |
123 | e.Cancel = true;
124 | Hide();
125 | }
126 |
127 | private void Window_Shutdown(object sender, EventArgs args)
128 | {
129 | _notifyIcon.Dispose();
130 | Properties.Settings.Default.Save();
131 | System.Windows.Application.Current.Shutdown();
132 | }
133 |
134 | private void KeyboardHook_HotKeyPressed(object sender, KeyPressedEventArgs e)
135 | {
136 | HotKey hotkey_pressed = e.HotKey;
137 | if (hotkey_pressed == Properties.Settings.Default.HotKeyOutputHeadphones)
138 | {
139 | ButtonSwitchToHeadphones_Click(sender, null);
140 | }
141 | else if (hotkey_pressed == Properties.Settings.Default.HotKeyOutputSpeakers)
142 | {
143 | ButtonSwitchToSpeakers_Click(sender, null);
144 | }
145 | else if (hotkey_pressed == Properties.Settings.Default.HotKeyOutputToggle)
146 | {
147 | ButtonToggleOutput_Click(sender, null);
148 | }
149 | }
150 |
151 | private void SystemEvents_PowerModeChanged(object sender, Microsoft.Win32.PowerModeChangedEventArgs e)
152 | {
153 | if (e.Mode == Microsoft.Win32.PowerModes.Resume)
154 | {
155 | // Seems like soundblaster needs a little bit of a delay after waking up to be active
156 | // For now I set it to 5s to be on the safe side
157 | System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();
158 | timer.Tick += (_, __) =>
159 | {
160 | timer.Stop();
161 | InitializeSBConnect();
162 | };
163 | timer.Interval = new TimeSpan(0, 0, 5);
164 | timer.Start();
165 | }
166 | }
167 |
168 | private void ButtonOpenSetup_Click(object sender, RoutedEventArgs e)
169 | {
170 | DependenciesSetup setup_window = new DependenciesSetup(Properties.Settings.Default.SBExecutablePath)
171 | {
172 | Owner = this
173 | };
174 | setup_window.ShowDialog();
175 |
176 | string exe_path = setup_window.FileBrowserSBExecutablePath.FilePath;
177 | SetupChanged(exe_path);
178 | }
179 |
180 | private void SetupChanged(string exe_path)
181 | {
182 | TextBoxSetupStatus.Background = new SolidColorBrush(StatusFailure);
183 | PanelSBConnect.IsEnabled = false;
184 | if (SBController.VerifySetup(exe_path))
185 | {
186 | Properties.Settings.Default.SBExecutablePath = exe_path;
187 |
188 | try
189 | {
190 | InitializeSBConnect();
191 |
192 | TextBoxSetupStatus.Text = string.Format("Setup Status");
193 | TextBoxSetupStatus.Background = new SolidColorBrush(StatusSuccess);
194 | PanelSBConnect.IsEnabled = true;
195 | }
196 | catch (Exception ex)
197 | {
198 | TextBoxSetupStatus.Text = string.Format("Setup Status - {0}", ex.Message);
199 | }
200 | }
201 | }
202 |
203 | private void ListDevices_SelectionChanged(object sender, SelectionChangedEventArgs e)
204 | {
205 | DeviceWrapper device_wrapper = (DeviceWrapper)ListDevices.SelectedItem;
206 | if (device_wrapper == null || device_wrapper.DeviceName != "G6")
207 | {
208 | GridOutputButtonsAndHotKeys.IsEnabled = false;
209 | return;
210 | }
211 |
212 | DeviceOutputModes output_mode = _sbConnectApi.GetOutputModeForDevice(device_wrapper);
213 | UpdateDeviceOuputModeView(output_mode);
214 | GridOutputButtonsAndHotKeys.IsEnabled = true;
215 | Properties.Settings.Default.LastSelectedDevice = device_wrapper.DeviceName;
216 | }
217 |
218 | private void SBConnect_OutputModeChanged(object sender, OutputModeChangedEventArgs e)
219 | {
220 | UpdateDeviceOuputModeView(e.OutputMode);
221 | EqualizerConfig_FilePathChanged(this, null);
222 | UpdateDirectMode();
223 | }
224 |
225 | private void UpdateDeviceOuputModeView(DeviceOutputModes output_mode)
226 | {
227 | List output_mode_images = new List
228 | {
229 | OutputModeHeadphonesImage,
230 | OutputModeSpeakersImage,
231 | OutputModeErrorImage
232 | };
233 |
234 | void set_visible_image(Image visible_image)
235 | {
236 | foreach (Image image in output_mode_images)
237 | {
238 | image.Visibility = image == visible_image ? Visibility.Visible : Visibility.Hidden;
239 | }
240 | }
241 |
242 | switch (output_mode)
243 | {
244 | case DeviceOutputModes.Headphones:
245 | set_visible_image(OutputModeHeadphonesImage);
246 | break;
247 | case DeviceOutputModes.Speakers:
248 | set_visible_image(OutputModeSpeakersImage);
249 | break;
250 | default:
251 | set_visible_image(OutputModeErrorImage);
252 | break;
253 | }
254 | }
255 |
256 | private void CheckboxEqualizerAPO_Changed(object sender, RoutedEventArgs e)
257 | {
258 | if (!IsInitialized)
259 | return;
260 |
261 | bool is_checked = CheckboxEqualizerAPO.IsChecked == true;
262 | FileBrowserHeadphonesConfig.IsEnabled = is_checked;
263 | FileBrowserSpeakersConfig.IsEnabled = is_checked;
264 | FileBrowserTargetConfig.IsEnabled = is_checked;
265 |
266 | EqualizerConfig_FilePathChanged(this, null);
267 | }
268 |
269 | private void ButtonSwitchToHeadphones_Click(object sender, RoutedEventArgs e)
270 | {
271 | DeviceWrapper device_wrapper = (DeviceWrapper)ListDevices.SelectedItem;
272 | if (device_wrapper != null)
273 | {
274 | _sbConnectApi.SwitchToOutputMode(device_wrapper, DeviceOutputModes.Headphones);
275 | }
276 | }
277 |
278 | private void ButtonSwitchToSpeakers_Click(object sender, RoutedEventArgs e)
279 | {
280 | DeviceWrapper device_wrapper = (DeviceWrapper)ListDevices.SelectedItem;
281 | if (device_wrapper != null)
282 | {
283 | _sbConnectApi.SwitchToOutputMode(device_wrapper, DeviceOutputModes.Speakers);
284 | }
285 | }
286 |
287 | private void ButtonToggleOutput_Click(object sender, RoutedEventArgs e)
288 | {
289 | DeviceWrapper device_wrapper = (DeviceWrapper)ListDevices.SelectedItem;
290 | if (device_wrapper != null)
291 | {
292 | DeviceOutputModes output_mode = _sbConnectApi.GetOutputModeForDevice(device_wrapper);
293 | DeviceOutputModes desired_output_mode = output_mode == DeviceOutputModes.Headphones ? DeviceOutputModes.Speakers : DeviceOutputModes.Headphones;
294 | _sbConnectApi.SwitchToOutputMode(device_wrapper, desired_output_mode);
295 | }
296 | }
297 |
298 | private void HotKeyHeadphonesOutput_HotKeyChanged(object sender, RoutedEventArgs e)
299 | {
300 | _keyboardHook.UnregisterHotKey(Properties.Settings.Default.HotKeyOutputHeadphones);
301 | _keyboardHook.RegisterHotKey(HotKeyOutputHeadphones.HotKey);
302 | Properties.Settings.Default.HotKeyOutputHeadphones = HotKeyOutputHeadphones.HotKey;
303 | ListDevices.Focus();
304 | }
305 | private void HotKeySpeakersOutput_HotKeyChanged(object sender, RoutedEventArgs e)
306 | {
307 | _keyboardHook.UnregisterHotKey(Properties.Settings.Default.HotKeyOutputSpeakers);
308 | _keyboardHook.RegisterHotKey(HotKeyOutputSpeakers.HotKey);
309 | Properties.Settings.Default.HotKeyOutputSpeakers = HotKeyOutputSpeakers.HotKey;
310 | ListDevices.Focus();
311 | }
312 | private void HotKeyToggleOutput_HotKeyChanged(object sender, RoutedEventArgs e)
313 | {
314 | _keyboardHook.UnregisterHotKey(Properties.Settings.Default.HotKeyOutputToggle);
315 | _keyboardHook.RegisterHotKey(HotKeyOutputToggle.HotKey);
316 | Properties.Settings.Default.HotKeyOutputToggle = HotKeyOutputToggle.HotKey;
317 | ListDevices.Focus();
318 | }
319 |
320 | private void EqualizerConfig_FilePathChanged(object sender, RoutedEventArgs e)
321 | {
322 | DeviceWrapper device_wrapper = (DeviceWrapper)ListDevices.SelectedItem;
323 | if (device_wrapper == null || CheckboxEqualizerAPO.IsChecked == false)
324 | {
325 | return;
326 | }
327 |
328 | try
329 | {
330 | EqualizerAPO.UpdateEqualizer(_sbConnectApi.GetOutputModeForDevice(device_wrapper));
331 | FileBrowserTargetConfig.ToolTip = "Target config - config.txt by default";
332 | FileBrowserTargetConfig.TextBoxFilePath.Background = new SolidColorBrush(Colors.Transparent);
333 | FileBrowserTargetConfig.TextBoxFilePath.Foreground = new SolidColorBrush(Colors.SlateGray);
334 | }
335 | catch (Exception ex)
336 | {
337 | FileBrowserTargetConfig.ToolTip = string.Format("Target config - config.txt by default\n\nUpdating the EQ config file failed.\nError: {0}", ex.Message);
338 | FileBrowserTargetConfig.TextBoxFilePath.Background = new SolidColorBrush(StatusFailure);
339 | FileBrowserTargetConfig.TextBoxFilePath.Foreground = new SolidColorBrush(Colors.White);
340 | }
341 | }
342 |
343 | private void UpdateDirectMode()
344 | {
345 | DeviceWrapper device_wrapper = (DeviceWrapper)ListDevices.SelectedItem;
346 | if (device_wrapper != null)
347 | {
348 | DeviceOutputModes output_mode = _sbConnectApi.GetOutputModeForDevice(device_wrapper);
349 | switch (output_mode)
350 | {
351 | case DeviceOutputModes.Headphones:
352 | {
353 | bool direct_mode_enabled = Properties.Settings.Default.HeadphonesDirectMode;
354 | _sbConnectApi.SwitchDirectMode(device_wrapper, direct_mode_enabled ? DirectModeStates.On : DirectModeStates.Off);
355 | break;
356 | }
357 | case DeviceOutputModes.Speakers:
358 | {
359 | bool direct_mode_enabled = Properties.Settings.Default.SpeakersDirectMode;
360 | _sbConnectApi.SwitchDirectMode(device_wrapper, direct_mode_enabled ? DirectModeStates.On : DirectModeStates.Off);
361 | break;
362 | }
363 | default:
364 | break;
365 | }
366 | }
367 | }
368 |
369 | private void CheckboxHeadphonesDirectMode_Changed(object sender, RoutedEventArgs e)
370 | {
371 | Properties.Settings.Default.HeadphonesDirectMode = HeadphonesDirectMode.IsChecked == true;
372 | UpdateDirectMode();
373 | }
374 |
375 | private void CheckboxSpeakersDirectMode_Changed(object sender, RoutedEventArgs e)
376 | {
377 | Properties.Settings.Default.SpeakersDirectMode = SpeakersDirectMode.IsChecked == true;
378 | UpdateDirectMode();
379 | }
380 | }
381 | }
382 |
--------------------------------------------------------------------------------