apprt/gtk: call new key2callback using the all-in-one key event

This commit is contained in:
Mitchell Hashimoto
2023-08-16 10:37:48 -07:00
parent c254a8b09e
commit 1a918bc64b
2 changed files with 37 additions and 49 deletions

View File

@ -1143,10 +1143,12 @@ pub fn key2Callback(
self: *Surface, self: *Surface,
event: input.KeyEvent, event: input.KeyEvent,
) !bool { ) !bool {
// log.debug("keyCallback event={}", .{event});
// Before encoding, we see if we have any keybindings for this // Before encoding, we see if we have any keybindings for this
// key. Those always intercept before any encoding tasks. // key. Those always intercept before any encoding tasks.
if (event.action == .press or event.action == .repeat) { if (event.action == .press or event.action == .repeat) {
const binding_mods = event.mods.effectiveMods().binding(); const binding_mods = event.effectiveMods().binding();
const binding_action_: ?input.Binding.Action = action: { const binding_action_: ?input.Binding.Action = action: {
var trigger: input.Binding.Trigger = .{ var trigger: input.Binding.Trigger = .{
.mods = binding_mods, .mods = binding_mods,
@ -1194,7 +1196,7 @@ pub fn key2Callback(
_ = self.io_thread.mailbox.push(.{ _ = self.io_thread.mailbox.push(.{
.write_small = .{ .write_small = .{
.data = data, .data = data,
.len = seq.len, .len = @intCast(seq.len),
}, },
}, .{ .forever = {} }); }, .{ .forever = {} });
try self.io_thread.wakeup.notify(); try self.io_thread.wakeup.notify();

View File

@ -1213,10 +1213,12 @@ pub const Surface = struct {
const event = c.gtk_event_controller_get_current_event(@ptrCast(ec_key)); const event = c.gtk_event_controller_get_current_event(@ptrCast(ec_key));
_ = c.gtk_im_context_filter_keypress(self.im_context, event) != 0; _ = c.gtk_im_context_filter_keypress(self.im_context, event) != 0;
// If we aren't composing, then we set our preedit to empty no matter what. // Get our consumed modifiers
if (!self.im_composing) { const consumed_mods: input.Mods = consumed: {
self.core_surface.preeditCallback(null) catch {}; const raw = c.gdk_key_event_get_consumed_modifiers(event);
} const masked = raw & c.GDK_MODIFIER_MASK;
break :consumed translateMods(masked);
};
// If we're not in a dead key state, we want to translate our text // If we're not in a dead key state, we want to translate our text
// to some input.Key. // to some input.Key.
@ -1252,48 +1254,29 @@ pub const Surface = struct {
// mods, // mods,
// }); // });
// 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 (key != .invalid or physical_key != .invalid) {
const consumed = self.core_surface.keyCallback(
.press,
key,
physical_key,
mods,
) catch |err| {
log.err("error in key callback err={}", .{err});
return 0;
};
// If we consume the key then we want to reset the dead key state.
if (consumed) {
c.gtk_im_context_reset(self.im_context);
self.core_surface.preeditCallback(null) catch {};
return 1;
}
}
// If this is a dead key, then we're composing a character and // 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. // we need to set our proper preedit state.
if (self.im_composing) { if (self.im_composing) preedit: {
const text = self.im_buf[0..self.im_len]; const text = self.im_buf[0..self.im_len];
const view = std.unicode.Utf8View.init(text) catch |err| { const view = std.unicode.Utf8View.init(text) catch |err| {
log.warn("cannot build utf8 view over input: {}", .{err}); log.warn("cannot build utf8 view over input: {}", .{err});
return 0; break :preedit;
}; };
var it = view.iterator(); var it = view.iterator();
const cp: u21 = it.nextCodepoint() orelse 0; const cp: u21 = it.nextCodepoint() orelse 0;
self.core_surface.preeditCallback(cp) catch |err| { self.core_surface.preeditCallback(cp) catch |err| {
log.err("error in preedit callback err={}", .{err}); log.err("error in preedit callback err={}", .{err});
return 0; break :preedit;
}; };
} else {
return 0; // If we aren't composing, then we set our preedit to
// empty no matter what.
self.core_surface.preeditCallback(null) catch {};
} }
// If we aren't composing and have no text, we try to convert the keyval // If we have no UTF-8 text, we try to convert our keyval to
// to a text value. We have to do this because GTK will not process // a text value. We have to do this because GTK will not process
// "Ctrl+Shift+1" (on US keyboards) as "Ctrl+!" but instead as "". // "Ctrl+Shift+1" (on US keyboards) as "Ctrl+!" but instead as "".
// But the keyval is set correctly so we can at least extract that. // But the keyval is set correctly so we can at least extract that.
if (self.im_len == 0) { if (self.im_len == 0) {
@ -1307,21 +1290,24 @@ pub const Surface = struct {
} }
} }
// Next, we want to call the char callback with each codepoint. // Invoke the core Ghostty logic to handle this input.
if (self.im_len > 0) { const consumed = self.core_surface.key2Callback(.{
const text = self.im_buf[0..self.im_len]; .action = .press,
const view = std.unicode.Utf8View.init(text) catch |err| { .key = key,
log.warn("cannot build utf8 view over input: {}", .{err}); .physical_key = physical_key,
return 0; .mods = mods,
}; .consumed_mods = consumed_mods,
var it = view.iterator(); .composing = self.im_composing,
while (it.nextCodepoint()) |cp| { .utf8 = self.im_buf[0..self.im_len],
self.core_surface.charCallback(cp, mods) catch |err| { }) catch |err| {
log.err("error in char callback err={}", .{err}); log.err("error in key callback err={}", .{err});
return 0; return 0;
}; };
}
// If we consume the key then we want to reset the dead key state.
if (consumed) {
c.gtk_im_context_reset(self.im_context);
self.core_surface.preeditCallback(null) catch {};
return 1; return 1;
} }