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

Simplified scan code input parsing

This commit is contained in:
Diogo Trindade 2023-04-06 15:32:02 +01:00
parent 93dafd420e
commit 02ecbfa708
2 changed files with 147 additions and 192 deletions

View File

@ -98,17 +98,21 @@ public class WindowsInputProvider : InputProvider
private void HandleKeyboardData(RawInputData data, RawInputKeyboardData keyboardData) private void HandleKeyboardData(RawInputData data, RawInputKeyboardData keyboardData)
{ {
KeyboardKey key = InputUtilities.CorrectVirtualKeyAndScanCode((uint)keyboardData.Keyboard.VirutalKey, (uint)keyboardData.Keyboard.ScanCode, (uint)keyboardData.Keyboard.Flags); KeyboardKey key = KeyboardKey.None;
try
{
key = InputUtilities.CorrectVirtualKeyAndScanCode(keyboardData.Keyboard.VirutalKey, keyboardData.Keyboard.ScanCode, (uint)keyboardData.Keyboard.Flags);
}
catch (Exception e)
{
_logger.Error("Failed to convert virtual key to Artemis key, please share this log with the developers. ScanCode: {scanCode} VK: {virtualKey} Flags: {flags}",
keyboardData.Keyboard.ScanCode, keyboardData.Keyboard.VirutalKey, keyboardData.Keyboard.Flags);
}
// Debug.WriteLine($"VK: {key} ({keyboardData.Keyboard.VirutalKey}), Flags: {keyboardData.Keyboard.Flags}, Scan code: {keyboardData.Keyboard.ScanCode}"); // Debug.WriteLine($"VK: {key} ({keyboardData.Keyboard.VirutalKey}), Flags: {keyboardData.Keyboard.Flags}, Scan code: {keyboardData.Keyboard.ScanCode}");
// Sometimes we get double hits and they resolve to None, ignore those
if (key == KeyboardKey.None) if (key == KeyboardKey.None)
return; return;
// Right alt triggers LeftCtrl with a different scan code for some reason, ignore those
if (key == KeyboardKey.LeftCtrl && keyboardData.Keyboard.ScanCode == 56)
return;
string? identifier = data.Device?.DevicePath; string? identifier = data.Device?.DevicePath;
// Let the core know there is an identifier so it can store new identifications if applicable // Let the core know there is an identifier so it can store new identifications if applicable
@ -126,20 +130,6 @@ public class WindowsInputProvider : InputProvider
_logger.Warning(e, "Failed to retrieve input device by its identifier"); _logger.Warning(e, "Failed to retrieve input device by its identifier");
} }
// 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 (keyboardData.Keyboard.Flags == RawKeyboardFlags.KeyE0 || keyboardData.Keyboard.Flags == (RawKeyboardFlags.KeyE0 | RawKeyboardFlags.Up))
{
if (key == KeyboardKey.Enter)
key = KeyboardKey.NumPadEnter;
if (key == KeyboardKey.LeftCtrl)
key = KeyboardKey.RightCtrl;
if (key == KeyboardKey.LeftAlt)
key = KeyboardKey.RightAlt;
}
if (key == KeyboardKey.LeftShift && keyboardData.Keyboard.ScanCode == 54)
key = KeyboardKey.RightShift;
bool isDown = keyboardData.Keyboard.Flags != RawKeyboardFlags.Up && bool isDown = keyboardData.Keyboard.Flags != RawKeyboardFlags.Up &&
keyboardData.Keyboard.Flags != (RawKeyboardFlags.Up | RawKeyboardFlags.KeyE0) && keyboardData.Keyboard.Flags != (RawKeyboardFlags.Up | RawKeyboardFlags.KeyE0) &&
keyboardData.Keyboard.Flags != (RawKeyboardFlags.Up | RawKeyboardFlags.KeyE1); keyboardData.Keyboard.Flags != (RawKeyboardFlags.Up | RawKeyboardFlags.KeyE1);

View File

