-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Add a custom tool to explore StreamDeck bitmap colors.
- Loading branch information
Showing
14 changed files
with
557 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<Application x:Class="StreamDeckPlayground.App" | ||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
xmlns:local="clr-namespace:StreamDeckPlayground" | ||
StartupUri="MainWindow.xaml" | ||
ThemeMode="System"> | ||
<Application.Resources> | ||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> | ||
<local:NullabilityToVisibilityConverter x:Key="NullabilityToVisibilityConverter" /> | ||
<local:ColorToBrushConverter x:Key="ColorToBrushConverter" /> | ||
</Application.Resources> | ||
</Application> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
using System.Windows; | ||
|
||
namespace StreamDeckPlayground; | ||
|
||
public partial class App : Application | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
)] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using System.Globalization; | ||
using System.Windows.Data; | ||
using System.Windows.Media; | ||
|
||
namespace StreamDeckPlayground; | ||
|
||
public sealed class ColorToBrushConverter : IValueConverter | ||
{ | ||
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) => value is Color color ? new SolidColorBrush(color) : null; | ||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotSupportedException(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
using System.Collections.ObjectModel; | ||
using System.Windows.Media; | ||
|
||
namespace StreamDeckPlayground; | ||
|
||
internal sealed class DesignMainViewModel | ||
{ | ||
public sealed class StreamDeckDevice | ||
{ | ||
public string DeviceName { get; } | ||
public string SerialNumber { get; } | ||
public string FirmwareVersion { get; } | ||
public int ButtonColumnCount { get; } | ||
public int ButtonRowCount { get; } | ||
public int ButtonImageWidth { get; } | ||
public int ButtonImageHeight { get; } | ||
public int ScreensaverImageWidth { get; } | ||
public int ScreensaverImageHeight { get; } | ||
public ReadOnlyCollection<StreamDeckButton> Buttons { get; } | ||
public StreamDeckButton? SelectedButton { get; set; } | ||
|
||
public StreamDeckDevice(string deviceName, string serialNumber, string firmwareVersion, int buttonColumnCount, int buttonRowCount, int buttonImageWidth, int buttonImageHeight, int screensaverImageWidth, int screensaverImageHeight) | ||
{ | ||
DeviceName = deviceName; | ||
SerialNumber = serialNumber; | ||
FirmwareVersion = firmwareVersion; | ||
ButtonColumnCount = buttonColumnCount; | ||
ButtonRowCount = buttonRowCount; | ||
ButtonImageWidth = buttonImageWidth; | ||
ButtonImageHeight = buttonImageHeight; | ||
ScreensaverImageWidth = screensaverImageWidth; | ||
ScreensaverImageHeight = screensaverImageHeight; | ||
Buttons = Array.AsReadOnly(Enumerable.Range(0, buttonColumnCount * buttonRowCount).Select(i => new StreamDeckButton()).ToArray()); | ||
SelectedButton = Buttons[2]; | ||
} | ||
} | ||
|
||
public sealed class StreamDeckButton | ||
{ | ||
public int Width => 96; | ||
public int Height => 96; | ||
|
||
public byte Red { get; set; } = 55; | ||
public byte Green { get; set; } = 207; | ||
public byte Blue { get; set; } = 29; | ||
public Color Color => Color.FromArgb(255, Red, Green, Blue); | ||
public string HtmlColorCode => $"#{Red:X2}{Green:X2}{Blue:X2}"; | ||
} | ||
|
||
public ReadOnlyObservableCollection<StreamDeckDevice> Devices { get; } | ||
public StreamDeckDevice? SelectedDevice { get; set; } | ||
|
||
public DesignMainViewModel() | ||
{ | ||
var device = new StreamDeckDevice(@"\\HID\Whatever", "SN0123456789", "42.42.42", 8, 4, 96, 96, 1024, 600); | ||
Devices = new([device]); | ||
SelectedDevice = device; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
using System.Collections.ObjectModel; | ||
using DeviceTools; | ||
using Exo.Ui; | ||
|
||
namespace StreamDeckPlayground; | ||
|
||
public sealed class MainViewModel : BindableObject, IAsyncDisposable | ||
{ | ||
private readonly ObservableCollection<StreamDeckViewModel> _devices; | ||
private readonly ReadOnlyObservableCollection<StreamDeckViewModel> _readOnlyDevices; | ||
private StreamDeckViewModel? _selectedDevice; | ||
private readonly Task _watchDevicesTask; | ||
private CancellationTokenSource? _cancellationTokenSource; | ||
|
||
public MainViewModel() | ||
{ | ||
_devices = new(); | ||
_readOnlyDevices = new(_devices); | ||
_cancellationTokenSource = new(); | ||
_watchDevicesTask = WatchDevicesAsync(_cancellationTokenSource.Token); | ||
} | ||
|
||
public async ValueTask DisposeAsync() | ||
{ | ||
if (Interlocked.Exchange(ref _cancellationTokenSource, null) is { } cts) | ||
{ | ||
cts.Cancel(); | ||
await _watchDevicesTask; | ||
cts.Dispose(); | ||
} | ||
} | ||
|
||
public StreamDeckViewModel? SelectedDevice | ||
{ | ||
get => _selectedDevice; | ||
set => SetValue(ref _selectedDevice, value); | ||
} | ||
|
||
public async Task WatchDevicesAsync(CancellationToken cancellationToken) | ||
{ | ||
try | ||
{ | ||
foreach | ||
( | ||
var device in await DeviceQuery.FindAllAsync | ||
( | ||
DeviceObjectKind.DeviceInterface, | ||
Properties.System.Devices.InterfaceClassGuid == DeviceInterfaceClassGuids.Hid & | ||
Properties.System.DeviceInterface.Hid.VendorId == 0x0FD9 & | ||
Properties.System.DeviceInterface.Hid.ProductId == 0x006C & | ||
Properties.System.Devices.InterfaceEnabled == true, | ||
cancellationToken | ||
) | ||
) | ||
{ | ||
_devices.Add(await StreamDeckViewModel.CreateAsync(device.Id, 0x006C, cancellationToken)); | ||
} | ||
} | ||
catch (OperationCanceledException) | ||
{ | ||
} | ||
} | ||
|
||
public ReadOnlyObservableCollection<StreamDeckViewModel> Devices => _readOnlyDevices; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
<Window x:Class="StreamDeckPlayground.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:StreamDeckPlayground" | ||
mc:Ignorable="d" | ||
d:DataContext="{d:DesignInstance Type=local:DesignMainViewModel, IsDesignTimeCreatable=True}" | ||
Title="StreamDeck Playground" Height="550" Width="800"> | ||
<Window.DataContext> | ||
<local:MainViewModel /> | ||
</Window.DataContext> | ||
<Grid Margin="6"> | ||
<Grid.RowDefinitions> | ||
<RowDefinition Height="Auto" /> | ||
<RowDefinition Height="*" /> | ||
</Grid.RowDefinitions> | ||
<Grid> | ||
<Grid.ColumnDefinitions> | ||
<ColumnDefinition Width="200" /> | ||
<ColumnDefinition Width="*" /> | ||
</Grid.ColumnDefinitions> | ||
<TextBlock Text="Device" Margin="0,6,0,6" VerticalAlignment="Center" /> | ||
<ComboBox Grid.Column="1" ItemsSource="{Binding Devices}" SelectedItem="{Binding SelectedDevice, Mode=TwoWay}" Margin="0,6,0,6" VerticalAlignment="Center"> | ||
<ComboBox.ItemTemplate> | ||
<DataTemplate DataType="local:StreamDeckViewModel"> | ||
<TextBlock Text="{Binding DeviceName}" /> | ||
</DataTemplate> | ||
</ComboBox.ItemTemplate> | ||
</ComboBox> | ||
</Grid> | ||
<ScrollViewer Grid.Row="1"> | ||
<Grid DataContext="{Binding SelectedDevice, Mode=OneWay}" Visibility="{Binding Converter={StaticResource NullabilityToVisibilityConverter}}"> | ||
<Grid.RowDefinitions> | ||
<RowDefinition Height="Auto" /> | ||
<RowDefinition Height="Auto" /> | ||
<RowDefinition Height="*" /> | ||
</Grid.RowDefinitions> | ||
<Expander Header="Device Information" IsExpanded="True" Margin="0,6,0,6"> | ||
<Grid> | ||
<Grid.ColumnDefinitions> | ||
<ColumnDefinition Width="200" /> | ||
<ColumnDefinition Width="*" /> | ||
</Grid.ColumnDefinitions> | ||
<Grid.RowDefinitions> | ||
<RowDefinition Height="Auto" /> | ||
<RowDefinition Height="Auto" /> | ||
<RowDefinition Height="Auto" /> | ||
<RowDefinition Height="Auto" /> | ||
<RowDefinition Height="Auto" /> | ||
</Grid.RowDefinitions> | ||
<TextBlock Grid.Row="0" Text="Serial Number" Margin="0,6,0,6" VerticalAlignment="Center" /> | ||
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding SerialNumber}" Margin="0,6,0,6" VerticalAlignment="Center" /> | ||
<TextBlock Grid.Row="1" Text="Firmware Version" Margin="0,6,0,6" VerticalAlignment="Center" /> | ||
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding FirmwareVersion}" Margin="0,6,0,6" VerticalAlignment="Center" /> | ||
<TextBlock Grid.Row="2" Text="Grid Size" Margin="0,6,0,6" VerticalAlignment="Center" /> | ||
<TextBlock Grid.Row="2" Grid.Column="1" Margin="0,6,0,6" VerticalAlignment="Center"><Run Text="{Binding ButtonColumnCount, Mode=OneWay}" /><Run Text="x" /><Run Text="{Binding ButtonRowCount, Mode=OneWay}" /></TextBlock> | ||
<TextBlock Grid.Row="3" Text="Button Size" Margin="0,6,0,6" VerticalAlignment="Center" /> | ||
<TextBlock Grid.Row="3" Grid.Column="1" Margin="0,6,0,6" VerticalAlignment="Center"><Run Text="{Binding ButtonImageWidth, Mode=OneWay}" /><Run Text="x" /><Run Text="{Binding ButtonImageHeight, Mode=OneWay}" /></TextBlock> | ||
<TextBlock Grid.Row="4" Text="Screen Size" Margin="0,6,0,6" VerticalAlignment="Center" /> | ||
<TextBlock Grid.Row="4" Grid.Column="1" Margin="0,6,0,6" VerticalAlignment="Center"><Run Text="{Binding ScreensaverImageWidth, Mode=OneWay}" /><Run Text="x" /><Run Text="{Binding ScreensaverImageHeight, Mode=OneWay}" /></TextBlock> | ||
</Grid> | ||
</Expander> | ||
<Expander Grid.Row="1" Header="Buttons" Margin="0,6,0,6" IsExpanded="True"> | ||
<Grid> | ||
<Grid.RowDefinitions> | ||
<RowDefinition Height="Auto" /> | ||
<RowDefinition Height="Auto" /> | ||
</Grid.RowDefinitions> | ||
<ListBox | ||
ItemsSource="{Binding Buttons}" | ||
SelectedItem="{Binding SelectedButton, Mode=TwoWay}" | ||
HorizontalAlignment="Center" | ||
HorizontalContentAlignment="Center"> | ||
<ListBox.ItemContainerStyle> | ||
<Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}"> | ||
<Setter Property="Margin" Value="0" /> | ||
<Setter Property="Padding" Value="2" /> | ||
<Setter Property="Width" Value="52" /> | ||
<Setter Property="Height" Value="52" /> | ||
</Style> | ||
</ListBox.ItemContainerStyle> | ||
<ListBox.ItemTemplate> | ||
<DataTemplate> | ||
<Rectangle HorizontalAlignment="Center" VerticalAlignment="Center" Width="48" Height="48" Fill="{Binding Color, Converter={StaticResource ColorToBrushConverter}}" /> | ||
</DataTemplate> | ||
</ListBox.ItemTemplate> | ||
<ListBox.ItemsPanel> | ||
<ItemsPanelTemplate> | ||
<UniformGrid Columns="{Binding ButtonColumnCount}" Rows="{Binding ButtonRowCount}" HorizontalAlignment="Center" VerticalAlignment="Center" /> | ||
</ItemsPanelTemplate> | ||
</ListBox.ItemsPanel> | ||
</ListBox> | ||
<Grid Grid.Row="1" DataContext="{Binding SelectedButton}" Visibility="{Binding Converter={StaticResource NullabilityToVisibilityConverter}}"> | ||
<Grid.ColumnDefinitions> | ||
<ColumnDefinition Width="100" /> | ||
<ColumnDefinition Width="370" /> | ||
</Grid.ColumnDefinitions> | ||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> | ||
<Rectangle Fill="{Binding Color, Converter={StaticResource ColorToBrushConverter}}" Width="48" Height="48" /> | ||
<TextBlock Text="{Binding HtmlColorCode}" /> | ||
</StackPanel> | ||
<Grid Grid.Column="1"> | ||
<Grid.ColumnDefinitions> | ||
<ColumnDefinition Width="50" /> | ||
<ColumnDefinition Width="*" /> | ||
<ColumnDefinition Width="30" /> | ||
</Grid.ColumnDefinitions> | ||
<Grid.RowDefinitions> | ||
<RowDefinition Height="Auto" /> | ||
<RowDefinition Height="Auto" /> | ||
<RowDefinition Height="Auto" /> | ||
</Grid.RowDefinitions> | ||
<TextBlock Grid.Row="0" Margin="0,6,0,6" VerticalAlignment="Center" Text="Red" /> | ||
<Slider Grid.Row="0" Grid.Column="1" Margin="0,6,0,6" VerticalAlignment="Center" Minimum="0" Maximum="255" Value="{Binding Red, Mode=TwoWay}" /> | ||
<TextBlock Grid.Row="0" Grid.Column="2" Margin="0,6,0,6" HorizontalAlignment="Right" VerticalAlignment="Center" Text="{Binding Red, Mode=OneWay}" /> | ||
<TextBlock Grid.Row="1" Margin="0,6,0,6" VerticalAlignment="Center" Text="Green" /> | ||
<Slider Grid.Row="1" Grid.Column="1" Margin="0,6,0,6" VerticalAlignment="Center" Minimum="0" Maximum="255" Value="{Binding Green, Mode=TwoWay}" /> | ||
<TextBlock Grid.Row="1" Grid.Column="2" Margin="0,6,0,6" HorizontalAlignment="Right" VerticalAlignment="Center" Text="{Binding Green, Mode=OneWay}" /> | ||
<TextBlock Grid.Row="2" Margin="0,6,0,6" VerticalAlignment="Center" Text="Blue" /> | ||
<Slider Grid.Row="2" Grid.Column="1" Margin="0,6,0,6" VerticalAlignment="Center" Minimum="0" Maximum="255" Value="{Binding Blue, Mode=TwoWay}" /> | ||
<TextBlock Grid.Row="2" Grid.Column="2" Margin="0,6,0,6" HorizontalAlignment="Right" VerticalAlignment="Center" Text="{Binding Blue, Mode=OneWay}" /> | ||
</Grid> | ||
</Grid> | ||
</Grid> | ||
</Expander> | ||
</Grid> | ||
</ScrollViewer> | ||
</Grid> | ||
</Window> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using System.Text; | ||
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 StreamDeckPlayground; | ||
/// <summary> | ||
/// Interaction logic for MainWindow.xaml | ||
/// </summary> | ||
public partial class MainWindow : Window | ||
{ | ||
public MainWindow() | ||
{ | ||
InitializeComponent(); | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
src/Tools/StreamDeckPlayground/NullabilityToVisibilityConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using System.Globalization; | ||
using System.Windows; | ||
using System.Windows.Data; | ||
|
||
namespace StreamDeckPlayground; | ||
|
||
public sealed class NullabilityToVisibilityConverter : IValueConverter | ||
{ | ||
private static readonly object Visible = Visibility.Visible; | ||
private static readonly object Collapsed = Visibility.Collapsed; | ||
|
||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => value is not null ? Visible : Collapsed; | ||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotSupportedException(); | ||
} |
Oops, something went wrong.