Merge pull request #1088 from mitchellh/kitty-mods

macos: proper event when sided mod released with other side pressed
This commit is contained in:
Mitchell Hashimoto
2023-12-13 21:57:30 -08:00
committed by GitHub
2 changed files with 71 additions and 9 deletions

View File

@ -905,10 +905,32 @@ extension Ghostty {
// but this is super cheap and flagsChanged isn't that common.
let mods = Ghostty.ghosttyMods(event.modifierFlags)
// If the key that pressed this is active, its a press, else release
// If the key that pressed this is active, its a press, else release.
var action = GHOSTTY_ACTION_RELEASE
if (mods.rawValue & mod != 0) { action = GHOSTTY_ACTION_PRESS }
if (mods.rawValue & mod != 0) {
// If the key is pressed, its slightly more complicated, because we
// want to check if the pressed modifier is the correct side. If the
// correct side is pressed then its a press event otherwise its a release
// event with the opposite modifier still held.
let sidePressed: Bool
switch (event.keyCode) {
case 0x3C:
sidePressed = event.modifierFlags.rawValue & UInt(NX_DEVICERSHIFTKEYMASK) != 0;
case 0x3E:
sidePressed = event.modifierFlags.rawValue & UInt(NX_DEVICERCTLKEYMASK) != 0;
case 0x3D:
sidePressed = event.modifierFlags.rawValue & UInt(NX_DEVICERALTKEYMASK) != 0;
case 0x36:
sidePressed = event.modifierFlags.rawValue & UInt(NX_DEVICERCMDKEYMASK) != 0;
default:
sidePressed = true
}
if (sidePressed) {
action = GHOSTTY_ACTION_PRESS
}
}
keyAction(action, event: event)
}

View File

@ -143,7 +143,11 @@ fn kitty(
var seq: KittySequence = .{
.key = entry.code,
.final = entry.final,
.mods = KittyMods.fromInput(all_mods),
.mods = KittyMods.fromInput(
self.event.action,
self.event.key,
all_mods,
),
};
if (self.kitty_flags.report_events) {
@ -596,12 +600,27 @@ const KittyMods = packed struct(u8) {
num_lock: bool = false,
/// Convert an input mods value into the CSI u mods value.
pub fn fromInput(mods: key.Mods) KittyMods {
pub fn fromInput(
action: key.Action,
k: key.Key,
mods: key.Mods,
) KittyMods {
// Annoying boolean logic, but according to the Kitty spec:
// "When both left and right control keys are pressed and one is
// released, the release event must again have the modifier bit reset"
// In other words, we allow a modifier if it is set AND the action
// is NOT a release. Or if the action is a release, then the key being
// released must not be the associated modifier key.
const shift = mods.shift and (action != .release or (k != .left_shift and k != .right_shift));
const alt = mods.alt and (action != .release or (k != .left_alt and k != .right_alt));
const ctrl = mods.ctrl and (action != .release or (k != .left_control and k != .right_control));
const super = mods.super and (action != .release or (k != .left_super and k != .right_super));
return .{
.shift = mods.shift,
.alt = mods.alt,
.ctrl = mods.ctrl,
.super = mods.super,
.shift = shift,
.alt = alt,
.ctrl = ctrl,
.super = super,
.caps_lock = mods.caps_lock,
.num_lock = mods.num_lock,
};
@ -982,6 +1001,27 @@ test "kitty: ctrl with all flags" {
try testing.expectEqualStrings("[57442;5u", actual[1..]);
}
test "kitty: ctrl release with ctrl mod set" {
var buf: [128]u8 = undefined;
var enc: KeyEncoder = .{
.event = .{
.action = .release,
.key = .left_control,
.mods = .{ .ctrl = true },
.utf8 = "",
},
.kitty_flags = .{
.disambiguate = true,
.report_events = true,
.report_alternates = true,
.report_all = true,
.report_associated = true,
},
};
const actual = try enc.kitty(&buf);
try testing.expectEqualStrings("[57442;1:3u", actual[1..]);
}
test "kitty: delete" {
var buf: [128]u8 = undefined;
{