1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Device dialog - Added input remapping for keyboards

Device dialog - Display layout author, if I missed anyone let me know!
This commit is contained in:
Robert 2021-04-10 12:52:43 +02:00
parent 8066586328
commit c66c21152f
12 changed files with 302 additions and 38 deletions

View File

@ -35,10 +35,9 @@ namespace Artemis.Core
IsEnabled = true; IsEnabled = true;
InputIdentifiers = new List<ArtemisDeviceInputIdentifier>(); InputIdentifiers = new List<ArtemisDeviceInputIdentifier>();
InputMappings = new Dictionary<ArtemisLed, ArtemisLed>();
Leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly(); UpdateLeds();
LedIds = new ReadOnlyDictionary<LedId, ArtemisLed>(Leds.ToDictionary(l => l.RgbLed.Id, l => l));
ApplyKeyboardLayout(); ApplyKeyboardLayout();
ApplyToEntity(); ApplyToEntity();
CalculateRenderProperties(); CalculateRenderProperties();
@ -52,12 +51,12 @@ namespace Artemis.Core
DeviceProvider = deviceProvider; DeviceProvider = deviceProvider;
InputIdentifiers = new List<ArtemisDeviceInputIdentifier>(); InputIdentifiers = new List<ArtemisDeviceInputIdentifier>();
InputMappings = new Dictionary<ArtemisLed, ArtemisLed>();
foreach (DeviceInputIdentifierEntity identifierEntity in DeviceEntity.InputIdentifiers) foreach (DeviceInputIdentifierEntity identifierEntity in DeviceEntity.InputIdentifiers)
InputIdentifiers.Add(new ArtemisDeviceInputIdentifier(identifierEntity.InputProvider, identifierEntity.Identifier)); InputIdentifiers.Add(new ArtemisDeviceInputIdentifier(identifierEntity.InputProvider, identifierEntity.Identifier));
Leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly(); UpdateLeds();
LedIds = new ReadOnlyDictionary<LedId, ArtemisLed>(Leds.ToDictionary(l => l.RgbLed.Id, l => l));
ApplyKeyboardLayout(); ApplyKeyboardLayout();
} }
@ -110,6 +109,8 @@ namespace Artemis.Core
/// </summary> /// </summary>
public List<ArtemisDeviceInputIdentifier> InputIdentifiers { get; } public List<ArtemisDeviceInputIdentifier> InputIdentifiers { get; }
public Dictionary<ArtemisLed, ArtemisLed> InputMappings { get; }
/// <summary> /// <summary>
/// Gets or sets the X-position of the device /// Gets or sets the X-position of the device
/// </summary> /// </summary>
@ -287,20 +288,27 @@ namespace Artemis.Core
/// Attempts to retrieve the <see cref="ArtemisLed" /> that corresponds the provided RGB.NET <see cref="Led" /> /// Attempts to retrieve the <see cref="ArtemisLed" /> that corresponds the provided RGB.NET <see cref="Led" />
/// </summary> /// </summary>
/// <param name="led">The RGB.NET <see cref="Led" /> to find the corresponding <see cref="ArtemisLed" /> for </param> /// <param name="led">The RGB.NET <see cref="Led" /> to find the corresponding <see cref="ArtemisLed" /> for </param>
/// <param name="applyInputMapping">If <see langword="true"/>, LEDs mapped to different LEDs <see cref="InputMappings"/> are taken into consideration</param>
/// <returns>If found, the corresponding <see cref="ArtemisLed" />; otherwise <see langword="null" />.</returns> /// <returns>If found, the corresponding <see cref="ArtemisLed" />; otherwise <see langword="null" />.</returns>
public ArtemisLed? GetLed(Led led) public ArtemisLed? GetLed(Led led, bool applyInputMapping)
{ {
return GetLed(led.Id); return GetLed(led.Id, applyInputMapping);
} }
/// <summary> /// <summary>
/// Attempts to retrieve the <see cref="ArtemisLed" /> that corresponds the provided RGB.NET <see cref="LedId" /> /// Attempts to retrieve the <see cref="ArtemisLed" /> that corresponds the provided RGB.NET <see cref="LedId" />
/// </summary> /// </summary>
/// <param name="ledId">The RGB.NET <see cref="LedId" /> to find the corresponding <see cref="ArtemisLed" /> for </param> /// <param name="ledId">The RGB.NET <see cref="LedId" /> to find the corresponding <see cref="ArtemisLed" /> for </param>
/// <param name="applyInputMapping">If <see langword="true"/>, LEDs mapped to different LEDs <see cref="InputMappings"/> are taken into consideration</param>
/// <returns>If found, the corresponding <see cref="ArtemisLed" />; otherwise <see langword="null" />.</returns> /// <returns>If found, the corresponding <see cref="ArtemisLed" />; otherwise <see langword="null" />.</returns>
public ArtemisLed? GetLed(LedId ledId) public ArtemisLed? GetLed(LedId ledId, bool applyInputMapping)
{ {
LedIds.TryGetValue(ledId, out ArtemisLed? artemisLed); LedIds.TryGetValue(ledId, out ArtemisLed? artemisLed);
if (artemisLed == null)
return null;
if (applyInputMapping && InputMappings.TryGetValue(artemisLed, out ArtemisLed? mappedLed))
return mappedLed;
return artemisLed; return artemisLed;
} }
@ -339,8 +347,7 @@ namespace Artemis.Core
if (layout.IsValid) if (layout.IsValid)
layout.RgbLayout!.ApplyTo(RgbDevice, createMissingLeds, removeExcessiveLeds); layout.RgbLayout!.ApplyTo(RgbDevice, createMissingLeds, removeExcessiveLeds);
Leds = RgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly(); UpdateLeds();
LedIds = new ReadOnlyDictionary<LedId, ArtemisLed>(Leds.ToDictionary(l => l.RgbLed.Id, l => l));
Layout = layout; Layout = layout;
Layout.ApplyDevice(this); Layout.ApplyDevice(this);
@ -348,6 +355,21 @@ namespace Artemis.Core
OnDeviceUpdated(); OnDeviceUpdated();
} }
private void UpdateLeds()
{
Leds = RgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
LedIds = new ReadOnlyDictionary<LedId, ArtemisLed>(Leds.ToDictionary(l => l.RgbLed.Id, l => l));
InputMappings.Clear();
foreach (InputMappingEntity deviceEntityInputMapping in DeviceEntity.InputMappings)
{
ArtemisLed? original = Leds.FirstOrDefault(l => l.RgbLed.Id == (LedId) deviceEntityInputMapping.OriginalLedId);
ArtemisLed? mapped = Leds.FirstOrDefault(l => l.RgbLed.Id == (LedId) deviceEntityInputMapping.MappedLedId);
if (original != null && mapped != null)
InputMappings.Add(original, mapped);
}
}
internal void ApplyToEntity() internal void ApplyToEntity()
{ {
// Other properties are computed // Other properties are computed
@ -362,6 +384,10 @@ namespace Artemis.Core
Identifier = identifier.Identifier Identifier = identifier.Identifier
}); });
} }
DeviceEntity.InputMappings.Clear();
foreach (var (original, mapped) in InputMappings)
DeviceEntity.InputMappings.Add(new InputMappingEntity {OriginalLedId = (int) original.RgbLed.Id, MappedLedId = (int) mapped.RgbLed.Id});
} }
internal void ApplyToRgbDevice() internal void ApplyToRgbDevice()

