diff --git a/src/Artemis.Core/Artemis.Core.csproj.DotSettings b/src/Artemis.Core/Artemis.Core.csproj.DotSettings
index 006fb1134..914c8e232 100644
--- a/src/Artemis.Core/Artemis.Core.csproj.DotSettings
+++ b/src/Artemis.Core/Artemis.Core.csproj.DotSettings
@@ -55,6 +55,7 @@
True
True
True
+ True
True
True
True
diff --git a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs
index 1bcb14540..8bffa761d 100644
--- a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs
+++ b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Artemis.Core.DeviceProviders;
@@ -22,6 +23,7 @@ namespace Artemis.Core
RgbDevice = rgbDevice;
DeviceProvider = deviceProvider;
Surface = surface;
+ InputIdentifiers = new List();
DeviceEntity = new DeviceEntity();
_leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
@@ -38,6 +40,7 @@ namespace Artemis.Core
RgbDevice = rgbDevice;
DeviceProvider = deviceProvider;
Surface = surface;
+ InputIdentifiers = new List();
DeviceEntity = deviceEntity;
_leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
}
@@ -84,6 +87,11 @@ namespace Artemis.Core
private set => SetAndNotify(ref _leds, value);
}
+ ///
+ /// Gets a list of input identifiers associated with this device
+ ///
+ public List InputIdentifiers { get; }
+
///
/// Gets or sets the X-position of the device
///
@@ -174,6 +182,16 @@ namespace Artemis.Core
{
// Other properties are computed
DeviceEntity.DeviceIdentifier = RgbDevice.GetDeviceIdentifier();
+
+ DeviceEntity.InputIdentifier.Clear();
+ foreach (ArtemisDeviceInputIdentifier identifier in InputIdentifiers)
+ {
+ DeviceEntity.InputIdentifier.Add(new DeviceInputIdentifierEntity
+ {
+ InputProvider = identifier.InputProvider,
+ Identifier = identifier.Identifier
+ });
+ }
}
internal void ApplyToRgbDevice()
@@ -186,6 +204,10 @@ namespace Artemis.Core
RgbDevice.Location = new Point(1, 1);
RgbDevice.Location = new Point(DeviceEntity.X, DeviceEntity.Y);
+ InputIdentifiers.Clear();
+ foreach (DeviceInputIdentifierEntity identifierEntity in DeviceEntity.InputIdentifier)
+ InputIdentifiers.Add(new ArtemisDeviceInputIdentifier(identifierEntity.InputProvider, identifierEntity.Identifier));
+
CalculateRenderProperties();
OnDeviceUpdated();
}
diff --git a/src/Artemis.Core/Models/Surface/ArtemisDeviceInputIdentifier.cs b/src/Artemis.Core/Models/Surface/ArtemisDeviceInputIdentifier.cs
new file mode 100644
index 000000000..6af52fccb
--- /dev/null
+++ b/src/Artemis.Core/Models/Surface/ArtemisDeviceInputIdentifier.cs
@@ -0,0 +1,31 @@
+using Artemis.Core.Services;
+
+namespace Artemis.Core
+{
+ ///
+ /// Represents a device input identifier used by a specific to identify the device
+ ///
+ public class ArtemisDeviceInputIdentifier
+ {
+ ///
+ /// Creates a new instance of the class
+ ///
+ /// The full type and namespace of the this identifier is used by
+ /// A value used to identify the device
+ public ArtemisDeviceInputIdentifier(string inputProvider, object identifier)
+ {
+ InputProvider = inputProvider;
+ Identifier = identifier;
+ }
+
+ ///
+ /// Gets or sets the full type and namespace of the this identifier is used by
+ ///
+ public string InputProvider { get; set; }
+
+ ///
+ /// Gets or sets a value used to identify the device
+ ///
+ public object Identifier { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/Input/InputKey.cs b/src/Artemis.Core/Services/Input/InputKey.cs
new file mode 100644
index 000000000..b40842b01
--- /dev/null
+++ b/src/Artemis.Core/Services/Input/InputKey.cs
@@ -0,0 +1,359 @@
+namespace Artemis.Core.Services
+{
+ /// Specifies the possible key values on a keyboard.
+ public enum InputKey
+ {
+ /// No key pressed.
+ None = 0,
+ /// The Cancel key.
+ Cancel = 1,
+ /// The Backspace key.
+ Back = 2,
+ /// The Tab key.
+ Tab = 3,
+ /// The Linefeed key.
+ LineFeed = 4,
+ /// The Clear key.
+ Clear = 5,
+ /// The Enter key.
+ Enter = 6,
+ /// The Return key.
+ Return = 6,
+ /// The Pause key.
+ Pause = 7,
+ /// The Caps Lock key.
+ CapsLock = 8,
+ /// The IME Hangul mode key.
+ HangulMode = 9,
+ /// The IME Junja mode key.
+ JunjaMode = 10, // 0x0000000A
+ /// The IME Final mode key.
+ FinalMode = 11, // 0x0000000B
+ /// The IME Hanja mode key.
+ HanjaMode = 12, // 0x0000000C
+ /// The ESC key.
+ Escape = 13, // 0x0000000D
+ /// The IME Convert key.
+ ImeConvert = 14, // 0x0000000E
+ /// The IME NonConvert key.
+ ImeNonConvert = 15, // 0x0000000F
+ /// The IME Accept key.
+ ImeAccept = 16, // 0x00000010
+ /// The IME Mode change request.
+ ImeModeChange = 17, // 0x00000011
+ /// The Spacebar key.
+ Space = 18, // 0x00000012
+ /// The Page Up key.
+ PageUp = 19, // 0x00000013
+ /// The Page Up key.
+ Prior = 19, // 0x00000013
+ /// The Page Down key.
+ Next = 20, // 0x00000014
+ /// The Page Down key.
+ PageDown = 20, // 0x00000014
+ /// The End key.
+ End = 21, // 0x00000015
+ /// The Home key.
+ Home = 22, // 0x00000016
+ /// The Left Arrow key.
+ Left = 23, // 0x00000017
+ /// The Up Arrow key.
+ Up = 24, // 0x00000018
+ /// The Right Arrow key.
+ Right = 25, // 0x00000019
+ /// The Down Arrow key.
+ Down = 26, // 0x0000001A
+ /// The Select key.
+ Select = 27, // 0x0000001B
+ /// The Print key.
+ Print = 28, // 0x0000001C
+ /// The Execute key.
+ Execute = 29, // 0x0000001D
+ /// The Print Screen key.
+ PrintScreen = 30, // 0x0000001E
+ /// The Insert key.
+ Insert = 31, // 0x0000001F
+ /// The Delete key.
+ Delete = 32, // 0x00000020
+ /// The Help key.
+ Help = 33, // 0x00000021
+ /// The 0 (zero) key.
+ D0 = 34, // 0x00000022
+ /// The 1 (one) key.
+ D1 = 35, // 0x00000023
+ /// The 2 key.
+ D2 = 36, // 0x00000024
+ /// The 3 key.
+ D3 = 37, // 0x00000025
+ /// The 4 key.
+ D4 = 38, // 0x00000026
+ /// The 5 key.
+ D5 = 39, // 0x00000027
+ /// The 6 key.
+ D6 = 40, // 0x00000028
+ /// The 7 key.
+ D7 = 41, // 0x00000029
+ /// The 8 key.
+ D8 = 42, // 0x0000002A
+ /// The 9 key.
+ D9 = 43, // 0x0000002B
+ /// The A key.
+ A = 44, // 0x0000002C
+ /// The B key.
+ B = 45, // 0x0000002D
+ /// The C key.
+ C = 46, // 0x0000002E
+ /// The D key.
+ D = 47, // 0x0000002F
+ /// The E key.
+ E = 48, // 0x00000030
+ /// The F key.
+ F = 49, // 0x00000031
+ /// The G key.
+ G = 50, // 0x00000032
+ /// The H key.
+ H = 51, // 0x00000033
+ /// The I key.
+ I = 52, // 0x00000034
+ /// The J key.
+ J = 53, // 0x00000035
+ /// The K key.
+ K = 54, // 0x00000036
+ /// The L key.
+ L = 55, // 0x00000037
+ /// The M key.
+ M = 56, // 0x00000038
+ /// The N key.
+ N = 57, // 0x00000039
+ /// The O key.
+ O = 58, // 0x0000003A
+ /// The P key.
+ P = 59, // 0x0000003B
+ /// The Q key.
+ Q = 60, // 0x0000003C
+ /// The R key.
+ R = 61, // 0x0000003D
+ /// The S key.
+ S = 62, // 0x0000003E
+ /// The T key.
+ T = 63, // 0x0000003F
+ /// The U key.
+ U = 64, // 0x00000040
+ /// The V key.
+ V = 65, // 0x00000041
+ /// The W key.
+ W = 66, // 0x00000042
+ /// The X key.
+ X = 67, // 0x00000043
+ /// The Y key.
+ Y = 68, // 0x00000044
+ /// The Z key.
+ Z = 69, // 0x00000045
+ /// The left Windows logo key (Microsoft Natural Keyboard).
+ LWin = 70, // 0x00000046
+ /// The right Windows logo key (Microsoft Natural Keyboard).
+ RWin = 71, // 0x00000047
+ /// The Application key (Microsoft Natural Keyboard). Also known as the Menu key, as it displays an application-specific context menu.
+ Apps = 72, // 0x00000048
+ /// The Computer Sleep key.
+ Sleep = 73, // 0x00000049
+ /// The 0 key on the numeric keypad.
+ NumPad0 = 74, // 0x0000004A
+ /// The 1 key on the numeric keypad.
+ NumPad1 = 75, // 0x0000004B
+ /// The 2 key on the numeric keypad.
+ NumPad2 = 76, // 0x0000004C
+ /// The 3 key on the numeric keypad.
+ NumPad3 = 77, // 0x0000004D
+ /// The 4 key on the numeric keypad.
+ NumPad4 = 78, // 0x0000004E
+ /// The 5 key on the numeric keypad.
+ NumPad5 = 79, // 0x0000004F
+ /// The 6 key on the numeric keypad.
+ NumPad6 = 80, // 0x00000050
+ /// The 7 key on the numeric keypad.
+ NumPad7 = 81, // 0x00000051
+ /// The 8 key on the numeric keypad.
+ NumPad8 = 82, // 0x00000052
+ /// The 9 key on the numeric keypad.
+ NumPad9 = 83, // 0x00000053
+ /// The Multiply key.
+ Multiply = 84, // 0x00000054
+ /// The Add key.
+ Add = 85, // 0x00000055
+ /// The Separator key.
+ Separator = 86, // 0x00000056
+ /// The Subtract key.
+ Subtract = 87, // 0x00000057
+ /// The Decimal key.
+ Decimal = 88, // 0x00000058
+ /// The Divide key.
+ Divide = 89, // 0x00000059
+ /// The F1 key.
+ F1 = 90, // 0x0000005A
+ /// The F2 key.
+ F2 = 91, // 0x0000005B
+ /// The F3 key.
+ F3 = 92, // 0x0000005C
+ /// The F4 key.
+ F4 = 93, // 0x0000005D
+ /// The F5 key.
+ F5 = 94, // 0x0000005E
+ /// The F6 key.
+ F6 = 95, // 0x0000005F
+ /// The F7 key.
+ F7 = 96, // 0x00000060
+ /// The F8 key.
+ F8 = 97, // 0x00000061
+ /// The F9 key.
+ F9 = 98, // 0x00000062
+ /// The F10 key.
+ F10 = 99, // 0x00000063
+ /// The F11 key.
+ F11 = 100, // 0x00000064
+ /// The F12 key.
+ F12 = 101, // 0x00000065
+ /// The F13 key.
+ F13 = 102, // 0x00000066
+ /// The F14 key.
+ F14 = 103, // 0x00000067
+ /// The F15 key.
+ F15 = 104, // 0x00000068
+ /// The F16 key.
+ F16 = 105, // 0x00000069
+ /// The F17 key.
+ F17 = 106, // 0x0000006A
+ /// The F18 key.
+ F18 = 107, // 0x0000006B
+ /// The F19 key.
+ F19 = 108, // 0x0000006C
+ /// The F20 key.
+ F20 = 109, // 0x0000006D
+ /// The F21 key.
+ F21 = 110, // 0x0000006E
+ /// The F22 key.
+ F22 = 111, // 0x0000006F
+ /// The F23 key.
+ F23 = 112, // 0x00000070
+ /// The F24 key.
+ F24 = 113, // 0x00000071
+ /// The Num Lock key.
+ NumLock = 114, // 0x00000072
+ /// The Scroll Lock key.
+ Scroll = 115, // 0x00000073
+ /// The left Shift key.
+ LeftShift = 116, // 0x00000074
+ /// The right Shift key.
+ RightShift = 117, // 0x00000075
+ /// The left CTRL key.
+ LeftCtrl = 118, // 0x00000076
+ /// The right CTRL key.
+ RightCtrl = 119, // 0x00000077
+ /// The left ALT key.
+ LeftAlt = 120, // 0x00000078
+ /// The right ALT key.
+ RightAlt = 121, // 0x00000079
+ /// The Browser Back key.
+ BrowserBack = 122, // 0x0000007A
+ /// The Browser Forward key.
+ BrowserForward = 123, // 0x0000007B
+ /// The Browser Refresh key.
+ BrowserRefresh = 124, // 0x0000007C
+ /// The Browser Stop key.
+ BrowserStop = 125, // 0x0000007D
+ /// The Browser Search key.
+ BrowserSearch = 126, // 0x0000007E
+ /// The Browser Favorites key.
+ BrowserFavorites = 127, // 0x0000007F
+ /// The Browser Home key.
+ BrowserHome = 128, // 0x00000080
+ /// The Volume Mute key.
+ VolumeMute = 129, // 0x00000081
+ /// The Volume Down key.
+ VolumeDown = 130, // 0x00000082
+ /// The Volume Up key.
+ VolumeUp = 131, // 0x00000083
+ /// The Media Next Track key.
+ MediaNextTrack = 132, // 0x00000084
+ /// The Media Previous Track key.
+ MediaPreviousTrack = 133, // 0x00000085
+ /// The Media Stop key.
+ MediaStop = 134, // 0x00000086
+ /// The Media Play Pause key.
+ MediaPlayPause = 135, // 0x00000087
+ /// The Launch Mail key.
+ LaunchMail = 136, // 0x00000088
+ /// The Select Media key.
+ SelectMedia = 137, // 0x00000089
+ /// The Launch Application1 key.
+ LaunchApplication1 = 138, // 0x0000008A
+ /// The Launch Application2 key.
+ LaunchApplication2 = 139, // 0x0000008B
+ /// The OEM Semicolon key.
+ OemSemicolon = 140, // 0x0000008C
+ /// The OEM Addition key.
+ OemPlus = 141, // 0x0000008D
+ /// The OEM Comma key.
+ OemComma = 142, // 0x0000008E
+ /// The OEM Minus key.
+ OemMinus = 143, // 0x0000008F
+ /// The OEM Period key.
+ OemPeriod = 144, // 0x00000091
+ /// The OEM Question key.
+ OemQuestion = 145, // 0x00000092
+ /// The OEM Tilde key.
+ OemTilde = 146, // 0x00000092
+ /// The ABNT_C1 (Brazilian) key.
+ AbntC1 = 147, // 0x00000093
+ /// The ABNT_C2 (Brazilian) key.
+ AbntC2 = 148, // 0x00000095
+ /// The OEM Open Brackets key.
+ OemOpenBrackets = 149, // 0x00000096
+ /// The OEM Pipe key.
+ OemPipe = 150, // 0x00000096
+ /// The OEM Close Brackets key.
+ OemCloseBrackets = 151, // 0x00000097
+ /// The OEM Quotes key.
+ OemQuotes = 152, // 0x00000098
+ /// The OEM Backslash key.
+ OemBackslash = 154, // 0x0000009A
+ /// A special key masking the real key being processed by an IME.
+ ImeProcessed = 155, // 0x0000009B
+ /// A special key masking the real key being processed as a system key.
+ System = 156, // 0x0000009C
+ /// The OEM ATTN key.
+ OemAttn = 157, // 0x0000009D
+ /// The OEM FINISH key.
+ OemFinish = 158, // 0x0000009E
+ /// The OEM COPY key.
+ OemCopy = 159, // 0x0000009F
+ /// The OEM AUTO key.
+ OemAuto = 160, // 0x000000A0
+ /// The OEM ENLW key.
+ OemEnlw = 161, // 0x000000A1
+ /// The OEM BACKTAB key.
+ OemBackTab = 162, // 0x000000A2
+ /// The ATTN key.
+ Attn = 163, // 0x000000A3
+ /// The CRSEL key.
+ CrSel = 164, // 0x000000A4
+ /// The EXSEL key.
+ ExSel = 165, // 0x000000A5
+ /// The ERASE EOF key.
+ EraseEof = 166, // 0x000000A6
+ /// The PLAY key.
+ Play = 167, // 0x000000A7
+ /// The ZOOM key.
+ Zoom = 168, // 0x000000A8
+ /// A constant reserved for future use.
+ NoName = 169, // 0x000000A9
+ /// The PA1 key.
+ Pa1 = 170, // 0x000000AA
+ /// The OEM Clear key.
+ OemClear = 171, // 0x000000AB
+ /// The key is used with another key to create a single combined character.
+ DeadCharProcessed = 172, // 0x000000AC,
+ /// The NumPad enter key
+ NumPadEnter,
+ }
+}
diff --git a/src/Artemis.Core/Services/Input/InputKeyLedIdMap.cs b/src/Artemis.Core/Services/Input/InputKeyLedIdMap.cs
new file mode 100644
index 000000000..bd53d2717
--- /dev/null
+++ b/src/Artemis.Core/Services/Input/InputKeyLedIdMap.cs
@@ -0,0 +1,185 @@
+using System.Collections.Generic;
+using RGB.NET.Core;
+
+namespace Artemis.Core.Services
+{
+ internal static class InputKeyUtilities
+ {
+ internal static readonly Dictionary LedIdMap = new Dictionary()
+ {
+ {InputKey.None, LedId.Keyboard_Custom1},
+ {InputKey.Cancel, LedId.Keyboard_Custom2},
+ {InputKey.Back, LedId.Keyboard_Backspace},
+ {InputKey.Tab, LedId.Keyboard_Tab},
+ {InputKey.LineFeed, LedId.Keyboard_Custom3},
+ {InputKey.Clear, LedId.Keyboard_Custom4},
+ {InputKey.Enter, LedId.Keyboard_Enter},
+ {InputKey.Pause, LedId.Keyboard_PauseBreak},
+ {InputKey.CapsLock, LedId.Keyboard_CapsLock},
+ {InputKey.HangulMode, LedId.Keyboard_Custom4},
+ {InputKey.JunjaMode, LedId.Keyboard_Custom5},
+ {InputKey.FinalMode, LedId.Keyboard_Custom6},
+ {InputKey.HanjaMode, LedId.Keyboard_Custom7},
+ {InputKey.Escape, LedId.Keyboard_Escape},
+ {InputKey.ImeConvert, LedId.Keyboard_Custom8},
+ {InputKey.ImeNonConvert, LedId.Keyboard_Custom9},
+ {InputKey.ImeAccept, LedId.Keyboard_Custom10},
+ {InputKey.ImeModeChange, LedId.Keyboard_Custom11},
+ {InputKey.Space, LedId.Keyboard_Space},
+ {InputKey.PageUp, LedId.Keyboard_PageUp},
+ {InputKey.PageDown, LedId.Keyboard_PageDown},
+ {InputKey.End, LedId.Keyboard_End},
+ {InputKey.Home, LedId.Keyboard_Home},
+ {InputKey.Left, LedId.Keyboard_ArrowLeft},
+ {InputKey.Up, LedId.Keyboard_ArrowUp},
+ {InputKey.Right, LedId.Keyboard_ArrowRight},
+ {InputKey.Down, LedId.Keyboard_ArrowDown},
+ {InputKey.Select, LedId.Keyboard_Custom12},
+ {InputKey.Print, LedId.Keyboard_Custom13},
+ {InputKey.Execute, LedId.Keyboard_Custom14},
+ {InputKey.PrintScreen, LedId.Keyboard_PrintScreen},
+ {InputKey.Insert, LedId.Keyboard_Insert},
+ {InputKey.Delete, LedId.Keyboard_Delete},
+ {InputKey.Help, LedId.Keyboard_Custom15},
+ {InputKey.D0, LedId.Keyboard_0},
+ {InputKey.D1, LedId.Keyboard_1},
+ {InputKey.D2, LedId.Keyboard_2},
+ {InputKey.D3, LedId.Keyboard_3},
+ {InputKey.D4, LedId.Keyboard_4},
+ {InputKey.D5, LedId.Keyboard_5},
+ {InputKey.D6, LedId.Keyboard_6},
+ {InputKey.D7, LedId.Keyboard_7},
+ {InputKey.D8, LedId.Keyboard_8},
+ {InputKey.D9, LedId.Keyboard_9},
+ {InputKey.A, LedId.Keyboard_A},
+ {InputKey.B, LedId.Keyboard_B},
+ {InputKey.C, LedId.Keyboard_C},
+ {InputKey.D, LedId.Keyboard_D},
+ {InputKey.E, LedId.Keyboard_E},
+ {InputKey.F, LedId.Keyboard_F},
+ {InputKey.G, LedId.Keyboard_G},
+ {InputKey.H, LedId.Keyboard_H},
+ {InputKey.I, LedId.Keyboard_I},
+ {InputKey.J, LedId.Keyboard_J},
+ {InputKey.K, LedId.Keyboard_K},
+ {InputKey.L, LedId.Keyboard_L},
+ {InputKey.M, LedId.Keyboard_M},
+ {InputKey.N, LedId.Keyboard_N},
+ {InputKey.O, LedId.Keyboard_O},
+ {InputKey.P, LedId.Keyboard_P},
+ {InputKey.Q, LedId.Keyboard_Q},
+ {InputKey.R, LedId.Keyboard_R},
+ {InputKey.S, LedId.Keyboard_S},
+ {InputKey.T, LedId.Keyboard_T},
+ {InputKey.U, LedId.Keyboard_U},
+ {InputKey.V, LedId.Keyboard_V},
+ {InputKey.W, LedId.Keyboard_W},
+ {InputKey.X, LedId.Keyboard_X},
+ {InputKey.Y, LedId.Keyboard_Y},
+ {InputKey.Z, LedId.Keyboard_Z},
+ {InputKey.LWin, LedId.Keyboard_LeftGui},
+ {InputKey.RWin, LedId.Keyboard_RightGui},
+ {InputKey.Apps, LedId.Keyboard_Application},
+ {InputKey.Sleep, LedId.Keyboard_Custom16},
+ {InputKey.NumPad0, LedId.Keyboard_Num0},
+ {InputKey.NumPad1, LedId.Keyboard_Num1},
+ {InputKey.NumPad2, LedId.Keyboard_Num2},
+ {InputKey.NumPad3, LedId.Keyboard_Num3},
+ {InputKey.NumPad4, LedId.Keyboard_Num4},
+ {InputKey.NumPad5, LedId.Keyboard_Num5},
+ {InputKey.NumPad6, LedId.Keyboard_Num6},
+ {InputKey.NumPad7, LedId.Keyboard_Num7},
+ {InputKey.NumPad8, LedId.Keyboard_Num8},
+ {InputKey.NumPad9, LedId.Keyboard_Num9},
+ {InputKey.Multiply, LedId.Keyboard_NumAsterisk},
+ {InputKey.Add, LedId.Keyboard_NumPlus},
+ {InputKey.Separator, LedId.Keyboard_NumEnter}, // unverified
+ {InputKey.Subtract, LedId.Keyboard_NumMinus},
+ {InputKey.Decimal, LedId.Keyboard_NumPeriodAndDelete},
+ {InputKey.Divide, LedId.Keyboard_NumSlash},
+ {InputKey.F1, LedId.Keyboard_F1},
+ {InputKey.F2, LedId.Keyboard_F2},
+ {InputKey.F3, LedId.Keyboard_F3},
+ {InputKey.F4, LedId.Keyboard_F4},
+ {InputKey.F5, LedId.Keyboard_F5},
+ {InputKey.F6, LedId.Keyboard_F6},
+ {InputKey.F7, LedId.Keyboard_F7},
+ {InputKey.F8, LedId.Keyboard_F8},
+ {InputKey.F9, LedId.Keyboard_F9},
+ {InputKey.F10, LedId.Keyboard_F10},
+ {InputKey.F11, LedId.Keyboard_F11},
+ {InputKey.F12, LedId.Keyboard_F12},
+ {InputKey.F13, LedId.Keyboard_Custom17},
+ {InputKey.F14, LedId.Keyboard_Custom18},
+ {InputKey.F15, LedId.Keyboard_Custom19},
+ {InputKey.F16, LedId.Keyboard_Custom20},
+ {InputKey.F17, LedId.Keyboard_Custom21},
+ {InputKey.F18, LedId.Keyboard_Custom22},
+ {InputKey.F19, LedId.Keyboard_Custom23},
+ {InputKey.F20, LedId.Keyboard_Custom24},
+ {InputKey.F21, LedId.Keyboard_Custom25},
+ {InputKey.F22, LedId.Keyboard_Custom26},
+ {InputKey.F23, LedId.Keyboard_Custom27},
+ {InputKey.F24, LedId.Keyboard_Custom28},
+ {InputKey.NumLock, LedId.Keyboard_NumLock},
+ {InputKey.Scroll, LedId.Keyboard_ScrollLock},
+ {InputKey.LeftShift, LedId.Keyboard_LeftShift},
+ {InputKey.RightShift, LedId.Keyboard_RightShift},
+ {InputKey.LeftCtrl, LedId.Keyboard_LeftCtrl},
+ {InputKey.RightCtrl, LedId.Keyboard_RightCtrl},
+ {InputKey.LeftAlt, LedId.Keyboard_LeftAlt},
+ {InputKey.RightAlt, LedId.Keyboard_RightAlt},
+ {InputKey.BrowserBack, LedId.Keyboard_Custom29},
+ {InputKey.BrowserForward, LedId.Keyboard_Custom30},
+ {InputKey.BrowserRefresh, LedId.Keyboard_Custom31},
+ {InputKey.BrowserStop, LedId.Keyboard_Custom32},
+ {InputKey.BrowserSearch, LedId.Keyboard_Custom33},
+ {InputKey.BrowserFavorites, LedId.Keyboard_Custom34},
+ {InputKey.BrowserHome, LedId.Keyboard_Custom35},
+ {InputKey.VolumeMute, LedId.Keyboard_MediaMute},
+ {InputKey.VolumeDown, LedId.Keyboard_MediaVolumeDown},
+ {InputKey.VolumeUp, LedId.Keyboard_MediaVolumeUp},
+ {InputKey.MediaNextTrack, LedId.Keyboard_MediaNextTrack},
+ {InputKey.MediaPreviousTrack, LedId.Keyboard_MediaPreviousTrack},
+ {InputKey.MediaStop, LedId.Keyboard_MediaStop},
+ {InputKey.MediaPlayPause, LedId.Keyboard_MediaPlay},
+ {InputKey.LaunchMail, LedId.Keyboard_Custom36},
+ {InputKey.SelectMedia, LedId.Keyboard_Custom37},
+ {InputKey.LaunchApplication1, LedId.Keyboard_Custom38},
+ {InputKey.LaunchApplication2, LedId.Keyboard_Custom39},
+ {InputKey.OemSemicolon, LedId.Keyboard_SemicolonAndColon},
+ {InputKey.OemPlus, LedId.Keyboard_EqualsAndPlus},
+ {InputKey.OemMinus, LedId.Keyboard_MinusAndUnderscore},
+ {InputKey.OemComma, LedId.Keyboard_CommaAndLessThan},
+ {InputKey.OemPeriod, LedId.Keyboard_PeriodAndBiggerThan},
+ {InputKey.OemQuestion, LedId.Keyboard_SlashAndQuestionMark},
+ {InputKey.OemTilde, LedId.Keyboard_GraveAccentAndTilde},
+ {InputKey.AbntC1, LedId.Keyboard_Custom40},
+ {InputKey.AbntC2, LedId.Keyboard_Custom41},
+ {InputKey.OemOpenBrackets, LedId.Keyboard_BracketLeft},
+ {InputKey.OemPipe, LedId.Keyboard_Backslash},
+ {InputKey.OemCloseBrackets, LedId.Keyboard_BracketRight},
+ {InputKey.OemQuotes, LedId.Keyboard_ApostropheAndDoubleQuote},
+ {InputKey.OemBackslash, LedId.Keyboard_Custom42}, // unverified
+ {InputKey.ImeProcessed, LedId.Keyboard_Custom43},
+ {InputKey.System, LedId.Keyboard_Custom44},
+ {InputKey.OemAttn, LedId.Keyboard_Custom45},
+ {InputKey.OemFinish, LedId.Keyboard_Custom46},
+ {InputKey.OemCopy, LedId.Keyboard_Custom47},
+ {InputKey.OemAuto, LedId.Keyboard_Custom48},
+ {InputKey.OemEnlw, LedId.Keyboard_Custom49},
+ {InputKey.OemBackTab, LedId.Keyboard_Custom50},
+ {InputKey.Attn, LedId.Keyboard_Custom51},
+ {InputKey.CrSel, LedId.Keyboard_Custom52},
+ {InputKey.ExSel, LedId.Keyboard_Custom53},
+ {InputKey.EraseEof, LedId.Keyboard_Custom54},
+ {InputKey.Play, LedId.Keyboard_MediaPlay},
+ {InputKey.Zoom, LedId.Keyboard_Custom55},
+ {InputKey.NoName, LedId.Keyboard_Custom56},
+ {InputKey.Pa1, LedId.Keyboard_Custom57},
+ {InputKey.OemClear, LedId.Keyboard_Custom58},
+ {InputKey.DeadCharProcessed, LedId.Keyboard_Custom59},
+ {InputKey.NumPadEnter, LedId.Keyboard_NumEnter},
+ };
+ }
+}
diff --git a/src/Artemis.Core/Services/Input/InputProvider.cs b/src/Artemis.Core/Services/Input/InputProvider.cs
new file mode 100644
index 000000000..07ddd71a6
--- /dev/null
+++ b/src/Artemis.Core/Services/Input/InputProvider.cs
@@ -0,0 +1,49 @@
+using System;
+
+namespace Artemis.Core.Services
+{
+ ///
+ /// Represents an interface for an input provider that provides and implementation for sending and receiving device
+ /// input
+ ///
+ public abstract class InputProvider : IDisposable
+ {
+ ///
+ /// Occurs when the input provided has received keyboard data
+ ///
+ public event EventHandler? KeyboardDataReceived;
+
+ ///
+ /// Invokes the event
+ ///
+ protected virtual void OnKeyboardDataReceived(InputProviderKeyboardEventArgs e)
+ {
+ KeyboardDataReceived?.Invoke(this, e);
+ }
+
+ #region IDisposable
+
+ ///
+ /// Releases the unmanaged resources used by the object and optionally releases the managed resources.
+ ///
+ ///
+ /// to release both managed and unmanaged resources;
+ /// to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ }
+ }
+
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/Input/InputProviderKeyboardEventArgs.cs b/src/Artemis.Core/Services/Input/InputProviderKeyboardEventArgs.cs
new file mode 100644
index 000000000..a021d0e6e
--- /dev/null
+++ b/src/Artemis.Core/Services/Input/InputProviderKeyboardEventArgs.cs
@@ -0,0 +1,37 @@
+using System;
+
+namespace Artemis.Core.Services
+{
+ ///
+ /// Contains data for input provider keyboard events
+ ///
+ public class InputProviderKeyboardEventArgs : EventArgs
+ {
+ ///
+ ///
+ /// The device that triggered the event
+ /// The key that triggered the event
+ /// Whether the key is pressed down
+ public InputProviderKeyboardEventArgs(ArtemisDevice device, InputKey key, bool isDown)
+ {
+ Device = device;
+ Key = key;
+ IsDown = isDown;
+ }
+
+ ///
+ /// Gets the device that triggered the event
+ ///
+ public ArtemisDevice Device { get; }
+
+ ///
+ /// Gets the key that triggered the event
+ ///
+ public InputKey Key { get; }
+
+ ///
+ /// Gets whether the key is pressed down
+ ///
+ public bool IsDown { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/Input/InputService.cs b/src/Artemis.Core/Services/Input/InputService.cs
new file mode 100644
index 000000000..d342352ef
--- /dev/null
+++ b/src/Artemis.Core/Services/Input/InputService.cs
@@ -0,0 +1,59 @@
+using System.Collections.Generic;
+using RGB.NET.Core;
+using Serilog;
+
+namespace Artemis.Core.Services
+{
+ internal class InputService : IInputService
+ {
+ private readonly ILogger _logger;
+ private readonly List _inputProviders;
+
+ public InputService(ILogger logger)
+ {
+ _logger = logger;
+ _inputProviders = new List();
+ }
+
+ public void AddInputProvider(InputProvider inputProvider)
+ {
+ _inputProviders.Add(inputProvider);
+ inputProvider.KeyboardDataReceived += InputProviderOnKeyboardDataReceived;
+ }
+
+ public void RemoveInputProvider(InputProvider inputProvider)
+ {
+ if (!_inputProviders.Contains(inputProvider))
+ return;
+
+ inputProvider.KeyboardDataReceived -= InputProviderOnKeyboardDataReceived;
+ }
+
+ private void InputProviderOnKeyboardDataReceived(object? sender, InputProviderKeyboardEventArgs e)
+ {
+ if (!(sender is InputProvider inputProvider))
+ return;
+
+ bool foundLedId = InputKeyUtilities.LedIdMap.TryGetValue(e.Key, out LedId ledId);
+ _logger.Verbose("Received keyboard data: LED ID: {ledId}, key: {key}, is down: {isDown}, device: {device} ", ledId, e.Key, e.IsDown, e.Device);
+ }
+ }
+
+ ///
+ /// A service that allows you to interact with keyboard and mice input events
+ ///
+ public interface IInputService : IArtemisService
+ {
+ ///
+ /// Adds an input provided
+ ///
+ /// The input provider the add
+ void AddInputProvider(InputProvider inputProvider);
+
+ ///
+ /// Removes an input provided
+ ///
+ /// The input provider the remove
+ void RemoveInputProvider(InputProvider inputProvider);
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs
index e9b401081..f0cafdff2 100644
--- a/src/Artemis.Core/Services/PluginManagementService.cs
+++ b/src/Artemis.Core/Services/PluginManagementService.cs
@@ -245,7 +245,7 @@ namespace Artemis.Core.Services
// Load the entity and fall back on creating a new one
Plugin plugin = new Plugin(pluginInfo, directory, _pluginRepository.GetPluginByGuid(pluginInfo.Guid));
OnPluginLoading(new PluginEventArgs(plugin));
-
+
// Locate the main assembly entry
string? mainFile = plugin.ResolveRelativePath(plugin.Info.Main);
if (!File.Exists(mainFile))
@@ -289,6 +289,8 @@ namespace Artemis.Core.Services
// Create the Ninject child kernel and load the module
plugin.Kernel = new ChildKernel(_kernel, new PluginModule(plugin));
+ OnPluginEnabling(new PluginEventArgs(plugin));
+
plugin.SetEnabled(true);
// Get the Plugin feature from the main assembly and if there is only one, instantiate it
diff --git a/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs b/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs
index 6bc93a3ad..38712cf13 100644
--- a/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs
+++ b/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs
@@ -1,12 +1,27 @@
-namespace Artemis.Storage.Entities.Surface
+using System.Collections.Generic;
+
+namespace Artemis.Storage.Entities.Surface
{
public class DeviceEntity
{
+ public DeviceEntity()
+ {
+ InputIdentifier = new List();
+ }
+
public string DeviceIdentifier { get; set; }
public double X { get; set; }
public double Y { get; set; }
public double Rotation { get; set; }
public double Scale { get; set; }
public int ZIndex { get; set; }
+
+ public List InputIdentifier { get; set; }
+ }
+
+ public class DeviceInputIdentifierEntity
+ {
+ public string InputProvider { get; set; }
+ public object Identifier { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj
index fa3a16690..00b623a35 100644
--- a/src/Artemis.UI/Artemis.UI.csproj
+++ b/src/Artemis.UI/Artemis.UI.csproj
@@ -142,6 +142,7 @@
+
diff --git a/src/Artemis.UI/Bootstrapper.cs b/src/Artemis.UI/Bootstrapper.cs
index 7f9496f63..0af16c76c 100644
--- a/src/Artemis.UI/Bootstrapper.cs
+++ b/src/Artemis.UI/Bootstrapper.cs
@@ -14,6 +14,7 @@ using Artemis.Core.Ninject;
using Artemis.Core.Services;
using Artemis.UI.Ninject;
using Artemis.UI.Screens;
+using Artemis.UI.Services;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using Artemis.UI.Stylet;
@@ -42,6 +43,7 @@ namespace Artemis.UI
ILogger logger = Kernel.Get();
IViewManager viewManager = Kernel.Get();
+ IRegistrationService registrationService = Kernel.Get();
StartupArguments = Args.ToList();
CreateDataDirectory(logger);
@@ -70,7 +72,7 @@ namespace Artemis.UI
{
if (StartupArguments.Contains("--autorun"))
{
- logger.Information("Sleeping for 15 seconds on auto run to allow applications like iCUE and LGS to start");
+ logger.Information("Sleeping for 15 seconds on auto run to allow vendor applications required for SDKs to start");
await Task.Delay(TimeSpan.FromSeconds(15));
}
@@ -83,6 +85,8 @@ namespace Artemis.UI
throw;
}
});
+
+ registrationService.RegisterInputProvider();
}
protected override void ConfigureIoC(IKernel kernel)
diff --git a/src/Artemis.UI/InputProviders/NativeWindowInputProvider.cs b/src/Artemis.UI/InputProviders/NativeWindowInputProvider.cs
new file mode 100644
index 000000000..41bb7dcd5
--- /dev/null
+++ b/src/Artemis.UI/InputProviders/NativeWindowInputProvider.cs
@@ -0,0 +1,141 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows.Forms;
+using System.Windows.Input;
+using Artemis.Core;
+using Artemis.Core.Services;
+using Linearstar.Windows.RawInput;
+using Linearstar.Windows.RawInput.Native;
+using RGB.NET.Core;
+
+namespace Artemis.UI.InputProviders
+{
+ public class NativeWindowInputProvider : InputProvider
+ {
+ private const int WM_INPUT = 0x00FF;
+
+ private readonly ISurfaceService _surfaceService;
+ private List _keyboards;
+ private DateTime _lastMouseUpdate;
+ private List _mice;
+ private SpongeWindow _sponge;
+
+ public NativeWindowInputProvider(ISurfaceService surfaceService)
+ {
+ _surfaceService = surfaceService;
+
+ _sponge = new SpongeWindow();
+ _sponge.WndProcCalled += SpongeOnWndProcCalled;
+
+ RawInputDevice.RegisterDevice(HidUsageAndPage.Keyboard, RawInputDeviceFlags.ExInputSink | RawInputDeviceFlags.NoLegacy, _sponge.Handle);
+ RawInputDevice.RegisterDevice(HidUsageAndPage.Mouse, RawInputDeviceFlags.InputSink, _sponge.Handle);
+
+ _surfaceService.ActiveSurfaceConfigurationSelected += SurfaceConfigurationChanged;
+ _surfaceService.SurfaceConfigurationUpdated += SurfaceConfigurationChanged;
+ GetDevices(surfaceService.ActiveSurface);
+ }
+
+ #region IDisposable
+
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _sponge?.DestroyHandle();
+ _sponge = null;
+
+ _surfaceService.ActiveSurfaceConfigurationSelected -= SurfaceConfigurationChanged;
+ _surfaceService.SurfaceConfigurationUpdated -= SurfaceConfigurationChanged;
+ }
+
+ base.Dispose(disposing);
+ }
+
+ #endregion
+
+ private void SurfaceConfigurationChanged(object sender, SurfaceConfigurationEventArgs e)
+ {
+ GetDevices(e.Surface);
+ }
+
+ private void GetDevices(ArtemisSurface surface)
+ {
+ _keyboards = surface.Devices.Where(d => d.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Keyboard).ToList();
+ _mice = surface.Devices.Where(d => d.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Mouse).ToList();
+ }
+
+ private void SpongeOnWndProcCalled(object sender, Message message)
+ {
+ if (message.Msg != WM_INPUT)
+ return;
+
+ RawInputData data = RawInputData.FromHandle(message.LParam);
+ switch (data)
+ {
+ case RawInputMouseData mouse:
+ HandleMouseData(mouse);
+ break;
+ case RawInputKeyboardData keyboard:
+ HandleKeyboardData(keyboard);
+ break;
+ }
+ }
+
+ private void HandleKeyboardData(RawInputKeyboardData data)
+ {
+ // Get the keyboard that submitted the data
+ ArtemisDevice match = _keyboards?.FirstOrDefault();
+ if (match == null)
+ return;
+
+ InputKey key = (InputKey) KeyInterop.KeyFromVirtualKey(data.Keyboard.VirutalKey);
+
+ // Debug.WriteLine($"VK: {key} ({data.Keyboard.VirutalKey}), Flags: {data.Keyboard.Flags}, Scan code: {data.Keyboard.ScanCode}");
+
+ // Sometimes we get double hits and they resolve to None, ignore those
+ if (key == InputKey.None)
+ return;
+
+ // Right alt triggers LeftCtrl with a different scan code for some reason, ignore those
+ if (key == InputKey.LeftCtrl && data.Keyboard.ScanCode == 56)
+ return;
+
+ // Duplicate keys with different positions can be identified by the LeftKey flag (even though its set of the key that's physically on the right)
+ if (data.Keyboard.Flags == RawKeyboardFlags.LeftKey || data.Keyboard.Flags == (RawKeyboardFlags.LeftKey | RawKeyboardFlags.Up))
+ {
+ if (key == InputKey.Enter)
+ key = InputKey.NumPadEnter;
+ if (key == InputKey.LeftCtrl)
+ key = InputKey.RightCtrl;
+ if (key == InputKey.LeftAlt)
+ key = InputKey.RightAlt;
+ }
+
+ if (key == InputKey.LeftShift && data.Keyboard.ScanCode == 54)
+ key = InputKey.RightShift;
+
+ bool isDown = data.Keyboard.Flags != RawKeyboardFlags.Up &&
+ data.Keyboard.Flags != (RawKeyboardFlags.Up | RawKeyboardFlags.LeftKey) &&
+ data.Keyboard.Flags != (RawKeyboardFlags.Up | RawKeyboardFlags.RightKey);
+
+ OnKeyboardDataReceived(new InputProviderKeyboardEventArgs(match, key, isDown));
+ }
+
+ private void HandleMouseData(RawInputMouseData data)
+ {
+ // Only handle mouse movement 25 times per second
+ if (data.Mouse.Buttons == RawMouseButtonFlags.None)
+ if (DateTime.Now - _lastMouseUpdate < TimeSpan.FromMilliseconds(40))
+ return;
+
+ _lastMouseUpdate = DateTime.Now;
+
+ // Get the keyboard that submitted the data
+ ArtemisDevice match = _mice?.FirstOrDefault();
+ if (match == null)
+ return;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/InputProviders/SpongeWindow.cs b/src/Artemis.UI/InputProviders/SpongeWindow.cs
new file mode 100644
index 000000000..34898ffcd
--- /dev/null
+++ b/src/Artemis.UI/InputProviders/SpongeWindow.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Windows.Forms;
+
+namespace Artemis.UI.InputProviders
+{
+ public sealed class SpongeWindow : NativeWindow
+ {
+ public SpongeWindow()
+ {
+ CreateHandle(new CreateParams());
+ }
+
+ public event EventHandler WndProcCalled;
+
+ protected override void WndProc(ref Message m)
+ {
+ OnWndProcCalled(m);
+ base.WndProc(ref m);
+ }
+
+ private void OnWndProcCalled(Message e)
+ {
+ WndProcCalled?.Invoke(this, e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Services/RegistrationService.cs b/src/Artemis.UI/Services/RegistrationService.cs
index cf4fc5ffc..de139a508 100644
--- a/src/Artemis.UI/Services/RegistrationService.cs
+++ b/src/Artemis.UI/Services/RegistrationService.cs
@@ -3,6 +3,7 @@ using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.DefaultTypes.DataModel.Display;
using Artemis.UI.DefaultTypes.DataModel.Input;
+using Artemis.UI.InputProviders;
using Artemis.UI.Ninject;
using Artemis.UI.PropertyInput;
using Artemis.UI.Services.Interfaces;
@@ -15,18 +16,26 @@ namespace Artemis.UI.Services
private readonly IDataModelUIService _dataModelUIService;
private readonly IProfileEditorService _profileEditorService;
private readonly IPluginManagementService _pluginManagementService;
+ private readonly ISurfaceService _surfaceService;
+ private readonly IInputService _inputService;
private bool _registeredBuiltInDataModelDisplays;
private bool _registeredBuiltInDataModelInputs;
private bool _registeredBuiltInPropertyEditors;
- public RegistrationService(IDataModelUIService dataModelUIService, IProfileEditorService profileEditorService, IPluginManagementService pluginManagementService)
+ public RegistrationService(IDataModelUIService dataModelUIService,
+ IProfileEditorService profileEditorService,
+ IPluginManagementService pluginManagementService,
+ ISurfaceService surfaceService,
+ IInputService inputService)
{
_dataModelUIService = dataModelUIService;
_profileEditorService = profileEditorService;
_pluginManagementService = pluginManagementService;
+ _surfaceService = surfaceService;
+ _inputService = inputService;
LoadPluginModules();
- pluginManagementService.PluginLoaded += PluginServiceOnPluginLoaded;
+ pluginManagementService.PluginEnabling += PluginServiceOnPluginEnabling;
}
public void RegisterBuiltInDataModelDisplays()
@@ -74,7 +83,12 @@ namespace Artemis.UI.Services
_registeredBuiltInPropertyEditors = true;
}
- private void PluginServiceOnPluginLoaded(object sender, PluginEventArgs e)
+ public void RegisterInputProvider()
+ {
+ _inputService.AddInputProvider(new NativeWindowInputProvider(_surfaceService));
+ }
+
+ private void PluginServiceOnPluginEnabling(object sender, PluginEventArgs e)
{
e.Plugin.Kernel.Load(new[] {new PluginUIModule(e.Plugin)});
}
@@ -91,5 +105,6 @@ namespace Artemis.UI.Services
void RegisterBuiltInDataModelDisplays();
void RegisterBuiltInDataModelInputs();
void RegisterBuiltInPropertyEditors();
+ void RegisterInputProvider();
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/packages.lock.json b/src/Artemis.UI/packages.lock.json
index 8d7a7ed8d..bf637b63b 100644
--- a/src/Artemis.UI/packages.lock.json
+++ b/src/Artemis.UI/packages.lock.json
@@ -80,6 +80,15 @@
"Ninject.Extensions.Factory": "3.3.2"
}
},
+ "RawInput.Sharp": {
+ "type": "Direct",
+ "requested": "[0.0.3, )",
+ "resolved": "0.0.3",
+ "contentHash": "X5EuJYuU0RWzOnA68cHmLEJ4czhgu0EsQj3o5RtYSdTNnTnXo/zVNAXQWPWbBXgoLsws1WTsT567yX0HKjS4aA==",
+ "dependencies": {
+ "NETStandard.Library": "1.6.1"
+ }
+ },
"Serilog": {
"type": "Direct",
"requested": "[2.9.0, )",