Compare commits
	
		
			7 Commits
		
	
	
		
			v1.1.1
			...
			609a7bdb65
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 609a7bdb65 | |||
| 13fdfde3e5 | |||
| bbad79b4f3 | |||
| 708180dc8e | |||
| 5711ace990 | |||
| d89c8b1ffa | |||
| f94052e54b | 
| @ -36,6 +36,7 @@ public class AudioHelper | ||||
| 		manager.GetSessionEnumerator(out var sessionEnumerator); | ||||
|  | ||||
| 		var results = new ActiveAudioSessionWrapper(); | ||||
| 		var currentIndex = int.MaxValue; | ||||
|  | ||||
| 		sessionEnumerator.GetCount(out var count); | ||||
| 		for (int i = 0; i < count; i++) | ||||
| @ -45,23 +46,33 @@ public class AudioHelper | ||||
| 			session.GetProcessId(out var sessionProcessId); | ||||
| 			var audioProcess = Process.GetProcessById(sessionProcessId); | ||||
|  | ||||
| 			if (processes.Any(x => x.Id == sessionProcessId || x.ProcessName == audioProcess?.ProcessName)) | ||||
| 			{ | ||||
| 				try | ||||
| 				{ | ||||
| 					var displayName = audioProcess.MainModule.FileVersionInfo.FileDescription; | ||||
| 					if (string.IsNullOrEmpty(displayName)) | ||||
| 					{ | ||||
| 						displayName = audioProcess.ProcessName; | ||||
| 					} | ||||
| 					results.DisplayName = displayName; | ||||
| 				} | ||||
| 				catch | ||||
| 				{ | ||||
| 					results.DisplayName ??= audioProcess.ProcessName; | ||||
| 				} | ||||
| 			var index = processes.FindIndex(x => x.Id == sessionProcessId || x.ProcessName == audioProcess?.ProcessName); | ||||
|  | ||||
| 				results.ExecutablePath ??= audioProcess.MainModule.FileName; | ||||
| 			if (index > -1) | ||||
| 			{ | ||||
| 				//processes will be ordered from best to worst (starts with the app, goes to parent) | ||||
| 				//so we want the display name and executable path to come from the process that is closest to the front of the list | ||||
| 				//but we want all matching sessions so things like discord work right | ||||
| 				if (index < currentIndex) | ||||
| 				{ | ||||
| 					try | ||||
| 					{ | ||||
| 						var displayName = audioProcess.MainModule.FileVersionInfo.FileDescription; | ||||
| 						if (string.IsNullOrEmpty(displayName)) | ||||
| 						{ | ||||
| 							displayName = audioProcess.ProcessName; | ||||
| 						} | ||||
| 						results.DisplayName = displayName; | ||||
| 					} | ||||
| 					catch | ||||
| 					{ | ||||
| 						results.DisplayName = audioProcess.ProcessName; | ||||
| 					} | ||||
|  | ||||
| 					results.ExecutablePath = audioProcess.MainModule.FileName; | ||||
|  | ||||
| 					currentIndex = index; | ||||
| 				} | ||||
|  | ||||
| 				//some apps like discord have multiple volume processes. | ||||
| 				results.AddSession(session); | ||||
| @ -137,10 +148,21 @@ public class AudioHelper | ||||
|  | ||||
| 		try | ||||
| 		{ | ||||
| 			var blah = ParentProcessUtilities.GetParentProcess(pid); | ||||
| 			if (blah != null && blah.ProcessName != "explorer" && blah.ProcessName != "svchost") | ||||
| 			//note. in instances where you launch a game from steam. this ends up mapping the process to both steam and to the game. which is unfortunate | ||||
| 			//The problem is that if you don't use the parent processes, then the actual steam window won't get recognized. But if you do, then games will map to steam. | ||||
| 			// | ||||
| 			//Additionally, I group all audio processes that match instead of just the most specific, or the first, etc. Because Discord uses two processes, one for voice chat, and one for discord sounds. | ||||
| 			// | ||||
| 			//Steam and Discord are both very common, and end up butting heads in the algorithm. | ||||
| 			//I want to avoid special cases, but since steam and discord are both so common, i'm making an exception. | ||||
| 			var parentProcess = ParentProcessUtilities.GetParentProcess(pid); | ||||
| 			if (parentProcess != null  | ||||
| 				&& parentProcess.ProcessName != "explorer"  | ||||
| 				&& parentProcess.ProcessName != "svchost" | ||||
| 				&& (parentProcess.ProcessName == "steam" && processes.Any(x => x.ProcessName == "steamwebhelper")) //only include steam if the parent process is the steamwebhelper | ||||
| 				) | ||||
| 			{ | ||||
| 				processes.Add(blah); | ||||
| 				processes.Add(parentProcess); | ||||
| 			} | ||||
| 		} | ||||
| 		catch | ||||
|  | ||||
| @ -10,6 +10,11 @@ namespace FocusVolumeControl.AudioSessions | ||||
| 	{ | ||||
| 		public static float GetAdjustedVolume(float startingVolume, int step, int ticks) | ||||
| 		{ | ||||
| 			if(step <= 0) | ||||
| 			{ | ||||
| 				step = 1; | ||||
| 			} | ||||
|  | ||||
| 			var level = startingVolume; | ||||
|  | ||||
| 			level += 0.01f * step * ticks; | ||||
|  | ||||
| @ -26,20 +26,13 @@ public class DialAction : EncoderBase | ||||
| 		{ | ||||
| 			PluginSettings instance = new PluginSettings(); | ||||
| 			instance.FallbackBehavior = FallbackBehavior.SystemSounds; | ||||
| 			instance.StepSize = 1; | ||||
| 			return instance; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	private PluginSettings settings; | ||||
|  | ||||
| 	IntPtr _foregroundWindowChangedEvent; | ||||
| 	Native.WinEventDelegate _delegate; | ||||
|  | ||||
| 	PluginSettings settings; | ||||
| 	AudioHelper _audioHelper = new AudioHelper(); | ||||
|  | ||||
| 	Thread _thread; | ||||
| 	Dispatcher _dispatcher; | ||||
|  | ||||
| 	UIState _previousState; | ||||
|  | ||||
| 	public DialAction(ISDConnection connection, InitialPayload payload) : base(connection, payload) | ||||
| @ -54,19 +47,7 @@ public class DialAction : EncoderBase | ||||
| 			settings = payload.Settings.ToObject<PluginSettings>(); | ||||
| 		} | ||||
|  | ||||
| 		_thread = new Thread(() => | ||||
| 		{ | ||||
| 			Logger.Instance.LogMessage(TracingLevel.DEBUG, "Registering for events"); | ||||
| 			_delegate = new Native.WinEventDelegate(WinEventProc); | ||||
| 			_foregroundWindowChangedEvent = Native.RegisterForForegroundWindowChangedEvent(_delegate); | ||||
|  | ||||
| 			Logger.Instance.LogMessage(TracingLevel.DEBUG, "Starting Dispatcher"); | ||||
| 			_dispatcher = Dispatcher.CurrentDispatcher; | ||||
| 			Dispatcher.Run(); | ||||
| 			Logger.Instance.LogMessage(TracingLevel.DEBUG, "Dispatcher Stopped"); | ||||
| 		}); | ||||
| 		_thread.SetApartmentState(ApartmentState.STA); | ||||
| 		_thread.Start(); | ||||
| 		WindowChangedEventLoop.Instance.WindowChanged += WindowChanged; | ||||
|  | ||||
| 		var session = _audioHelper.GetActiveSession(settings.FallbackBehavior); | ||||
| 		_ = UpdateStateIfNeeded(session); | ||||
| @ -74,19 +55,15 @@ public class DialAction : EncoderBase | ||||
|  | ||||
| 	public override void Dispose() | ||||
| 	{ | ||||
| 		Logger.Instance.LogMessage(TracingLevel.DEBUG, "Disposing"); | ||||
| 		if (_foregroundWindowChangedEvent != IntPtr.Zero) | ||||
| 		{ | ||||
| 			Native.UnhookWinEvent(_foregroundWindowChangedEvent); | ||||
| 		} | ||||
| 		_dispatcher.InvokeShutdown(); | ||||
| 		//Logger.Instance.LogMessage(TracingLevel.DEBUG, "Disposing"); | ||||
| 		WindowChangedEventLoop.Instance.WindowChanged -= WindowChanged; | ||||
| 	} | ||||
|  | ||||
| 	public override async void DialDown(DialPayload payload) | ||||
| 	{ | ||||
| 		try | ||||
| 		{ | ||||
| 			Logger.Instance.LogMessage(TracingLevel.INFO, "Dial Down"); | ||||
| 			//Logger.Instance.LogMessage(TracingLevel.INFO, "Dial Down"); | ||||
| 			await ToggleMuteAsync(); | ||||
| 		} | ||||
| 		catch (Exception ex) | ||||
| @ -100,7 +77,7 @@ public class DialAction : EncoderBase | ||||
| 	{ | ||||
| 		try | ||||
| 		{ | ||||
| 			Logger.Instance.LogMessage(TracingLevel.INFO, "Touch Press"); | ||||
| 			//Logger.Instance.LogMessage(TracingLevel.INFO, "Touch Press"); | ||||
| 			if (payload.IsLongPress) | ||||
| 			{ | ||||
| 				await ResetAllAsync(); | ||||
| @ -120,7 +97,7 @@ public class DialAction : EncoderBase | ||||
| 	{ | ||||
| 		try | ||||
| 		{ | ||||
| 			Logger.Instance.LogMessage(TracingLevel.INFO, "Dial Rotate"); | ||||
| 			//Logger.Instance.LogMessage(TracingLevel.INFO, "Dial Rotate"); | ||||
| 			//dial rotated. ticks positive for right, negative for left | ||||
| 			var activeSession = _audioHelper.Current; | ||||
| 			if (activeSession != null) | ||||
| @ -258,7 +235,7 @@ public class DialAction : EncoderBase | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) | ||||
| 	public void WindowChanged() | ||||
| 	{ | ||||
| 		try | ||||
| 		{ | ||||
| @ -266,7 +243,7 @@ public class DialAction : EncoderBase | ||||
| 		} | ||||
| 		catch (Exception ex) | ||||
| 		{ | ||||
| 			Logger.Instance.LogMessage(TracingLevel.ERROR, $"Unexpected Error in DialDown:\n {ex}"); | ||||
| 			Logger.Instance.LogMessage(TracingLevel.ERROR, $"Unexpected Error in Window Down:\n {ex}"); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -70,6 +70,7 @@ | ||||
|     <Compile Include="Properties\AssemblyInfo.cs" /> | ||||
|     <Compile Include="UI\UIState.cs" /> | ||||
|     <Compile Include="UI\ValueWithOpacity.cs" /> | ||||
|     <Compile Include="WindowChangedEventLoop.cs" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <None Include="App.config" /> | ||||
|  | ||||
							
								
								
									
										54
									
								
								src/FocusVolumeControl/WindowChangedEventLoop.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/FocusVolumeControl/WindowChangedEventLoop.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | ||||
| using BarRaider.SdTools; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Runtime.InteropServices; | ||||
| using System.Text; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| using System.Windows.Threading; | ||||
|  | ||||
| namespace FocusVolumeControl | ||||
| { | ||||
| 	internal class WindowChangedEventLoop | ||||
| 	{ | ||||
| 		private static readonly Lazy<WindowChangedEventLoop> _lazy = new Lazy<WindowChangedEventLoop>(() => new WindowChangedEventLoop()); | ||||
| 		public static WindowChangedEventLoop Instance => _lazy.Value; | ||||
|  | ||||
| 		readonly Thread _thread; | ||||
| 		Dispatcher _dispatcher; | ||||
|  | ||||
| 		IntPtr _foregroundWindowChangedEvent; | ||||
| 		Native.WinEventDelegate _delegate; | ||||
|  | ||||
| 		private WindowChangedEventLoop() | ||||
| 		{ | ||||
| 			_thread = new Thread(() => | ||||
| 			{ | ||||
| 				Logger.Instance.LogMessage(TracingLevel.DEBUG, "Starting Window Changed Event Loop"); | ||||
| 				_delegate = new Native.WinEventDelegate(WinEventProc); | ||||
| 				_foregroundWindowChangedEvent = Native.RegisterForForegroundWindowChangedEvent(_delegate); | ||||
|  | ||||
| 				_dispatcher = Dispatcher.CurrentDispatcher; | ||||
| 				Dispatcher.Run(); | ||||
| 				Logger.Instance.LogMessage(TracingLevel.DEBUG, "Window Changed Event Loop Stopped"); | ||||
| 			}); | ||||
| 			_thread.SetApartmentState(ApartmentState.STA); | ||||
| 			_thread.Start(); | ||||
| 		} | ||||
|  | ||||
| 		public event Action WindowChanged; | ||||
|  | ||||
| 		private void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) | ||||
| 		{ | ||||
| 			try | ||||
| 			{ | ||||
| 				WindowChanged?.Invoke(); | ||||
| 			} | ||||
| 			catch (Exception ex) | ||||
| 			{ | ||||
| 				Logger.Instance.LogMessage(TracingLevel.ERROR, $"Unexpected Error in EventHandler:\n {ex}"); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -33,7 +33,7 @@ | ||||
|   "Name": "Focused Application Volume", | ||||
|   "Description": "Control the volume of the focused application", | ||||
|   "URL": "https://github.com/dlprows/FocusVolumeControl", | ||||
|   "Version": "1.1.1", | ||||
|   "Version": "1.1.2", | ||||
|   "CodePath": "FocusVolumeControl", | ||||
|   "Category": "Volume Control [dlprows]", | ||||
|   "Icon": "Images/pluginIcon", | ||||
|  | ||||
		Reference in New Issue
	
	Block a user