Fixed: send initial values when device connects
Implemented various TODO's
This commit is contained in:
parent
de27a6ccee
commit
cd1ab91f23
@ -6,7 +6,7 @@ namespace MassiveKnob.Plugin.CoreAudio.Base
|
|||||||
{
|
{
|
||||||
public Guid? DeviceId { get; set; }
|
public Guid? DeviceId { get; set; }
|
||||||
|
|
||||||
// TODO more options, like positioning and style
|
// TODO (nice to have) more options, like positioning and style
|
||||||
public bool OSD { get; set; } = true;
|
public bool OSD { get; set; } = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,9 @@
|
|||||||
using System;
|
namespace MassiveKnob.Plugin.CoreAudio.Base
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
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 MassiveKnob.Plugin.CoreAudio.Base
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for BaseDeviceSettingsView.xaml
|
/// Interaction logic for BaseDeviceSettingsView.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class BaseDeviceSettingsView : UserControl
|
public partial class BaseDeviceSettingsView
|
||||||
{
|
{
|
||||||
public BaseDeviceSettingsView()
|
public BaseDeviceSettingsView()
|
||||||
{
|
{
|
||||||
|
@ -6,8 +6,6 @@ using Microsoft.Extensions.Logging;
|
|||||||
|
|
||||||
namespace MassiveKnob.Plugin.CoreAudio.GetMuted
|
namespace MassiveKnob.Plugin.CoreAudio.GetMuted
|
||||||
{
|
{
|
||||||
// TODO send out initial muted state after proper initialization
|
|
||||||
|
|
||||||
public class DeviceGetMutedAction : IMassiveKnobAction
|
public class DeviceGetMutedAction : IMassiveKnobAction
|
||||||
{
|
{
|
||||||
public Guid ActionId { get; } = new Guid("86646ca7-f472-4c5a-8d0f-7e5d2d162ab9");
|
public Guid ActionId { get; } = new Guid("86646ca7-f472-4c5a-8d0f-7e5d2d162ab9");
|
||||||
@ -54,6 +52,9 @@ namespace MassiveKnob.Plugin.CoreAudio.GetMuted
|
|||||||
|
|
||||||
deviceChanged?.Dispose();
|
deviceChanged?.Dispose();
|
||||||
deviceChanged = playbackDevice?.MuteChanged.Subscribe(MuteChanged);
|
deviceChanged = playbackDevice?.MuteChanged.Subscribe(MuteChanged);
|
||||||
|
|
||||||
|
if (playbackDevice != null)
|
||||||
|
actionContext.SetDigitalOutput(settings.Inverted ? !playbackDevice.IsMuted : playbackDevice.IsMuted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,8 +6,6 @@ using Microsoft.Extensions.Logging;
|
|||||||
|
|
||||||
namespace MassiveKnob.Plugin.CoreAudio.GetVolume
|
namespace MassiveKnob.Plugin.CoreAudio.GetVolume
|
||||||
{
|
{
|
||||||
// TODO send out initial volume after proper initialization
|
|
||||||
|
|
||||||
public class DeviceGetVolumeAction : IMassiveKnobAction
|
public class DeviceGetVolumeAction : IMassiveKnobAction
|
||||||
{
|
{
|
||||||
public Guid ActionId { get; } = new Guid("6ebf91af-8240-4a75-9729-c6a1eb60dcba");
|
public Guid ActionId { get; } = new Guid("6ebf91af-8240-4a75-9729-c6a1eb60dcba");
|
||||||
@ -54,6 +52,9 @@ namespace MassiveKnob.Plugin.CoreAudio.GetVolume
|
|||||||
|
|
||||||
deviceChanged?.Dispose();
|
deviceChanged?.Dispose();
|
||||||
deviceChanged = playbackDevice?.VolumeChanged.Subscribe(VolumeChanged);
|
deviceChanged = playbackDevice?.VolumeChanged.Subscribe(VolumeChanged);
|
||||||
|
|
||||||
|
if (playbackDevice != null)
|
||||||
|
actionContext.SetAnalogOutput((byte)playbackDevice.Volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using MassiveKnob.Plugin.CoreAudio.SetMuted;
|
namespace MassiveKnob.Plugin.CoreAudio.GetVolume
|
||||||
|
|
||||||
namespace MassiveKnob.Plugin.CoreAudio.GetVolume
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for DeviceGetVolumeActionSettingsView.xaml
|
/// Interaction logic for DeviceGetVolumeActionSettingsView.xaml
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Security.RightsManagement;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using AudioSwitcher.AudioApi;
|
using AudioSwitcher.AudioApi;
|
||||||
|
|
||||||
|
@ -14,34 +14,35 @@
|
|||||||
x:Key="SpeakerIcon"
|
x:Key="SpeakerIcon"
|
||||||
d:DataContext="{d:DesignInstance osd:OSDWindowViewModel}">
|
d:DataContext="{d:DesignInstance osd:OSDWindowViewModel}">
|
||||||
<Canvas Width="256" Height="256">
|
<Canvas Width="256" Height="256">
|
||||||
<Polygon Visibility="{Binding IsNotMutedVisibility}" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Points=" 133.5,215.101 61.75,168 8.75,168 8.75,88 61.75,88 133.5,40.899 " Name="Speaker_1_" FillRule="NonZero" StrokeThickness="12" Stroke="#FFFFFFFF" StrokeMiterLimit="10" StrokeLineJoin="Round"/>
|
<Polygon Visibility="{Binding IsNotMutedVisibility}"
|
||||||
<Path Visibility="{Binding VolumeLowVisibility}" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="Low" StrokeThickness="12" Stroke="#FFFFFFFF" StrokeMiterLimit="10" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
|
Points=" 133.5,215.101 61.75,168 8.75,168 8.75,88 61.75,88 133.5,40.899 " Name="Speaker_1_" FillRule="NonZero" StrokeThickness="12" Stroke="#FFFFFFFF" StrokeMiterLimit="10" StrokeLineJoin="Round"/>
|
||||||
|
<Path Visibility="{Binding VolumeLowVisibility}" Name="Low" StrokeThickness="12" Stroke="#FFFFFFFF" StrokeMiterLimit="10" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
|
||||||
<Path.Data>
|
<Path.Data>
|
||||||
<PathGeometry Figures=" M166.806 86c0 0 12.528 15.833 12.528 40.167s-12.528 43.823-12.528 43.823" FillRule="NonZero"/>
|
<PathGeometry Figures=" M166.806 86c0 0 12.528 15.833 12.528 40.167s-12.528 43.823-12.528 43.823" FillRule="NonZero"/>
|
||||||
</Path.Data>
|
</Path.Data>
|
||||||
</Path>
|
</Path>
|
||||||
<Path Visibility="{Binding VolumeMediumVisibility}" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="Medium" StrokeThickness="12" Stroke="#FFFFFFFF" StrokeMiterLimit="10" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
|
<Path Visibility="{Binding VolumeMediumVisibility}" Name="Medium" StrokeThickness="12" Stroke="#FFFFFFFF" StrokeMiterLimit="10" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
|
||||||
<Path.Data>
|
<Path.Data>
|
||||||
<PathGeometry Figures=" M188.479 57c0 0 21.183 26.769 21.183 67.91c0 41.141-21.183 74.089-21.183 74.089" FillRule="NonZero"/>
|
<PathGeometry Figures=" M188.479 57c0 0 21.183 26.769 21.183 67.91c0 41.141-21.183 74.089-21.183 74.089" FillRule="NonZero"/>
|
||||||
</Path.Data>
|
</Path.Data>
|
||||||
</Path>
|
</Path>
|
||||||
<Path Visibility="{Binding VolumeHighVisibility}" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="High" StrokeThickness="12" Stroke="#FFFFFFFF" StrokeMiterLimit="10" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
|
<Path Visibility="{Binding VolumeHighVisibility}" Name="High" StrokeThickness="12" Stroke="#FFFFFFFF" StrokeMiterLimit="10" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
|
||||||
<Path.Data>
|
<Path.Data>
|
||||||
<PathGeometry Figures=" M216.737 35.517c0 0 27.944 35.316 27.944 89.593s-27.944 97.75-27.944 97.75" FillRule="NonZero"/>
|
<PathGeometry Figures=" M216.737 35.517c0 0 27.944 35.316 27.944 89.593s-27.944 97.75-27.944 97.75" FillRule="NonZero"/>
|
||||||
</Path.Data>
|
</Path.Data>
|
||||||
</Path>
|
</Path>
|
||||||
|
|
||||||
<Path Visibility="{Binding IsMutedVisibility}" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path4561" Fill="#FFFFFFFF">
|
<Path Visibility="{Binding IsMutedVisibility}" Name="path4561" Fill="#FFFFFFFF">
|
||||||
<Path.Data>
|
<Path.Data>
|
||||||
<PathGeometry Figures="M160.503 221.101c-1.717 0-3.421-0.732-4.608-2.153L10.395 44.746c-2.125-2.543-1.785-6.327 0.759-8.451 c2.544-2.125 6.328-1.784 8.451 0.759l145.5 174.201c2.124 2.544 1.784 6.327-0.759 8.452 C163.224 220.644 161.859 221.101 160.503 221.101z" FillRule="NonZero"/>
|
<PathGeometry Figures="M160.503 221.101c-1.717 0-3.421-0.732-4.608-2.153L10.395 44.746c-2.125-2.543-1.785-6.327 0.759-8.451 c2.544-2.125 6.328-1.784 8.451 0.759l145.5 174.201c2.124 2.544 1.784 6.327-0.759 8.452 C163.224 220.644 161.859 221.101 160.503 221.101z" FillRule="NonZero"/>
|
||||||
</Path.Data>
|
</Path.Data>
|
||||||
</Path>
|
</Path>
|
||||||
<Path Visibility="{Binding IsMutedVisibility}" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path4563" Fill="#FFFFFFFF">
|
<Path Visibility="{Binding IsMutedVisibility}" Name="path4563" Fill="#FFFFFFFF">
|
||||||
<Path.Data>
|
<Path.Data>
|
||||||
<PathGeometry Figures="M127.5 203.984l-62.458-41C64.064 162.342 62.92 162 61.75 162h-47V94h28.967L33.694 82H8.75c-3.313 0-6 2.687-6 6v80 c0 3.313 2.687 6 6 6h51.207l70.25 46.116c0.997 0.654 2.144 0.984 3.293 0.984c0.979 0 1.958-0.238 2.85-0.72 c1.94-1.048 3.15-3.075 3.15-5.28v-6.423l-12-14.367V203.984z" FillRule="NonZero"/>
|
<PathGeometry Figures="M127.5 203.984l-62.458-41C64.064 162.342 62.92 162 61.75 162h-47V94h28.967L33.694 82H8.75c-3.313 0-6 2.687-6 6v80 c0 3.313 2.687 6 6 6h51.207l70.25 46.116c0.997 0.654 2.144 0.984 3.293 0.984c0.979 0 1.958-0.238 2.85-0.72 c1.94-1.048 3.15-3.075 3.15-5.28v-6.423l-12-14.367V203.984z" FillRule="NonZero"/>
|
||||||
</Path.Data>
|
</Path.Data>
|
||||||
</Path>
|
</Path>
|
||||||
<Path Visibility="{Binding IsMutedVisibility}" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path4565" Fill="#FFFFFFFF">
|
<Path Visibility="{Binding IsMutedVisibility}" Name="path4565" Fill="#FFFFFFFF">
|
||||||
<Path.Data>
|
<Path.Data>
|
||||||
<PathGeometry Figures="M127.5 52.016v104.856l12 14.367V40.899c0-2.205-1.21-4.232-3.15-5.28c-1.939-1.047-4.299-0.947-6.143 0.264L63.19 79.877 l7.744 9.271L127.5 52.016z" FillRule="NonZero"/>
|
<PathGeometry Figures="M127.5 52.016v104.856l12 14.367V40.899c0-2.205-1.21-4.232-3.15-5.28c-1.939-1.047-4.299-0.947-6.143 0.264L63.19 79.877 l7.744 9.271L127.5 52.016z" FillRule="NonZero"/>
|
||||||
</Path.Data>
|
</Path.Data>
|
||||||
|
@ -4,6 +4,5 @@ namespace MassiveKnob.Plugin.CoreAudio.SetVolume
|
|||||||
{
|
{
|
||||||
public class DeviceSetVolumeActionSettings : BaseDeviceSettings
|
public class DeviceSetVolumeActionSettings : BaseDeviceSettings
|
||||||
{
|
{
|
||||||
// TODO OSD
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
@ -73,7 +73,7 @@ namespace MassiveKnob.Plugin.SerialDevice.Settings
|
|||||||
|
|
||||||
serialPorts = SerialPort.GetPortNames();
|
serialPorts = SerialPort.GetPortNames();
|
||||||
|
|
||||||
// TODO subscribe to device notification to refresh list
|
// TODO (must have - port from old source) subscribe to device notification to refresh list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,6 +12,10 @@ namespace MassiveKnob.Plugin
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called right after this instance is created.
|
/// Called right after this instance is created.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Do not perform anything but basic initialization until this method is called, as the action
|
||||||
|
/// instance will be created temporarily at startup to verify it is correctly implemented!
|
||||||
|
/// </remarks>
|
||||||
/// <param name="context">Provides an interface to the Massive Knob settings and device. Can be stored until the action instance is disposed.</param>
|
/// <param name="context">Provides an interface to the Massive Knob settings and device. Can be stored until the action instance is disposed.</param>
|
||||||
void Initialize(IMassiveKnobActionContext context);
|
void Initialize(IMassiveKnobActionContext context);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
// ReSharper disable UnusedMember.Global - public API
|
||||||
|
|
||||||
namespace MassiveKnob.Plugin
|
namespace MassiveKnob.Plugin
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EOF/@EntryIndexedValue">EOF</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EOF/@EntryIndexedValue">EOF</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MIN/@EntryIndexedValue">MIN</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OSD/@EntryIndexedValue">OSD</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OSD/@EntryIndexedValue">OSD</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SOF/@EntryIndexedValue">SOF</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SOF/@EntryIndexedValue">SOF</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
|
||||||
|
@ -5,7 +5,6 @@ using System.Reactive.Subjects;
|
|||||||
using MassiveKnob.Helpers;
|
using MassiveKnob.Helpers;
|
||||||
using MassiveKnob.Plugin;
|
using MassiveKnob.Plugin;
|
||||||
using MassiveKnob.Settings;
|
using MassiveKnob.Settings;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Serilog.Extensions.Logging;
|
using Serilog.Extensions.Logging;
|
||||||
using ILogger = Serilog.ILogger;
|
using ILogger = Serilog.ILogger;
|
||||||
@ -30,6 +29,9 @@ namespace MassiveKnob.Model
|
|||||||
private readonly List<ActionMapping> analogOutputs = new List<ActionMapping>();
|
private readonly List<ActionMapping> analogOutputs = new List<ActionMapping>();
|
||||||
private readonly List<ActionMapping> digitalOutputs = new List<ActionMapping>();
|
private readonly List<ActionMapping> digitalOutputs = new List<ActionMapping>();
|
||||||
|
|
||||||
|
private readonly Dictionary<int, byte> analogOutputValues = new Dictionary<int, byte>();
|
||||||
|
private readonly Dictionary<int, bool> digitalOutputValues = new Dictionary<int, bool>();
|
||||||
|
|
||||||
|
|
||||||
public MassiveKnobDeviceInfo ActiveDevice
|
public MassiveKnobDeviceInfo ActiveDevice
|
||||||
{
|
{
|
||||||
@ -58,17 +60,22 @@ namespace MassiveKnob.Model
|
|||||||
{
|
{
|
||||||
activeDevice?.Instance?.Dispose();
|
activeDevice?.Instance?.Dispose();
|
||||||
|
|
||||||
void DisposeMappings(IEnumerable<ActionMapping> mappings)
|
void DisposeMappings(ICollection<ActionMapping> mappings)
|
||||||
{
|
{
|
||||||
foreach (var mapping in mappings)
|
foreach (var mapping in mappings)
|
||||||
mapping?.ActionInfo.Instance?.Dispose();
|
mapping?.ActionInfo.Instance?.Dispose();
|
||||||
|
|
||||||
|
mappings.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DisposeMappings(analogInputs);
|
lock (settingsLock)
|
||||||
DisposeMappings(digitalInputs);
|
{
|
||||||
DisposeMappings(analogOutputs);
|
DisposeMappings(analogInputs);
|
||||||
DisposeMappings(digitalOutputs);
|
DisposeMappings(digitalInputs);
|
||||||
|
DisposeMappings(analogOutputs);
|
||||||
|
DisposeMappings(digitalOutputs);
|
||||||
|
}
|
||||||
|
|
||||||
activeDeviceInfoSubject?.Dispose();
|
activeDeviceInfoSubject?.Dispose();
|
||||||
}
|
}
|
||||||
@ -101,24 +108,29 @@ namespace MassiveKnob.Model
|
|||||||
|
|
||||||
public MassiveKnobActionInfo GetAction(MassiveKnobActionType actionType, int index)
|
public MassiveKnobActionInfo GetAction(MassiveKnobActionType actionType, int index)
|
||||||
{
|
{
|
||||||
var list = GetActionMappingList(actionType);
|
lock (settingsLock)
|
||||||
return index >= list.Count ? null : list[index]?.ActionInfo;
|
{
|
||||||
|
var list = GetActionMappingList(actionType);
|
||||||
|
return index >= list.Count ? null : list[index]?.ActionInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public MassiveKnobActionInfo SetAction(MassiveKnobActionType actionType, int index, IMassiveKnobAction action)
|
public MassiveKnobActionInfo SetAction(MassiveKnobActionType actionType, int index, IMassiveKnobAction action)
|
||||||
{
|
{
|
||||||
var list = GetActionMappingList(actionType);
|
List<ActionMapping> list;
|
||||||
if (index >= list.Count)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (list[index]?.ActionInfo.Info == action)
|
|
||||||
return list[index].ActionInfo;
|
|
||||||
|
|
||||||
list[index]?.ActionInfo.Instance?.Dispose();
|
|
||||||
|
|
||||||
lock (settingsLock)
|
lock (settingsLock)
|
||||||
{
|
{
|
||||||
|
list = GetActionMappingList(actionType);
|
||||||
|
if (index >= list.Count)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (list[index]?.ActionInfo.Info == action)
|
||||||
|
return list[index].ActionInfo;
|
||||||
|
|
||||||
|
list[index]?.ActionInfo.Instance?.Dispose();
|
||||||
|
|
||||||
var settingsList = GetActionSettingsList(actionType);
|
var settingsList = GetActionSettingsList(actionType);
|
||||||
while (index >= settingsList.Count)
|
while (index >= settingsList.Count)
|
||||||
settingsList.Add(null);
|
settingsList.Add(null);
|
||||||
@ -139,7 +151,11 @@ namespace MassiveKnob.Model
|
|||||||
initializeAfterRegistration = () => actionInstance.Initialize(actionContext);
|
initializeAfterRegistration = () => actionInstance.Initialize(actionContext);
|
||||||
});
|
});
|
||||||
|
|
||||||
list[index] = mapping;
|
lock (settingsLock)
|
||||||
|
{
|
||||||
|
list[index] = mapping;
|
||||||
|
}
|
||||||
|
|
||||||
initializeAfterRegistration?.Invoke();
|
initializeAfterRegistration?.Invoke();
|
||||||
|
|
||||||
return mapping?.ActionInfo;
|
return mapping?.ActionInfo;
|
||||||
@ -225,15 +241,15 @@ namespace MassiveKnob.Model
|
|||||||
|
|
||||||
protected T GetActionSettings<T>(IMassiveKnobActionContext context, IMassiveKnobAction action, int index) where T : class, new()
|
protected T GetActionSettings<T>(IMassiveKnobActionContext context, IMassiveKnobAction action, int index) where T : class, new()
|
||||||
{
|
{
|
||||||
var list = GetActionMappingList(action.ActionType);
|
|
||||||
if (index >= list.Count)
|
|
||||||
return new T();
|
|
||||||
|
|
||||||
if (list[index]?.Context != context)
|
|
||||||
throw new InvalidOperationException("Caller must be the active action to retrieve the settings");
|
|
||||||
|
|
||||||
lock (settingsLock)
|
lock (settingsLock)
|
||||||
{
|
{
|
||||||
|
var list = GetActionMappingList(action.ActionType);
|
||||||
|
if (index >= list.Count)
|
||||||
|
return new T();
|
||||||
|
|
||||||
|
if (list[index]?.Context != context)
|
||||||
|
throw new InvalidOperationException("Caller must be the active action to retrieve the settings");
|
||||||
|
|
||||||
var settingsList = GetActionSettingsList(action.ActionType);
|
var settingsList = GetActionSettingsList(action.ActionType);
|
||||||
if (index >= settingsList.Count)
|
if (index >= settingsList.Count)
|
||||||
return new T();
|
return new T();
|
||||||
@ -245,15 +261,15 @@ namespace MassiveKnob.Model
|
|||||||
|
|
||||||
protected void SetActionSettings<T>(IMassiveKnobActionContext context, IMassiveKnobAction action, int index, T actionSettings) where T : class, new()
|
protected void SetActionSettings<T>(IMassiveKnobActionContext context, IMassiveKnobAction action, int index, T actionSettings) where T : class, new()
|
||||||
{
|
{
|
||||||
var list = GetActionMappingList(action.ActionType);
|
|
||||||
if (index >= list.Count)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (list[index]?.Context != context)
|
|
||||||
throw new InvalidOperationException("Caller must be the active action to retrieve the settings");
|
|
||||||
|
|
||||||
lock (settingsLock)
|
lock (settingsLock)
|
||||||
{
|
{
|
||||||
|
var list = GetActionMappingList(action.ActionType);
|
||||||
|
if (index >= list.Count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (list[index]?.Context != context)
|
||||||
|
throw new InvalidOperationException("Caller must be the active action to retrieve the settings");
|
||||||
|
|
||||||
var settingsList = GetActionSettingsList(action.ActionType);
|
var settingsList = GetActionSettingsList(action.ActionType);
|
||||||
|
|
||||||
while (index >= settingsList.Count)
|
while (index >= settingsList.Count)
|
||||||
@ -272,19 +288,29 @@ namespace MassiveKnob.Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO store output values for when the device connects and should receive initial values
|
|
||||||
|
|
||||||
protected void AnalogChanged(IMassiveKnobDeviceContext context, int analogInputIndex, byte value)
|
protected void AnalogChanged(IMassiveKnobDeviceContext context, int analogInputIndex, byte value)
|
||||||
{
|
{
|
||||||
if (context != activeDeviceContext)
|
if (context != activeDeviceContext)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var mapping = GetActionMappingList(MassiveKnobActionType.InputAnalog);
|
IMassiveKnobAnalogAction analogAction;
|
||||||
if (mapping == null || analogInputIndex >= mapping.Count || mapping[analogInputIndex] == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (mapping[analogInputIndex].ActionInfo.Instance is IMassiveKnobAnalogAction analogAction)
|
lock (settingsLock)
|
||||||
analogAction.AnalogChanged(value);
|
{
|
||||||
|
if (analogOutputValues.TryGetValue(analogInputIndex, out var currentValue) && currentValue == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
analogOutputValues[analogInputIndex] = value;
|
||||||
|
|
||||||
|
var mapping = GetActionMappingList(MassiveKnobActionType.InputAnalog);
|
||||||
|
if (mapping == null || analogInputIndex >= mapping.Count || mapping[analogInputIndex] == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
analogAction = mapping[analogInputIndex].ActionInfo.Instance as IMassiveKnobAnalogAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
analogAction?.AnalogChanged(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -293,44 +319,70 @@ namespace MassiveKnob.Model
|
|||||||
if (context != activeDeviceContext)
|
if (context != activeDeviceContext)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var mapping = GetActionMappingList(MassiveKnobActionType.InputDigital);
|
IMassiveKnobDigitalAction digitalAction;
|
||||||
if (mapping == null || digitalInputIndex >= mapping.Count || mapping[digitalInputIndex] == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (mapping[digitalInputIndex].ActionInfo.Instance is IMassiveKnobDigitalAction digitalAction)
|
lock (settingsLock)
|
||||||
digitalAction.DigitalChanged(on);
|
{
|
||||||
|
if (digitalOutputValues.TryGetValue(digitalInputIndex, out var currentValue) && currentValue == on)
|
||||||
|
return;
|
||||||
|
|
||||||
|
digitalOutputValues[digitalInputIndex] = on;
|
||||||
|
|
||||||
|
|
||||||
|
var mapping = GetActionMappingList(MassiveKnobActionType.InputDigital);
|
||||||
|
if (mapping == null || digitalInputIndex >= mapping.Count || mapping[digitalInputIndex] == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
digitalAction = mapping[digitalInputIndex].ActionInfo.Instance as IMassiveKnobDigitalAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
digitalAction?.DigitalChanged(on);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void SetAnalogOutput(IMassiveKnobActionContext context, IMassiveKnobAction action, int index, byte value)
|
public void SetAnalogOutput(IMassiveKnobActionContext context, int index, byte value)
|
||||||
{
|
{
|
||||||
if (activeDevice == null)
|
if (activeDevice == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var list = GetActionMappingList(action.ActionType);
|
IMassiveKnobDeviceInstance deviceInstance;
|
||||||
if (index >= list.Count)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (list[index]?.Context != context)
|
lock (settingsLock)
|
||||||
return;
|
{
|
||||||
|
var list = GetActionMappingList(MassiveKnobActionType.OutputAnalog);
|
||||||
|
if (index >= list.Count)
|
||||||
|
return;
|
||||||
|
|
||||||
activeDevice.Instance.SetAnalogOutput(index, value);
|
if (context != null && list[index]?.Context != context)
|
||||||
|
return;
|
||||||
|
|
||||||
|
deviceInstance = activeDevice.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceInstance.SetAnalogOutput(index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void SetDigitalOutput(IMassiveKnobActionContext context, IMassiveKnobAction action, int index, bool on)
|
public void SetDigitalOutput(IMassiveKnobActionContext context, int index, bool on)
|
||||||
{
|
{
|
||||||
if (activeDevice == null)
|
if (activeDevice == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var list = GetActionMappingList(action.ActionType);
|
IMassiveKnobDeviceInstance deviceInstance;
|
||||||
if (index >= list.Count)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (list[index]?.Context != context)
|
lock (settingsLock)
|
||||||
return;
|
{
|
||||||
|
var list = GetActionMappingList(MassiveKnobActionType.OutputDigital);
|
||||||
|
if (index >= list.Count)
|
||||||
|
return;
|
||||||
|
|
||||||
activeDevice.Instance.SetDigitalOutput(index, on);
|
if (context != null && list[index]?.Context != context)
|
||||||
|
return;
|
||||||
|
|
||||||
|
deviceInstance = activeDevice.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceInstance.SetDigitalOutput(index, on);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -424,6 +476,14 @@ namespace MassiveKnob.Model
|
|||||||
ActiveDevice.Info,
|
ActiveDevice.Info,
|
||||||
ActiveDevice.Instance,
|
ActiveDevice.Instance,
|
||||||
specs);
|
specs);
|
||||||
|
|
||||||
|
|
||||||
|
// Send out all cached values to initialize the device's outputs
|
||||||
|
foreach (var pair in analogOutputValues.Where(pair => pair.Key < specs.AnalogOutputCount))
|
||||||
|
SetAnalogOutput(null, pair.Key, pair.Value);
|
||||||
|
|
||||||
|
foreach (var pair in digitalOutputValues.Where(pair => pair.Key < specs.DigitalOutputCount))
|
||||||
|
SetDigitalOutput(null, pair.Key, pair.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -520,14 +580,13 @@ namespace MassiveKnob.Model
|
|||||||
|
|
||||||
public void Connecting()
|
public void Connecting()
|
||||||
{
|
{
|
||||||
// TODO update status ?
|
// TODO (should have) update status ?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Connected(DeviceSpecs specs)
|
public void Connected(DeviceSpecs specs)
|
||||||
{
|
{
|
||||||
// TODO update status ?
|
// TODO (should have) update status ?
|
||||||
// TODO send out initial values for outputs
|
|
||||||
|
|
||||||
owner.UpdateActiveDeviceSpecs(this, specs);
|
owner.UpdateActiveDeviceSpecs(this, specs);
|
||||||
}
|
}
|
||||||
@ -535,7 +594,7 @@ namespace MassiveKnob.Model
|
|||||||
|
|
||||||
public void Disconnected()
|
public void Disconnected()
|
||||||
{
|
{
|
||||||
// TODO update status ?
|
// TODO (should have) update status ?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -581,13 +640,13 @@ namespace MassiveKnob.Model
|
|||||||
|
|
||||||
public void SetAnalogOutput(byte value)
|
public void SetAnalogOutput(byte value)
|
||||||
{
|
{
|
||||||
owner.SetAnalogOutput(this, action, index, value);
|
owner.SetAnalogOutput(this, index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void SetDigitalOutput(bool on)
|
public void SetDigitalOutput(bool on)
|
||||||
{
|
{
|
||||||
owner.SetDigitalOutput(this, action, index, on);
|
owner.SetDigitalOutput(this, index, on);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using MassiveKnob.Plugin;
|
using MassiveKnob.Plugin;
|
||||||
|
using Serilog;
|
||||||
|
using Serilog.Extensions.Logging;
|
||||||
|
|
||||||
namespace MassiveKnob.Model
|
namespace MassiveKnob.Model
|
||||||
{
|
{
|
||||||
@ -29,9 +31,16 @@ namespace MassiveKnob.Model
|
|||||||
|
|
||||||
public class PluginManager : IPluginManager
|
public class PluginManager : IPluginManager
|
||||||
{
|
{
|
||||||
|
private readonly ILogger logger;
|
||||||
private readonly List<IMassiveKnobPlugin> plugins = new List<IMassiveKnobPlugin>();
|
private readonly List<IMassiveKnobPlugin> plugins = new List<IMassiveKnobPlugin>();
|
||||||
|
|
||||||
|
|
||||||
|
public PluginManager(ILogger logger)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public IEnumerable<IMassiveKnobDevicePlugin> GetDevicePlugins()
|
public IEnumerable<IMassiveKnobDevicePlugin> GetDevicePlugins()
|
||||||
{
|
{
|
||||||
return plugins.Where(p => p is IMassiveKnobDevicePlugin).Cast<IMassiveKnobDevicePlugin>();
|
return plugins.Where(p => p is IMassiveKnobDevicePlugin).Cast<IMassiveKnobDevicePlugin>();
|
||||||
@ -101,7 +110,7 @@ namespace MassiveKnob.Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void ValidateRegistration(string filename, IMassiveKnobPlugin plugin, RegisteredIds registeredIds)
|
private void ValidateRegistration(string filename, IMassiveKnobPlugin plugin, RegisteredIds registeredIds)
|
||||||
{
|
{
|
||||||
// Make sure all GUIDs are actually unique and someone has not copy/pasted a plugin without
|
// Make sure all GUIDs are actually unique and someone has not copy/pasted a plugin without
|
||||||
// modifying the values. This way we can safely make that assumption in other code.
|
// modifying the values. This way we can safely make that assumption in other code.
|
||||||
@ -133,13 +142,42 @@ namespace MassiveKnob.Model
|
|||||||
throw new MassiveKnobPluginIdConflictException(action.ActionId, conflictingActionFilename, filename);
|
throw new MassiveKnobPluginIdConflictException(action.ActionId, conflictingActionFilename, filename);
|
||||||
|
|
||||||
registeredIds.ActionById.Add(action.ActionId, filename);
|
registeredIds.ActionById.Add(action.ActionId, filename);
|
||||||
|
ValidateActionType(action);
|
||||||
// TODO check ActionType vs. implemented interfaces
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ValidateActionType(IMassiveKnobAction action)
|
||||||
|
{
|
||||||
|
var instance = action.Create(new SerilogLoggerProvider(logger).CreateLogger(null));
|
||||||
|
if (instance == null)
|
||||||
|
throw new NullReferenceException("Create method must not return null");
|
||||||
|
|
||||||
|
switch (action.ActionType)
|
||||||
|
{
|
||||||
|
case MassiveKnobActionType.InputAnalog:
|
||||||
|
if (!(instance is IMassiveKnobAnalogAction))
|
||||||
|
throw new InvalidCastException("InputAnalog action must implement IMassiveKnobAnalogAction");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MassiveKnobActionType.InputDigital:
|
||||||
|
if (!(instance is IMassiveKnobDigitalAction))
|
||||||
|
throw new InvalidCastException("InputDigital action must implement IMassiveKnobDigitalAction");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MassiveKnobActionType.OutputAnalog:
|
||||||
|
case MassiveKnobActionType.OutputDigital:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(action.ActionType), action.ActionType, @"Unsupported action type: " + (int)action.ActionType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private class RegisteredIds
|
private class RegisteredIds
|
||||||
{
|
{
|
||||||
public readonly Dictionary<Guid, string> PluginById = new Dictionary<Guid, string>();
|
public readonly Dictionary<Guid, string> PluginById = new Dictionary<Guid, string>();
|
||||||
|
@ -21,7 +21,7 @@ namespace MassiveKnob
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
public static int Main()
|
public static int Main()
|
||||||
{
|
{
|
||||||
// TODO make configurable
|
// TODO (should have) make configurable
|
||||||
var loggingLevelSwitch = new LoggingLevelSwitch();
|
var loggingLevelSwitch = new LoggingLevelSwitch();
|
||||||
//var loggingLevelSwitch = new LoggingLevelSwitch(LogEventLevel.Verbose);
|
//var loggingLevelSwitch = new LoggingLevelSwitch(LogEventLevel.Verbose);
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ namespace MassiveKnob
|
|||||||
.CreateLogger();
|
.CreateLogger();
|
||||||
|
|
||||||
|
|
||||||
var pluginManager = new PluginManager();
|
var pluginManager = new PluginManager(logger);
|
||||||
|
|
||||||
var messages = new StringBuilder();
|
var messages = new StringBuilder();
|
||||||
pluginManager.Load((exception, filename) =>
|
pluginManager.Load((exception, filename) =>
|
||||||
|
@ -10,7 +10,6 @@ namespace MassiveKnob.ViewModel
|
|||||||
{
|
{
|
||||||
public class InputOutputViewModel : INotifyPropertyChanged
|
public class InputOutputViewModel : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
private readonly SettingsViewModel settingsViewModel;
|
|
||||||
private readonly IMassiveKnobOrchestrator orchestrator;
|
private readonly IMassiveKnobOrchestrator orchestrator;
|
||||||
private readonly MassiveKnobActionType actionType;
|
private readonly MassiveKnobActionType actionType;
|
||||||
private readonly int index;
|
private readonly int index;
|
||||||
@ -61,7 +60,6 @@ namespace MassiveKnob.ViewModel
|
|||||||
|
|
||||||
public InputOutputViewModel(SettingsViewModel settingsViewModel, IMassiveKnobOrchestrator orchestrator, MassiveKnobActionType actionType, int index)
|
public InputOutputViewModel(SettingsViewModel settingsViewModel, IMassiveKnobOrchestrator orchestrator, MassiveKnobActionType actionType, int index)
|
||||||
{
|
{
|
||||||
this.settingsViewModel = settingsViewModel;
|
|
||||||
this.orchestrator = orchestrator;
|
this.orchestrator = orchestrator;
|
||||||
this.actionType = actionType;
|
this.actionType = actionType;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
|
@ -10,7 +10,7 @@ using MassiveKnob.Plugin;
|
|||||||
|
|
||||||
namespace MassiveKnob.ViewModel
|
namespace MassiveKnob.ViewModel
|
||||||
{
|
{
|
||||||
// TODO better design-time version
|
// TODO (nice to have) better design-time version
|
||||||
public class SettingsViewModel : INotifyPropertyChanged
|
public class SettingsViewModel : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
private readonly IMassiveKnobOrchestrator orchestrator;
|
private readonly IMassiveKnobOrchestrator orchestrator;
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 223cfafaf40e0e26e7660860ddfd755cb671f81b
|
Subproject commit 6db7da6234713a50a2c278c00bcd710249738e5e
|
Loading…
Reference in New Issue
Block a user