SendKeyEvent() now uses TranslateAhkCode()

pull/84/head
Clive Galway 2 years ago
parent fde9deabf4
commit 18436bd5cb

@ -35,18 +35,12 @@ namespace AutoHotInterception.DeviceHandlers
/// <param name="state">The State to send (1 = pressed, 0 = released)</param>
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

@ -27,8 +27,20 @@ namespace AutoHotInterception.Helpers
69, // Numlock
};
// Keys which have an E0 state, but have no extended modifier
private static HashSet<ushort> _e1Keys = new HashSet<ushort>()
{
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<ushort, Order> _twoStrokeKeys = new Dictionary<ushort, Order>()
// Also used by SendKeyEvent to work out what extended keys to send
public static readonly Dictionary<ushort, Order> _twoStrokeKeys = new Dictionary<ushort, Order>()
{
{ 55, Order.Wrapped }, // PrtScr
{ 69, Order.Prefixed }, // Pause
@ -58,6 +70,11 @@ namespace AutoHotInterception.Helpers
}
}
/// <summary>
/// Used by ProcessStrokes() KeyboardHandler to translate incoming key(s) from Interception to AHK format
/// </summary>
/// <param name="strokes">A list of one or two Strokes that describe a single key</param>
/// <returns>An AHK ScanCode and State</returns>
public static TranslatedKey TranslateScanCodes(List<Stroke> strokes)
{
if (strokes.Count == 2)
@ -90,6 +107,92 @@ namespace AutoHotInterception.Helpers
throw new Exception($"Expected 1 or 2 strokes, but got {strokes.Count}");
}
}
/// <summary>
/// Used by SendKeyEvent() in KeyboardHandler to translate from AHK code / state into Interception Stroke(s)
/// </summary>
/// <param name="code">The AHK code of the key</param>
/// <param name="state">The AH< state of the key/param>
/// <returns>A list of Strokes to send to simulate this key being pressed</returns>
public static List<Stroke> TranslateAhkCode(ushort code, int ahkState)
{
var strokes = new List<Stroke>();
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

@ -10,10 +10,10 @@ namespace TestApp
//var mmt = new MouseMoveTester(TestDevices.LogitechWheelMouse);
//var mbt = new MouseButtonTester(TestDevices.LogitechWheelMouse, MouseButtons.Left, true);
//var ambt = new MouseButtonsTester(TestDevices.LogitechWheelMouse, true);
var kt = new KeyboardTester(TestDevices.WyseKeyboard, true);
//var kt = new KeyboardTester(TestDevices.WyseKeyboard, true);
//var kkt = new KeyboardKeyTester(TestDevices.WyseKeyboard, AhkKeys.Obj("1"), true);
//var tt = new TabletTester(TestDevices.ParbloIslandA609);
//var sct = new ScanCodeTester(TestDevices.WyseKeyboard, true);
var sct = new ScanCodeTester(TestDevices.WyseKeyboard, true);
//var sst = new SetStateTester(TestDevices.WyseKeyboard, AhkKeys.Obj("1"));
Console.ReadLine();
}

@ -17,7 +17,7 @@ namespace TestApp
public void OnKeyEvent(List<KeyEvent> 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} | ";

@ -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<ManagedWrapper.Stroke> pressResult, List<ManagedWrapper.Stroke> releaseResult)
{
var actualResult = ScanCodeHelper.TranslateAhkCode((ushort)code, 1);
AssertResults(pressResult, actualResult);
actualResult = ScanCodeHelper.TranslateAhkCode((ushort)code, 0);
AssertResults(releaseResult, actualResult);
}
private void AssertResults(List<ManagedWrapper.Stroke> expectedResult, List<ManagedWrapper.Stroke> 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<ManagedWrapper.Stroke> Result(ushort code1, ushort state1, ushort? code2 = null, ushort? state2 = null)
{
var strokes = new List<ManagedWrapper.Stroke>();
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<TestCaseData> 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));
}
}
}

@ -38,7 +38,7 @@ namespace UnitTests
}
[TestFixture]
class ScanCodeHelperTests
class TranslateScanCodesTests
{
private static List<Stroke> Stroke(ushort code1, ushort state1, ushort code2 = 0, ushort state2 = 0)
{
@ -76,10 +76,14 @@ namespace UnitTests
private static IEnumerable<TestCaseData> 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));

@ -40,7 +40,8 @@
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="ScanCodeHelperTests.cs" />
<Compile Include="TranslateAhkCodeTests.cs" />
<Compile Include="TranslateScanCodesTests.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

Loading…
Cancel
Save