using BarRaider.SdTools; using BarRaider.SdTools.Payloads; using CoreAudio; 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 { /* 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 { public static PluginSettings CreateDefaultSettings() { PluginSettings instance = new PluginSettings(); return instance; } } private PluginSettings settings; IntPtr _foregroundWindowChangedEvent; Native.WinEventDelegate _delegate; ActiveAudioSessionWrapper _currentAudioSession; AudioHelper _audioHelper = new AudioHelper(); Thread _thread; Dispatcher _dispatcher; UIState _previousState; 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(); } _thread = new Thread(() => { Logger.Instance.LogMessage(TracingLevel.DEBUG, "Registering for events"); _delegate = new Native.WinEventDelegate(WinEventProc); _foregroundWindowChangedEvent = Native.RegisterForForegroundWindowChangedEvent(_delegate); Logger.Instance.LogMessage(TracingLevel.DEBUG, "Starting Dispatcher"); _dispatcher = Dispatcher.CurrentDispatcher; Dispatcher.Run(); Logger.Instance.LogMessage(TracingLevel.DEBUG, "Dispatcher Stopped"); }); _thread.SetApartmentState(ApartmentState.STA); _thread.Start(); } public override async void DialDown(DialPayload payload) { //dial pressed down Logger.Instance.LogMessage(TracingLevel.INFO, "Dial Down"); await ToggleMuteAsync(); } 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 { await ToggleMuteAsync(); } } async Task ToggleMuteAsync() { if (_currentAudioSession != null) { _currentAudioSession.ToggleMute(); await UpdateStateIfNeeded(); } 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.IncrementVolumeLevel(1, payload.Ticks); await UpdateStateIfNeeded(); } else { await Connection.ShowAlert(); } } public override void DialUp(DialPayload payload) { //dial unpressed Logger.Instance.LogMessage(TracingLevel.INFO, "Dial Up"); } public override void Dispose() { Logger.Instance.LogMessage(TracingLevel.DEBUG, "Disposing"); if(_foregroundWindowChangedEvent != IntPtr.Zero) { Native.UnhookWinEvent(_foregroundWindowChangedEvent); } _dispatcher.InvokeShutdown(); } 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; } await UpdateStateIfNeeded(); } private async Task UpdateStateIfNeeded() { if (_currentAudioSession != null) { var uiState = UIState.Build(_currentAudioSession); if ( _previousState != null && uiState != null && uiState.Title == _previousState.Title && uiState.Value.Value == _previousState.Value.Value && uiState.Value.Opacity == _previousState.Value.Opacity && uiState.Indicator.Value == _previousState.Indicator.Value && uiState.Indicator.Opacity == _previousState.Indicator.Opacity && uiState.icon.Value == _previousState.icon.Value && uiState.icon.Opacity == _previousState.icon.Opacity ) { return; } await Connection.SetFeedbackAsync(uiState); _previousState = 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 void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) { OnTick(); } } }