1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 13:21:38 +03:00

macos: workaround weird CMD-. behavior

There are certain key combinations that macOS prefers to handle
without giving the application much opportunity to process them.

CTRL-ESC and CMD-. both cause doCommandBySelector(cancel:) to be
called.  The former we had already special cased but since we
can't disambiguate the two things, we need a better way.

performKeyEquivalent: is a method we can implement to have an
opportunity to "do something" and prevent the default macOS behavior.

So we implement that. What's interesting is that saying that we handled
CMD-. results in no further processing at all by macOS, whereas saying
that we handled CTRL-ESC results in macOS doing the normal key event
dispatch.  So we need to route that event for ourselves in that one
case.

Doesn't feel great!

refs: https://github.com/wez/wezterm/issues/1867
This commit is contained in:
Wez Furlong 2022-04-12 17:41:37 -07:00
parent e615720444
commit e680cc848a

View File

@ -1481,14 +1481,7 @@ impl WindowView {
let selector = format!("{:?}", a_selector); let selector = format!("{:?}", a_selector);
log::trace!("do_command_by_selector {:?}", selector); log::trace!("do_command_by_selector {:?}", selector);
let (key, modifiers) = match selector.as_ref() { match selector.as_ref() {
"cancel:" => {
// FIXME: this isn't scalable to various keys
// and we lose eg: SHIFT if that is also pressed at the same time.
// However, CTRL-ESC is processed BEFORE sending any other
// key events so we have no choice but to do it this way.
(KeyCode::Char('\x1b'), Modifiers::CTRL)
}
"scrollToBeginningOfDocument:" "scrollToBeginningOfDocument:"
| "scrollToEndOfDocument:" | "scrollToEndOfDocument:"
| "scrollPageUp:" | "scrollPageUp:"
@ -1510,7 +1503,6 @@ impl WindowView {
inner.ime_state = ImeDisposition::Continue; inner.ime_state = ImeDisposition::Continue;
inner.ime_last_event.take(); inner.ime_last_event.take();
} }
return;
} }
_ => { _ => {
log::warn!("UNHANDLED: IME: do_command_by_selector: {:?}", selector); log::warn!("UNHANDLED: IME: do_command_by_selector: {:?}", selector);
@ -1520,24 +1512,7 @@ impl WindowView {
inner.ime_state = ImeDisposition::Continue; inner.ime_state = ImeDisposition::Continue;
inner.ime_last_event.take(); inner.ime_last_event.take();
} }
return;
} }
};
let event = KeyEvent {
key,
modifiers,
repeat_count: 1,
key_is_down: true,
raw: None,
}
.normalize_shift();
if let Some(myself) = Self::get_this(this) {
let mut inner = myself.inner.borrow_mut();
inner.ime_state = ImeDisposition::Acted;
inner.ime_last_event.replace(event.clone());
inner.events.dispatch(WindowEvent::KeyEvent(event));
} }
} }
@ -2338,6 +2313,38 @@ impl WindowView {
} }
} }
extern "C" fn perform_key_equivalent(this: &mut Object, _sel: Sel, nsevent: id) -> BOOL {
let chars = unsafe { nsstring_to_str(nsevent.characters()) };
let modifier_flags = unsafe { nsevent.modifierFlags() };
let modifiers = key_modifiers(modifier_flags);
log::trace!(
"perform_key_equivalent: chars=`{}` modifiers=`{:?}`",
chars.escape_debug(),
modifiers,
);
if chars == "." && modifiers == Modifiers::SUPER {
// Synthesize a key down event for this, because macOS will
// not do that, even though we tell it that we handled this event.
// <https://github.com/wez/wezterm/issues/1867>
Self::key_common(this, nsevent, true);
// Prevent macOS from calling doCommandBySelector(cancel:)
YES
} else if chars == "\u{1b}" && modifiers == Modifiers::CTRL {
// We don't need to synthesize a key down event for this,
// because macOS will do that once we return YES.
// We need to return YES to prevent macOS from calling
// doCommandBySelector(cancel:) on us.
YES
} else {
// Allow macOS to process built-in shortcuts like CMD-`
// to cycle though windows
NO
}
}
extern "C" fn key_down(this: &mut Object, _sel: Sel, nsevent: id) { extern "C" fn key_down(this: &mut Object, _sel: Sel, nsevent: id) {
Self::key_common(this, nsevent, true); Self::key_common(this, nsevent, true);
} }
@ -2597,6 +2604,11 @@ impl WindowView {
Self::key_up as extern "C" fn(&mut Object, Sel, id), Self::key_up as extern "C" fn(&mut Object, Sel, id),
); );
cls.add_method(
sel!(performKeyEquivalent:),
Self::perform_key_equivalent as extern "C" fn(&mut Object, Sel, id) -> BOOL,
);
cls.add_method( cls.add_method(
sel!(acceptsFirstResponder), sel!(acceptsFirstResponder),
Self::accepts_first_responder as extern "C" fn(&mut Object, Sel) -> BOOL, Self::accepts_first_responder as extern "C" fn(&mut Object, Sel) -> BOOL,