1
1
mirror of https://github.com/wez/wezterm.git synced 2024-09-20 11:17:15 +03:00

allow binding opt + key based on pre-composed key presses

This diff adds some plumbing to track the `raw_key` in the KeyEvent;
this is the key prior to composing or eg: mapping dead keys.

With that field in place, we can teach the termwindow layer to attempt
looking up that key mapping from the user defined key bindings.

If we get a match then we can stop further key processing.
This commit is contained in:
Wez Furlong 2019-11-05 21:32:23 -08:00
parent 11137aa613
commit eb1bc7f736
5 changed files with 80 additions and 26 deletions

View File

@ -184,14 +184,19 @@ impl WindowCallbacks for TermWindow {
return false;
}
let mux = Mux::get().unwrap();
if let Some(tab) = mux.get_active_tab_for_window(self.mux_window_id) {
let modifiers = window_mods_to_termwiz_mods(key.modifiers);
// log::error!("key_event {:?}", key);
enum Key {
Code(::termwiz::input::KeyCode),
Composed(String),
None,
}
fn win_key_code_to_termwiz_key_code(key: &::window::KeyCode) -> Key {
use ::termwiz::input::KeyCode as KC;
use ::window::KeyCode as WK;
let key = match key.key {
let code = match key {
// TODO: consider eliminating these codes from termwiz::input::KeyCode
WK::Char('\r') => KC::Enter,
WK::Char('\t') => KC::Tab,
@ -199,12 +204,11 @@ impl WindowCallbacks for TermWindow {
WK::Char('\u{1b}') => KC::Escape,
WK::Char('\u{7f}') => KC::Delete,
WK::Char(c) => KC::Char(c),
WK::Char(c) => KC::Char(*c),
WK::Composed(ref s) => {
tab.writer().write_all(s.as_bytes()).ok();
return true;
return Key::Composed(s.to_owned());
}
WK::Function(f) => KC::Function(f),
WK::Function(f) => KC::Function(*f),
WK::LeftArrow => KC::LeftArrow,
WK::RightArrow => KC::RightArrow,
WK::UpArrow => KC::UpArrow,
@ -251,7 +255,7 @@ impl WindowCallbacks for TermWindow {
WK::Numpad(7) => KC::Numpad7,
WK::Numpad(8) => KC::Numpad8,
WK::Numpad(9) => KC::Numpad9,
WK::Numpad(_) => return false,
WK::Numpad(_) => return Key::None,
WK::Separator => KC::Separator,
WK::Subtract => KC::Subtract,
WK::Decimal => KC::Decimal,
@ -277,12 +281,39 @@ impl WindowCallbacks for TermWindow {
WK::ApplicationUpArrow => KC::ApplicationUpArrow,
WK::ApplicationDownArrow => KC::ApplicationDownArrow,
};
Key::Code(code)
}
if let Some(assignment) = self.keys.lookup(key, modifiers) {
self.perform_key_assignment(&tab, &assignment).ok();
return true;
} else if tab.key_down(key, modifiers).is_ok() {
return true;
let mux = Mux::get().unwrap();
if let Some(tab) = mux.get_active_tab_for_window(self.mux_window_id) {
let modifiers = window_mods_to_termwiz_mods(key.modifiers);
// First chance to operate on the raw key; if it matches a
// user-defined key binding then we execute it and stop there.
if let Some(key) = &key.raw_key {
if let Key::Code(key) = win_key_code_to_termwiz_key_code(&key) {
if let Some(assignment) = self.keys.lookup(key, modifiers) {
self.perform_key_assignment(&tab, &assignment).ok();
return true;
}
}
}
let key = win_key_code_to_termwiz_key_code(&key.key);
match key {
Key::Code(key) => {
if let Some(assignment) = self.keys.lookup(key, modifiers) {
self.perform_key_assignment(&tab, &assignment).ok();
return true;
} else if tab.key_down(key, modifiers).is_ok() {
return true;
}
}
Key::Composed(s) => {
tab.writer().write_all(s.as_bytes()).ok();
return true;
}
Key::None => {}
}
}

View File

@ -135,9 +135,15 @@ pub struct MouseEvent {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KeyEvent {
/// Which key was pressed
/// Which key was pressed.
/// This is the potentially processed/composed version
/// of the input.
pub key: KeyCode,
/// The raw unprocessed key press if it was different from
/// the processed/composed version
pub raw_key: Option<KeyCode>,
/// Which modifiers are down
pub modifiers: Modifiers,

View File

@ -226,6 +226,9 @@ pub(crate) struct WindowInner {
}
fn function_key_to_keycode(function_key: char) -> KeyCode {
// FIXME: CTRL-C is 0x3, should it be normalized to C here
// using the unmod string? Or should be normalize the 0x3
// as the canonical representation of that input?
use cocoa::appkit;
match function_key as u16 {
appkit::NSUpArrowFunctionKey => KeyCode::UpArrow,
@ -638,6 +641,7 @@ impl WindowView {
let event = KeyEvent {
key,
raw_key: None,
modifiers: Modifiers::default(),
repeat_count: 1,
key_is_down: true,
@ -673,6 +677,7 @@ impl WindowView {
let event = KeyEvent {
key: KeyCode::Composed(s.to_string()),
raw_key: None,
modifiers: Modifiers::default(),
repeat_count: 1,
key_is_down: true,
@ -866,7 +871,7 @@ impl WindowView {
fn key_common(this: &mut Object, nsevent: id, key_is_down: bool) {
let is_a_repeat = unsafe { nsevent.isARepeat() == YES };
let chars = unsafe { nsstring_to_str(nsevent.characters()) };
// let unmod = unsafe { nsstring_to_str(nsevent.charactersIgnoringModifiers()) };
let unmod = unsafe { nsstring_to_str(nsevent.charactersIgnoringModifiers()) };
let modifiers = unsafe { key_modifiers(nsevent.modifierFlags()) };
if modifiers.is_empty() && !is_a_repeat {
@ -879,21 +884,30 @@ impl WindowView {
}
}
let mut char_iter = chars.chars();
if let Some(first_char) = char_iter.next() {
let key = if char_iter.next().is_none() {
// A single unicode char
function_key_to_keycode(first_char)
fn key_string_to_key_code(s: &str) -> Option<KeyCode> {
let mut char_iter = s.chars();
if let Some(first_char) = char_iter.next() {
if char_iter.next().is_none() {
// A single unicode char
Some(function_key_to_keycode(first_char))
} else {
Some(KeyCode::Composed(s.to_owned()))
}
} else {
KeyCode::Composed(chars.to_owned())
};
None
}
}
// FIXME: CTRL-C is 0x3, should it be normalized to C here
// using the unmod string? Or should be normalize the 0x3
// as the canonical representation of that input?
if let Some(key) = key_string_to_key_code(chars) {
let raw_key = if chars == unmod {
None
} else {
key_string_to_key_code(unmod)
};
let event = KeyEvent {
key,
raw_key,
modifiers,
repeat_count: 1,
key_is_down,

View File

@ -758,6 +758,7 @@ unsafe fn ime_composition(
Ok(s) => {
let key = KeyEvent {
key: KeyCode::Composed(s),
raw_key: None,
modifiers: Modifiers::default(),
repeat_count: 1,
key_is_down: true,
@ -945,6 +946,7 @@ unsafe fn key(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) -> Option<L
if let Some(key) = key {
let key = KeyEvent {
key,
raw_key: None,
modifiers,
repeat_count: repeat,
key_is_down: !releasing,

View File

@ -261,6 +261,7 @@ impl WindowInner {
if let Some((code, mods)) = self.conn.keyboard.process_key_event(key_press) {
let key = KeyEvent {
key: code,
raw_key: None,
modifiers: mods,
repeat_count: 1,
key_is_down: r == xcb::KEY_PRESS,