View File

@ -1,4 +1,5 @@
using Artemis.Core.Services; using Artemis.Core.Services;
using RGB.NET.Core;
namespace Artemis.Core namespace Artemis.Core
{ {
@ -12,7 +13,7 @@ namespace Artemis.Core
/// </summary> /// </summary>
/// <param name="inputProvider">The full type and namespace of the <see cref="Services.InputProvider" /> this identifier is used by</param> /// <param name="inputProvider">The full type and namespace of the <see cref="Services.InputProvider" /> this identifier is used by</param>
/// <param name="identifier">A value used to identify the device</param> /// <param name="identifier">A value used to identify the device</param>
public ArtemisDeviceInputIdentifier(string inputProvider, object identifier) internal ArtemisDeviceInputIdentifier(string inputProvider, object identifier)
{ {
InputProvider = inputProvider; InputProvider = inputProvider;
Identifier = identifier; Identifier = identifier;
@ -28,4 +29,16 @@ namespace Artemis.Core
/// </summary> /// </summary>
public object Identifier { get; set; } public object Identifier { get; set; }
} }
public class ArtemisDeviceInputMapping
{
public ArtemisLed OriginalLed { get; }
public ArtemisLed MappedLed { get; }
internal ArtemisDeviceInputMapping(ArtemisLed originalLed, ArtemisLed mappedLed)
{
OriginalLed = originalLed;
MappedLed = mappedLed;
}
}
} }

