From 18436bd5cb24ed116b6cd4f27362a82a0cd5a6cd Mon Sep 17 00:00:00 2001 From: Clive Galway Date: Tue, 18 Jan 2022 23:49:25 +0000 Subject: [PATCH] SendKeyEvent() now uses TranslateAhkCode() --- .../DeviceHandlers/KeyboardHandler.cs | 14 +-- .../Helpers/ScanCodeHelper.cs | 105 +++++++++++++++++- C#/AutoHotInterception/KeyCode notes.xlsx | Bin 12583 -> 12631 bytes C#/TestApp/Program.cs | 4 +- C#/TestApp/ScanCodeTester.cs | 2 +- C#/UnitTests/TranslateAhkCodeTests.cs | 73 ++++++++++++ ...perTests.cs => TranslateScanCodesTests.cs} | 6 +- C#/UnitTests/UnitTests.csproj | 3 +- 8 files changed, 191 insertions(+), 16 deletions(-) create mode 100644 C#/UnitTests/TranslateAhkCodeTests.cs rename C#/UnitTests/{ScanCodeHelperTests.cs => TranslateScanCodesTests.cs} (94%) diff --git a/C#/AutoHotInterception/DeviceHandlers/KeyboardHandler.cs b/C#/AutoHotInterception/DeviceHandlers/KeyboardHandler.cs index 47e2046..106610c 100644 --- a/C#/AutoHotInterception/DeviceHandlers/KeyboardHandler.cs +++ b/C#/AutoHotInterception/DeviceHandlers/KeyboardHandler.cs @@ -35,18 +35,12 @@ namespace AutoHotInterception.DeviceHandlers /// The State to send (1 = pressed, 0 = released) public void SendKeyEvent(ushort code, int state) { - var st = 1 - state; - var stroke = new ManagedWrapper.Stroke(); - if (code > 255) + var strokes = ScanCodeHelper.TranslateAhkCode(code, state); + for (int i = 0; i < strokes.Count; i++) { - code -= 256; - if (code != 54) // RShift has > 256 code, but state is 0/1 - st += 2; + var stroke = strokes[i]; + ManagedWrapper.Send(DeviceContext, DeviceId, ref stroke, 1); } - - stroke.key.code = code; - stroke.key.state = (ushort)st; - ManagedWrapper.Send(DeviceContext, DeviceId, ref stroke, 1); } #endregion diff --git a/C#/AutoHotInterception/Helpers/ScanCodeHelper.cs b/C#/AutoHotInterception/Helpers/ScanCodeHelper.cs index e64bf63..29cb5f0 100644 --- a/C#/AutoHotInterception/Helpers/ScanCodeHelper.cs +++ b/C#/AutoHotInterception/Helpers/ScanCodeHelper.cs @@ -27,8 +27,20 @@ namespace AutoHotInterception.Helpers 69, // Numlock }; + // Keys which have an E0 state, but have no extended modifier + private static HashSet _e1Keys = new HashSet() + { + 29, // Right Control + 53, // Numpad Div + 56, // Right Alt + 91, // Left Windows + 92, // Right Windows + 93, // Apps + }; + // List of two-stroke keys, used to build _twoStrokeKeyConverter - private static Dictionary _twoStrokeKeys = new Dictionary() + // Also used by SendKeyEvent to work out what extended keys to send + public static readonly Dictionary _twoStrokeKeys = new Dictionary() { { 55, Order.Wrapped }, // PrtScr { 69, Order.Prefixed }, // Pause @@ -58,6 +70,11 @@ namespace AutoHotInterception.Helpers } } + /// + /// Used by ProcessStrokes() KeyboardHandler to translate incoming key(s) from Interception to AHK format + /// + /// A list of one or two Strokes that describe a single key + /// An AHK ScanCode and State public static TranslatedKey TranslateScanCodes(List strokes) { if (strokes.Count == 2) @@ -90,6 +107,92 @@ namespace AutoHotInterception.Helpers throw new Exception($"Expected 1 or 2 strokes, but got {strokes.Count}"); } } + + /// + /// Used by SendKeyEvent() in KeyboardHandler to translate from AHK code / state into Interception Stroke(s) + /// + /// The AHK code of the key + /// The AH< state of the key/param> + /// A list of Strokes to send to simulate this key being pressed + public static List TranslateAhkCode(ushort code, int ahkState) + { + var strokes = new List(); + Order order; + ushort state = (ushort)(1 - ahkState); + if (code > 256) + { + code -= 256; + if (_highCodeE0Keys.Contains(code) || _e1Keys.Contains(code)) + { + order = Order.Normal; + } + else if (_twoStrokeKeys.ContainsKey(code)) + { + order = _twoStrokeKeys[code]; + } + else + { + throw new Exception($"Do not know how to handle ScanCode of {code}"); + } + } + else if (code == 69) + { + order = Order.Prefixed; + } + else + { + order = Order.Normal; + } + + if (_e1Keys.Contains(code)) + { + state += 2; + } + else + { + state += (ushort)((ushort)order * 2); + } + + if (order == Order.Normal) + { + strokes.Add(new Stroke() { key = { code = code, state = state } }); + } + else if (order == Order.Wrapped) + { + // Wrapped (E1) + if (ahkState == 1) + { + // Press + strokes.Add(new Stroke() { key = { code = 42, state = state } }); + strokes.Add(new Stroke() { key = { code = code, state = state } }); + } + else + { + // Release + strokes.Add(new Stroke() { key = { code = code, state = state } }); + strokes.Add(new Stroke() { key = { code = 42, state = state } }); + } + } + else + { + // Prefixed (E2) + if (ahkState == 1) + { + // Press + strokes.Add(new Stroke() { key = { code = 29, state = state } }); + strokes.Add(new Stroke() { key = { code = code, state = state } }); + } + else + { + // Release + strokes.Add(new Stroke() { key = { code = 29, state = state } }); + strokes.Add(new Stroke() { key = { code = code, state = state } }); + } + } + + return strokes; + } + } // Holds the AHK code and state equivalent of a one or two-stroke set diff --git a/C#/AutoHotInterception/KeyCode notes.xlsx b/C#/AutoHotInterception/KeyCode notes.xlsx index 21bc857500cd125b0fd1df59556fe6e636c62e01..6cc9c33b12ab2d939aad23110e7b279d4939490f 100644 GIT binary patch delta 4551 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 Mq#)#T;{T5Q3u)hl^#A|> delta 4512 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 keyEvents) { - var str = $"{keyEvents.Count} - "; + var str = ""; foreach (var keyEvent in keyEvents) { str += $"Code: {keyEvent.Code} (0x{keyEvent.Code.ToString("X")}) - {keyEvent.Code + 256}, State: {keyEvent.State} | "; diff --git a/C#/UnitTests/TranslateAhkCodeTests.cs b/C#/UnitTests/TranslateAhkCodeTests.cs new file mode 100644 index 0000000..c7ba27f --- /dev/null +++ b/C#/UnitTests/TranslateAhkCodeTests.cs @@ -0,0 +1,73 @@ +using AutoHotInterception.Helpers; +using NUnit.Framework; +using System.Collections.Generic; + +namespace UnitTests +{ + [TestFixture] + class TranslateAhkCodeTests + { + [Test, TestCaseSource("TestKeyProvider")] + public void PressRelease(string name, int code, List pressResult, List releaseResult) + { + var actualResult = ScanCodeHelper.TranslateAhkCode((ushort)code, 1); + AssertResults(pressResult, actualResult); + + actualResult = ScanCodeHelper.TranslateAhkCode((ushort)code, 0); + AssertResults(releaseResult, actualResult); + } + + private void AssertResults(List expectedResult, List actualResult) + { + Assert.That(actualResult.Count == expectedResult.Count, $"Expecting {expectedResult.Count} strokes, but got {actualResult.Count}"); + for (int i = 0; i < expectedResult.Count; i++) + { + + Assert.That(actualResult[i].key.code, Is.EqualTo(expectedResult[i].key.code), + $"Code should be {expectedResult[i].key.code}, got {actualResult[i].key.code}"); + Assert.That(actualResult[i].key.state, Is.EqualTo(expectedResult[i].key.state), + $"Code should be {expectedResult[i].key.state}, got {actualResult[i].key.state}"); + } + } + + private static List Result(ushort code1, ushort state1, ushort? code2 = null, ushort? state2 = null) + { + var strokes = new List(); + strokes.Add(new ManagedWrapper.Stroke() { key = { code = code1, state = state1 } }); + if (code2 != null) + { + strokes.Add(new ManagedWrapper.Stroke() { key = { code = (ushort)code2, state = (ushort)state2 } }); + } + return strokes; + } + + private static IEnumerable TestKeyProvider() + { + yield return new TestCaseData("One", 2, Result(2, 0), Result(2, 1)); + yield return new TestCaseData("Scroll Lock", 70, Result(70, 0), Result(70, 1)); + + yield return new TestCaseData("Numpad Enter", 284, Result(28, 0), Result(28, 1)); + yield return new TestCaseData("Right Control", 285, Result(29, 2), Result(29, 3)); + yield return new TestCaseData("Numpad Div", 309, Result(53, 2), Result(53, 3)); + yield return new TestCaseData("Right Shift", 310, Result(54, 0), Result(54, 1)); + yield return new TestCaseData("Print Screen", 311, Result(42, 2, 55, 2), Result(55, 3, 42, 3)); + yield return new TestCaseData("Right Alt", 312, Result(56, 2), Result(56, 3)); + yield return new TestCaseData("Numlock", 325, Result(69, 0), Result(69, 1)); + yield return new TestCaseData("Pause", 69, Result(29, 4, 69, 4), Result(29, 5, 69, 5)); + yield return new TestCaseData("Home", 327, Result(42, 2, 71, 2), Result(71, 3, 42, 3)); + yield return new TestCaseData("Up", 328, Result(42, 2, 72, 2), Result(72, 3, 42, 3)); + yield return new TestCaseData("PgUp", 329, Result(42, 2, 73, 2), Result(73, 3, 42, 3)); + yield return new TestCaseData("Left", 331, Result(42, 2, 75, 2), Result(75, 3, 42, 3)); + yield return new TestCaseData("Right", 333, Result(42, 2, 77, 2), Result(77, 3, 42, 3)); + yield return new TestCaseData("End", 335, Result(42, 2, 79, 2), Result(79, 3, 42, 3)); + yield return new TestCaseData("Down", 336, Result(42, 2, 80, 2), Result(80, 3, 42, 3)); + yield return new TestCaseData("PgDn", 337, Result(42, 2, 81, 2), Result(81, 3, 42, 3)); + yield return new TestCaseData("PgDn", 338, Result(42, 2, 82, 2), Result(82, 3, 42, 3)); + yield return new TestCaseData("Delete", 339, Result(42, 2, 83, 2), Result(83, 3, 42, 3)); + yield return new TestCaseData("Left Win", 347, Result(91, 2), Result(91, 3)); + yield return new TestCaseData("Right Win", 348, Result(92, 2), Result(92, 3)); + yield return new TestCaseData("Apps", 349, Result(93, 2), Result(93, 3)); + } + } + +} diff --git a/C#/UnitTests/ScanCodeHelperTests.cs b/C#/UnitTests/TranslateScanCodesTests.cs similarity index 94% rename from C#/UnitTests/ScanCodeHelperTests.cs rename to C#/UnitTests/TranslateScanCodesTests.cs index 38cb1e3..0d715ca 100644 --- a/C#/UnitTests/ScanCodeHelperTests.cs +++ b/C#/UnitTests/TranslateScanCodesTests.cs @@ -38,7 +38,7 @@ namespace UnitTests } [TestFixture] - class ScanCodeHelperTests + class TranslateScanCodesTests { private static List Stroke(ushort code1, ushort state1, ushort code2 = 0, ushort state2 = 0) { @@ -76,10 +76,14 @@ namespace UnitTests private static IEnumerable TestKeyProvider() { + yield return new TestCaseData("One", Stroke(2, 0), Stroke(2, 1), Result(2, 1), Result(2, 0)); + yield return new TestCaseData("Scroll Lock", Stroke(70, 0), Stroke(70, 1), Result(70, 1), Result(70, 0)); + yield return new TestCaseData("Numpad Enter", Stroke(28, 0), Stroke(28, 1), Result(284, 1), Result(284, 0)); yield return new TestCaseData("Right Control", Stroke(29, 2), Stroke(29, 3), Result(285, 1), Result(285, 0)); yield return new TestCaseData("Numpad Div", Stroke(53, 2), Stroke(53, 3), Result(309, 1), Result(309, 0)); yield return new TestCaseData("Right Shift", Stroke(54, 0), Stroke(54, 1), Result(310, 1), Result(310, 0)); + yield return new TestCaseData("Print Screen", Stroke(42, 2, 55, 2), Stroke(55, 3, 42, 3), Result(311, 1), Result(311, 0)); yield return new TestCaseData("Right Alt", Stroke(56, 2), Stroke(56, 3), Result(312, 1), Result(312, 0)); yield return new TestCaseData("Numlock", Stroke(69, 0), Stroke(69, 1), Result(325, 1), Result(325, 0)); yield return new TestCaseData("Pause", Stroke(29, 4, 69, 0), Stroke(29, 5, 69, 1), Result(69, 1), Result(69, 0)); diff --git a/C#/UnitTests/UnitTests.csproj b/C#/UnitTests/UnitTests.csproj index 8152d7e..6c21cb1 100644 --- a/C#/UnitTests/UnitTests.csproj +++ b/C#/UnitTests/UnitTests.csproj @@ -40,7 +40,8 @@ - + +