input: key must provide unshifted codepoint

This commit is contained in:
Mitchell Hashimoto
2023-08-17 09:24:44 -07:00
parent 37daf02804
commit fe0e1f5ee8
3 changed files with 55 additions and 12 deletions

View File

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

View File

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

View File

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