mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
core: note when keyCallback processed the input
This commit is contained in:
@ -1022,13 +1022,19 @@ pub fn charCallback(self: *Surface, codepoint: u21) !void {
|
|||||||
try self.io_thread.wakeup.notify();
|
try self.io_thread.wakeup.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Called for a single key event.
|
||||||
|
///
|
||||||
|
/// This will return true if the key was handled/consumed. In that case,
|
||||||
|
/// the caller doesn't need to call a subsequent `charCallback` for the
|
||||||
|
/// same event. However, the caller can call `charCallback` if they want,
|
||||||
|
/// the surface will retain state to ensure the event is ignored.
|
||||||
pub fn keyCallback(
|
pub fn keyCallback(
|
||||||
self: *Surface,
|
self: *Surface,
|
||||||
action: input.Action,
|
action: input.Action,
|
||||||
key: input.Key,
|
key: input.Key,
|
||||||
unmapped_key: input.Key,
|
unmapped_key: input.Key,
|
||||||
mods: input.Mods,
|
mods: input.Mods,
|
||||||
) !void {
|
) !bool {
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
@ -1079,7 +1085,7 @@ pub fn keyCallback(
|
|||||||
self.ignore_char = true;
|
self.ignore_char = true;
|
||||||
|
|
||||||
// No matter what, if there is a binding then we are done.
|
// No matter what, if there is a binding then we are done.
|
||||||
return;
|
return self.ignore_char;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle non-printables
|
// Handle non-printables
|
||||||
@ -1172,6 +1178,8 @@ pub fn keyCallback(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return self.ignore_char;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn focusCallback(self: *Surface, focused: bool) !void {
|
pub fn focusCallback(self: *Surface, focused: bool) !void {
|
||||||
|
@ -408,17 +408,6 @@ pub const Surface = struct {
|
|||||||
// mods,
|
// mods,
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// If this is a dead key, then we're composing a character and
|
|
||||||
// we end processing here. We don't process keybinds for dead keys.
|
|
||||||
if (result.composing) {
|
|
||||||
// TODO: we ultimately want to update some surface state so that
|
|
||||||
// we can show the user that we're in dead key mode and the
|
|
||||||
// precomposed character. For now, we can just ignore and that
|
|
||||||
// is not incorrect behavior.
|
|
||||||
log.warn("dead key mode, currently composing", .{});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We want to get the physical unmapped key to process keybinds.
|
// We want to get the physical unmapped key to process keybinds.
|
||||||
const physical_key = keycode: for (input.keycodes.entries) |entry| {
|
const physical_key = keycode: for (input.keycodes.entries) |entry| {
|
||||||
if (entry.native == keycode) break :keycode entry.key;
|
if (entry.native == keycode) break :keycode entry.key;
|
||||||
@ -428,7 +417,9 @@ pub const Surface = struct {
|
|||||||
// and attempt to translate it to a key enum and call the key callback.
|
// and attempt to translate it to a key enum and call the key callback.
|
||||||
// If the length is greater than 1 then we're going to call the
|
// If the length is greater than 1 then we're going to call the
|
||||||
// charCallback.
|
// charCallback.
|
||||||
const key = if (result.text.len == 1) key: {
|
//
|
||||||
|
// We also only do key translation if this is not a dead key.
|
||||||
|
const key = if (!result.composing and result.text.len == 1) key: {
|
||||||
// A completed key. If the length of the key is one then we can
|
// A completed key. If the length of the key is one then we can
|
||||||
// attempt to translate it to a key enum and call the key callback.
|
// attempt to translate it to a key enum and call the key callback.
|
||||||
break :key input.Key.fromASCII(result.text[0]) orelse physical_key;
|
break :key input.Key.fromASCII(result.text[0]) orelse physical_key;
|
||||||
@ -437,10 +428,32 @@ pub const Surface = struct {
|
|||||||
// If both keys are invalid then we won't call the key callback. But
|
// If both keys are invalid then we won't call the key callback. But
|
||||||
// if either one is valid, we want to give it a chance.
|
// if either one is valid, we want to give it a chance.
|
||||||
if (key != .invalid or physical_key != .invalid) {
|
if (key != .invalid or physical_key != .invalid) {
|
||||||
self.core_surface.keyCallback(action, key, physical_key, mods) catch |err| {
|
const consumed = self.core_surface.keyCallback(
|
||||||
|
action,
|
||||||
|
key,
|
||||||
|
physical_key,
|
||||||
|
mods,
|
||||||
|
) catch |err| {
|
||||||
log.err("error in key callback err={}", .{err});
|
log.err("error in key callback err={}", .{err});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// If we consume the key then we want to reset the dead key state.
|
||||||
|
if (consumed) {
|
||||||
|
self.keymap_state = .{};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is a dead key, then we're composing a character and
|
||||||
|
// we end processing here. We don't process keybinds for dead keys.
|
||||||
|
if (result.composing) {
|
||||||
|
// TODO: we ultimately want to update some surface state so that
|
||||||
|
// we can show the user that we're in dead key mode and the
|
||||||
|
// precomposed character. For now, we can just ignore and that
|
||||||
|
// is not incorrect behavior.
|
||||||
|
log.warn("dead key mode, currently composing", .{});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, we want to call the char callback with each codepoint.
|
// Next, we want to call the char callback with each codepoint.
|
||||||
|
@ -740,7 +740,7 @@ pub const Surface = struct {
|
|||||||
// TODO: we need to do mapped keybindings
|
// TODO: we need to do mapped keybindings
|
||||||
|
|
||||||
const core_win = window.getUserPointer(CoreSurface) orelse return;
|
const core_win = window.getUserPointer(CoreSurface) orelse return;
|
||||||
core_win.keyCallback(action, key, key, mods) catch |err| {
|
_ = core_win.keyCallback(action, key, key, mods) catch |err| {
|
||||||
log.err("error in key callback err={}", .{err});
|
log.err("error in key callback err={}", .{err});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -1167,25 +1167,13 @@ pub const Surface = struct {
|
|||||||
const key = translateKey(keyval);
|
const key = translateKey(keyval);
|
||||||
const mods = translateMods(state);
|
const mods = translateMods(state);
|
||||||
log.debug("key-press code={} key={} mods={}", .{ keycode, key, mods });
|
log.debug("key-press code={} key={} mods={}", .{ keycode, key, mods });
|
||||||
self.core_surface.keyCallback(.press, key, key, mods) catch |err| {
|
const processed = self.core_surface.keyCallback(.press, key, key, mods) catch |err| {
|
||||||
log.err("error in key callback err={}", .{err});
|
log.err("error in key callback err={}", .{err});
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// We generally just say we didn't handle it. We control our
|
// If we processed the key, we say we handled it.
|
||||||
// GTK environment so for any keys that matter we'll grab them.
|
return if (processed) 1 else 0;
|
||||||
// One of the reasons we say we didn't handle it is so that the
|
|
||||||
// IME can still work.
|
|
||||||
return switch (keyval) {
|
|
||||||
// If the key is tab, we say we handled it because we don't want
|
|
||||||
// tab to move focus from our surface.
|
|
||||||
c.GDK_KEY_Tab => 1,
|
|
||||||
// We do the same for up, because that steals focus from the surface,
|
|
||||||
// in case we have multiple tabs open.
|
|
||||||
c.GDK_KEY_Up => 1,
|
|
||||||
|
|
||||||
else => 0,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtkKeyReleased(
|
fn gtkKeyReleased(
|
||||||
|
Reference in New Issue
Block a user