mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 21:32:13 +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:
parent
11137aa613
commit
eb1bc7f736
@ -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 => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user