Rename ime_key -> key_char and update behavior (#20953)

As part of the recent changes to keyboard support, ime_key is no longer
populated by the IME; but instead by the keyboard.

As part of #20877 I changed some code to assume that falling back to key
was
ok, but this was not ok; instead we need to populate this more similarly
to how
it was done before #20336.

The alternative fix could be to instead of simulating these events in
our own
code to push a fake native event back to the platform input handler.

Closes #ISSUE

Release Notes:

- Fixed a bug where tapping `shift` coudl type "shift" if you had a
binding on "shift shift"
This commit is contained in:
Conrad Irwin 2024-11-20 20:29:47 -07:00 committed by GitHub
parent 37a59d6b2e
commit e062f30d9e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 77 additions and 79 deletions

View file

@ -12,14 +12,15 @@ pub struct Keystroke {
/// e.g. for option-s, key is "s"
pub key: String,
/// ime_key is the character inserted by the IME engine when that key was pressed.
/// e.g. for option-s, ime_key is "ß"
pub ime_key: Option<String>,
/// key_char is the character that could have been typed when
/// this binding was pressed.
/// e.g. for s this is "s", for option-s "ß", and cmd-s None
pub key_char: Option<String>,
}
impl Keystroke {
/// When matching a key we cannot know whether the user intended to type
/// the ime_key or the key itself. On some non-US keyboards keys we use in our
/// the key_char or the key itself. On some non-US keyboards keys we use in our
/// bindings are behind option (for example `$` is typed `alt-ç` on a Czech keyboard),
/// and on some keyboards the IME handler converts a sequence of keys into a
/// specific character (for example `"` is typed as `" space` on a brazilian keyboard).
@ -27,10 +28,10 @@ impl Keystroke {
/// This method assumes that `self` was typed and `target' is in the keymap, and checks
/// both possibilities for self against the target.
pub(crate) fn should_match(&self, target: &Keystroke) -> bool {
if let Some(ime_key) = self
.ime_key
if let Some(key_char) = self
.key_char
.as_ref()
.filter(|ime_key| ime_key != &&self.key)
.filter(|key_char| key_char != &&self.key)
{
let ime_modifiers = Modifiers {
control: self.modifiers.control,
@ -38,7 +39,7 @@ impl Keystroke {
..Default::default()
};
if &target.key == ime_key && target.modifiers == ime_modifiers {
if &target.key == key_char && target.modifiers == ime_modifiers {
return true;
}
}
@ -47,9 +48,9 @@ impl Keystroke {
}
/// key syntax is:
/// [ctrl-][alt-][shift-][cmd-][fn-]key[->ime_key]
/// ime_key syntax is only used for generating test events,
/// when matching a key with an ime_key set will be matched without it.
/// [ctrl-][alt-][shift-][cmd-][fn-]key[->key_char]
/// key_char syntax is only used for generating test events,
/// when matching a key with an key_char set will be matched without it.
pub fn parse(source: &str) -> anyhow::Result<Self> {
let mut control = false;
let mut alt = false;
@ -57,7 +58,7 @@ impl Keystroke {
let mut platform = false;
let mut function = false;
let mut key = None;
let mut ime_key = None;
let mut key_char = None;
let mut components = source.split('-').peekable();
while let Some(component) = components.next() {
@ -74,7 +75,7 @@ impl Keystroke {
break;
} else if next.len() > 1 && next.starts_with('>') {
key = Some(String::from(component));
ime_key = Some(String::from(&next[1..]));
key_char = Some(String::from(&next[1..]));
components.next();
} else {
return Err(anyhow!("Invalid keystroke `{}`", source));
@ -118,7 +119,7 @@ impl Keystroke {
function,
},
key,
ime_key,
key_char: key_char,
})
}
@ -154,7 +155,7 @@ impl Keystroke {
/// Returns true if this keystroke left
/// the ime system in an incomplete state.
pub fn is_ime_in_progress(&self) -> bool {
self.ime_key.is_none()
self.key_char.is_none()
&& (is_printable_key(&self.key) || self.key.is_empty())
&& !(self.modifiers.platform
|| self.modifiers.control
@ -162,17 +163,17 @@ impl Keystroke {
|| self.modifiers.alt)
}
/// Returns a new keystroke with the ime_key filled.
/// Returns a new keystroke with the key_char filled.
/// This is used for dispatch_keystroke where we want users to
/// be able to simulate typing "space", etc.
pub fn with_simulated_ime(mut self) -> Self {
if self.ime_key.is_none()
if self.key_char.is_none()
&& !self.modifiers.platform
&& !self.modifiers.control
&& !self.modifiers.function
&& !self.modifiers.alt
{
self.ime_key = match self.key.as_str() {
self.key_char = match self.key.as_str() {
"space" => Some(" ".into()),
"tab" => Some("\t".into()),
"enter" => Some("\n".into()),