View File

@ -3,9 +3,15 @@ using RGB.NET.Core;
namespace Artemis.Core.Services namespace Artemis.Core.Services
{ {
internal static class InputKeyUtilities /// <summary>
/// Utilities for mapping keys and buttons to LEDs
/// </summary>
public static class InputKeyUtilities
{ {
internal static readonly Dictionary<KeyboardKey, LedId> KeyboardKeyLedIdMap = new() /// <summary>
/// A dictionary of mappings between <see cref="KeyboardKey" /> and <see cref="LedId" />
/// </summary>
public static readonly Dictionary<KeyboardKey, LedId> KeyboardKeyLedIdMap = new()
{ {
{KeyboardKey.None, LedId.Keyboard_Custom1}, {KeyboardKey.None, LedId.Keyboard_Custom1},
{KeyboardKey.Cancel, LedId.Keyboard_Custom2}, {KeyboardKey.Cancel, LedId.Keyboard_Custom2},
@ -182,7 +188,10 @@ namespace Artemis.Core.Services
{KeyboardKey.NumPadEnter, LedId.Keyboard_NumEnter} {KeyboardKey.NumPadEnter, LedId.Keyboard_NumEnter}
}; };
internal static readonly Dictionary<MouseButton, LedId> MouseButtonLedIdMap = new() /// <summary>
/// A dictionary of mappings between <see cref="MouseButton" /> and <see cref="LedId" />
/// </summary>
public static readonly Dictionary<MouseButton, LedId> MouseButtonLedIdMap = new()
{ {
{MouseButton.Left, LedId.Mouse1}, {MouseButton.Left, LedId.Mouse1},
{MouseButton.Middle, LedId.Mouse2}, {MouseButton.Middle, LedId.Mouse2},

View File

@ -201,7 +201,7 @@ namespace Artemis.Core.Services
bool foundLedId = InputKeyUtilities.KeyboardKeyLedIdMap.TryGetValue(e.Key, out LedId ledId); bool foundLedId = InputKeyUtilities.KeyboardKeyLedIdMap.TryGetValue(e.Key, out LedId ledId);
ArtemisLed? led = null; ArtemisLed? led = null;
if (foundLedId && e.Device != null) if (foundLedId && e.Device != null)
led = e.Device.GetLed(ledId); led = e.Device.GetLed(ledId, true);
// Create the UpDown event args because it can be used for every event // Create the UpDown event args because it can be used for every event
ArtemisKeyboardKeyUpDownEventArgs eventArgs = new(e.Device, led, e.Key, keyboardModifierKey, e.IsDown); ArtemisKeyboardKeyUpDownEventArgs eventArgs = new(e.Device, led, e.Key, keyboardModifierKey, e.IsDown);

View File

@ -7,6 +7,7 @@ namespace Artemis.Storage.Entities.Surface
public DeviceEntity() public DeviceEntity()
{ {
InputIdentifiers = new List<DeviceInputIdentifierEntity>(); InputIdentifiers = new List<DeviceInputIdentifierEntity>();
InputMappings = new List<InputMappingEntity>();
} }
public string Id { get; set; } public string Id { get; set; }
@ -25,9 +26,16 @@ namespace Artemis.Storage.Entities.Surface
public string CustomLayoutPath { get; set; } public string CustomLayoutPath { get; set; }
public List<DeviceInputIdentifierEntity> InputIdentifiers { get; set; } public List<DeviceInputIdentifierEntity> InputIdentifiers { get; set; }
public List<InputMappingEntity> InputMappings { get; set; }
} }
public class InputMappingEntity
{
public int OriginalLedId { get; set; }
public int MappedLedId { get; set; }
}
public class DeviceInputIdentifierEntity public class DeviceInputIdentifierEntity
{ {
public string InputProvider { get; set; } public string InputProvider { get; set; }

View File

@ -49,6 +49,7 @@ namespace Artemis.UI.Ninject.Factories
DevicePropertiesTabViewModel DevicePropertiesTabViewModel(ArtemisDevice device); DevicePropertiesTabViewModel DevicePropertiesTabViewModel(ArtemisDevice device);
DeviceInfoTabViewModel DeviceInfoTabViewModel(ArtemisDevice device); DeviceInfoTabViewModel DeviceInfoTabViewModel(ArtemisDevice device);
DeviceLedsTabViewModel DeviceLedsTabViewModel(ArtemisDevice device); DeviceLedsTabViewModel DeviceLedsTabViewModel(ArtemisDevice device);
InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device);
} }
public interface IProfileTreeVmFactory : IVmFactory public interface IProfileTreeVmFactory : IVmFactory

View File

@ -77,6 +77,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
_layerBrushSettingsWindowVm = new LayerBrushSettingsWindowViewModel(viewModel, configurationViewModel); _layerBrushSettingsWindowVm = new LayerBrushSettingsWindowViewModel(viewModel, configurationViewModel);
_windowManager.ShowDialog(_layerBrushSettingsWindowVm); _windowManager.ShowDialog(_layerBrushSettingsWindowVm);
// Save changes after the dialog closes
_profileEditorService.UpdateSelectedProfile();
} }
catch (Exception e) catch (Exception e)
{ {
@ -104,6 +107,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
_layerEffectSettingsWindowVm = new LayerEffectSettingsWindowViewModel(viewModel, configurationViewModel); _layerEffectSettingsWindowVm = new LayerEffectSettingsWindowViewModel(viewModel, configurationViewModel);
_windowManager.ShowDialog(_layerEffectSettingsWindowVm); _windowManager.ShowDialog(_layerEffectSettingsWindowVm);
// Save changes after the dialog closes
_profileEditorService.UpdateSelectedProfile();
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -21,6 +21,9 @@
d:DesignHeight="800" d:DesignWidth="800" d:DesignHeight="800" d:DesignWidth="800"
d:DataContext="{d:DesignInstance device:DeviceDialogViewModel}" d:DataContext="{d:DesignInstance device:DeviceDialogViewModel}"
Icon="/Resources/Images/Logo/logo-512.png"> Icon="/Resources/Images/Logo/logo-512.png">
<mde:MaterialWindow.Resources>
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter"/>
</mde:MaterialWindow.Resources>
<mde:MaterialWindow.InputBindings> <mde:MaterialWindow.InputBindings>
<KeyBinding Command="{s:Action ClearSelection}" Key="Escape" /> <KeyBinding Command="{s:Action ClearSelection}" Key="Escape" />
</mde:MaterialWindow.InputBindings> </mde:MaterialWindow.InputBindings>
@ -111,6 +114,14 @@
VerticalAlignment="Center" VerticalAlignment="Center"
ShowColors="True" ShowColors="True"
LedClicked="{s:Action OnLedClicked}"/> LedClicked="{s:Action OnLedClicked}"/>
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
Visibility="{Binding Device.Layout.RgbLayout.Author, Converter={StaticResource NullToVisibilityConverter}}"
VerticalAlignment="Bottom"
HorizontalAlignment="Left"
Margin="15">
Device layout by <Run FontWeight="Bold" Text="{Binding Device.Layout.RgbLayout.Author}"/>
</TextBlock>
</Grid> </Grid>
<GridSplitter Grid.Column="1" Width="15" Margin="-15 0 0 0" Background="Transparent" HorizontalAlignment="Stretch" Panel.ZIndex="3" /> <GridSplitter Grid.Column="1" Width="15" Margin="-15 0 0 0" Background="Transparent" HorizontalAlignment="Stretch" Panel.ZIndex="3" />

View File

@ -12,6 +12,7 @@ using Artemis.UI.Shared;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using MaterialDesignThemes.Wpf; using MaterialDesignThemes.Wpf;
using Ookii.Dialogs.Wpf; using Ookii.Dialogs.Wpf;
using RGB.NET.Core;
using RGB.NET.Layout; using RGB.NET.Layout;
using SkiaSharp; using SkiaSharp;
using Stylet; using Stylet;
@ -42,14 +43,16 @@ namespace Artemis.UI.Screens.Settings.Device
Device = device; Device = device;
PanZoomViewModel = new PanZoomViewModel(); PanZoomViewModel = new PanZoomViewModel();
SelectedLeds = new BindableCollection<ArtemisLed>();
Items.Add(factory.DevicePropertiesTabViewModel(device)); Items.Add(factory.DevicePropertiesTabViewModel(device));
if (device.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Keyboard)
Items.Add(factory.InputMappingsTabViewModel(device));
Items.Add(factory.DeviceInfoTabViewModel(device)); Items.Add(factory.DeviceInfoTabViewModel(device));
Items.Add(factory.DeviceLedsTabViewModel(device)); Items.Add(factory.DeviceLedsTabViewModel(device));
ActiveItem = Items.First(); ActiveItem = Items.First();
DisplayName = $"{device.RgbDevice.DeviceInfo.Model} | Artemis"; DisplayName = $"{device.RgbDevice.DeviceInfo.Model} | Artemis";
SelectedLeds = new BindableCollection<ArtemisLed>();
} }
public ArtemisDevice Device { get; } public ArtemisDevice Device { get; }

View File

@ -0,0 +1,83 @@
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Settings.Device.Tabs"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:Shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared" x:Class="Artemis.UI.Screens.Settings.Device.Tabs.InputMappingsTabView"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type local:InputMappingsTabViewModel}}">
<UserControl.Resources>
<ResourceDictionary>
<Shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<Style x:Key="CenteredTextColumn" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</ResourceDictionary>
</UserControl.Resources>
<Grid Margin="15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}">
<Run Text="Introduction" />
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" TextWrapping="Wrap">
In some cases you may want Artemis to map key presses to different LEDs.
This is useful when your logical layout swaps keys around (like Hungarian layouts where the Z and Y keys are swapped).<LineBreak /><LineBreak />
In this tab you can set up these custom input mappings, simply click on a LED and press a key, Artemis will from then on consider that LED pressed whenever you press the same key again.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="1" Margin="0 20" Visibility="{Binding SelectedLed, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}">
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextAlignment="Center">Select a LED in the preview on the left side to get started...</TextBlock>
</StackPanel>
<StackPanel Grid.Row="1" Margin="0 20" Visibility="{Binding SelectedLed, Converter={StaticResource NullToVisibilityConverter}}">
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextAlignment="Center">
<Run Text="Current target LED: " /><Run Text="{Binding SelectedLed.RgbLed.Id, Mode=OneWay}" />
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" TextAlignment="Center">
<Run Text="Press the key you want to remap" /><Run Text=" " /><Run FontWeight="Bold" Text="{Binding SelectedLed.RgbLed.Id, Mode=OneWay}" /><Run Text=" " /><Run Text="to..." />
</TextBlock>
</StackPanel>
<DataGrid Grid.Row="2"
ItemsSource="{Binding InputMappings}"
CanUserSortColumns="True"
IsReadOnly="True"
CanUserAddRows="False"
AutoGenerateColumns="False"
CanUserResizeRows="False"
materialDesign:DataGridAssist.CellPadding="8"
materialDesign:DataGridAssist.ColumnHeaderPadding="8"
VirtualizingPanel.VirtualizationMode="Standard"
Margin="10">
<DataGrid.Columns>
<materialDesign:DataGridTextColumn Binding="{Binding Item1.RgbLed.Id}" ElementStyle="{StaticResource CenteredTextColumn}" Header="Original LED ID" Width="*" />
<materialDesign:DataGridTextColumn Binding="{Binding Item2.RgbLed.Id}" ElementStyle="{StaticResource CenteredTextColumn}" Header="Remapped LED ID" Width="*" />
<DataGridTemplateColumn Width="45" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Command="{s:Action DeleteMapping}"
CommandParameter="{Binding}"
Style="{StaticResource MaterialDesignIconForegroundButton}"
ToolTip="Delete mapping"
Width="25"
Height="25">
<materialDesign:PackIcon Kind="Delete" Width="18" Height="18" />
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>