@ -67,79 +67,63 @@ public static class InputUtilities
MAPVK_VK_TO_VSC_EX = 0x04 MAPVK_VK_TO_VSC_EX = 0x04
} }
private readonly record struct KeystrokeInfo(int ScanCode, int VirtualKey, bool IsE0, bool IsE1);
/// <summary> /// <summary>
/// https://blog.molecular-matters.com/2011/09/05/properly-handling-keyboard-input/ /// https://blog.molecular-matters.com/2011/09/05/properly-handling-keyboard-input/
/// </summary> /// </summary>
public static KeyboardKey CorrectVirtualKeyAndScanCode(uint virtualKey, uint scanCode, uint flags) public static KeyboardKey CorrectVirtualKeyAndScanCode(int virtualKey, int scanCode, uint flags)
{ {
if (virtualKey == 255) KeystrokeInfo info = new()
{ {
// discard "fake keys" which are part of an escaped sequence ScanCode = scanCode,
return KeyboardKey.None; VirtualKey = virtualKey,
} IsE0 = (flags & 2) != 0,
IsE1 = (flags & 4) != 0
if (virtualKey == NativeMethods.VK_CONTROL && scanCode == 0x38)
{
//fake altgr ctrl
return KeyboardKey.None;
}
if (virtualKey == NativeMethods.VK_SHIFT)
{
// correct left-hand / right-hand SHIFT
virtualKey = MapVirtualKey(scanCode, MapVirtualKeyMapTypes.MAPVK_VSC_TO_VK);
}
else if (virtualKey == NativeMethods.VK_NUMLOCK)
{
// correct PAUSE/BREAK and NUM LOCK silliness, and set the extended bit
scanCode = MapVirtualKey(virtualKey, MapVirtualKeyMapTypes.MAPVK_VK_TO_VSC) | 0x100;
}
const byte RI_KEY_E0 = 0x02;
const byte RI_KEY_E1 = 0x04;
bool isE0 = (flags & RI_KEY_E0) != 0;
bool isE1 = (flags & RI_KEY_E1) != 0;
if (isE1)
{
if (virtualKey == NativeMethods.VK_PAUSE)
{
scanCode = 0x45;
}
else
{
scanCode = MapVirtualKey(virtualKey, MapVirtualKeyMapTypes.MAPVK_VK_TO_VSC);
}
}
KeyboardKey key = (short)virtualKey switch
{
NativeMethods.VK_CONTROL => isE0 ? KeyboardKey.RightCtrl : KeyboardKey.LeftCtrl,
NativeMethods.VK_MENU => isE0 ? KeyboardKey.RightAlt : KeyboardKey.LeftAlt,
NativeMethods.VK_RETURN => isE0 ? KeyboardKey.NumPadEnter : KeyboardKey.Enter,
NativeMethods.VK_INSERT => !isE0 ? KeyboardKey.NumPad0 : KeyboardKey.Insert,
NativeMethods.VK_DELETE => !isE0 ? KeyboardKey.NumPadDecimal : KeyboardKey.Delete,
NativeMethods.VK_HOME => !isE0 ? KeyboardKey.NumPad7 : KeyboardKey.Home,
NativeMethods.VK_END => !isE0 ? KeyboardKey.NumPad1 : KeyboardKey.End,
NativeMethods.VK_PRIOR => !isE0 ? KeyboardKey.NumPad9 : KeyboardKey.PageUp,
NativeMethods.VK_NEXT => !isE0 ? KeyboardKey.NumPad3 : KeyboardKey.PageDown,
NativeMethods.VK_LEFT => !isE0 ? KeyboardKey.NumPad4 : KeyboardKey.Left,
NativeMethods.VK_RIGHT => !isE0 ? KeyboardKey.NumPad6 : KeyboardKey.Right,
NativeMethods.VK_UP => !isE0 ? KeyboardKey.NumPad8 : KeyboardKey.Up,
NativeMethods.VK_DOWN => !isE0 ? KeyboardKey.NumPad2 : KeyboardKey.Down,
NativeMethods.VK_CLEAR => !isE0 ? KeyboardKey.NumPad5 : KeyboardKey.Clear,
NativeMethods.VK_DIVIDE => isE0 ? KeyboardKey.NumPadDivide : KeyboardKey.Divide,
NativeMethods.VK_MULTIPLY => isE0 ? KeyboardKey.NumPadMultiply : KeyboardKey.Multiply,
_ => KeyboardKey.None
}; };
if (key != KeyboardKey.None)
return key;
key = KeyFromScanCode(scanCode);
if (key != KeyboardKey.None)
return key;
return KeyFromVirtualKey((int)virtualKey);
return info switch
{
// Fake keys, usually escape sequences
{ VirtualKey: 255 } => KeyboardKey.None,
// AltGr
{ ScanCode: 56, VirtualKey: NativeMethods.VK_CONTROL, IsE0: true } => KeyboardKey.None,
{ ScanCode: 28, IsE0: true } => KeyboardKey.NumPadEnter,
{ ScanCode: 28, IsE0: false } => KeyboardKey.Return,
{ ScanCode: 29, IsE1: true } => KeyboardKey.Pause,
{ ScanCode: 29, IsE0: true } => KeyboardKey.RightCtrl,
{ ScanCode: 29, IsE0: false } => KeyboardKey.LeftCtrl,
{ ScanCode: 56, IsE0: true } => KeyboardKey.RightAlt,
{ ScanCode: 56, IsE0: false } => KeyboardKey.LeftAlt,
{ ScanCode: 53, IsE0: true } => KeyboardKey.NumPadDivide,
{ ScanCode: 53, IsE0: false } => KeyboardKey.OemQuestion,
{ ScanCode: 55, IsE0: true } => KeyboardKey.PrintScreen,
{ ScanCode: 55, IsE0: false } => KeyboardKey.NumPadMultiply,
{ ScanCode: 71, IsE0: true } => KeyboardKey.Home,
{ ScanCode: 71, IsE0: false } => KeyboardKey.NumPad7,
{ ScanCode: 72, IsE0: true } => KeyboardKey.Up,
{ ScanCode: 72, IsE0: false } => KeyboardKey.NumPad8,
{ ScanCode: 73, IsE0: true } => KeyboardKey.PageUp,
{ ScanCode: 73, IsE0: false } => KeyboardKey.NumPad9,
{ ScanCode: 75, IsE0: true } => KeyboardKey.Left,
{ ScanCode: 75, IsE0: false } => KeyboardKey.NumPad4,
{ ScanCode: 76, IsE0: true } => KeyboardKey.Clear,
{ ScanCode: 76, IsE0: false } => KeyboardKey.NumPad5,
{ ScanCode: 77, IsE0: true } => KeyboardKey.Right,
{ ScanCode: 77, IsE0: false } => KeyboardKey.NumPad6,
{ ScanCode: 79, IsE0: true } => KeyboardKey.End,
{ ScanCode: 79, IsE0: false } => KeyboardKey.NumPad1,
{ ScanCode: 80, IsE0: true } => KeyboardKey.Down,
{ ScanCode: 80, IsE0: false } => KeyboardKey.NumPad2,
{ ScanCode: 81, IsE0: true } => KeyboardKey.PageDown,
{ ScanCode: 81, IsE0: false } => KeyboardKey.NumPad3,
{ ScanCode: 82, IsE0: true } => KeyboardKey.Insert,
{ ScanCode: 82, IsE0: false } => KeyboardKey.NumPad0,
{ ScanCode: 83, IsE0: true } => KeyboardKey.Delete,
{ ScanCode: 83, IsE0: false } => KeyboardKey.NumPadDecimal,
_ => KeyFromScanCode((uint)info.ScanCode),
};
} }
public static bool IsKeyDown(KeyboardKey key) public static bool IsKeyDown(KeyboardKey key)
{ {
@ -529,112 +513,93 @@ public static class InputUtilities
{ {
return scanCode switch return scanCode switch
{ {
0x01 => KeyboardKey.Escape, 1 => KeyboardKey.Escape,
0x02 => KeyboardKey.D1, 2 => KeyboardKey.D1,
0x03 => KeyboardKey.D2, 3 => KeyboardKey.D2,
0x04 => KeyboardKey.D3, 4 => KeyboardKey.D3,
0x05 => KeyboardKey.D4, 5 => KeyboardKey.D4,
0x06 => KeyboardKey.D5, 6 => KeyboardKey.D5,
0x07 => KeyboardKey.D6, 7 => KeyboardKey.D6,
0x08 => KeyboardKey.D7, 8 => KeyboardKey.D7,
0x09 => KeyboardKey.D8, 9 => KeyboardKey.D8,
0x0A => KeyboardKey.D9, 10 => KeyboardKey.D9,
0x0B => KeyboardKey.D0, 11 => KeyboardKey.D0,
0x0C => KeyboardKey.OemMinus, 12 => KeyboardKey.OemMinus,
0x0D => KeyboardKey.OemPlus, 13 => KeyboardKey.OemPlus,
0x0E => KeyboardKey.Back, 14 => KeyboardKey.Back,
0x0F => KeyboardKey.Tab, 15 => KeyboardKey.Tab,
0x10 => KeyboardKey.Q, 16 => KeyboardKey.Q,
0x11 => KeyboardKey.W, 17 => KeyboardKey.W,
0x12 => KeyboardKey.E, 18 => KeyboardKey.E,
0x13 => KeyboardKey.R, 19 => KeyboardKey.R,
0x14 => KeyboardKey.T, 20 => KeyboardKey.T,
0x15 => KeyboardKey.Y, 21 => KeyboardKey.Y,
0x16 => KeyboardKey.U, 22 => KeyboardKey.U,
0x17 => KeyboardKey.I, 23 => KeyboardKey.I,
0x18 => KeyboardKey.O, 24 => KeyboardKey.O,
0x19 => KeyboardKey.P, 25 => KeyboardKey.P,
0x1A => KeyboardKey.OemOpenBrackets, 26 => KeyboardKey.OemOpenBrackets,
0x1B => KeyboardKey.OemCloseBrackets, 27 => KeyboardKey.OemCloseBrackets,
0x1C => KeyboardKey.Enter, 30 => KeyboardKey.A,
0x1D => KeyboardKey.LeftCtrl, 31 => KeyboardKey.S,
0x1E => KeyboardKey.A, 32 => KeyboardKey.D,
0x1F => KeyboardKey.S, 33 => KeyboardKey.F,
0x20 => KeyboardKey.D, 34 => KeyboardKey.G,
0x21 => KeyboardKey.F, 35 => KeyboardKey.H,
0x22 => KeyboardKey.G, 36 => KeyboardKey.J,
0x23 => KeyboardKey.H, 37 => KeyboardKey.K,
0x24 => KeyboardKey.J, 38 => KeyboardKey.L,
0x25 => KeyboardKey.K, 39 => KeyboardKey.OemSemicolon,
0x26 => KeyboardKey.L, 40 => KeyboardKey.OemQuotes,
0x27 => KeyboardKey.OemSemicolon, 41 => KeyboardKey.OemTilde,
0x28 => KeyboardKey.OemQuotes, 42 => KeyboardKey.LeftShift,
0x29 => KeyboardKey.OemTilde, 43 => KeyboardKey.OemPipe,
0x2A => KeyboardKey.LeftShift, 44 => KeyboardKey.Z,
0x2B => KeyboardKey.OemPipe, 45 => KeyboardKey.X,
0x2C => KeyboardKey.Z, 46 => KeyboardKey.C,
0x2D => KeyboardKey.X, 47 => KeyboardKey.V,
0x2E => KeyboardKey.C, 48 => KeyboardKey.B,
0x2F => KeyboardKey.V, 49 => KeyboardKey.N,
0x30 => KeyboardKey.B, 50 => KeyboardKey.M,
0x31 => KeyboardKey.N, 51 => KeyboardKey.OemComma,
0x32 => KeyboardKey.M, 52 => KeyboardKey.OemPeriod,
0x33 => KeyboardKey.OemComma, 54 => KeyboardKey.RightShift,
0x34 => KeyboardKey.OemPeriod, 57 => KeyboardKey.Space,
0x35 => KeyboardKey.OemQuestion, 58 => KeyboardKey.CapsLock,
0x36 => KeyboardKey.RightShift, 59 => KeyboardKey.F1,
0x37 => KeyboardKey.PrintScreen, 60 => KeyboardKey.F2,
0x38 => KeyboardKey.LeftAlt, 61 => KeyboardKey.F3,
0x39 => KeyboardKey.Space, 62 => KeyboardKey.F4,
0x3A => KeyboardKey.CapsLock, 63 => KeyboardKey.F5,
0x3B => KeyboardKey.F1, 64 => KeyboardKey.F6,
0x3C => KeyboardKey.F2, 65 => KeyboardKey.F7,
0x3D => KeyboardKey.F3, 66 => KeyboardKey.F8,
0x3E => KeyboardKey.F4, 67 => KeyboardKey.F9,
0x3F => KeyboardKey.F5, 68 => KeyboardKey.F10,
0x40 => KeyboardKey.F6, 69 => KeyboardKey.NumLock,
0x41 => KeyboardKey.F7, 70 => KeyboardKey.Scroll,
0x42 => KeyboardKey.F8, 74 => KeyboardKey.NumPadSubtract,
0x43 => KeyboardKey.F9, 78 => KeyboardKey.NumPadAdd,
0x44 => KeyboardKey.F10, 86 => KeyboardKey.OemBackslash, //On iso, it's the key between left shift and Z
0x45 => KeyboardKey.Pause, 87 => KeyboardKey.F11,
0x46 => KeyboardKey.Scroll, 88 => KeyboardKey.F12,
0x47 => KeyboardKey.NumPad7, 91 => KeyboardKey.LWin,
0x48 => KeyboardKey.NumPad8, 92 => KeyboardKey.RWin,
0x49 => KeyboardKey.NumPad9,
0x4A => KeyboardKey.Subtract, //28 = enter or numpad enter
0x4B => KeyboardKey.NumPad4, //29 = left ctrl or right ctrl
0x4C => KeyboardKey.NumPad5, //53 = numpad slash or slash
0x4D => KeyboardKey.NumPad6, //55 = numpad asterisk or print screen
0x4E => KeyboardKey.Add, //56 = left alt or right alt
0x4F => KeyboardKey.NumPad1, 28 or 29 or 53 or 55 or 56 => throw new ArgumentException($"This key is unsupported: {scanCode}", nameof(scanCode)),
0x50 => KeyboardKey.NumPad2, //numpad 789 or home, up, page up
0x51 => KeyboardKey.NumPad3, >= 71 and <= 73 => throw new ArgumentException("Scan code is for a numpad key. These keys are unsupported.", nameof(scanCode)),
0x52 => KeyboardKey.NumPad0, //numpad 456 or left, clear, right
0x53 => KeyboardKey.Decimal, >= 75 and <= 77 => throw new ArgumentException("Scan code is for a numpad key. These keys are unsupported.", nameof(scanCode)),
0x56 => KeyboardKey.OemBackslash, //numpad 1230., or end, down, page down, ins, del
0x57 => KeyboardKey.F11, >= 79 and <= 83 => throw new ArgumentException("Scan code is for a numpad key. These keys are unsupported.", nameof(scanCode)),
0x58 => KeyboardKey.F12, //shouldn't happen, but there might be more weird keys in other layouts
0x5C => KeyboardKey.RWin, _ => throw new ArgumentException($"This key is unsupported: {scanCode}", nameof(scanCode)),
0x64 => KeyboardKey.F13,
0x65 => KeyboardKey.F14,
0x66 => KeyboardKey.F15,
//0x70 => KeyboardKey.kana,
0x73 => KeyboardKey.AbntC1,
//0x79 => KeyboardKey.Convert,
//0x7B => KeyboardKey.NoConvert,
//0x7D => KeyboardKey.Yen,
0x7E => KeyboardKey.AbntC2,
// 0x8D => KeyboardKey.NumPadEquals,
// 0x90 => KeyboardKey.PreviousTrack,
// 0x91 => KeyboardKey.At,
// 0x92 => KeyboardKey.Colon,
// 0x93 => KeyboardKey.Underline,
// 0x94 => KeyboardKey.Kanji,
// 0x95 => KeyboardKey.Stop,
// 0x96 => KeyboardKey.Ax,
0x145 => KeyboardKey.NumLock,
_ => KeyboardKey.None
}; };
} }
} }