mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-09-21 04:58:09 +00:00
Translate printable physical keybindings through the current macOS keyboard layout before assigning menu key equivalents. Previously these bindings could not be represented because SwiftUI shortcuts are character-based, so actions such as super+backquote had no native menu shortcut. Keep native keycodes as dispatch identity so translated display characters do not change physical semantics or precedence over Unicode bindings. Refresh shortcuts when the input source changes, and prevent AppKit from transforming equivalents that are already localized.
103 lines
3.7 KiB
Swift
103 lines
3.7 KiB
Swift
import AppKit
|
|
import Testing
|
|
@testable import Ghostty
|
|
|
|
@Suite
|
|
struct NormalizedMenuShortcutKeyTests {
|
|
typealias Key = Ghostty.MenuShortcutManager.MenuShortcutKey
|
|
|
|
// MARK: - Init from keyEquivalent + modifiers
|
|
|
|
@Test func returnsNilForEmptyKeyEquivalent() {
|
|
let key = Key(keyEquivalent: "", modifiers: .command)
|
|
#expect(key == nil)
|
|
}
|
|
|
|
@Test func lowercasesKeyEquivalent() {
|
|
let key = Key(keyEquivalent: "A", modifiers: .command)
|
|
#expect(key?.keyEquivalent == "a")
|
|
}
|
|
|
|
@Test func stripsNonShortcutModifiers() {
|
|
// .capsLock and .function should be stripped
|
|
let key = Key(keyEquivalent: "c", modifiers: [.command, .capsLock, .function])
|
|
let expected = Key(keyEquivalent: "c", modifiers: .command)
|
|
#expect(key == expected)
|
|
}
|
|
|
|
@Test func preservesShortcutModifiers() {
|
|
let key = Key(keyEquivalent: "c", modifiers: [.shift, .control, .option, .command])
|
|
let allMods: NSEvent.ModifierFlags = [.shift, .control, .option, .command]
|
|
#expect(key?.modifierFlags == allMods)
|
|
}
|
|
|
|
@Test func uppercaseLetterInsertsShift() {
|
|
// "A" is uppercase and case-sensitive, so .shift should be added
|
|
let key = Key(keyEquivalent: "A", modifiers: .command)
|
|
let expected = NSEvent.ModifierFlags([.command, .shift])
|
|
#expect(key?.modifierFlags == expected)
|
|
}
|
|
|
|
@Test func lowercaseLetterDoesNotInsertShift() {
|
|
let key = Key(keyEquivalent: "a", modifiers: .command)
|
|
let expected = NSEvent.ModifierFlags.command
|
|
#expect(key?.modifierFlags == expected)
|
|
}
|
|
|
|
@Test func nonCaseSensitiveCharacterDoesNotInsertShift() {
|
|
// "1" is not case-sensitive (uppercased == lowercased is false for digits,
|
|
// but "1".uppercased() == "1".lowercased() == "1" so isCaseSensitive is false)
|
|
let key = Key(keyEquivalent: "1", modifiers: .command)
|
|
let expected = NSEvent.ModifierFlags.command
|
|
#expect(key?.modifierFlags == expected)
|
|
}
|
|
|
|
// MARK: - Equality / Hashing
|
|
|
|
@Test func sameKeyAndModsAreEqual() {
|
|
let a = Key(keyEquivalent: "c", modifiers: .command)
|
|
let b = Key(keyEquivalent: "c", modifiers: .command)
|
|
#expect(a == b)
|
|
}
|
|
|
|
@Test func uppercaseAndLowercaseWithShiftAreEqual() {
|
|
// "C" with .command should equal "c" with [.command, .shift]
|
|
// because the uppercase init auto-inserts .shift
|
|
let fromUpper = Key(keyEquivalent: "C", modifiers: .command)
|
|
let fromLowerWithShift = Key(keyEquivalent: "c", modifiers: [.command, .shift])
|
|
#expect(fromUpper == fromLowerWithShift)
|
|
}
|
|
|
|
@Test func differentKeysAreNotEqual() {
|
|
let a = Key(keyEquivalent: "a", modifiers: .command)
|
|
let b = Key(keyEquivalent: "b", modifiers: .command)
|
|
#expect(a != b)
|
|
}
|
|
|
|
@Test func physicalKeysUseKeyCodeIdentity() {
|
|
let configured = Key(keyEquivalent: "`", physicalKeyCode: 0x32, modifiers: .command)
|
|
let event = Key(physicalKeyCode: 0x32, modifiers: .command)
|
|
let unicode = Key(keyEquivalent: "`", modifiers: .command)
|
|
|
|
#expect(configured == event)
|
|
#expect(configured != unicode)
|
|
}
|
|
|
|
@Test func differentModifiersAreNotEqual() {
|
|
let a = Key(keyEquivalent: "c", modifiers: .command)
|
|
let b = Key(keyEquivalent: "c", modifiers: .option)
|
|
#expect(a != b)
|
|
}
|
|
|
|
@Test func canBeUsedAsDictionaryKey() {
|
|
let key = Key(keyEquivalent: "c", modifiers: .command)!
|
|
var dict: [Key: String] = [:]
|
|
dict[key] = "copy"
|
|
#expect(dict[key] == "copy")
|
|
|
|
// Same key created separately should find the same entry
|
|
let key2 = Key(keyEquivalent: "c", modifiers: .command)!
|
|
#expect(dict[key2] == "copy")
|
|
}
|
|
}
|