mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-08-26 17:11:40 +00:00
macOS: update default behaviour of KeyboardLayout.character(for:modifiers:) (#14009)
Follow up for #13888, and prepare for #13205. The comments are copied from the history commit. ## AI Disclosure The tests are updated by Claude, I cherrypicked them.
This commit is contained in:
@@ -29,9 +29,11 @@ extension Ghostty {
|
||||
Self.writingSystemKeyRange.contains(physical.rawValue),
|
||||
let inputKey = Input.Key(cKey: physical),
|
||||
let keyCode = inputKey.keyCode,
|
||||
// Command can select a distinct layout table. Other modifiers remain
|
||||
// separate in the menu's modifier mask and must not affect this character.
|
||||
let character = KeyboardLayout.character(
|
||||
for: keyCode,
|
||||
modifiers: modifierFlags)
|
||||
modifiers: modifierFlags.intersection(.command))
|
||||
else { return nil }
|
||||
|
||||
// Printable physical keys must be translated through the current layout.
|
||||
|
||||
@@ -16,6 +16,8 @@ class KeyboardLayout {
|
||||
/// Translate a physical keycode for use as a menu key equivalent.
|
||||
///
|
||||
/// AppKit retranslates against the current input source without changing its dead key state.
|
||||
///
|
||||
/// - Important: Must be called on the main thread because underlying Text Input Sources APIs are not thread-safe.
|
||||
@MainActor static func character(
|
||||
for keyCode: UInt16,
|
||||
modifiers: NSEvent.ModifierFlags
|
||||
@@ -32,7 +34,7 @@ class KeyboardLayout {
|
||||
charactersIgnoringModifiers: "",
|
||||
isARepeat: false,
|
||||
keyCode: keyCode),
|
||||
let result = event.characters(byApplyingModifiers: modifiers.intersection(.command)),
|
||||
let result = event.characters(byApplyingModifiers: modifiers),
|
||||
result.count == 1
|
||||
else { return nil }
|
||||
|
||||
|
||||
@@ -17,21 +17,11 @@ struct KeyboardLayoutTests {
|
||||
#expect(KeyboardLayout.character(for: UInt16.max, modifiers: []) == nil)
|
||||
}
|
||||
|
||||
@Test(arguments: [
|
||||
([.shift, .control, .option], []),
|
||||
([.command, .shift, .control, .option], .command),
|
||||
] as [(NSEvent.ModifierFlags, NSEvent.ModifierFlags)])
|
||||
func characterUsesOnlyCommandModifier(
|
||||
modifiers: NSEvent.ModifierFlags,
|
||||
effectiveModifiers: NSEvent.ModifierFlags
|
||||
) throws {
|
||||
@Test func characterAppliesModifiers() throws {
|
||||
let keyCode: UInt16 = 0x00 // W3C KeyA
|
||||
let expected = try #require(KeyboardLayout.character(
|
||||
for: keyCode,
|
||||
modifiers: effectiveModifiers))
|
||||
let actual = try #require(KeyboardLayout.character(
|
||||
for: keyCode,
|
||||
modifiers: modifiers))
|
||||
#expect(actual == expected)
|
||||
let unmodified = try #require(KeyboardLayout.character(for: keyCode, modifiers: []))
|
||||
let shifted = try #require(KeyboardLayout.character(for: keyCode, modifiers: .shift))
|
||||
#expect(shifted != unmodified)
|
||||
#expect(String(shifted).lowercased() == String(unmodified).lowercased())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user