mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
core: match and emit function keys
This commit is contained in:
@ -1074,7 +1074,9 @@ pub fn keyCallback(
|
||||
} else |_| {}
|
||||
}
|
||||
|
||||
if (action == .press or action == .repeat) {
|
||||
// We only handle press events
|
||||
if (action != .press and action != .repeat) return false;
|
||||
|
||||
// Mods for bindings never include caps/num lock.
|
||||
const binding_mods = mods: {
|
||||
var binding_mods = mods;
|
||||
@ -1083,6 +1085,9 @@ pub fn keyCallback(
|
||||
break :mods binding_mods;
|
||||
};
|
||||
|
||||
// Check if we're processing a binding first. If so, that negates
|
||||
// any further key processing.
|
||||
{
|
||||
const binding_action_: ?input.Binding.Action = action: {
|
||||
var trigger: input.Binding.Trigger = .{
|
||||
.mods = binding_mods,
|
||||
@ -1104,6 +1109,59 @@ pub fn keyCallback(
|
||||
try self.performBindingAction(binding_action);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// We'll need to know these values here on.
|
||||
self.renderer_state.mutex.lock();
|
||||
const cursor_key_application = self.io.terminal.modes.cursor_keys;
|
||||
self.renderer_state.mutex.unlock();
|
||||
|
||||
// Check if we're processing a function key.
|
||||
for (input.function_keys.keys.get(key)) |entry| {
|
||||
switch (entry.cursor) {
|
||||
.any => {},
|
||||
.normal => if (cursor_key_application) continue,
|
||||
.application => if (!cursor_key_application) continue,
|
||||
}
|
||||
|
||||
switch (entry.keypad) {
|
||||
.any => {},
|
||||
else => {}, // TODO
|
||||
}
|
||||
|
||||
switch (entry.modify_other_keys) {
|
||||
.any => {},
|
||||
|
||||
// TODO
|
||||
.set => {},
|
||||
.set_other => continue,
|
||||
}
|
||||
|
||||
const mods_int: u8 = @bitCast(binding_mods);
|
||||
const entry_mods_int: u8 = @bitCast(entry.mods);
|
||||
if (entry_mods_int == 0) {
|
||||
if (mods_int != 0 and !entry.mods_empty_is_any) continue;
|
||||
// mods are either empty, or empty means any so we allow it.
|
||||
} else if (entry_mods_int != mods_int) {
|
||||
// any set mods require an exact match
|
||||
continue;
|
||||
}
|
||||
|
||||
// log.debug("function key match: {}", .{entry});
|
||||
|
||||
// We found a match, send the sequence and return we as handled.
|
||||
var data: termio.Message.WriteReq.Small.Array = undefined;
|
||||
@memcpy(data[0..entry.sequence.len], entry.sequence);
|
||||
_ = self.io_thread.mailbox.push(.{
|
||||
.write_small = .{
|
||||
.data = data,
|
||||
.len = @intCast(entry.sequence.len),
|
||||
},
|
||||
}, .{ .forever = {} });
|
||||
try self.io_thread.wakeup.notify();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we have alt pressed, we're going to prefix any of the
|
||||
// translations below with ESC (0x1B).
|
||||
@ -1128,8 +1186,8 @@ pub fn keyCallback(
|
||||
// composed characters. But not all app runtimes will do this;
|
||||
// some only compose printable characters. So we manually handle
|
||||
// this here.
|
||||
if (mods_int == ctrl_only) {
|
||||
const val: u8 = switch (key) {
|
||||
if (mods_int != ctrl_only) break :char 0;
|
||||
break :char switch (key) {
|
||||
.space => 0,
|
||||
.slash => 0x1F,
|
||||
.zero => 0x30,
|
||||
@ -1145,7 +1203,6 @@ pub fn keyCallback(
|
||||
.backslash => 0x1C,
|
||||
.left_bracket => 0x1B,
|
||||
.right_bracket => 0x1D,
|
||||
.backspace => 0x08,
|
||||
.a => 0x01,
|
||||
.b => 0x02,
|
||||
.c => 0x03,
|
||||
@ -1174,18 +1231,6 @@ pub fn keyCallback(
|
||||
.z => 0x1A,
|
||||
else => 0,
|
||||
};
|
||||
|
||||
if (val > 0) break :char val;
|
||||
}
|
||||
|
||||
// Otherwise, we don't care what modifiers we press we do this.
|
||||
break :char switch (key) {
|
||||
.backspace => 0x7F,
|
||||
.enter => '\r',
|
||||
.tab => '\t',
|
||||
.escape => 0x1B,
|
||||
else => 0,
|
||||
};
|
||||
};
|
||||
if (char > 0) {
|
||||
// Ask our IO thread to write the data
|
||||
@ -1221,7 +1266,6 @@ pub fn keyCallback(
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -270,6 +270,16 @@ fn pcStyle(comptime fmt: []const u8) []const Entry {
|
||||
}
|
||||
|
||||
test "keys" {
|
||||
const testing = std.testing;
|
||||
|
||||
// Force resolution for comptime evaluation.
|
||||
_ = keys;
|
||||
|
||||
// All key sequences must fit into a termio array.
|
||||
const max = @import("../termio.zig").Message.WriteReq.Small.Max;
|
||||
for (keys.values) |entries| {
|
||||
for (entries) |entry| {
|
||||
try testing.expect(entry.sequence.len <= max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user