View File

@ -0,0 +1,103 @@
using System;
using System.Collections.Specialized;
using System.Linq;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Exceptions;
using RGB.NET.Core;
using Stylet;
namespace Artemis.UI.Screens.Settings.Device.Tabs
{
public class InputMappingsTabViewModel : Screen
{
private readonly IRgbService _rgbService;
private readonly IInputService _inputService;
private ArtemisLed _selectedLed;
public InputMappingsTabViewModel(ArtemisDevice device, IRgbService rgbService, IInputService inputService)
{
if (device.RgbDevice.DeviceInfo.DeviceType != RGBDeviceType.Keyboard)
throw new ArtemisUIException("The input mappings tab only supports keyboards");
_rgbService = rgbService;
_inputService = inputService;
Device = device;
DisplayName = "INPUT MAPPINGS";
InputMappings = new BindableCollection<Tuple<ArtemisLed, ArtemisLed>>();
}
public ArtemisDevice Device { get; }
public ArtemisLed SelectedLed
{
get => _selectedLed;
set => SetAndNotify(ref _selectedLed, value);
}
public BindableCollection<Tuple<ArtemisLed, ArtemisLed>> InputMappings { get; }
public void DeleteMapping(Tuple<ArtemisLed, ArtemisLed> inputMapping)
{
Device.InputMappings.Remove(inputMapping.Item1);
UpdateInputMappings();
}
private void InputServiceOnKeyboardKeyUp(object sender, ArtemisKeyboardKeyEventArgs e)
{
if (SelectedLed == null || e.Led == null)
return;
// Locate the original LED the same way the InputService did it, but supply false to Device.GetLed
bool foundLedId = InputKeyUtilities.KeyboardKeyLedIdMap.TryGetValue(e.Key, out LedId ledId);
if (!foundLedId)
return;
ArtemisLed artemisLed = Device.GetLed(ledId, false);
if (artemisLed == null)
return;
// Apply the new LED mapping
Device.InputMappings[SelectedLed] = artemisLed;
_rgbService.SaveDevice(Device);
((DeviceDialogViewModel) Parent).SelectedLeds.Clear();
UpdateInputMappings();
}
private void UpdateInputMappings()
{
if (InputMappings.Any())
InputMappings.Clear();
InputMappings.AddRange(Device.InputMappings.Select(m => new Tuple<ArtemisLed, ArtemisLed>(m.Key, m.Value)));
}
private void SelectedLedsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
SelectedLed = ((DeviceDialogViewModel) Parent).SelectedLeds.FirstOrDefault();
}
#region Overrides of Screen
/// <inheritdoc />
protected override void OnActivate()
{
UpdateInputMappings();
_inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp;
((DeviceDialogViewModel) Parent).SelectedLeds.CollectionChanged += SelectedLedsOnCollectionChanged;
base.OnActivate();
}
/// <inheritdoc />
protected override void OnDeactivate()
{
InputMappings.Clear();
_inputService.KeyboardKeyUp -= InputServiceOnKeyboardKeyUp;
((DeviceDialogViewModel) Parent).SelectedLeds.CollectionChanged -= SelectedLedsOnCollectionChanged;
base.OnDeactivate();
}
#endregion
}
}

