feat: initial release of SplitOverlay (KeyOverlay 1.0.0)
CI / build-and-test (push) Canceled after 0s
CI / build-and-test (push) Canceled after 0s
Semi-transparent always-on-top Windows overlay that shows the keymap of a Vial/QMK split keyboard (Silakka54). - draws all layers from a Vial .vil layout, transparent keys fall through - detects the active layer from the keyboard via a Raw HID command (firmware/) - shows characters of the active Windows input language - can split the two halves into separate, independently movable windows - highlights pressed keys; tray menu for opacity, size and options - Inno Setup installer and portable build; GitHub-style CI workflow
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
using KeyOverlay.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace KeyOverlay.Core.Tests;
|
||||
|
||||
public class KeymapTests
|
||||
{
|
||||
// 2 layers, 10 matrix rows x 6 cols. Layer 1 is mostly transparent.
|
||||
private static string Vil(string layer0Row0, string layer1Row0, string layer0Row5 = "[\"KC_BSPACE\",\"KC_0\",\"KC_9\",\"KC_8\",\"KC_7\",\"KC_6\"]")
|
||||
{
|
||||
string Layer(string row0, string row5)
|
||||
{
|
||||
var rows = new List<string>();
|
||||
for (var r = 0; r < 10; r++)
|
||||
{
|
||||
rows.Add(r switch
|
||||
{
|
||||
0 => row0,
|
||||
5 => row5,
|
||||
4 or 9 => "[-1,-1,-1,\"KC_TRNS\",\"KC_TRNS\",\"KC_TRNS\"]",
|
||||
_ => "[\"KC_TRNS\",\"KC_TRNS\",\"KC_TRNS\",\"KC_TRNS\",\"KC_TRNS\",\"KC_TRNS\"]",
|
||||
});
|
||||
}
|
||||
return "[" + string.Join(",", rows) + "]";
|
||||
}
|
||||
var tr = "[\"KC_TRNS\",\"KC_TRNS\",\"KC_TRNS\",\"KC_TRNS\",\"KC_TRNS\",\"KC_TRNS\"]";
|
||||
return "{\"layout\":[" + Layer(layer0Row0, layer0Row5) + "," + Layer(layer1Row0, tr) + "]}";
|
||||
}
|
||||
|
||||
private static readonly string Row0L0 = "[\"KC_ESCAPE\",\"KC_1\",\"KC_2\",\"KC_3\",\"KC_4\",\"KC_5\"]";
|
||||
private static readonly string Row0L1 = "[\"KC_GRAVE\",\"KC_F1\",\"KC_TRNS\",\"KC_TRNS\",\"KC_TRNS\",\"MO(2)\"]";
|
||||
|
||||
[Fact]
|
||||
public void Parse_ReadsLayerCount()
|
||||
{
|
||||
var km = Keymap.Parse(Vil(Row0L0, Row0L1));
|
||||
Assert.Equal(2, km.LayerCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_MapsLeftHalfRowsAndCols()
|
||||
{
|
||||
var km = Keymap.Parse(Vil(Row0L0, Row0L1));
|
||||
Assert.Equal("KC_ESCAPE", km.GetRaw(0, new KeyId(Side.Left, 0, 0)));
|
||||
Assert.Equal("KC_5", km.GetRaw(0, new KeyId(Side.Left, 0, 5)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_MapsRightHalfFromMatrixRows5To9()
|
||||
{
|
||||
var km = Keymap.Parse(Vil(Row0L0, Row0L1));
|
||||
Assert.Equal("KC_BSPACE", km.GetRaw(0, new KeyId(Side.Right, 0, 0)));
|
||||
Assert.Equal("KC_6", km.GetRaw(0, new KeyId(Side.Right, 0, 5)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_SkipsMinusOnePositions()
|
||||
{
|
||||
var km = Keymap.Parse(Vil(Row0L0, Row0L1));
|
||||
Assert.Null(km.GetRaw(0, new KeyId(Side.Left, 4, 0)));
|
||||
Assert.NotNull(km.GetRaw(0, new KeyId(Side.Left, 4, 3)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Describe_TransparentFallsThroughToLowerLayer()
|
||||
{
|
||||
var km = Keymap.Parse(Vil(Row0L0, Row0L1));
|
||||
var d = km.Describe(1, new KeyId(Side.Left, 0, 2));
|
||||
Assert.Equal("2", d.Main);
|
||||
Assert.True(d.FromLowerLayer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Describe_OwnKeyIsNotFromLowerLayer()
|
||||
{
|
||||
var km = Keymap.Parse(Vil(Row0L0, Row0L1));
|
||||
var d = km.Describe(1, new KeyId(Side.Left, 0, 1));
|
||||
Assert.Equal("F1", d.Main);
|
||||
Assert.False(d.FromLowerLayer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UsedLayers_SkipsLayersWithoutOwnKeys()
|
||||
{
|
||||
var allTransparent = "[\"KC_TRNS\",\"KC_TRNS\",\"KC_TRNS\",\"KC_TRNS\",\"KC_TRNS\",\"KC_TRNS\"]";
|
||||
var km = Keymap.Parse(Vil(Row0L0, allTransparent));
|
||||
Assert.Equal(new[] { 0 }, km.UsedLayers);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UsedLayers_IncludesLayersWithOwnKeys()
|
||||
{
|
||||
var km = Keymap.Parse(Vil(Row0L0, Row0L1));
|
||||
Assert.Equal(new[] { 0, 1 }, km.UsedLayers);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("{}")]
|
||||
[InlineData("{\"layout\":[]}")]
|
||||
[InlineData("{\"layout\":[[[\"KC_A\"]]]}")]
|
||||
[InlineData("not json")]
|
||||
public void Parse_RejectsInvalidInput(string json) =>
|
||||
Assert.Throws<FormatException>(() => Keymap.Parse(json));
|
||||
|
||||
[Fact]
|
||||
public void IsLit_RequiresBaseKeyDown()
|
||||
{
|
||||
var pressed = new PressedKeys();
|
||||
var a = Keycodes.Describe("KC_A");
|
||||
Assert.False(Keymap.IsLit(a, pressed));
|
||||
pressed.Apply(0x1E, false, true);
|
||||
Assert.True(Keymap.IsLit(a, pressed));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsLit_ShiftWrappedKeyNeedsShift()
|
||||
{
|
||||
var pressed = new PressedKeys();
|
||||
var bang = Keycodes.Describe("LSFT(KC_1)");
|
||||
pressed.Apply(0x02, false, true);
|
||||
Assert.False(Keymap.IsLit(bang, pressed));
|
||||
pressed.Apply(0x2A, false, true);
|
||||
Assert.True(Keymap.IsLit(bang, pressed));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user