Compare commits
7 Commits
v1.1.1
...
v1.1.2-pre
Author | SHA1 | Date | |
---|---|---|---|
609a7bdb65 | |||
13fdfde3e5 | |||
bbad79b4f3 | |||
708180dc8e | |||
5711ace990 | |||
d89c8b1ffa | |||
f94052e54b |
@ -36,6 +36,7 @@ public class AudioHelper
|
|||||||
manager.GetSessionEnumerator(out var sessionEnumerator);
|
manager.GetSessionEnumerator(out var sessionEnumerator);
|
||||||
|
|
||||||
var results = new ActiveAudioSessionWrapper();
|
var results = new ActiveAudioSessionWrapper();
|
||||||
|
var currentIndex = int.MaxValue;
|
||||||
|
|
||||||
sessionEnumerator.GetCount(out var count);
|
sessionEnumerator.GetCount(out var count);
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
@ -45,7 +46,14 @@ public class AudioHelper
|
|||||||
session.GetProcessId(out var sessionProcessId);
|
session.GetProcessId(out var sessionProcessId);
|
||||||
var audioProcess = Process.GetProcessById(sessionProcessId);
|
var audioProcess = Process.GetProcessById(sessionProcessId);
|
||||||
|
|
||||||
if (processes.Any(x => x.Id == sessionProcessId || x.ProcessName == audioProcess?.ProcessName))
|
var index = processes.FindIndex(x => x.Id == sessionProcessId || x.ProcessName == audioProcess?.ProcessName);
|
||||||
|
|
||||||
|
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
|
try
|
||||||
{
|
{
|
||||||
@ -58,10 +66,13 @@ public class AudioHelper
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
results.DisplayName ??= audioProcess.ProcessName;
|
results.DisplayName = audioProcess.ProcessName;
|
||||||
}
|
}
|
||||||
|
|
||||||
results.ExecutablePath ??= audioProcess.MainModule.FileName;
|
results.ExecutablePath = audioProcess.MainModule.FileName;
|
||||||
|
|
||||||
|
currentIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
//some apps like discord have multiple volume processes.
|
//some apps like discord have multiple volume processes.
|
||||||
results.AddSession(session);
|
results.AddSession(session);
|
||||||
@ -137,10 +148,21 @@ public class AudioHelper
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var blah = ParentProcessUtilities.GetParentProcess(pid);
|
//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
|
||||||
if (blah != null && blah.ProcessName != "explorer" && blah.ProcessName != "svchost")
|
//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
|
catch
|
||||||
|
@ -10,6 +10,11 @@ namespace FocusVolumeControl.AudioSessions
|
|||||||
{
|
{
|
||||||
public static float GetAdjustedVolume(float startingVolume, int step, int ticks)
|
public static float GetAdjustedVolume(float startingVolume, int step, int ticks)
|
||||||
{
|
{
|
||||||
|
if(step <= 0)
|
||||||
|
{
|
||||||
|
step = 1;
|
||||||
|
}
|
||||||
|
|
||||||
var level = startingVolume;
|
var level = startingVolume;
|
||||||
|
|
||||||
level += 0.01f * step * ticks;
|
level += 0.01f * step * ticks;
|
||||||
|
@ -26,20 +26,13 @@ public class DialAction : EncoderBase
|
|||||||
{
|
{
|
||||||
PluginSettings instance = new PluginSettings();
|
PluginSettings instance = new PluginSettings();
|
||||||
instance.FallbackBehavior = FallbackBehavior.SystemSounds;
|
instance.FallbackBehavior = FallbackBehavior.SystemSounds;
|
||||||
|
instance.StepSize = 1;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PluginSettings settings;
|
PluginSettings settings;
|
||||||
|
|
||||||
IntPtr _foregroundWindowChangedEvent;
|
|
||||||
Native.WinEventDelegate _delegate;
|
|
||||||
|
|
||||||
AudioHelper _audioHelper = new AudioHelper();
|
AudioHelper _audioHelper = new AudioHelper();
|
||||||
|
|
||||||
Thread _thread;
|
|
||||||
Dispatcher _dispatcher;
|
|
||||||
|
|
||||||
UIState _previousState;
|
UIState _previousState;
|
||||||
|
|
||||||
public DialAction(ISDConnection connection, InitialPayload payload) : base(connection, payload)
|
public DialAction(ISDConnection connection, InitialPayload payload) : base(connection, payload)
|
||||||
@ -54,19 +47,7 @@ public class DialAction : EncoderBase
|
|||||||
settings = payload.Settings.ToObject<PluginSettings>();
|
settings = payload.Settings.ToObject<PluginSettings>();
|
||||||
}
|
}
|
||||||
|
|
||||||
_thread = new Thread(() =>
|
WindowChangedEventLoop.Instance.WindowChanged += WindowChanged;
|
||||||
{
|
|
||||||
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();
|
|
||||||
|
|
||||||
var session = _audioHelper.GetActiveSession(settings.FallbackBehavior);
|
var session = _audioHelper.GetActiveSession(settings.FallbackBehavior);
|
||||||
_ = UpdateStateIfNeeded(session);
|
_ = UpdateStateIfNeeded(session);
|
||||||
@ -74,19 +55,15 @@ public class DialAction : EncoderBase
|
|||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
Logger.Instance.LogMessage(TracingLevel.DEBUG, "Disposing");
|
//Logger.Instance.LogMessage(TracingLevel.DEBUG, "Disposing");
|
||||||
if (_foregroundWindowChangedEvent != IntPtr.Zero)
|
WindowChangedEventLoop.Instance.WindowChanged -= WindowChanged;
|
||||||
{
|
|
||||||
Native.UnhookWinEvent(_foregroundWindowChangedEvent);
|
|
||||||
}
|
|
||||||
_dispatcher.InvokeShutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async void DialDown(DialPayload payload)
|
public override async void DialDown(DialPayload payload)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Logger.Instance.LogMessage(TracingLevel.INFO, "Dial Down");
|
//Logger.Instance.LogMessage(TracingLevel.INFO, "Dial Down");
|
||||||
await ToggleMuteAsync();
|
await ToggleMuteAsync();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -100,7 +77,7 @@ public class DialAction : EncoderBase
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Logger.Instance.LogMessage(TracingLevel.INFO, "Touch Press");
|
//Logger.Instance.LogMessage(TracingLevel.INFO, "Touch Press");
|
||||||
if (payload.IsLongPress)
|
if (payload.IsLongPress)
|
||||||
{
|
{
|
||||||
await ResetAllAsync();
|
await ResetAllAsync();
|
||||||
@ -120,7 +97,7 @@ public class DialAction : EncoderBase
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Logger.Instance.LogMessage(TracingLevel.INFO, "Dial Rotate");
|
//Logger.Instance.LogMessage(TracingLevel.INFO, "Dial Rotate");
|
||||||
//dial rotated. ticks positive for right, negative for left
|
//dial rotated. ticks positive for right, negative for left
|
||||||
var activeSession = _audioHelper.Current;
|
var activeSession = _audioHelper.Current;
|
||||||
if (activeSession != null)
|
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
|
try
|
||||||
{
|
{
|
||||||
@ -266,7 +243,7 @@ public class DialAction : EncoderBase
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
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="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="UI\UIState.cs" />
|
<Compile Include="UI\UIState.cs" />
|
||||||
<Compile Include="UI\ValueWithOpacity.cs" />
|
<Compile Include="UI\ValueWithOpacity.cs" />
|
||||||
|
<Compile Include="WindowChangedEventLoop.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="App.config" />
|
<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",
|
"Name": "Focused Application Volume",
|
||||||
"Description": "Control the volume of the focused application",
|
"Description": "Control the volume of the focused application",
|
||||||
"URL": "https://github.com/dlprows/FocusVolumeControl",
|
"URL": "https://github.com/dlprows/FocusVolumeControl",
|
||||||
"Version": "1.1.1",
|
"Version": "1.1.2",
|
||||||
"CodePath": "FocusVolumeControl",
|
"CodePath": "FocusVolumeControl",
|
||||||
"Category": "Volume Control [dlprows]",
|
"Category": "Volume Control [dlprows]",
|
||||||
"Icon": "Images/pluginIcon",
|
"Icon": "Images/pluginIcon",
|
||||||
|
Reference in New Issue
Block a user