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>
|