feat: configurable hotkey binding and ModifierKeyTracker

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 14:58:31 +02:00
co-authored by Claude Sonnet 5.5
parent 7eb3a156d4
commit 2c4b096850
5 changed files with 100 additions and 6 deletions
@@ -0,0 +1,32 @@
import Testing
@testable import SstCore
struct HotkeyBindingTests {
@Test func allowedBindingsMatchTheSpec() {
#expect(HotkeyBinding.allowed.map(\.id) == ["fn", "rightOption", "rightCommand", "rightControl", "leftControl"])
#expect(HotkeyBinding.allowed.map(\.keyCode) == [63, 61, 54, 62, 59])
}
@Test func idsAndKeyCodesAreUnique() {
#expect(Set(HotkeyBinding.allowed.map(\.id)).count == HotkeyBinding.allowed.count)
#expect(Set(HotkeyBinding.allowed.map(\.keyCode)).count == HotkeyBinding.allowed.count)
}
@Test func lookupByKeyCodeAndId() {
#expect(HotkeyBinding.binding(keyCode: 61) == .rightOption)
#expect(HotkeyBinding.binding(id: "leftControl") == .leftControl)
}
@Test func unsupportedKeysAreRejected() {
#expect(HotkeyBinding.binding(keyCode: 56) == nil) // left shift
#expect(HotkeyBinding.binding(keyCode: 57) == nil) // caps lock
#expect(HotkeyBinding.binding(id: "nope") == nil)
}
@Test func everyBindingHasAFlagAndName() {
for binding in HotkeyBinding.allowed {
#expect(binding.flagRawValue != 0)
#expect(!binding.displayName.isEmpty)
}
}
}
@@ -0,0 +1,18 @@
import Testing
@testable import SstCore
struct ModifierKeyTrackerTests {
@Test func emitsPressedThenReleasedOnlyOnTransitions() {
var tracker = ModifierKeyTracker()
#expect(tracker.process(isDown: false) == nil)
#expect(tracker.process(isDown: true) == .pressed)
#expect(tracker.process(isDown: true) == nil)
#expect(tracker.process(isDown: false) == .released)
#expect(tracker.process(isDown: false) == nil)
}
@Test func freshTrackerStartsReleased() {
var tracker = ModifierKeyTracker()
#expect(tracker.process(isDown: true) == .pressed)
}
}