View File

@ -72,17 +72,17 @@
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Startup delay</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">Startup delay</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap">
Set the amount of seconds to wait before running Artemis with Windows. <LineBreak/> Set the amount of seconds to wait before running Artemis with Windows. <LineBreak />
If some devices don't work because Artemis starts before the manufacturer's software, try increasing this value. If some devices don't work because Artemis starts before the manufacturer's software, try increasing this value.
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<TextBox Style="{StaticResource MaterialDesignFilledTextBox}" <TextBox Style="{StaticResource MaterialDesignFilledTextBox}"
Text="{Binding AutoRunDelay}" Text="{Binding AutoRunDelay}"
IsEnabled="{Binding StartWithWindows}" IsEnabled="{Binding StartWithWindows}"
Width="100" Width="100"
materialDesign:TextFieldAssist.SuffixText="sec" materialDesign:TextFieldAssist.SuffixText="sec"
materialDesign:HintAssist.IsFloating="false"/> materialDesign:HintAssist.IsFloating="false" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" /> <Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
@ -103,13 +103,13 @@
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ComboBox Style="{StaticResource MaterialDesignFilledComboBox}" <ComboBox Style="{StaticResource MaterialDesignFilledComboBox}"
Width="100" Width="100"
SelectedValue="{Binding SelectedColorScheme}" SelectedValue="{Binding SelectedColorScheme}"
ItemsSource="{Binding ColorSchemes}" ItemsSource="{Binding ColorSchemes}"
SelectedValuePath="Value" SelectedValuePath="Value"
DisplayMemberPath="Description" DisplayMemberPath="Description"
materialDesign:HintAssist.IsFloating="false"/> materialDesign:HintAssist.IsFloating="false" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" /> <Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
@ -130,13 +130,13 @@
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ComboBox Style="{StaticResource MaterialDesignFilledComboBox}" <ComboBox Style="{StaticResource MaterialDesignFilledComboBox}"
Width="100" Width="100"
SelectedValue="{Binding SelectedLogLevel}" SelectedValue="{Binding SelectedLogLevel}"
ItemsSource="{Binding LogLevels}" ItemsSource="{Binding LogLevels}"
SelectedValuePath="Value" SelectedValuePath="Value"
DisplayMemberPath="Description" DisplayMemberPath="Description"
materialDesign:HintAssist.IsFloating="false"/> materialDesign:HintAssist.IsFloating="false" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" /> <Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
@ -187,7 +187,7 @@
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<TextBox Style="{StaticResource MaterialDesignFilledTextBox}" Text="{Binding WebServerPortSetting.Value}" Width="100" <TextBox Style="{StaticResource MaterialDesignFilledTextBox}" Text="{Binding WebServerPortSetting.Value}" Width="100"
materialDesign:HintAssist.IsFloating="false"/> materialDesign:HintAssist.IsFloating="false" />
</StackPanel> </StackPanel>
</Grid> </Grid>
</StackPanel> </StackPanel>
@ -343,7 +343,7 @@
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ComboBox Style="{StaticResource MaterialDesignFilledComboBox}" <ComboBox Style="{StaticResource MaterialDesignFilledComboBox}"
Width="100" Width="100"
SelectedItem="{Binding PreferredGraphicsContext}" SelectedItem="{Binding PreferredGraphicsContext}"
materialDesign:HintAssist.IsFloating="false"> materialDesign:HintAssist.IsFloating="false">
<system:String>Software</system:String> <system:String>Software</system:String>
<system:String>Vulkan</system:String> <system:String>Vulkan</system:String>
@ -364,16 +364,17 @@
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Render scale</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">Render scale</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap">
Sets the resolution Artemis renders at, higher scale means more CPU-usage, especially on large surfaces. Sets the resolution Artemis renders at, higher scale means more CPU-usage, especially on large surfaces. <LineBreak />
<Run Foreground="GoldenRod">A scale of 25% may be required for very large surfaces but could cause LED dimming or bleeding.</Run>
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ComboBox Style="{StaticResource MaterialDesignFilledComboBox}" <ComboBox Style="{StaticResource MaterialDesignFilledComboBox}"
Width="100" Width="100"
SelectedItem="{Binding SelectedRenderScale}" SelectedItem="{Binding SelectedRenderScale}"
ItemsSource="{Binding RenderScales}" ItemsSource="{Binding RenderScales}"
DisplayMemberPath="Item1" DisplayMemberPath="Item1"
materialDesign:HintAssist.IsFloating="false"/> materialDesign:HintAssist.IsFloating="false" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" /> <Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
@ -399,7 +400,7 @@
SelectedItem="{Binding SelectedTargetFrameRate}" SelectedItem="{Binding SelectedTargetFrameRate}"
ItemsSource="{Binding TargetFrameRates}" ItemsSource="{Binding TargetFrameRates}"
DisplayMemberPath="Item1" DisplayMemberPath="Item1"
materialDesign:HintAssist.IsFloating="false"/> materialDesign:HintAssist.IsFloating="false" />
</StackPanel> </StackPanel>
</Grid> </Grid>
</StackPanel> </StackPanel>