core: note when keyCallback processed the input

This commit is contained in:
Mitchell Hashimoto
2023-08-10 15:29:46 -07:00
parent d5df8aea9a
commit 4fe739cae0
4 changed files with 40 additions and 31 deletions

View File

@ -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 {

View File

@ -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.

View File

@ -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;
}; };

View File

@ -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(