mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
apprt/gtk: use map_keycode to get the proper unshifted key for a layout
Fixes #1014 There were a couple overlapping issues here: 1. To determine the "unshifted" key, we were using `keyval_to_lower`. This only works if the key is uppercase and not all layouts are uppercase for the unshifted value. 2. If we couldn't case the unicode value of a key or unshifted key to ASCII, we'd say the key was the same as the physical key. This is incorrect because the physical key is always the layout of the physical keyboard so for example with the Turkish layout on a US keyboard, you'd get US letters when a key may only correspond to non-US letters. To fix the first issue, we are using map_keycode to map the hardware keycode to all possible keyvals from it. We then use the currently active layout to find the unshifted value. To fix the scond issue, we no longer fallback to the physical key if there was IM text or non-ASCII unicode values for the key. I tested Turkish with #1014 and I tested Dvorak to make sure those basics still work.
This commit is contained in:
@ -1210,13 +1210,48 @@ fn keyEvent(
|
|||||||
// Get the unshifted unicode value of the keyval. This is used
|
// Get the unshifted unicode value of the keyval. This is used
|
||||||
// by the Kitty keyboard protocol.
|
// by the Kitty keyboard protocol.
|
||||||
const keyval_unicode_unshifted: u21 = unshifted: {
|
const keyval_unicode_unshifted: u21 = unshifted: {
|
||||||
// Note: this can't possibly always be right, specifically in the
|
// We need to get the currently active keyboard layout so we know
|
||||||
// case of multi-level/group keyboards. But, this works for Dvorak,
|
// what group to look at.
|
||||||
// Norwegian, and French layouts and thats what we have real users for
|
const layout = c.gdk_key_event_get_layout(@ptrCast(event));
|
||||||
// right now.
|
|
||||||
const lower = c.gdk_keyval_to_lower(keyval);
|
// Get all the possible keyboard mappings for this keycode. A keycode
|
||||||
const lower_unicode = c.gdk_keyval_to_unicode(lower);
|
// is the physical key pressed.
|
||||||
break :unshifted std.math.cast(u21, lower_unicode) orelse 0;
|
const display = c.gtk_widget_get_display(@ptrCast(self.gl_area));
|
||||||
|
var keys: [*]c.GdkKeymapKey = undefined;
|
||||||
|
var keyvals: [*]c.guint = undefined;
|
||||||
|
var n_keys: c_int = 0;
|
||||||
|
if (c.gdk_display_map_keycode(
|
||||||
|
display,
|
||||||
|
keycode,
|
||||||
|
@ptrCast(&keys),
|
||||||
|
@ptrCast(&keyvals),
|
||||||
|
&n_keys,
|
||||||
|
) == 0) break :unshifted 0;
|
||||||
|
|
||||||
|
defer c.g_free(keys);
|
||||||
|
defer c.g_free(keyvals);
|
||||||
|
|
||||||
|
// debugging:
|
||||||
|
// log.debug("layout={}", .{layout});
|
||||||
|
// for (0..@intCast(n_keys)) |i| {
|
||||||
|
// log.debug("keymap key={} codepoint={x}", .{
|
||||||
|
// keys[i],
|
||||||
|
// c.gdk_keyval_to_unicode(keyvals[i]),
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
for (0..@intCast(n_keys)) |i| {
|
||||||
|
if (keys[i].group == layout and
|
||||||
|
keys[i].level == 0)
|
||||||
|
{
|
||||||
|
break :unshifted std.math.cast(
|
||||||
|
u21,
|
||||||
|
c.gdk_keyval_to_unicode(keyvals[i]),
|
||||||
|
) orelse 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break :unshifted 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// We always reset our committed text when ending a keypress so that
|
// We always reset our committed text when ending a keypress so that
|
||||||
@ -1369,6 +1404,14 @@ fn keyEvent(
|
|||||||
break :key key;
|
break :key key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have im text then this is invalid. This means that
|
||||||
|
// the keypress generated some character that we don't know about
|
||||||
|
// in our key enum. We don't want to use the physical key because
|
||||||
|
// it can be simply wrong. For example on "Turkish Q" the "i" key
|
||||||
|
// on a US layout results in "ı" which is not the same as "i" so
|
||||||
|
// we shouldn't use the physical key.
|
||||||
|
if (self.im_len > 0 or keyval_unicode_unshifted != 0) break :key .invalid;
|
||||||
|
|
||||||
break :key physical_key;
|
break :key physical_key;
|
||||||
} else .invalid;
|
} else .invalid;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user