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

@ -364,7 +364,8 @@
<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">