windows: Fix keystroke & keymap (#36572)
Closes #36300 This PR follows Windows conventions by introducing `KeybindingKeystroke`, so shortcuts now show up as `ctrl-shift-4` instead of `ctrl-$`. It also fixes issues with keyboard layouts: when `use_key_equivalents` is set to true, keys are remapped based on their virtual key codes. For example, `ctrl-\` on a standard English layout will be mapped to `ctrl-ё` on a Russian layout. Release Notes: - N/A --------- Co-authored-by: Kate <kate@zed.dev>
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use collections::HashMap;
|
||||
|
||||
use crate::{Action, InvalidKeystrokeError, KeyBindingContextPredicate, Keystroke, SharedString};
|
||||
use crate::{
|
||||
Action, AsKeystroke, DummyKeyboardMapper, InvalidKeystrokeError, KeyBindingContextPredicate,
|
||||
KeybindingKeystroke, Keystroke, PlatformKeyboardMapper, SharedString,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
/// A keybinding and its associated metadata, from the keymap.
|
||||
pub struct KeyBinding {
|
||||
pub(crate) action: Box<dyn Action>,
|
||||
pub(crate) keystrokes: SmallVec<[Keystroke; 2]>,
|
||||
pub(crate) keystrokes: SmallVec<[KeybindingKeystroke; 2]>,
|
||||
pub(crate) context_predicate: Option<Rc<KeyBindingContextPredicate>>,
|
||||
pub(crate) meta: Option<KeyBindingMetaIndex>,
|
||||
/// The json input string used when building the keybinding, if any
|
||||
@@ -32,7 +33,15 @@ impl KeyBinding {
|
||||
pub fn new<A: Action>(keystrokes: &str, action: A, context: Option<&str>) -> Self {
|
||||
let context_predicate =
|
||||
context.map(|context| KeyBindingContextPredicate::parse(context).unwrap().into());
|
||||
Self::load(keystrokes, Box::new(action), context_predicate, None, None).unwrap()
|
||||
Self::load(
|
||||
keystrokes,
|
||||
Box::new(action),
|
||||
context_predicate,
|
||||
false,
|
||||
None,
|
||||
&DummyKeyboardMapper,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Load a keybinding from the given raw data.
|
||||
@@ -40,24 +49,22 @@ impl KeyBinding {
|
||||
keystrokes: &str,
|
||||
action: Box<dyn Action>,
|
||||
context_predicate: Option<Rc<KeyBindingContextPredicate>>,
|
||||
key_equivalents: Option<&HashMap<char, char>>,
|
||||
use_key_equivalents: bool,
|
||||
action_input: Option<SharedString>,
|
||||
keyboard_mapper: &dyn PlatformKeyboardMapper,
|
||||
) -> std::result::Result<Self, InvalidKeystrokeError> {
|
||||
let mut keystrokes: SmallVec<[Keystroke; 2]> = keystrokes
|
||||
let keystrokes: SmallVec<[KeybindingKeystroke; 2]> = keystrokes
|
||||
.split_whitespace()
|
||||
.map(Keystroke::parse)
|
||||
.map(|source| {
|
||||
let keystroke = Keystroke::parse(source)?;
|
||||
Ok(KeybindingKeystroke::new(
|
||||
keystroke,
|
||||
use_key_equivalents,
|
||||
keyboard_mapper,
|
||||
))
|
||||
})
|
||||
.collect::<std::result::Result<_, _>>()?;
|
||||
|
||||
if let Some(equivalents) = key_equivalents {
|
||||
for keystroke in keystrokes.iter_mut() {
|
||||
if keystroke.key.chars().count() == 1
|
||||
&& let Some(key) = equivalents.get(&keystroke.key.chars().next().unwrap())
|
||||
{
|
||||
keystroke.key = key.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
keystrokes,
|
||||
action,
|
||||
@@ -79,13 +86,13 @@ impl KeyBinding {
|
||||
}
|
||||
|
||||
/// Check if the given keystrokes match this binding.
|
||||
pub fn match_keystrokes(&self, typed: &[Keystroke]) -> Option<bool> {
|
||||
pub fn match_keystrokes(&self, typed: &[impl AsKeystroke]) -> Option<bool> {
|
||||
if self.keystrokes.len() < typed.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
for (target, typed) in self.keystrokes.iter().zip(typed.iter()) {
|
||||
if !typed.should_match(target) {
|
||||
if !typed.as_keystroke().should_match(target) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
@@ -94,7 +101,7 @@ impl KeyBinding {
|
||||
}
|
||||
|
||||
/// Get the keystrokes associated with this binding
|
||||
pub fn keystrokes(&self) -> &[Keystroke] {
|
||||
pub fn keystrokes(&self) -> &[KeybindingKeystroke] {
|
||||
self.keystrokes.as_slice()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user