1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-23 15:04:36 +03:00

keys: default assignments can now be set to mapped or physical

A bit of a PITA, this commit:

* Introduces a DeferredKeyCode type that defers resolving a concrete
  keycode
* Adds key_map_preference config which can be Mapped or Physical
* Key map building resolves the keycode using key_map_preference
* Default key assignments have been re-phrased in order to produce
  DeferredKeyCodes
* User-specified keys without `mapped:` or `phys:` prefixes will
  resolve according to key_map_preference

refs: https://github.com/wez/wezterm/issues/1788
refs: https://github.com/wez/wezterm/issues/1784
This commit is contained in:
Wez Furlong 2022-04-01 08:07:23 -07:00
parent 76cbcb1341
commit 508baabc79
8 changed files with 306 additions and 331 deletions

View File

@ -16,8 +16,8 @@ use crate::unix::UnixDomain;
use crate::wsl::WslDomain;
use crate::{
de_number, de_vec_table, default_config_with_overrides_applied, default_one_point_oh,
default_one_point_oh_f64, default_true, make_lua_context, LoadedConfig, CONFIG_DIR,
CONFIG_FILE_OVERRIDE, CONFIG_OVERRIDES, CONFIG_SKIP, HOME_DIR,
default_one_point_oh_f64, default_true, make_lua_context, KeyMapPreference, LoadedConfig,
CONFIG_DIR, CONFIG_FILE_OVERRIDE, CONFIG_OVERRIDES, CONFIG_SKIP, HOME_DIR,
};
use anyhow::Context;
use luahelper::impl_lua_conversion;
@ -249,7 +249,7 @@ pub struct Config {
#[serde(default = "default_mux_env_remove", deserialize_with = "de_vec_table")]
pub mux_env_remove: Vec<String>,
#[serde(default)]
#[serde(default, deserialize_with = "de_vec_table")]
pub keys: Vec<Key>,
#[serde(
default = "default_bypass_mouse_reporting_modifiers",
@ -612,6 +612,9 @@ pub struct Config {
#[serde(default)]
pub xcursor_size: Option<u32>,
#[serde(default)]
pub key_map_preference: KeyMapPreference,
}
impl_lua_conversion!(Config);
@ -781,7 +784,11 @@ impl Config {
let mut map = HashMap::new();
for k in &self.keys {
let (key, mods) = k.key.key.normalize_shift(k.key.mods);
let (key, mods) = k
.key
.key
.resolve(self.key_map_preference)
.normalize_shift(k.key.mods);
map.insert((key, mods), k.action.clone());
}

View File

@ -1,12 +1,13 @@
use crate::keys::KeyNoAction;
use crate::{de_notnan, ConfigHandle, LeaderKey};
use crate::{de_notnan, ConfigHandle};
use luahelper::impl_lua_conversion;
use ordered_float::NotNan;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::convert::TryFrom;
use std::path::PathBuf;
use wezterm_input_types::{KeyCode, Modifiers, PhysKeyCode};
use std::time::Duration;
use wezterm_input_types::{KeyCode, Modifiers};
use wezterm_term::input::MouseButton;
#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
@ -351,7 +352,7 @@ impl_lua_conversion!(KeyAssignment);
pub struct InputMap {
pub keys: HashMap<(KeyCode, Modifiers), KeyAssignment>,
pub mouse: HashMap<(MouseEventTrigger, Modifiers), KeyAssignment>,
leader: Option<LeaderKey>,
leader: Option<(KeyCode, Modifiers, Duration)>,
}
impl InputMap {
@ -360,12 +361,21 @@ impl InputMap {
let mut keys = config.key_bindings();
let leader = config.leader.clone();
let leader = config.leader.as_ref().map(|leader| {
(
leader.key.key.resolve(config.key_map_preference).clone(),
leader.key.mods,
Duration::from_millis(leader.timeout_milliseconds),
)
});
macro_rules! k {
($([$mod:expr, $code:expr, $action:expr]),* $(,)?) => {
($([$mod:expr, $code:literal, $action:expr]),* $(,)?) => {
$(
keys.entry(($code, $mod)).or_insert($action);
let key = crate::DeferredKeyCode::try_from($code)
.unwrap()
.resolve(config.key_map_preference).clone();
keys.entry((key, $mod)).or_insert($action);
)*
};
}
@ -388,290 +398,177 @@ impl InputMap {
// Clipboard
[
Modifiers::SHIFT,
KeyCode::Physical(PhysKeyCode::Insert),
"Insert",
PasteFrom(ClipboardPasteSource::PrimarySelection)
],
[
Modifiers::CTRL,
KeyCode::Physical(PhysKeyCode::Insert),
"Insert",
CopyTo(ClipboardCopyDestination::PrimarySelection)
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::C),
"c",
CopyTo(ClipboardCopyDestination::Clipboard)
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::V),
PasteFrom(ClipboardPasteSource::Clipboard)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::C),
CopyTo(ClipboardCopyDestination::Clipboard)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::V),
"v",
PasteFrom(ClipboardPasteSource::Clipboard)
],
[ctrl_shift, "C", CopyTo(ClipboardCopyDestination::Clipboard)],
[ctrl_shift, "c", CopyTo(ClipboardCopyDestination::Clipboard)],
[ctrl_shift, "V", PasteFrom(ClipboardPasteSource::Clipboard)],
[ctrl_shift, "v", PasteFrom(ClipboardPasteSource::Clipboard)],
[
Modifiers::NONE,
KeyCode::Copy,
"Copy",
CopyTo(ClipboardCopyDestination::Clipboard)
],
[
Modifiers::NONE,
KeyCode::Paste,
"Paste",
PasteFrom(ClipboardPasteSource::Clipboard)
],
// Window management
[
Modifiers::ALT,
KeyCode::Physical(PhysKeyCode::Return),
ToggleFullScreen
],
[Modifiers::SUPER, KeyCode::Physical(PhysKeyCode::M), Hide],
[Modifiers::ALT, "Return", ToggleFullScreen],
[Modifiers::SUPER, "m", Hide],
[Modifiers::SUPER, "n", SpawnWindow],
[ctrl_shift, "M", Hide],
[ctrl_shift, "m", Hide],
[ctrl_shift, "N", SpawnWindow],
[ctrl_shift, "n", SpawnWindow],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::N),
SpawnWindow
],
[ctrl_shift, KeyCode::Physical(PhysKeyCode::M), Hide],
[ctrl_shift, KeyCode::Physical(PhysKeyCode::N), SpawnWindow],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::K),
"k",
ClearScrollback(ScrollbackEraseMode::ScrollbackOnly)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::K),
"K",
ClearScrollback(ScrollbackEraseMode::ScrollbackOnly)
],
[
ctrl_shift,
"k",
ClearScrollback(ScrollbackEraseMode::ScrollbackOnly)
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::F),
"f",
Search(Pattern::CaseSensitiveString("".into()))
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::F),
"F",
Search(Pattern::CaseSensitiveString("".into()))
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::L),
ShowDebugOverlay
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::Space),
QuickSelect
"f",
Search(Pattern::CaseSensitiveString("".into()))
],
[ctrl_shift, "L", ShowDebugOverlay],
[ctrl_shift, "l", ShowDebugOverlay],
[ctrl_shift, "Space", QuickSelect],
// Font size manipulation
[
Modifiers::CTRL,
KeyCode::Physical(PhysKeyCode::Minus),
DecreaseFontSize
],
[
Modifiers::CTRL,
KeyCode::Physical(PhysKeyCode::K0),
ResetFontSize
],
[
Modifiers::CTRL,
KeyCode::Physical(PhysKeyCode::Equal),
IncreaseFontSize
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::Minus),
DecreaseFontSize
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::K0),
ResetFontSize
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::Equal),
IncreaseFontSize
],
[Modifiers::SUPER, "-", DecreaseFontSize],
[Modifiers::SUPER, "0", ResetFontSize],
[Modifiers::SUPER, "=", IncreaseFontSize],
// Font size, CTRL variant.
[Modifiers::CTRL, "-", DecreaseFontSize],
[Modifiers::CTRL, "0", ResetFontSize],
[Modifiers::CTRL, "=", IncreaseFontSize],
// Font size, CTRL+SHIFT variant.
// Ugh. Combinations of these to account for varying degrees
// of shift/mapping normalizing on different systems.
[Modifiers::CTRL | Modifiers::SHIFT, "-", DecreaseFontSize],
[Modifiers::CTRL | Modifiers::SHIFT, "_", DecreaseFontSize],
[Modifiers::CTRL, "_", DecreaseFontSize],
[Modifiers::CTRL | Modifiers::SHIFT, "0", ResetFontSize],
[Modifiers::CTRL | Modifiers::SHIFT, ")", ResetFontSize],
[Modifiers::CTRL, ")", ResetFontSize],
[Modifiers::CTRL | Modifiers::SHIFT, "=", IncreaseFontSize],
[Modifiers::CTRL | Modifiers::SHIFT, "+", IncreaseFontSize],
[Modifiers::CTRL, "+", IncreaseFontSize],
// Tab navigation and management
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::T),
"t",
SpawnTab(SpawnTabDomain::CurrentPaneDomain)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::T),
SpawnTab(SpawnTabDomain::CurrentPaneDomain)
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::K1),
ActivateTab(0)
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::K2),
ActivateTab(1)
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::K3),
ActivateTab(2)
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::K4),
ActivateTab(3)
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::K5),
ActivateTab(4)
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::K6),
ActivateTab(5)
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::K7),
ActivateTab(6)
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::K8),
ActivateTab(7)
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::K9),
ActivateTab(-1)
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::W),
CloseCurrentTab { confirm: true }
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::K1),
ActivateTab(0)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::K2),
ActivateTab(1)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::K3),
ActivateTab(2)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::K4),
ActivateTab(3)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::K5),
ActivateTab(4)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::K6),
ActivateTab(5)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::K7),
ActivateTab(6)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::K8),
ActivateTab(7)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::K9),
ActivateTab(-1)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::W),
CloseCurrentTab { confirm: true }
],
[ctrl_shift, "t", SpawnTab(SpawnTabDomain::CurrentPaneDomain)],
[ctrl_shift, "T", SpawnTab(SpawnTabDomain::CurrentPaneDomain)],
[Modifiers::SUPER, "1", ActivateTab(0)],
[Modifiers::SUPER, "2", ActivateTab(1)],
[Modifiers::SUPER, "3", ActivateTab(2)],
[Modifiers::SUPER, "4", ActivateTab(3)],
[Modifiers::SUPER, "5", ActivateTab(4)],
[Modifiers::SUPER, "6", ActivateTab(5)],
[Modifiers::SUPER, "7", ActivateTab(6)],
[Modifiers::SUPER, "8", ActivateTab(7)],
[Modifiers::SUPER, "9", ActivateTab(-1)],
[Modifiers::SUPER, "w", CloseCurrentTab { confirm: true }],
[ctrl_shift, "1", ActivateTab(0)],
[ctrl_shift, "2", ActivateTab(1)],
[ctrl_shift, "3", ActivateTab(2)],
[ctrl_shift, "4", ActivateTab(3)],
[ctrl_shift, "5", ActivateTab(4)],
[ctrl_shift, "6", ActivateTab(5)],
[ctrl_shift, "7", ActivateTab(6)],
[ctrl_shift, "8", ActivateTab(7)],
[ctrl_shift, "9", ActivateTab(-1)],
[ctrl_shift, "W", CloseCurrentTab { confirm: true }],
[
Modifiers::SUPER | Modifiers::SHIFT,
KeyCode::Physical(PhysKeyCode::LeftBracket),
"[",
ActivateTabRelative(-1)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::Tab),
Modifiers::SUPER | Modifiers::SHIFT,
"{",
ActivateTabRelative(-1)
],
[Modifiers::CTRL, KeyCode::PageUp, ActivateTabRelative(-1)],
[ctrl_shift, "Tab", ActivateTabRelative(-1)],
[Modifiers::CTRL, "PageUp", ActivateTabRelative(-1)],
[
Modifiers::SUPER | Modifiers::SHIFT,
KeyCode::Physical(PhysKeyCode::RightBracket),
"]",
ActivateTabRelative(1)
],
[
Modifiers::CTRL,
KeyCode::Physical(PhysKeyCode::Tab),
Modifiers::SUPER | Modifiers::SHIFT,
"}",
ActivateTabRelative(1)
],
[
Modifiers::CTRL,
KeyCode::Physical(PhysKeyCode::PageDown),
ActivateTabRelative(1)
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::R),
ReloadConfiguration
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::R),
ReloadConfiguration
],
[ctrl_shift, KeyCode::PageUp, MoveTabRelative(-1)],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::PageDown),
MoveTabRelative(1)
],
[Modifiers::CTRL, "Tab", ActivateTabRelative(1)],
[Modifiers::CTRL, "PageDown", ActivateTabRelative(1)],
[Modifiers::SUPER, "r", ReloadConfiguration],
[ctrl_shift, "R", ReloadConfiguration],
[ctrl_shift, "PageUp", MoveTabRelative(-1)],
[ctrl_shift, "PageDown", MoveTabRelative(1)],
[
Modifiers::SHIFT,
KeyCode::PageUp,
"PageUp",
ScrollByPage(NotNan::new(-1.0).unwrap())
],
[
Modifiers::SHIFT,
KeyCode::Physical(PhysKeyCode::PageDown),
"PageDown",
ScrollByPage(NotNan::new(1.0).unwrap())
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::X),
ActivateCopyMode
],
[ctrl_shift, "X", ActivateCopyMode],
[
Modifiers::CTRL | Modifiers::ALT | Modifiers::SHIFT,
KeyCode::Physical(PhysKeyCode::Quote),
"'",
SplitVertical(SpawnCommand {
domain: SpawnTabDomain::CurrentPaneDomain,
..Default::default()
})
],
[
Modifiers::CTRL | Modifiers::ALT,
"\"",
SplitVertical(SpawnCommand {
domain: SpawnTabDomain::CurrentPaneDomain,
..Default::default()
@ -679,7 +576,15 @@ impl InputMap {
],
[
Modifiers::CTRL | Modifiers::ALT | Modifiers::SHIFT,
KeyCode::Physical(PhysKeyCode::K5),
"5",
SplitHorizontal(SpawnCommand {
domain: SpawnTabDomain::CurrentPaneDomain,
..Default::default()
})
],
[
Modifiers::CTRL | Modifiers::ALT,
"%",
SplitHorizontal(SpawnCommand {
domain: SpawnTabDomain::CurrentPaneDomain,
..Default::default()
@ -687,63 +592,51 @@ impl InputMap {
],
[
Modifiers::CTRL | Modifiers::ALT | Modifiers::SHIFT,
KeyCode::Physical(PhysKeyCode::LeftArrow),
"LeftArrow",
AdjustPaneSize(PaneDirection::Left, 1)
],
[
Modifiers::CTRL | Modifiers::ALT | Modifiers::SHIFT,
KeyCode::Physical(PhysKeyCode::RightArrow),
"RightArrow",
AdjustPaneSize(PaneDirection::Right, 1)
],
[
Modifiers::CTRL | Modifiers::ALT | Modifiers::SHIFT,
KeyCode::Physical(PhysKeyCode::UpArrow),
"UpArrow",
AdjustPaneSize(PaneDirection::Up, 1)
],
[
Modifiers::CTRL | Modifiers::ALT | Modifiers::SHIFT,
KeyCode::Physical(PhysKeyCode::DownArrow),
"DownArrow",
AdjustPaneSize(PaneDirection::Down, 1)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::LeftArrow),
"LeftArrow",
ActivatePaneDirection(PaneDirection::Left)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::RightArrow),
"RightArrow",
ActivatePaneDirection(PaneDirection::Right)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::UpArrow),
"UpArrow",
ActivatePaneDirection(PaneDirection::Up)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::DownArrow),
"DownArrow",
ActivatePaneDirection(PaneDirection::Down)
],
[
ctrl_shift,
KeyCode::Physical(PhysKeyCode::Z),
TogglePaneZoomState
],
[ctrl_shift, "Z", TogglePaneZoomState],
);
#[cfg(target_os = "macos")]
k!(
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::H),
HideApplication
],
[
Modifiers::SUPER,
KeyCode::Physical(PhysKeyCode::Q),
QuitApplication
],
[Modifiers::SUPER, "h", HideApplication],
[Modifiers::SUPER, "q", QuitApplication],
);
}
@ -879,11 +772,9 @@ impl InputMap {
}
pub fn is_leader(&self, key: &KeyCode, mods: Modifiers) -> Option<std::time::Duration> {
if let Some(leader) = self.leader.as_ref() {
if leader.key.key == *key && leader.key.mods == mods {
return Some(std::time::Duration::from_millis(
leader.timeout_milliseconds,
));
if let Some((leader_key, leader_mods, timeout)) = self.leader.as_ref() {
if *leader_key == *key && *leader_mods == mods {
return Some(timeout.clone());
}
}
None

View File

@ -5,10 +5,130 @@ use std::collections::HashMap;
use std::convert::TryFrom;
use wezterm_input_types::{KeyCode, Modifiers, PhysKeyCode};
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
pub enum KeyMapPreference {
Physical,
Mapped,
}
impl_lua_conversion!(KeyMapPreference);
impl Default for KeyMapPreference {
fn default() -> Self {
Self::Mapped
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[serde(into = "String", try_from = "String")]
pub enum DeferredKeyCode {
KeyCode(KeyCode),
Either { physical: KeyCode, mapped: KeyCode },
}
impl DeferredKeyCode {
pub fn resolve(&self, position: KeyMapPreference) -> &KeyCode {
match (self, position) {
(Self::KeyCode(key), _) => key,
(Self::Either { mapped, .. }, KeyMapPreference::Mapped) => mapped,
(Self::Either { physical, .. }, KeyMapPreference::Physical) => physical,
}
}
fn as_string(key: &KeyCode) -> String {
if let Some(s) = INV_KEYCODE_MAP.get(key) {
s.to_string()
} else {
key.to_string()
}
}
fn parse_str(s: &str) -> anyhow::Result<KeyCode> {
if let Some(c) = KEYCODE_MAP.get(s) {
return Ok(c.clone());
}
if let Some(phys) = s.strip_prefix("phys:") {
let phys = PhysKeyCode::try_from(phys).map_err(|_| {
anyhow::anyhow!("expected phys:CODE physical keycode string, got: {}", s)
})?;
return Ok(KeyCode::Physical(phys));
}
if let Some(raw) = s.strip_prefix("raw:") {
let num: u32 = raw.parse().map_err(|_| {
anyhow::anyhow!("expected raw:<NUMBER> raw keycode string, got: {}", s)
})?;
return Ok(KeyCode::RawCode(num));
}
if let Some(mapped) = s.strip_prefix("mapped:") {
let chars: Vec<char> = mapped.chars().collect();
return if chars.len() == 1 {
Ok(KeyCode::Char(chars[0]))
} else {
anyhow::bail!("invalid KeyCode string {}", s);
};
}
let chars: Vec<char> = s.chars().collect();
if chars.len() == 1 {
let k = KeyCode::Char(chars[0]);
if let Some(phys) = k.to_phys() {
Ok(KeyCode::Physical(phys))
} else {
Ok(k)
}
} else {
anyhow::bail!("invalid KeyCode string {}", s);
}
}
}
impl Into<String> for DeferredKeyCode {
fn into(self) -> String {
match self {
DeferredKeyCode::KeyCode(key) => Self::as_string(&key),
DeferredKeyCode::Either { mapped, .. } => {
let mapped = Self::as_string(&mapped);
mapped
.strip_prefix("mapped:")
.expect("to have mapped: prefix")
.to_string()
}
}
}
}
impl TryFrom<String> for DeferredKeyCode {
type Error = anyhow::Error;
fn try_from(s: String) -> anyhow::Result<DeferredKeyCode> {
DeferredKeyCode::try_from(s.as_str())
}
}
impl TryFrom<&str> for DeferredKeyCode {
type Error = anyhow::Error;
fn try_from(s: &str) -> anyhow::Result<DeferredKeyCode> {
if s.starts_with("mapped:") || s.starts_with("phys:") {
let key = Self::parse_str(&s)?;
return Ok(DeferredKeyCode::KeyCode(key));
}
let mapped = Self::parse_str(&format!("mapped:{}", s));
let phys = Self::parse_str(&format!("phys:{}", s));
match (mapped, phys) {
(Ok(mapped), Ok(physical)) => Ok(DeferredKeyCode::Either { mapped, physical }),
(Ok(mapped), Err(_)) => Ok(DeferredKeyCode::KeyCode(mapped)),
(Err(_), Ok(phys)) => Ok(DeferredKeyCode::KeyCode(phys)),
(Err(a), Err(b)) => anyhow::bail!("invalid keycode {}: {:#}, {:#}", s, a, b),
}
}
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
pub struct KeyNoAction {
#[serde(deserialize_with = "de_keycode", serialize_with = "ser_keycode")]
pub key: KeyCode,
pub key: DeferredKeyCode,
#[serde(
deserialize_with = "de_modifiers",
serialize_with = "ser_modifiers",
@ -60,10 +180,10 @@ fn make_map() -> HashMap<String, KeyCode> {
$(
let v = KeyCode::$val;
if let Some(phys) = v.to_phys() {
map.insert(stringify!($val).to_string(), KeyCode::Physical(phys));
map.insert(format!("phys:{}", stringify!($val)), KeyCode::Physical(phys));
map.insert(format!("mapped:{}", stringify!($val)), v);
} else {
map.insert(stringify!($val).to_string(), v);
map.insert(format!("mapped:{}", stringify!($val)), v);
}
)*
}
@ -143,14 +263,14 @@ fn make_map() -> HashMap<String, KeyCode> {
("Escape", PhysKeyCode::Escape),
("Tab", PhysKeyCode::Tab),
] {
map.insert(label.to_string(), KeyCode::Physical(*phys));
map.insert(format!("phys:{}", label), KeyCode::Physical(*phys));
map.insert(format!("mapped:{}", label), phys.to_key_code());
}
for i in 0..=9 {
let k = KeyCode::Numpad(i);
map.insert(
format!("Numpad{}", i),
format!("phys:Numpad{}", i),
KeyCode::Physical(k.to_phys().unwrap()),
);
// Not sure how likely someone is to remap the numpad, but...
@ -160,11 +280,11 @@ fn make_map() -> HashMap<String, KeyCode> {
for i in 1..=24 {
let k = KeyCode::Function(i);
if let Some(phys) = k.to_phys() {
map.insert(format!("F{}", i), KeyCode::Physical(phys));
map.insert(format!("phys:F{}", i), KeyCode::Physical(phys));
map.insert(format!("mapped:F{}", i), k);
} else {
// 21 and up don't have phys equivalents
map.insert(format!("F{}", i), k);
map.insert(format!("mapped:F{}", i), k);
}
}
@ -184,76 +304,6 @@ lazy_static::lazy_static! {
static ref INV_KEYCODE_MAP: HashMap<KeyCode, String> = make_inv_map();
}
pub(crate) fn ser_keycode<S>(key: &KeyCode, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if let Some(s) = INV_KEYCODE_MAP.get(key) {
serializer.serialize_str(s)
} else {
let s = key.to_string();
serializer.serialize_str(&s)
}
}
fn de_keycode<'de, D>(deserializer: D) -> Result<KeyCode, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
if let Some(c) = KEYCODE_MAP.get(&s) {
return Ok(c.clone());
}
if s.len() > 5 && s.starts_with("phys:") {
let phys = PhysKeyCode::try_from(&s[5..]).map_err(|_| {
serde::de::Error::custom(format!(
"expected phys:CODE physical keycode string, got: {}",
s
))
})?;
return Ok(KeyCode::Physical(phys));
}
if s.len() > 4 && s.starts_with("raw:") {
let num: u32 = s[4..].parse().map_err(|_| {
serde::de::Error::custom(format!(
"expected raw:<NUMBER> raw keycode string, got: {}",
s
))
})?;
return Ok(KeyCode::RawCode(num));
}
if let Some(mapped) = s.strip_prefix("mapped:") {
let chars: Vec<char> = mapped.chars().collect();
return if chars.len() == 1 {
Ok(KeyCode::Char(chars[0]))
} else {
Err(serde::de::Error::custom(format!(
"invalid KeyCode string {}",
s
)))
};
}
let chars: Vec<char> = s.chars().collect();
if chars.len() == 1 {
let k = KeyCode::Char(chars[0]);
if let Some(phys) = k.to_phys() {
Ok(KeyCode::Physical(phys))
} else {
Ok(k)
}
} else {
Err(serde::de::Error::custom(format!(
"invalid KeyCode string {}",
s
)))
}
}
pub(crate) fn ser_modifiers<S>(mods: &Modifiers, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,

View File

@ -13,6 +13,7 @@ As features stabilize some brief notes about them will accumulate here.
#### New
#### Changed
* Default key assignments are `mapped:` again. A new [key_map_preference](config/lua/config/key_map_preference.md) option allows the defaults to use `"Mapped"` or `"Physical"`.
* Disabled ligatures for `"Monaco"` and `"Menlo"` fonts, as those ligatures match even for words such as `find`. [#1786](https://github.com/wez/wezterm/issues/1786) [#1736](https://github.com/wez/wezterm/issues/1736)
#### Updated and Improved
* Bundled harfbuzz to 4.1.0

View File

@ -275,6 +275,15 @@ your config, you will need to change it to either
`{key="N", mods="CMD|SHIFT", ..}` or `{key="mapped:N", mods="CMD", ..}`
in order to continue to respect the `SHIFT` modifier.
*Since: nightly builds only*
A new `key_map_preference` option controls how keys without an explicit `phys:`
or `mapped:` prefix are treated. If `key_map_preference = "Mapped"` (the
default), then `mapped:` is assumed. If `key_map_preference = "Physical"` then
`phys:` is assumed.
The default key assignments will respect `key_map_preference`.
### Leader Key
*Since: 20201031-154415-9614e117*

View File

@ -0,0 +1,11 @@
# `key_map_preference = "Mapped"`
*Since: nightly builds only*
Controls how keys without an explicit `phys:` or `mapped:` prefix are treated.
If `key_map_preference = "Mapped"` (the default), then `mapped:` is assumed. If
`key_map_preference = "Physical"` then `phys:` is assumed.
Default key assignments also respect `key_map_preference`.

View File

@ -2032,7 +2032,9 @@ impl TermWindow {
SendKey(key) => {
use keyevent::{window_mods_to_termwiz_mods, Key};
let mods = window_mods_to_termwiz_mods(key.mods);
if let Key::Code(key) = self.win_key_code_to_termwiz_key_code(&key.key) {
if let Key::Code(key) = self.win_key_code_to_termwiz_key_code(
&key.key.resolve(self.config.key_map_preference),
) {
pane.key_down(key, mods)?;
}
}

View File

@ -618,7 +618,11 @@ impl PhysKeyCode {
macro_rules! m {
($($val:ident),* $(,)?) => {
$(
map.insert(stringify!($val).to_string(), PhysKeyCode::$val);
let key = stringify!($val).to_string();
if key.len() == 1 {
map.insert(key.to_ascii_lowercase(), PhysKeyCode::$val);
}
map.insert(key, PhysKeyCode::$val);
)*
}
}