Inital commit
263
.gitignore
vendored
Normal file
@ -0,0 +1,263 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
###################
|
||||
# compiled source #
|
||||
###################
|
||||
*.com
|
||||
*.class
|
||||
*.dll
|
||||
*.exe
|
||||
*.pdb
|
||||
*.dll.config
|
||||
*.cache
|
||||
*.suo
|
||||
# Include dlls if they’re in the NuGet packages directory
|
||||
!/packages/*/lib/*.dll
|
||||
# Include dlls if they're in the CommonReferences directory
|
||||
!*CommonReferences/*.dll
|
||||
####################
|
||||
# VS Upgrade stuff #
|
||||
####################
|
||||
_UpgradeReport_Files/
|
||||
###############
|
||||
# Directories #
|
||||
###############
|
||||
bin/
|
||||
obj/
|
||||
TestResults/
|
||||
###################
|
||||
# Web publish log #
|
||||
###################
|
||||
*.Publish.xml
|
||||
#############
|
||||
# Resharper #
|
||||
#############
|
||||
/_ReSharper.*
|
||||
*.ReSharper.*
|
||||
############
|
||||
# Packages #
|
||||
############
|
||||
# it’s better to unpack these files and commit the raw source
|
||||
# git has its own built in compression methods
|
||||
*.7z
|
||||
*.dmg
|
||||
*.gz
|
||||
*.iso
|
||||
*.jar
|
||||
*.rar
|
||||
*.tar
|
||||
*.zip
|
||||
######################
|
||||
# Logs and databases #
|
||||
######################
|
||||
*.log
|
||||
*.sqlite
|
||||
# OS generated files #
|
||||
######################
|
||||
.DS_Store?
|
||||
ehthumbs.db
|
||||
Icon?
|
||||
Thumbs.db
|
||||
|
||||
|
||||
# User-specific files
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
build/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# Visual Studo 2015 cache/options directory
|
||||
.vs/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
bower_components/
|
||||
orleans.codegen.cs
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
31
src/FocusVolumeControl.sln
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.6.33829.357
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FocusVolumeControl", "FocusVolumeControl\FocusVolumeControl.csproj", "{4635D874-69C0-4010-BE46-77EF92EB1553}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SoundBrowser", "SoundBrowser\SoundBrowser.csproj", "{0E8AB334-82F1-4DBC-9BDA-B6F9714A1847}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4635D874-69C0-4010-BE46-77EF92EB1553}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4635D874-69C0-4010-BE46-77EF92EB1553}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4635D874-69C0-4010-BE46-77EF92EB1553}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4635D874-69C0-4010-BE46-77EF92EB1553}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0E8AB334-82F1-4DBC-9BDA-B6F9714A1847}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0E8AB334-82F1-4DBC-9BDA-B6F9714A1847}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0E8AB334-82F1-4DBC-9BDA-B6F9714A1847}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0E8AB334-82F1-4DBC-9BDA-B6F9714A1847}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {22FD348F-67D1-423B-B3E3-C8C0022DCD96}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
17
src/FocusVolumeControl/ActiveAudioSessionWrapper.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using CoreAudio;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FocusVolumeControl
|
||||
{
|
||||
internal class ActiveAudioSessionWrapper
|
||||
{
|
||||
public string DisplayName { get; set; }
|
||||
public string ExecutablePath { get; set; }
|
||||
public SimpleAudioVolume Volume { get; set; }
|
||||
|
||||
}
|
||||
}
|
26
src/FocusVolumeControl/App.config
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="CommandLine" publicKeyToken="5a870481e358d379" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.9.1.0" newVersion="2.9.1.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Drawing.Common" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0"/>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="NLog" publicKeyToken="5120e14c03d0593c" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0"/>
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
63
src/FocusVolumeControl/AudioHelper.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using CoreAudio;
|
||||
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
|
||||
{
|
||||
internal class AudioHelper
|
||||
{
|
||||
ActiveAudioSessionWrapper GetSessionForProcess(Process process)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var audioProcess = Process.GetProcessById((int)session.ProcessID);
|
||||
|
||||
if (session.ProcessID == process.Id || audioProcess?.ProcessName == process.ProcessName)
|
||||
{
|
||||
var displayName = audioProcess.MainModule.FileVersionInfo.FileDescription;
|
||||
var path = audioProcess.MainModule.FileName;
|
||||
return new ActiveAudioSessionWrapper()
|
||||
{
|
||||
DisplayName = displayName,
|
||||
ExecutablePath = path,
|
||||
Volume = session.SimpleAudioVolume
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal ActiveAudioSessionWrapper GetActiveSession()
|
||||
{
|
||||
const int nChars = 256;
|
||||
IntPtr handle = IntPtr.Zero;
|
||||
StringBuilder Buff = new StringBuilder(nChars);
|
||||
handle = Native.GetForegroundWindow();
|
||||
|
||||
if (handle == IntPtr.Zero)
|
||||
{
|
||||
//todo: return system or something like that?
|
||||
return null;
|
||||
}
|
||||
|
||||
var tid = Native.GetWindowThreadProcessId(handle, out var pid);
|
||||
var process = Process.GetProcessById(pid);
|
||||
|
||||
return GetSessionForProcess(process);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
203
src/FocusVolumeControl/DialAction.cs
Normal file
@ -0,0 +1,203 @@
|
||||
using BarRaider.SdTools;
|
||||
using BarRaider.SdTools.Payloads;
|
||||
using CoreAudio;
|
||||
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.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FocusVolumeControl
|
||||
{
|
||||
|
||||
/*
|
||||
todo:
|
||||
link both discord processes
|
||||
steam not detecting
|
||||
|
||||
long press reset
|
||||
|
||||
option for what to do when on app without sound
|
||||
|
||||
gitea
|
||||
*/
|
||||
|
||||
|
||||
[PluginActionId("com.dlprows.focusvolumecontrol.dialaction")]
|
||||
public class DialAction : EncoderBase
|
||||
{
|
||||
private class PluginSettings
|
||||
{
|
||||
public static PluginSettings CreateDefaultSettings()
|
||||
{
|
||||
PluginSettings instance = new PluginSettings();
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
private PluginSettings settings;
|
||||
//IntPtr _foregroundWindowChangedEvent;
|
||||
//WinEventDelegate _delegate;
|
||||
ActiveAudioSessionWrapper _currentAudioSession;
|
||||
AudioHelper _audioHelper = new AudioHelper();
|
||||
|
||||
public DialAction(ISDConnection connection, InitialPayload payload) : base(connection, payload)
|
||||
{
|
||||
if (payload.Settings == null || payload.Settings.Count == 0)
|
||||
{
|
||||
settings = PluginSettings.CreateDefaultSettings();
|
||||
SaveSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
settings = payload.Settings.ToObject<PluginSettings>();
|
||||
}
|
||||
|
||||
//_delegate = new WinEventDelegate(WinEventProc);
|
||||
//_foregroundWindowChangedEvent = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, _delegate, 0, 0, WINEVENT_OUTOFCONTEXT);
|
||||
}
|
||||
|
||||
public override async void DialDown(DialPayload payload)
|
||||
{
|
||||
//dial pressed down
|
||||
Logger.Instance.LogMessage(TracingLevel.INFO, "Dial Down");
|
||||
if(_currentAudioSession != null)
|
||||
{
|
||||
_currentAudioSession.Volume.Mute = !_currentAudioSession.Volume.Mute;
|
||||
var uiState = UIState.Build(_currentAudioSession);
|
||||
await Connection.SetFeedbackAsync(uiState);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Connection.ShowAlert();
|
||||
}
|
||||
}
|
||||
|
||||
public override async void TouchPress(TouchpadPressPayload payload)
|
||||
{
|
||||
Logger.Instance.LogMessage(TracingLevel.INFO, "Touch Press");
|
||||
if (payload.IsLongPress)
|
||||
{
|
||||
//todo: iterate through all sessions setting them back to 100 except the master volume
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
if (_currentAudioSession != null)
|
||||
{
|
||||
_currentAudioSession.Volume.Mute = !_currentAudioSession.Volume.Mute;
|
||||
var uiState = UIState.Build(_currentAudioSession);
|
||||
await Connection.SetFeedbackAsync(uiState);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Connection.ShowAlert();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override async void DialRotate(DialRotatePayload payload)
|
||||
{
|
||||
Logger.Instance.LogMessage(TracingLevel.INFO, "Dial Rotate");
|
||||
//dial rotated. ticks positive for right, negative for left
|
||||
if(_currentAudioSession != null)
|
||||
{
|
||||
_currentAudioSession.Volume.MasterVolume += (0.01f) * payload.Ticks;
|
||||
|
||||
var uiState = UIState.Build(_currentAudioSession);
|
||||
await Connection.SetFeedbackAsync(uiState);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Connection.ShowAlert();
|
||||
}
|
||||
}
|
||||
|
||||
public override void DialUp(DialPayload payload)
|
||||
{
|
||||
//dial unpressed
|
||||
Logger.Instance.LogMessage(TracingLevel.INFO, "Dial Up");
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
/*
|
||||
if(_foregroundWindowChangedEvent != IntPtr.Zero)
|
||||
{
|
||||
Native.UnhookWinEvent(_foregroundWindowChangedEvent);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (activeSession == null)
|
||||
{
|
||||
//todo: something?
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentAudioSession = activeSession;
|
||||
}
|
||||
|
||||
if(_currentAudioSession != null)
|
||||
{
|
||||
var uiState = UIState.BuildWithImage(_currentAudioSession);
|
||||
await Connection.SetFeedbackAsync(uiState);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void ReceivedGlobalSettings(ReceivedGlobalSettingsPayload payload)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public override void ReceivedSettings(ReceivedSettingsPayload payload)
|
||||
{
|
||||
Tools.AutoPopulateSettings(settings, payload.Settings);
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
private Task SaveSettings()
|
||||
{
|
||||
return Connection.SetSettingsAsync(JObject.FromObject(settings));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public async void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
|
||||
{
|
||||
var activeSession = _audioHelper.GetActiveSession();
|
||||
|
||||
|
||||
if(activeSession == null)
|
||||
{
|
||||
//todo: something?
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentAudioSession = activeSession;
|
||||
|
||||
//populate the UI
|
||||
await Connection.SetTitleAsync(_currentAudioSession.DisplayName);
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
133
src/FocusVolumeControl/FocusVolumeControl.csproj
Normal file
@ -0,0 +1,133 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{4635D874-69C0-4010-BE46-77EF92EB1553}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>FocusVolumeControl</RootNamespace>
|
||||
<AssemblyName>FocusVolumeControl</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\com.dlprows.focusvolumecontrol.sdPlugin\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\com.dlprows.focusvolumecontrol.sdPlugin\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Transactions" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ActiveAudioSessionWrapper.cs" />
|
||||
<Compile Include="AudioHelper.cs" />
|
||||
<Compile Include="DialAction.cs" />
|
||||
<Compile Include="ISDConnectionExtensions.cs" />
|
||||
<Compile Include="Native.cs" />
|
||||
<Compile Include="PluginAction.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="UIState.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="install.bat" />
|
||||
<None Include="manifest.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Images\categoryIcon%402x.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\categoryIcon.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\actionIcon%402x.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\actionIcon.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\icon%402x.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\icon.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\pluginAction%402x.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\pluginAction.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\pluginIcon%402x.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\pluginIcon.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="PropertyInspector\PluginActionPI.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="PropertyInspector\PluginActionPI.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CoreAudio">
|
||||
<Version>1.27.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json">
|
||||
<Version>13.0.3</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NLog">
|
||||
<Version>5.2.3</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="streamdeck-client-csharp">
|
||||
<Version>4.3.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="StreamDeck-Tools">
|
||||
<Version>6.1.1</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
18
src/FocusVolumeControl/ISDConnectionExtensions.cs
Normal file
@ -0,0 +1,18 @@
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
BIN
src/FocusVolumeControl/Images/actionIcon.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
src/FocusVolumeControl/Images/actionIcon@2x.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
src/FocusVolumeControl/Images/categoryIcon.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
src/FocusVolumeControl/Images/categoryIcon@2x.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
src/FocusVolumeControl/Images/download (12).png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/FocusVolumeControl/Images/icon.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
src/FocusVolumeControl/Images/icon@2x.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
src/FocusVolumeControl/Images/pluginAction.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
src/FocusVolumeControl/Images/pluginAction@2x.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
src/FocusVolumeControl/Images/pluginIcon.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
src/FocusVolumeControl/Images/pluginIcon@2x.png
Normal file
After Width: | Height: | Size: 36 KiB |
34
src/FocusVolumeControl/Native.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FocusVolumeControl
|
||||
{
|
||||
internal class Native
|
||||
{
|
||||
internal delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern bool UnhookWinEvent(IntPtr hWinEventHook);
|
||||
|
||||
|
||||
private const uint WINEVENT_OUTOFCONTEXT = 0;
|
||||
private const uint EVENT_SYSTEM_FOREGROUND = 3;
|
||||
|
||||
internal static IntPtr RegisterForForegroundWindowChangedEvent(WinEventDelegate dele) => SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
|
||||
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern IntPtr GetForegroundWindow();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int processId);
|
||||
|
||||
}
|
||||
}
|
83
src/FocusVolumeControl/PluginAction.cs
Normal file
@ -0,0 +1,83 @@
|
||||
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
|
||||
}
|
||||
}
|
20
src/FocusVolumeControl/Program.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using BarRaider.SdTools;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FocusVolumeControl
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// Uncomment this line of code to allow for debugging
|
||||
//while (!System.Diagnostics.Debugger.IsAttached) { System.Threading.Thread.Sleep(100); }
|
||||
|
||||
SDWrapper.Run(args);
|
||||
}
|
||||
}
|
||||
}
|
36
src/FocusVolumeControl/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("FocusVolumeControl")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("FocusVolumeControl")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("1478b282-5356-4535-b478-b68cfa9cca59")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
17
src/FocusVolumeControl/PropertyInspector/PluginActionPI.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,minimal-ui,viewport-fit=cover">
|
||||
<meta name=apple-mobile-web-app-capable content=yes>
|
||||
<meta name=apple-mobile-web-app-status-bar-style content=black>
|
||||
<title>FocusVolumeControl Settings</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/barraider/streamdeck-easypi@latest/src/sdpi.css">
|
||||
<script src="https://cdn.jsdelivr.net/gh/barraider/streamdeck-easypi@latest/src/sdtools.common.js"></script>
|
||||
<script src="PluginActionPI.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="sdpi-wrapper">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1 @@
|
||||
|
75
src/FocusVolumeControl/UIState.cs
Normal file
@ -0,0 +1,75 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FocusVolumeControl
|
||||
{
|
||||
internal class UIState
|
||||
{
|
||||
public static Dictionary<string, object> Build(ActiveAudioSessionWrapper session)
|
||||
{
|
||||
var volume = (int)(session.Volume.MasterVolume * 100);
|
||||
|
||||
var valueThing = new Dictionary<string, string>()
|
||||
{
|
||||
{ "value", $"{volume}%" },
|
||||
{ "opacity", "0.5" }
|
||||
};
|
||||
var opacity = session.Volume.Mute ? 0.5f : 1;
|
||||
|
||||
var payload = new Dictionary<string, object>()
|
||||
{
|
||||
{ "indicator", ValueWithOpacity(volume, opacity) },
|
||||
{ "value", ValueWithOpacity($"{volume}%", opacity ) },
|
||||
{ "title", session.DisplayName },
|
||||
};
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
public static Dictionary<string, object> ValueWithOpacity(object value, float opacity)
|
||||
{
|
||||
return new Dictionary<string, object>()
|
||||
{
|
||||
{ "value", value },
|
||||
{ "opacity", opacity }
|
||||
};
|
||||
}
|
||||
|
||||
public static Dictionary<string, object> BuildWithImage(ActiveAudioSessionWrapper session)
|
||||
{
|
||||
var payload = Build(session);
|
||||
var opacity = session.Volume.Mute ? 0.5f : 1;
|
||||
|
||||
var iconData = "";
|
||||
|
||||
try
|
||||
{
|
||||
var icon = Icon.ExtractAssociatedIcon(session.ExecutablePath);
|
||||
var bitmap = new Bitmap(icon.ToBitmap(), 48, 48);
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
|
||||
|
||||
|
||||
var base64Icon = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
iconData = $"data:image/png;base64,{base64Icon}";
|
||||
}
|
||||
catch
|
||||
{
|
||||
iconData = "Image/pluginIcon.png";
|
||||
}
|
||||
|
||||
payload["icon"] = ValueWithOpacity(iconData, opacity);
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
27
src/FocusVolumeControl/install.bat
Normal file
@ -0,0 +1,27 @@
|
||||
@echo off
|
||||
REM USAGE: Install.bat <DEBUG/RELEASE>
|
||||
setlocal
|
||||
|
||||
REM cd to directory of install.bat
|
||||
cd /d %~dp0
|
||||
|
||||
REM cd to bin/<Debug|Release>
|
||||
cd bin/%1
|
||||
|
||||
|
||||
SET DISTRIBUTION_TOOL="%~dp0%DistributionTool.exe"
|
||||
SET STREAM_DECK_FILE="c:\Program Files\Elgato\StreamDeck\StreamDeck.exe"
|
||||
SET STREAM_DECK_LOAD_TIMEOUT=7
|
||||
|
||||
REM close processes
|
||||
taskkill /f /im streamdeck.exe
|
||||
taskkill /f /im FocusVolumeControl.exe
|
||||
timeout /t 2
|
||||
|
||||
del com.dlprows.focusvolumecontrol.streamDeckPlugin
|
||||
%DISTRIBUTION_TOOL% -b -i com.dlprows.focusvolumecontrol.sdPlugin -o ./
|
||||
rmdir %APPDATA%\Elgato\StreamDeck\Plugins\com.dlprows.focusvolumecontrol.sdPlugin /s /q
|
||||
START "" %STREAM_DECK_FILE%
|
||||
|
||||
timeout /t %STREAM_DECK_LOAD_TIMEOUT%
|
||||
com.dlprows.focusvolumecontrol.streamDeckPlugin
|
51
src/FocusVolumeControl/manifest.json
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"Actions": [
|
||||
{
|
||||
"Name": "Focused App Volume",
|
||||
"Icon": "Images/icon",
|
||||
"States": [
|
||||
{
|
||||
"Image": "Images/pluginAction",
|
||||
"TitleAlignment": "middle",
|
||||
"FontSize": "12"
|
||||
}
|
||||
],
|
||||
"Controllers": [ "Encoder" ],
|
||||
"Encoder": {
|
||||
"background": "backgroundImage",
|
||||
"Icon": "Images/actionIcon",
|
||||
"layout": "$B1",
|
||||
"StackColor": "#AABBCC",
|
||||
"TriggerDescription": {
|
||||
"Rotate": "Change the volume",
|
||||
"Push": "Mute/UnMute",
|
||||
"Touch": "Mute/UnMute",
|
||||
"LongTouch": "Reset all apps"
|
||||
}
|
||||
},
|
||||
"SupportedInMultiActions": false,
|
||||
"Tooltip": "Control the volume of the focused application",
|
||||
"UUID": "com.dlprows.focusvolumecontrol.dialaction",
|
||||
"PropertyInspectorPath": "PropertyInspector/PluginActionPI.html"
|
||||
}
|
||||
],
|
||||
"Author": "Daniel Prows",
|
||||
"Name": "FocusVolumeControl",
|
||||
"Description": "Control the volume of the focused application",
|
||||
"URL": "https://encyclopediaofdaniel.com",
|
||||
"Version": "1.0",
|
||||
"CodePath": "FocusVolumeControl",
|
||||
"Category": "Volume Control [dlprows]",
|
||||
"Icon": "Images/pluginIcon",
|
||||
"CategoryIcon": "Images/categoryIcon",
|
||||
"OS": [
|
||||
{
|
||||
"Platform": "windows",
|
||||
"MinimumVersion": "10"
|
||||
}
|
||||
],
|
||||
"SDKVersion": 2,
|
||||
"Software": {
|
||||
"MinimumVersion": "6.0"
|
||||
}
|
||||
}
|
9
src/SoundBrowser/App.xaml
Normal file
@ -0,0 +1,9 @@
|
||||
<Application x:Class="SoundBrowser.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:SoundBrowser"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
17
src/SoundBrowser/App.xaml.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace SoundBrowser
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
10
src/SoundBrowser/AssemblyInfo.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System.Windows;
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
15
src/SoundBrowser/MainWindow.xaml
Normal file
@ -0,0 +1,15 @@
|
||||
<Window x:Class="SoundBrowser.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:SoundBrowser"
|
||||
mc:Ignorable="d"
|
||||
Title="MainWindow" Height="150" Width="800">
|
||||
<Grid>
|
||||
<StackPanel>
|
||||
<TextBlock x:Name="_tf">blah</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</Window>
|
116
src/SoundBrowser/MainWindow.xaml.cs
Normal file
@ -0,0 +1,116 @@
|
||||
using CoreAudio;
|
||||
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;
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
dele = new WinEventDelegate(WinEventProc);
|
||||
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
|
||||
}
|
||||
|
||||
|
||||
WinEventDelegate dele = null;
|
||||
|
||||
|
||||
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
|
||||
|
||||
private const uint WINEVENT_OUTOFCONTEXT = 0;
|
||||
private const uint EVENT_SYSTEM_FOREGROUND = 3;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
static extern IntPtr GetForegroundWindow();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int processId);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
|
||||
|
||||
private static SimpleAudioVolume GetVolumeObject(Process process)
|
||||
{
|
||||
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.ProcessID == process.Id)
|
||||
{
|
||||
return session.SimpleAudioVolume;
|
||||
}
|
||||
|
||||
var audioProcess = Process.GetProcessById((int)session.ProcessID);
|
||||
if(audioProcess?.ProcessName == process.ProcessName)
|
||||
{
|
||||
Console.WriteLine(process.MainModule.FileVersionInfo.FileDescription);
|
||||
return session.SimpleAudioVolume;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
SimpleAudioVolume _current;
|
||||
|
||||
private string GetActiveWindowTitle()
|
||||
{
|
||||
const int nChars = 256;
|
||||
IntPtr handle = IntPtr.Zero;
|
||||
StringBuilder Buff = new StringBuilder(nChars);
|
||||
handle = GetForegroundWindow();
|
||||
|
||||
if (handle <= 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
var tid = GetWindowThreadProcessId(handle, out var pid);
|
||||
var process = Process.GetProcessById(pid);
|
||||
|
||||
var vol = GetVolumeObject(process);
|
||||
_current = vol;
|
||||
if(vol != null)
|
||||
{
|
||||
vol.Mute = true;
|
||||
}
|
||||
|
||||
return $"{pid} vol:{vol?.MasterVolume ?? -1} - {process.ProcessName}";
|
||||
}
|
||||
|
||||
|
||||
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
|
||||
{
|
||||
_tf.Text = GetActiveWindowTitle();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
14
src/SoundBrowser/SoundBrowser.csproj
Normal file
@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CoreAudio" Version="1.27.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|