Add settings for fallback behavior
update action icon with padding
This commit is contained in:
parent
1dc8ab8a2d
commit
90c014e932
@ -1,73 +0,0 @@
|
||||
using CoreAudio;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FocusVolumeControl
|
||||
{
|
||||
public class ActiveAudioSessionWrapper
|
||||
{
|
||||
public string DisplayName { get; set; }
|
||||
public string ExecutablePath { get; set; }
|
||||
private List<SimpleAudioVolume> Volume { get; } = new List<SimpleAudioVolume>();
|
||||
|
||||
public string Icon { get; set; }
|
||||
|
||||
public bool Any()
|
||||
{
|
||||
return Volume.Any();
|
||||
}
|
||||
public int Count => Volume.Count;
|
||||
|
||||
public void AddVolume(SimpleAudioVolume volume)
|
||||
{
|
||||
Volume.Add(volume);
|
||||
}
|
||||
|
||||
public void ToggleMute()
|
||||
{
|
||||
//when all volumes are muted, Volume.All will return true
|
||||
//so we swap from muted to false (opposite of Volume.All)
|
||||
|
||||
//when any volumes are unmuted, Volume.All will return false
|
||||
//so we set muted to true (opposite of Volume.All)
|
||||
|
||||
var muted = Volume.All(x => x.Mute);
|
||||
|
||||
Volume.ForEach(x => x.Mute = !muted);
|
||||
}
|
||||
|
||||
public bool? GetMuted()
|
||||
{
|
||||
var muted = Volume.All(x => x.Mute);
|
||||
var unmuted = Volume.All(x => !x.Mute);
|
||||
|
||||
if(muted == !unmuted)
|
||||
{
|
||||
return muted;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void IncrementVolumeLevel(int step, int ticks)
|
||||
{
|
||||
//if you have more than one volume. they will all get set based on the first volume control
|
||||
var level = Volume.FirstOrDefault()?.MasterVolume ?? 0;
|
||||
|
||||
level += (0.01f * step) * ticks;
|
||||
level = Math.Max(level, 0);
|
||||
|
||||
Volume.ForEach(x => x.MasterVolume = level);
|
||||
}
|
||||
|
||||
public int GetVolumeLevel()
|
||||
{
|
||||
var level = Volume.FirstOrDefault()?.MasterVolume ?? 0;
|
||||
return (int)(level * 100);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,20 +1,18 @@
|
||||
using CoreAudio;
|
||||
using FocusVolumeControl.AudioSessions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FocusVolumeControl
|
||||
namespace FocusVolumeControl;
|
||||
|
||||
public class AudioHelper
|
||||
{
|
||||
public class AudioHelper
|
||||
{
|
||||
ActiveAudioSessionWrapper _current;
|
||||
IAudioSession _current;
|
||||
List<Process> _currentProcesses;
|
||||
|
||||
public ActiveAudioSessionWrapper FindSession(List<Process> processes)
|
||||
public IAudioSession FindSession(List<Process> processes)
|
||||
{
|
||||
var deviceEnumerator = new MMDeviceEnumerator(Guid.NewGuid());
|
||||
|
||||
@ -34,7 +32,7 @@ namespace FocusVolumeControl
|
||||
try
|
||||
{
|
||||
var displayName = audioProcess.MainModule.FileVersionInfo.FileDescription;
|
||||
if(string.IsNullOrEmpty(displayName))
|
||||
if (string.IsNullOrEmpty(displayName))
|
||||
{
|
||||
displayName = audioProcess.ProcessName;
|
||||
}
|
||||
@ -54,7 +52,11 @@ namespace FocusVolumeControl
|
||||
return matchingSession.Any() ? matchingSession : null;
|
||||
}
|
||||
|
||||
public ActiveAudioSessionWrapper GetActiveSession()
|
||||
static object _lock = new object();
|
||||
|
||||
public IAudioSession GetActiveSession(FallbackBehavior fallbackBehavior)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
var processes = GetPossibleProcesses();
|
||||
|
||||
@ -63,9 +65,22 @@ namespace FocusVolumeControl
|
||||
_current = FindSession(processes);
|
||||
}
|
||||
|
||||
if(_current == null)
|
||||
{
|
||||
if(fallbackBehavior == FallbackBehavior.SystemSounds)
|
||||
{
|
||||
_current = GetSystemSounds();
|
||||
}
|
||||
else if(fallbackBehavior == FallbackBehavior.SystemVolume)
|
||||
{
|
||||
_current = GetSystemVolume();
|
||||
}
|
||||
}
|
||||
|
||||
_currentProcesses = processes;
|
||||
return _current;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the list of processes that might be currently selected
|
||||
@ -117,5 +132,49 @@ namespace FocusVolumeControl
|
||||
|
||||
}
|
||||
|
||||
public void ResetAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
var deviceEnumerator = new MMDeviceEnumerator(Guid.NewGuid());
|
||||
|
||||
using var device = deviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
|
||||
using var manager = device.AudioSessionManager2;
|
||||
|
||||
foreach (var session in manager.Sessions)
|
||||
{
|
||||
session.SimpleAudioVolume.MasterVolume = 1;
|
||||
session.SimpleAudioVolume.Mute = false;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public IAudioSession GetSystemSounds()
|
||||
{
|
||||
var deviceEnumerator = new MMDeviceEnumerator(Guid.NewGuid());
|
||||
|
||||
using var device = deviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
|
||||
using var manager = device.AudioSessionManager2;
|
||||
|
||||
var sessions = manager.Sessions;
|
||||
|
||||
foreach (var session in sessions)
|
||||
{
|
||||
if (session.IsSystemSoundsSession)
|
||||
{
|
||||
return new SystemSoundsAudioSession(session.SimpleAudioVolume);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
public IAudioSession GetSystemVolume()
|
||||
{
|
||||
var deviceEnumerator = new MMDeviceEnumerator(Guid.NewGuid());
|
||||
|
||||
using var device = deviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
|
||||
return new SystemVolumeAudioSession(device.AudioEndpointVolume);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,82 @@
|
||||
using CoreAudio;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BarRaider.SdTools;
|
||||
using System.Drawing;
|
||||
|
||||
namespace FocusVolumeControl.AudioSessions;
|
||||
|
||||
public class ActiveAudioSessionWrapper : IAudioSession
|
||||
{
|
||||
public string DisplayName { get; set; }
|
||||
public string ExecutablePath { get; set; }
|
||||
private List<SimpleAudioVolume> Volume { get; } = new List<SimpleAudioVolume>();
|
||||
|
||||
string _icon;
|
||||
|
||||
public string GetIcon()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_icon))
|
||||
{
|
||||
try
|
||||
{
|
||||
var tmp = Icon.ExtractAssociatedIcon(ExecutablePath);
|
||||
_icon = Tools.ImageToBase64(tmp.ToBitmap(), true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_icon = "Image/pluginIcon.png";
|
||||
}
|
||||
}
|
||||
return _icon;
|
||||
}
|
||||
|
||||
public bool Any()
|
||||
{
|
||||
return Volume.Any();
|
||||
}
|
||||
public int Count => Volume.Count;
|
||||
|
||||
public void AddVolume(SimpleAudioVolume volume)
|
||||
{
|
||||
Volume.Add(volume);
|
||||
}
|
||||
|
||||
public void ToggleMute()
|
||||
{
|
||||
//when all volumes are muted, Volume.All will return true
|
||||
//so we swap from muted to false (opposite of Volume.All)
|
||||
|
||||
//when any volumes are unmuted, Volume.All will return false
|
||||
//so we set muted to true (opposite of Volume.All)
|
||||
|
||||
var muted = Volume.All(x => x.Mute);
|
||||
|
||||
Volume.ForEach(x => x.Mute = !muted);
|
||||
}
|
||||
|
||||
public bool IsMuted()
|
||||
{
|
||||
return Volume.All(x => x.Mute);
|
||||
}
|
||||
|
||||
public void IncrementVolumeLevel(int step, int ticks)
|
||||
{
|
||||
//if you have more than one volume. they will all get set based on the first volume control
|
||||
var level = Volume.FirstOrDefault()?.MasterVolume ?? 0;
|
||||
|
||||
level += (0.01f * step) * ticks;
|
||||
level = Math.Max(level, 0);
|
||||
level = Math.Min(level, 1);
|
||||
|
||||
Volume.ForEach(x => x.MasterVolume = level);
|
||||
}
|
||||
|
||||
public int GetVolumeLevel()
|
||||
{
|
||||
var level = Volume.FirstOrDefault()?.MasterVolume ?? 0;
|
||||
return (int)(level * 100);
|
||||
}
|
||||
|
||||
}
|
16
src/FocusVolumeControl/AudioSessions/IAudioSession.cs
Normal file
16
src/FocusVolumeControl/AudioSessions/IAudioSession.cs
Normal file
@ -0,0 +1,16 @@
|
||||
namespace FocusVolumeControl.AudioSessions;
|
||||
|
||||
public interface IAudioSession
|
||||
{
|
||||
public string DisplayName { get; }
|
||||
|
||||
public string GetIcon();
|
||||
|
||||
public void ToggleMute();
|
||||
|
||||
public bool IsMuted();
|
||||
|
||||
public void IncrementVolumeLevel(int step, int ticks);
|
||||
|
||||
public int GetVolumeLevel();
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
using CoreAudio;
|
||||
using System;
|
||||
|
||||
namespace FocusVolumeControl.AudioSessions;
|
||||
|
||||
internal class SystemSoundsAudioSession : IAudioSession
|
||||
{
|
||||
public SystemSoundsAudioSession(SimpleAudioVolume volumeControl)
|
||||
{
|
||||
_volumeControl = volumeControl;
|
||||
}
|
||||
|
||||
SimpleAudioVolume _volumeControl;
|
||||
|
||||
public string DisplayName => "System sounds";
|
||||
public string GetIcon() => "Images/systemSounds";
|
||||
|
||||
public void ToggleMute()
|
||||
{
|
||||
_volumeControl.Mute = !_volumeControl.Mute;
|
||||
}
|
||||
|
||||
public bool IsMuted() => _volumeControl.Mute;
|
||||
|
||||
public void IncrementVolumeLevel(int step, int ticks)
|
||||
{
|
||||
var level = _volumeControl.MasterVolume;
|
||||
|
||||
level += (0.01f * step) * ticks;
|
||||
level = Math.Max(level, 0);
|
||||
level = Math.Min(level, 1);
|
||||
|
||||
_volumeControl.MasterVolume = level;
|
||||
}
|
||||
|
||||
public int GetVolumeLevel() => (int)(_volumeControl.MasterVolume * 100);
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
using CoreAudio;
|
||||
using System;
|
||||
|
||||
namespace FocusVolumeControl.AudioSessions;
|
||||
|
||||
internal class SystemVolumeAudioSession : IAudioSession
|
||||
{
|
||||
public SystemVolumeAudioSession(AudioEndpointVolume volumeControl)
|
||||
{
|
||||
_volumeControl = volumeControl;
|
||||
}
|
||||
|
||||
AudioEndpointVolume _volumeControl;
|
||||
|
||||
public string DisplayName => "System Volume";
|
||||
public string GetIcon() => "Images/actionIcon";
|
||||
|
||||
public void ToggleMute()
|
||||
{
|
||||
_volumeControl.Mute = !_volumeControl.Mute;
|
||||
}
|
||||
|
||||
public bool IsMuted() => _volumeControl.Mute;
|
||||
|
||||
public void IncrementVolumeLevel(int step, int ticks)
|
||||
{
|
||||
var level = _volumeControl.MasterVolumeLevelScalar;
|
||||
|
||||
level += (0.01f * step) * ticks;
|
||||
level = Math.Max(level, 0);
|
||||
level = Math.Min(level, 1);
|
||||
|
||||
_volumeControl.MasterVolumeLevelScalar = level;
|
||||
}
|
||||
|
||||
public int GetVolumeLevel() => (int)(_volumeControl.MasterVolumeLevelScalar * 100);
|
||||
|
||||
}
|
@ -1,46 +1,29 @@
|
||||
using BarRaider.SdTools;
|
||||
using BarRaider.SdTools.Payloads;
|
||||
using CoreAudio;
|
||||
using FocusVolumeControl.AudioSessions;
|
||||
using FocusVolumeControl.UI;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.ServiceModel.Description;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace FocusVolumeControl
|
||||
namespace FocusVolumeControl;
|
||||
|
||||
[PluginActionId("com.dlprows.focusvolumecontrol.dialaction")]
|
||||
public class DialAction : EncoderBase
|
||||
{
|
||||
|
||||
/*
|
||||
todo:
|
||||
link both discord processes
|
||||
steam not detecting
|
||||
|
||||
long press reset
|
||||
|
||||
option for what to do when on app without sound
|
||||
|
||||
*/
|
||||
|
||||
|
||||
[PluginActionId("com.dlprows.focusvolumecontrol.dialaction")]
|
||||
public class DialAction : EncoderBase
|
||||
{
|
||||
private class PluginSettings
|
||||
{
|
||||
|
||||
[JsonProperty("onVolumeNotFound")]
|
||||
public FallbackBehavior FallbackBehavior { get; set; }
|
||||
|
||||
public static PluginSettings CreateDefaultSettings()
|
||||
{
|
||||
PluginSettings instance = new PluginSettings();
|
||||
instance.FallbackBehavior = FallbackBehavior.PreviousApp;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
@ -50,7 +33,7 @@ namespace FocusVolumeControl
|
||||
IntPtr _foregroundWindowChangedEvent;
|
||||
Native.WinEventDelegate _delegate;
|
||||
|
||||
ActiveAudioSessionWrapper _currentAudioSession;
|
||||
IAudioSession _currentAudioSession;
|
||||
AudioHelper _audioHelper = new AudioHelper();
|
||||
|
||||
Thread _thread;
|
||||
@ -84,6 +67,8 @@ namespace FocusVolumeControl
|
||||
_thread.SetApartmentState(ApartmentState.STA);
|
||||
_thread.Start();
|
||||
|
||||
|
||||
_currentAudioSession = settings.FallbackBehavior == FallbackBehavior.SystemSounds ? _audioHelper.GetSystemSounds() : _audioHelper.GetSystemVolume();
|
||||
}
|
||||
|
||||
public override async void DialDown(DialPayload payload)
|
||||
@ -98,7 +83,7 @@ namespace FocusVolumeControl
|
||||
Logger.Instance.LogMessage(TracingLevel.INFO, "Touch Press");
|
||||
if (payload.IsLongPress)
|
||||
{
|
||||
//todo: iterate through all sessions setting them back to 100 except the master volume
|
||||
_audioHelper.ResetAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -108,6 +93,9 @@ namespace FocusVolumeControl
|
||||
|
||||
async Task ToggleMuteAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
if (_currentAudioSession != null)
|
||||
{
|
||||
_currentAudioSession.ToggleMute();
|
||||
@ -118,11 +106,19 @@ namespace FocusVolumeControl
|
||||
await Connection.ShowAlert();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Connection.ShowAlert();
|
||||
Logger.Instance.LogMessage(TracingLevel.ERROR, $"Unable to toggle mute: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public override async void DialRotate(DialRotatePayload payload)
|
||||
{
|
||||
Logger.Instance.LogMessage(TracingLevel.INFO, "Dial Rotate");
|
||||
//dial rotated. ticks positive for right, negative for left
|
||||
try
|
||||
{
|
||||
if (_currentAudioSession != null)
|
||||
{
|
||||
_currentAudioSession.IncrementVolumeLevel(1, payload.Ticks);
|
||||
@ -133,6 +129,12 @@ namespace FocusVolumeControl
|
||||
await Connection.ShowAlert();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Connection.ShowAlert();
|
||||
Logger.Instance.LogMessage(TracingLevel.ERROR, $"Unable to toggle mute: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public override void DialUp(DialPayload payload)
|
||||
{
|
||||
@ -152,14 +154,10 @@ namespace FocusVolumeControl
|
||||
|
||||
public override async void OnTick()
|
||||
{
|
||||
//called once every 1000ms and can be used for updating the title/image fo the key
|
||||
var activeSession = _audioHelper.GetActiveSession();
|
||||
//called once every 1000ms and can be used for updating the title/image of the key
|
||||
var activeSession = _audioHelper.GetActiveSession(settings.FallbackBehavior);
|
||||
|
||||
if (activeSession == null)
|
||||
{
|
||||
//todo: something?
|
||||
}
|
||||
else
|
||||
if(activeSession != null)
|
||||
{
|
||||
_currentAudioSession = activeSession;
|
||||
}
|
||||
@ -172,7 +170,7 @@ namespace FocusVolumeControl
|
||||
if (_currentAudioSession != null)
|
||||
{
|
||||
|
||||
var uiState = UIState.Build(_currentAudioSession);
|
||||
var uiState = new UIState(_currentAudioSession);
|
||||
|
||||
if ( _previousState != null && uiState != null &&
|
||||
uiState.Title == _previousState.Title &&
|
||||
@ -216,6 +214,4 @@ namespace FocusVolumeControl
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
8
src/FocusVolumeControl/FallbackBehavior.cs
Normal file
8
src/FocusVolumeControl/FallbackBehavior.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace FocusVolumeControl;
|
||||
|
||||
public enum FallbackBehavior
|
||||
{
|
||||
PreviousApp,
|
||||
SystemSounds,
|
||||
SystemVolume
|
||||
}
|
@ -54,13 +54,16 @@
|
||||
<Reference Include="WindowsBase" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ActiveAudioSessionWrapper.cs" />
|
||||
<Compile Include="AudioSessions\ActiveAudioSessionWrapper.cs" />
|
||||
<Compile Include="AudioHelper.cs" />
|
||||
<Compile Include="AudioSessions\SystemSoundsAudioSession.cs" />
|
||||
<Compile Include="AudioSessions\SystemVolumeAudioSession.cs" />
|
||||
<Compile Include="DialAction.cs" />
|
||||
<Compile Include="ISDConnectionExtensions.cs" />
|
||||
<Compile Include="AudioSessions\IAudioSession.cs" />
|
||||
<Compile Include="FallbackBehavior.cs" />
|
||||
<Compile Include="UI\ISDConnectionExtensions.cs" />
|
||||
<Compile Include="Native.cs" />
|
||||
<Compile Include="ParentProcessUtilities.cs" />
|
||||
<Compile Include="PluginAction.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="UI\UIState.cs" />
|
||||
@ -104,6 +107,12 @@
|
||||
<Content Include="Images\pluginIcon.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\systemSounds%402x.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\systemSounds.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="PropertyInspector\PluginActionPI.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
@ -1,18 +0,0 @@
|
||||
using BarRaider.SdTools;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FocusVolumeControl
|
||||
{
|
||||
internal static class ISDConnectionExtensions
|
||||
{
|
||||
public static async Task SetFeedbackAsync(this ISDConnection _this, object feedbackPayload)
|
||||
{
|
||||
await _this.SetFeedbackAsync(JObject.FromObject(feedbackPayload));
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.8 KiB |
BIN
src/FocusVolumeControl/Images/systemSounds.png
Normal file
BIN
src/FocusVolumeControl/Images/systemSounds.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
src/FocusVolumeControl/Images/systemSounds@2x.png
Normal file
BIN
src/FocusVolumeControl/Images/systemSounds@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
@ -1,14 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FocusVolumeControl
|
||||
namespace FocusVolumeControl;
|
||||
|
||||
public class Native
|
||||
{
|
||||
public class Native
|
||||
{
|
||||
public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
@ -59,6 +56,7 @@ namespace FocusVolumeControl
|
||||
return ids;
|
||||
}
|
||||
|
||||
[DllImport("ntdll.dll")]
|
||||
public static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FocusVolumeControl
|
||||
namespace FocusVolumeControl;
|
||||
|
||||
/// <summary>
|
||||
/// A utility class to determine a process parent.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ParentProcessUtilities
|
||||
{
|
||||
/// <summary>
|
||||
/// A utility class to determine a process parent.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ParentProcessUtilities
|
||||
{
|
||||
// These members must match PROCESS_BASIC_INFORMATION
|
||||
internal IntPtr Reserved1;
|
||||
internal IntPtr PebBaseAddress;
|
||||
@ -22,8 +18,6 @@ namespace FocusVolumeControl
|
||||
internal IntPtr UniqueProcessId;
|
||||
internal IntPtr InheritedFromUniqueProcessId;
|
||||
|
||||
[DllImport("ntdll.dll")]
|
||||
private static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent process of specified process.
|
||||
@ -44,7 +38,7 @@ namespace FocusVolumeControl
|
||||
public static Process GetParentProcess(Process process)
|
||||
{
|
||||
var data = new ParentProcessUtilities();
|
||||
int status = NtQueryInformationProcess(process.Handle, 0, ref data, Marshal.SizeOf(data), out var returnLength);
|
||||
int status = Native.NtQueryInformationProcess(process.Handle, 0, ref data, Marshal.SizeOf(data), out var returnLength);
|
||||
if (status != 0)
|
||||
{
|
||||
return null;
|
||||
@ -60,6 +54,4 @@ namespace FocusVolumeControl
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,83 +0,0 @@
|
||||
using BarRaider.SdTools;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FocusVolumeControl
|
||||
{
|
||||
[PluginActionId("FocusVolumeControl.pluginaction")]
|
||||
public class PluginAction : KeypadBase
|
||||
{
|
||||
private class PluginSettings
|
||||
{
|
||||
public static PluginSettings CreateDefaultSettings()
|
||||
{
|
||||
PluginSettings instance = new PluginSettings();
|
||||
instance.OutputFileName = String.Empty;
|
||||
instance.InputString = String.Empty;
|
||||
return instance;
|
||||
}
|
||||
|
||||
[FilenameProperty]
|
||||
[JsonProperty(PropertyName = "outputFileName")]
|
||||
public string OutputFileName { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "inputString")]
|
||||
public string InputString { get; set; }
|
||||
}
|
||||
|
||||
#region Private Members
|
||||
|
||||
private PluginSettings settings;
|
||||
|
||||
#endregion
|
||||
public PluginAction(SDConnection connection, InitialPayload payload) : base(connection, payload)
|
||||
{
|
||||
if (payload.Settings == null || payload.Settings.Count == 0)
|
||||
{
|
||||
this.settings = PluginSettings.CreateDefaultSettings();
|
||||
SaveSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.settings = payload.Settings.ToObject<PluginSettings>();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
Logger.Instance.LogMessage(TracingLevel.INFO, $"Destructor called");
|
||||
}
|
||||
|
||||
public override void KeyPressed(KeyPayload payload)
|
||||
{
|
||||
Logger.Instance.LogMessage(TracingLevel.INFO, "Key Pressed");
|
||||
}
|
||||
|
||||
public override void KeyReleased(KeyPayload payload) { }
|
||||
|
||||
public override void OnTick() { }
|
||||
|
||||
public override void ReceivedSettings(ReceivedSettingsPayload payload)
|
||||
{
|
||||
Tools.AutoPopulateSettings(settings, payload.Settings);
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
public override void ReceivedGlobalSettings(ReceivedGlobalSettingsPayload payload) { }
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private Task SaveSettings()
|
||||
{
|
||||
return Connection.SetSettingsAsync(JObject.FromObject(settings));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,14 +1,9 @@
|
||||
using BarRaider.SdTools;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FocusVolumeControl
|
||||
namespace FocusVolumeControl;
|
||||
|
||||
internal class Program
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// Uncomment this line of code to allow for debugging
|
||||
@ -16,5 +11,4 @@ namespace FocusVolumeControl
|
||||
|
||||
SDWrapper.Run(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,24 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="sdpi-wrapper">
|
||||
<div class="sdpi-item">
|
||||
<div class="sdpi-item-label">Fallback Behavior</div>
|
||||
<select class="sdpi-item-value sdProperty" id="fallbackBehavior" oninput="setSettings()">
|
||||
<option value="0">Previous App</option>
|
||||
<option value="1">System Sounds</option>
|
||||
<option value="2">Main System Volume</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="sdpi-item">
|
||||
<details class="message">
|
||||
<p>If the focused app does not have a volume control you can pick your desired behavior</p>
|
||||
<ul>
|
||||
<li>Previous App - the focused app will be the last app that had a volume control</li>
|
||||
<li>System Sounds - switch to control system sounds. For example, if you're using an app that makes a windows "error" sound, its volume is controlled by system sounds. So you can adjust the error sound without impacting other apps</li>
|
||||
<li>Main System Volume - switch to the main volume control for the system. This will change the volume of all apps</li>
|
||||
</ul>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
13
src/FocusVolumeControl/UI/ISDConnectionExtensions.cs
Normal file
13
src/FocusVolumeControl/UI/ISDConnectionExtensions.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using BarRaider.SdTools;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FocusVolumeControl.UI;
|
||||
|
||||
internal static class ISDConnectionExtensions
|
||||
{
|
||||
public static async Task SetFeedbackAsync(this ISDConnection _this, object feedbackPayload)
|
||||
{
|
||||
await _this.SetFeedbackAsync(JObject.FromObject(feedbackPayload));
|
||||
}
|
||||
}
|
@ -8,11 +8,12 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BarRaider.SdTools;
|
||||
using Newtonsoft.Json;
|
||||
using FocusVolumeControl.AudioSessions;
|
||||
|
||||
namespace FocusVolumeControl.UI
|
||||
namespace FocusVolumeControl.UI;
|
||||
|
||||
internal class UIState
|
||||
{
|
||||
internal class UIState
|
||||
{
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; private init; }
|
||||
|
||||
@ -25,41 +26,16 @@ namespace FocusVolumeControl.UI
|
||||
[JsonProperty("icon")]
|
||||
public ValueWithOpacity<string> icon { get; private init; }
|
||||
|
||||
public static UIState Build(ActiveAudioSessionWrapper session)
|
||||
public UIState(IAudioSession session)
|
||||
{
|
||||
var volume = session.GetVolumeLevel();
|
||||
var opacity = session.IsMuted() ? 0.5f : 1;
|
||||
var iconData = session.GetIcon();
|
||||
|
||||
var opacity = session.GetMuted() != true ? 1 : 0.5f;
|
||||
|
||||
var iconData = "";
|
||||
|
||||
if (session.Icon != null)
|
||||
{
|
||||
iconData = session.Icon;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
var icon = Icon.ExtractAssociatedIcon(session.ExecutablePath);
|
||||
iconData = Tools.ImageToBase64(icon.ToBitmap(), true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
iconData = "Image/pluginIcon.png";
|
||||
}
|
||||
session.Icon = iconData;
|
||||
Title = session.DisplayName;
|
||||
Value = new() { Value = $"{volume}%", Opacity = opacity };
|
||||
Indicator = new() { Value = volume, Opacity = opacity };
|
||||
icon = new() { Value = iconData, Opacity = opacity };
|
||||
}
|
||||
|
||||
|
||||
return new UIState()
|
||||
{
|
||||
Title = session.DisplayName,
|
||||
Value = new() { Value = $"{volume}%", Opacity = opacity },
|
||||
Indicator = new() { Value = volume, Opacity = opacity },
|
||||
icon = new() { Value = iconData, Opacity = opacity },
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,13 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlTypes;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FocusVolumeControl.UI
|
||||
namespace FocusVolumeControl.UI;
|
||||
|
||||
internal class ValueWithOpacity<T>
|
||||
{
|
||||
internal class ValueWithOpacity<T>
|
||||
{
|
||||
[JsonProperty("value")]
|
||||
public required T Value { get; init; }
|
||||
|
||||
[JsonProperty("opacity")]
|
||||
public required float Opacity { get; init; }
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,17 @@
|
||||
using CoreAudio;
|
||||
using FocusVolumeControl;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace SoundBrowser
|
||||
namespace SoundBrowser;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
|
||||
AudioHelper _audioHelper;
|
||||
Native.WinEventDelegate _delegate;
|
||||
@ -91,7 +77,6 @@ namespace SoundBrowser
|
||||
sb.AppendLine("picked the following best match");
|
||||
sb.AppendLine($"\tsession: {session.DisplayName}");
|
||||
sb.AppendLine($"\tvolume: {session.GetVolumeLevel()}");
|
||||
sb.AppendLine($"\tcount: {session.Count}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -130,6 +115,4 @@ namespace SoundBrowser
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,65 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SoundBrowser
|
||||
{
|
||||
/// <summary>
|
||||
/// A utility class to determine a process parent.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ParentProcessUtilities
|
||||
{
|
||||
// These members must match PROCESS_BASIC_INFORMATION
|
||||
internal IntPtr Reserved1;
|
||||
internal IntPtr PebBaseAddress;
|
||||
internal IntPtr Reserved2_0;
|
||||
internal IntPtr Reserved2_1;
|
||||
internal IntPtr UniqueProcessId;
|
||||
internal IntPtr InheritedFromUniqueProcessId;
|
||||
|
||||
[DllImport("ntdll.dll")]
|
||||
private static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent process of specified process.
|
||||
/// </summary>
|
||||
/// <param name="id">The process id.</param>
|
||||
/// <returns>An instance of the Process class.</returns>
|
||||
public static Process? GetParentProcess(int id)
|
||||
{
|
||||
Process process = Process.GetProcessById(id);
|
||||
return GetParentProcess(process.Handle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent process of a specified process.
|
||||
/// </summary>
|
||||
/// <param name="handle">The process handle.</param>
|
||||
/// <returns>An instance of the Process class.</returns>
|
||||
public static Process? GetParentProcess(IntPtr handle)
|
||||
{
|
||||
ParentProcessUtilities pbi = new ParentProcessUtilities();
|
||||
int returnLength;
|
||||
int status = NtQueryInformationProcess(handle, 0, ref pbi, Marshal.SizeOf(pbi), out returnLength);
|
||||
if (status != 0)
|
||||
throw new Win32Exception(status);
|
||||
|
||||
try
|
||||
{
|
||||
return Process.GetProcessById(pbi.InheritedFromUniqueProcessId.ToInt32());
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
// not found
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user