mirror of
https://github.com/wez/wezterm.git
synced 2024-12-24 22:01:47 +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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mux = Mux::get().unwrap();
|
// log::error!("key_event {:?}", key);
|
||||||
if let Some(tab) = mux.get_active_tab_for_window(self.mux_window_id) {
|
|
||||||
let modifiers = window_mods_to_termwiz_mods(key.modifiers);
|
|
||||||
|
|
||||||
|
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 ::termwiz::input::KeyCode as KC;
|
||||||
use ::window::KeyCode as WK;
|
use ::window::KeyCode as WK;
|
||||||
|
|
||||||
let key = match key.key {
|
let code = match key {
|
||||||
// TODO: consider eliminating these codes from termwiz::input::KeyCode
|
// TODO: consider eliminating these codes from termwiz::input::KeyCode
|
||||||
WK::Char('\r') => KC::Enter,
|
WK::Char('\r') => KC::Enter,
|
||||||
WK::Char('\t') => KC::Tab,
|
WK::Char('\t') => KC::Tab,
|
||||||
@ -199,12 +204,11 @@ impl WindowCallbacks for TermWindow {
|
|||||||
WK::Char('\u{1b}') => KC::Escape,
|
WK::Char('\u{1b}') => KC::Escape,
|
||||||
WK::Char('\u{7f}') => KC::Delete,
|
WK::Char('\u{7f}') => KC::Delete,
|
||||||
|
|
||||||
WK::Char(c) => KC::Char(c),
|
WK::Char(c) => KC::Char(*c),
|
||||||
WK::Composed(ref s) => {
|
WK::Composed(ref s) => {
|
||||||
tab.writer().write_all(s.as_bytes()).ok();
|
return Key::Composed(s.to_owned());
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
WK::Function(f) => KC::Function(f),
|
WK::Function(f) => KC::Function(*f),
|
||||||
WK::LeftArrow => KC::LeftArrow,
|
WK::LeftArrow => KC::LeftArrow,
|
||||||
WK::RightArrow => KC::RightArrow,
|
WK::RightArrow => KC::RightArrow,
|
||||||
WK::UpArrow => KC::UpArrow,
|
WK::UpArrow => KC::UpArrow,
|
||||||
@ -251,7 +255,7 @@ impl WindowCallbacks for TermWindow {
|
|||||||
WK::Numpad(7) => KC::Numpad7,
|
WK::Numpad(7) => KC::Numpad7,
|
||||||
WK::Numpad(8) => KC::Numpad8,
|
WK::Numpad(8) => KC::Numpad8,
|
||||||
WK::Numpad(9) => KC::Numpad9,
|
WK::Numpad(9) => KC::Numpad9,
|
||||||
WK::Numpad(_) => return false,
|
WK::Numpad(_) => return Key::None,
|
||||||
WK::Separator => KC::Separator,
|
WK::Separator => KC::Separator,
|
||||||
WK::Subtract => KC::Subtract,
|
WK::Subtract => KC::Subtract,
|
||||||
WK::Decimal => KC::Decimal,
|
WK::Decimal => KC::Decimal,
|
||||||
@ -277,7 +281,27 @@ impl WindowCallbacks for TermWindow {
|
|||||||
WK::ApplicationUpArrow => KC::ApplicationUpArrow,
|
WK::ApplicationUpArrow => KC::ApplicationUpArrow,
|
||||||
WK::ApplicationDownArrow => KC::ApplicationDownArrow,
|
WK::ApplicationDownArrow => KC::ApplicationDownArrow,
|
||||||
};
|
};
|
||||||
|
Key::Code(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
if let Some(assignment) = self.keys.lookup(key, modifiers) {
|
||||||
self.perform_key_assignment(&tab, &assignment).ok();
|
self.perform_key_assignment(&tab, &assignment).ok();
|
||||||
return true;
|
return true;
|
||||||
@ -285,6 +309,13 @@ impl WindowCallbacks for TermWindow {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Key::Composed(s) => {
|
||||||
|
tab.writer().write_all(s.as_bytes()).ok();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Key::None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -135,9 +135,15 @@ pub struct MouseEvent {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct KeyEvent {
|
pub struct KeyEvent {
|
||||||
/// Which key was pressed
|
/// Which key was pressed.
|
||||||
|
/// This is the potentially processed/composed version
|
||||||
|
/// of the input.
|
||||||
pub key: KeyCode,
|
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
|
/// Which modifiers are down
|
||||||
pub modifiers: Modifiers,
|
pub modifiers: Modifiers,
|
||||||
|
|
||||||
|
@ -226,6 +226,9 @@ pub(crate) struct WindowInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn function_key_to_keycode(function_key: char) -> KeyCode {
|
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;
|
use cocoa::appkit;
|
||||||
match function_key as u16 {
|
match function_key as u16 {
|
||||||
appkit::NSUpArrowFunctionKey => KeyCode::UpArrow,
|
appkit::NSUpArrowFunctionKey => KeyCode::UpArrow,
|
||||||
@ -638,6 +641,7 @@ impl WindowView {
|
|||||||
|
|
||||||
let event = KeyEvent {
|
let event = KeyEvent {
|
||||||
key,
|
key,
|
||||||
|
raw_key: None,
|
||||||
modifiers: Modifiers::default(),
|
modifiers: Modifiers::default(),
|
||||||
repeat_count: 1,
|
repeat_count: 1,
|
||||||
key_is_down: true,
|
key_is_down: true,
|
||||||
@ -673,6 +677,7 @@ impl WindowView {
|
|||||||
|
|
||||||
let event = KeyEvent {
|
let event = KeyEvent {
|
||||||
key: KeyCode::Composed(s.to_string()),
|
key: KeyCode::Composed(s.to_string()),
|
||||||
|
raw_key: None,
|
||||||
modifiers: Modifiers::default(),
|
modifiers: Modifiers::default(),
|
||||||
repeat_count: 1,
|
repeat_count: 1,
|
||||||
key_is_down: true,
|
key_is_down: true,
|
||||||
@ -866,7 +871,7 @@ impl WindowView {
|
|||||||
fn key_common(this: &mut Object, nsevent: id, key_is_down: bool) {
|
fn key_common(this: &mut Object, nsevent: id, key_is_down: bool) {
|
||||||
let is_a_repeat = unsafe { nsevent.isARepeat() == YES };
|
let is_a_repeat = unsafe { nsevent.isARepeat() == YES };
|
||||||
let chars = unsafe { nsstring_to_str(nsevent.characters()) };
|
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()) };
|
let modifiers = unsafe { key_modifiers(nsevent.modifierFlags()) };
|
||||||
|
|
||||||
if modifiers.is_empty() && !is_a_repeat {
|
if modifiers.is_empty() && !is_a_repeat {
|
||||||
@ -879,21 +884,30 @@ impl WindowView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut char_iter = chars.chars();
|
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 let Some(first_char) = char_iter.next() {
|
||||||
let key = if char_iter.next().is_none() {
|
if char_iter.next().is_none() {
|
||||||
// A single unicode char
|
// A single unicode char
|
||||||
function_key_to_keycode(first_char)
|
Some(function_key_to_keycode(first_char))
|
||||||
} else {
|
} else {
|
||||||
KeyCode::Composed(chars.to_owned())
|
Some(KeyCode::Composed(s.to_owned()))
|
||||||
};
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: CTRL-C is 0x3, should it be normalized to C here
|
if let Some(key) = key_string_to_key_code(chars) {
|
||||||
// using the unmod string? Or should be normalize the 0x3
|
let raw_key = if chars == unmod {
|
||||||
// as the canonical representation of that input?
|
None
|
||||||
|
} else {
|
||||||
|
key_string_to_key_code(unmod)
|
||||||
|
};
|
||||||
|
|
||||||
let event = KeyEvent {
|
let event = KeyEvent {
|
||||||
key,
|
key,
|
||||||
|
raw_key,
|
||||||
modifiers,
|
modifiers,
|
||||||
repeat_count: 1,
|
repeat_count: 1,
|
||||||
key_is_down,
|
key_is_down,
|
||||||
|
@ -758,6 +758,7 @@ unsafe fn ime_composition(
|
|||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
let key = KeyEvent {
|
let key = KeyEvent {
|
||||||
key: KeyCode::Composed(s),
|
key: KeyCode::Composed(s),
|
||||||
|
raw_key: None,
|
||||||
modifiers: Modifiers::default(),
|
modifiers: Modifiers::default(),
|
||||||
repeat_count: 1,
|
repeat_count: 1,
|
||||||
key_is_down: true,
|
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 {
|
if let Some(key) = key {
|
||||||
let key = KeyEvent {
|
let key = KeyEvent {
|
||||||
key,
|
key,
|
||||||
|
raw_key: None,
|
||||||
modifiers,
|
modifiers,
|
||||||
repeat_count: repeat,
|
repeat_count: repeat,
|
||||||
key_is_down: !releasing,
|
key_is_down: !releasing,
|
||||||
|
@ -261,6 +261,7 @@ impl WindowInner {
|
|||||||
if let Some((code, mods)) = self.conn.keyboard.process_key_event(key_press) {
|
if let Some((code, mods)) = self.conn.keyboard.process_key_event(key_press) {
|
||||||
let key = KeyEvent {
|
let key = KeyEvent {
|
||||||
key: code,
|
key: code,
|
||||||
|
raw_key: None,
|
||||||
modifiers: mods,
|
modifiers: mods,
|
||||||
repeat_count: 1,
|
repeat_count: 1,
|
||||||
key_is_down: r == xcb::KEY_PRESS,
|
key_is_down: r == xcb::KEY_PRESS,
|
||||||
|
Loading…
Reference in New Issue
Block a user