mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
input: key must provide unshifted codepoint
This commit is contained in:
@ -458,6 +458,26 @@ pub const Surface = struct {
|
||||
// then we've consumed our translate mods.
|
||||
const consumed_mods: input.Mods = if (result.text.len > 0) translate_mods else .{};
|
||||
|
||||
// We need to always do a translation with no modifiers at all in
|
||||
// order to get the "unshifted_codepoint" for the key event.
|
||||
const unshifted_codepoint: u21 = unshifted: {
|
||||
var nomod_buf: [128]u8 = undefined;
|
||||
var nomod_state: input.Keymap.State = undefined;
|
||||
const nomod = try self.app.keymap.translate(
|
||||
&nomod_buf,
|
||||
&nomod_state,
|
||||
@intCast(keycode),
|
||||
.{},
|
||||
);
|
||||
|
||||
const view = std.unicode.Utf8View.init(nomod.text) catch |err| {
|
||||
log.warn("cannot build utf8 view over text: {}", .{err});
|
||||
break :unshifted 0;
|
||||
};
|
||||
var it = view.iterator();
|
||||
break :unshifted it.nextCodepoint() orelse 0;
|
||||
};
|
||||
|
||||
// log.warn("TRANSLATE: action={} keycode={x} dead={} key_len={} key={any} key_str={s} mods={}", .{
|
||||
// action,
|
||||
// keycode,
|
||||
@ -489,18 +509,9 @@ pub const Surface = struct {
|
||||
}
|
||||
}
|
||||
|
||||
// If that doesn't work then we try to translate without
|
||||
// any modifiers and convert that.
|
||||
var nomod_buf: [128]u8 = undefined;
|
||||
var nomod_state: input.Keymap.State = undefined;
|
||||
const nomod = try self.app.keymap.translate(
|
||||
&nomod_buf,
|
||||
&nomod_state,
|
||||
@intCast(keycode),
|
||||
.{},
|
||||
);
|
||||
if (nomod.text.len == 1) {
|
||||
if (input.Key.fromASCII(nomod.text[0])) |key| {
|
||||
// If the above doesn't work, we use the unmodified value.
|
||||
if (std.math.cast(u8, unshifted_codepoint)) |ascii| {
|
||||
if (input.Key.fromASCII(ascii)) |key| {
|
||||
break :key key;
|
||||
}
|
||||
}
|
||||
@ -517,6 +528,7 @@ pub const Surface = struct {
|
||||
.consumed_mods = consumed_mods,
|
||||
.composing = result.composing,
|
||||
.utf8 = result.text,
|
||||
.unshifted_codepoint = unshifted_codepoint,
|
||||
}) catch |err| {
|
||||
log.err("error in key callback err={}", .{err});
|
||||
return;
|
||||
@ -549,6 +561,7 @@ pub const Surface = struct {
|
||||
.consumed_mods = .{},
|
||||
.composing = false,
|
||||
.utf8 = buf[0..len],
|
||||
.unshifted_codepoint = 0,
|
||||
}) catch |err| {
|
||||
log.err("error in key callback err={}", .{err});
|
||||
return;
|
||||
|
@ -1212,6 +1212,31 @@ pub const Surface = struct {
|
||||
const keyval_unicode = c.gdk_keyval_to_unicode(keyval);
|
||||
const event = c.gtk_event_controller_get_current_event(@ptrCast(ec_key));
|
||||
|
||||
// Get the unshifted unicode value of the keyval. This is used
|
||||
// by the Kitty keyboard protocol.
|
||||
const keyval_unicode_unshifted: u21 = unshifted: {
|
||||
var n: c_int = undefined;
|
||||
var keys: [*c]c.GdkKeymapKey = undefined;
|
||||
var keyvals: [*c]c.guint = undefined;
|
||||
if (c.gdk_display_map_keycode(
|
||||
c.gdk_event_get_display(event),
|
||||
keycode,
|
||||
&keys,
|
||||
&keyvals,
|
||||
&n,
|
||||
) == 0) break :unshifted 0;
|
||||
|
||||
defer c.g_free(keys);
|
||||
defer c.g_free(keyvals);
|
||||
for (keys[0..@intCast(n)], 0..) |key, i| {
|
||||
if (key.group == 0 and key.level == 0) {
|
||||
break :unshifted @intCast(c.gdk_keyval_to_unicode(keyvals[i]));
|
||||
}
|
||||
}
|
||||
|
||||
break :unshifted 0;
|
||||
};
|
||||
|
||||
// We always reset our committed text when ending a keypress so that
|
||||
// future keypresses don't think we have a commit event.
|
||||
defer self.im_len = 0;
|
||||
@ -1317,6 +1342,7 @@ pub const Surface = struct {
|
||||
.consumed_mods = consumed_mods,
|
||||
.composing = self.im_composing,
|
||||
.utf8 = self.im_buf[0..self.im_len],
|
||||
.unshifted_codepoint = keyval_unicode_unshifted,
|
||||
}) catch |err| {
|
||||
log.err("error in key callback err={}", .{err});
|
||||
return false;
|
||||
|
@ -41,6 +41,10 @@ pub const KeyEvent = struct {
|
||||
/// text.
|
||||
utf8: []const u8 = "",
|
||||
|
||||
/// The codepoint for this key when it is unshifted. For example,
|
||||
/// shift+a is "A" in UTF-8 but unshifted would provide 'a'.
|
||||
unshifted_codepoint: u21 = 0,
|
||||
|
||||
/// Returns the effective modifiers for this event. The effective
|
||||
/// modifiers are the mods that should be considered for keybindings.
|
||||
pub fn effectiveMods(self: KeyEvent) Mods {
|
||||
|
Reference in New Issue
Block a user