apprt/embedded: keycallback should use nomod text to determine key

To determine the logical key that was pressed, we previously just
trusted that the translated text would have the right value. But if
modifiers are pressed, the text may not translate.

For example on macOS, Ctrl+C does not produce any text. As a result, we
would fall back to the physical key. On layouts like Dvorak, the
physical key for "C" is "I". This means "Ctrl+C" sequences weren't
working.

Instead, if there is no text or the text doesn't map to a key, we
translate again using no modifiers to try to get the raw text of the
input and then base the key on that.
This commit is contained in:
Mitchell Hashimoto
2023-08-15 11:13:01 -07:00
parent d27bc1f0fe
commit 2b2b23dcf6
2 changed files with 32 additions and 3 deletions

View File

@ -1134,6 +1134,13 @@ pub fn keyCallback(
const tracy = trace(@src());
defer tracy.end();
// log.warn("KEY CALLBACK action={} key={} physical_key={} mods={}", .{
// action,
// key,
// physical_key,
// mods,
// });
// Dev Mode
if (DevMode.enabled and DevMode.instance.visible) {
// If the event was handled by imgui, ignore it.

View File

@ -422,10 +422,11 @@ pub const Surface = struct {
self.core_surface.preeditCallback(null) catch {};
}
// log.warn("TRANSLATE: action={} keycode={x} dead={} key={any} key_str={s} mods={}", .{
// log.warn("TRANSLATE: action={} keycode={x} dead={} key_len={} key={any} key_str={s} mods={}", .{
// action,
// keycode,
// result.composing,
// result.text.len,
// result.text,
// result.text,
// mods,
@ -444,8 +445,29 @@ pub const Surface = struct {
// 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
// attempt to translate it to a key enum and call the key callback.
break :key input.Key.fromASCII(result.text[0]) orelse physical_key;
// attempt to translate it to a key enum and call the key
// callback. First try plain ASCII.
if (input.Key.fromASCII(result.text[0])) |key| {
break :key key;
}
// 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| {
break :key key;
}
}
break :key physical_key;
} else .invalid;
// If both keys are invalid then we won't call the key callback. But