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

macos: improve ime vs dead key composing

When we translate a dead key, send the composed event immediately
and don't try to route the current key press via the IME.

Improve rendering when in the composing state: overlay the composing
text at the cursor position to show what the composing text would
look like, even though it hasn't been committed to the input stream
yet.

refs: https://github.com/wez/wezterm/issues/1504
This commit is contained in:
Wez Furlong 2022-01-05 07:50:12 -07:00
parent 71dae34b75
commit 0d6fbc1aa2
3 changed files with 65 additions and 20 deletions

View File

@ -815,6 +815,9 @@ impl TermWindow {
log::trace!("DeadKeyStatus now: {:?}", status);
self.dead_key_status = status;
self.update_title();
// Ensure that we repaint so that any composing
// text is updated
window.invalidate();
Ok(true)
}
WindowEvent::NeedRepaint => Ok(self.do_paint(window)),

View File

@ -1730,20 +1730,45 @@ impl super::TermWindow {
let local_shaped;
let cell_clusters;
let shaped = match params.pre_shaped {
Some(s) => s,
None => {
// Break the line into clusters of cells with the same attributes
cell_clusters = params.line.cluster();
metrics::histogram!("render_screen_line_opengl.line.cluster", start.elapsed());
log::trace!(
"cluster -> {} clusters, elapsed {:?}",
cell_clusters.len(),
start.elapsed()
);
local_shaped = self.cluster_and_shape(&cell_clusters, &params)?;
&local_shaped
// Referencing the text being composed, but only if it belongs to this pane
let composing = if params.pane.is_some()
&& params.is_active
&& params.stable_line_idx == Some(params.cursor.y)
{
if let DeadKeyStatus::Composing(composing) = &self.dead_key_status {
Some(composing)
} else {
None
}
} else {
None
};
// Do we need to shape immediately, or can we use the pre-shaped data?
let to_shape = if let Some(composing) = composing {
// Create an updated line with the composition overlaid
let mut line = params.line.clone();
line.overlay_text_with_attribute(
params.cursor.x,
composing,
CellAttributes::blank(),
termwiz::surface::SEQ_ZERO,
);
cell_clusters = line.cluster();
Some(&cell_clusters)
} else if params.pre_shaped.is_none() {
cell_clusters = params.line.cluster();
Some(&cell_clusters)
} else {
None
};
let shaped = if let Some(cell_clusters) = to_shape {
local_shaped = self.cluster_and_shape(&cell_clusters, &params)?;
&local_shaped
} else {
params.pre_shaped.unwrap()
};
let bounding_rect = euclid::rect(

View File

@ -1488,12 +1488,14 @@ impl WindowView {
modifiers: Modifiers::NONE,
repeat_count: 1,
key_is_down,
}
.normalize_shift();
};
inner.ime_text.clear();
inner
.events
.dispatch(WindowEvent::AdviseDeadKeyStatus(DeadKeyStatus::None));
inner.ime_last_event.replace(event.clone());
inner.events.dispatch(WindowEvent::KeyEvent(event));
inner.ime_text.clear();
inner.ime_state = ImeDisposition::Acted;
}
}
@ -1849,7 +1851,6 @@ impl WindowView {
let modifier_flags = unsafe { nsevent.modifierFlags() };
let modifiers = key_modifiers(modifier_flags);
let virtual_key = unsafe { nsevent.keyCode() };
let translated;
log::debug!(
"key_common: chars=`{}` unmod=`{}` modifiers=`{:?}` virtual_key={:?} key_is_down:{}",
@ -1928,12 +1929,18 @@ impl WindowView {
return;
}
Some(Ok(s)) => {
Some(Ok(translated)) => {
inner
.events
.dispatch(WindowEvent::AdviseDeadKeyStatus(DeadKeyStatus::None));
translated = s;
&translated
let event = KeyEvent {
key: KeyCode::composed(&translated),
modifiers: Modifiers::NONE,
repeat_count: 1,
key_is_down,
};
inner.events.dispatch(WindowEvent::KeyEvent(event));
return;
}
Some(Err(e)) => {
log::error!("Failed to translate dead key: {}", e);
@ -1994,6 +2001,7 @@ impl WindowView {
let mut inner = myself.inner.borrow_mut();
inner.key_is_down.replace(key_is_down);
inner.ime_state = ImeDisposition::None;
inner.ime_text.clear();
}
unsafe {
@ -2050,8 +2058,17 @@ impl WindowView {
inner.ime_last_event.as_ref().map(|e| e.clone())
{
inner.events.dispatch(WindowEvent::KeyEvent(event));
return;
}
}
let status = if inner.ime_text.is_empty() {
DeadKeyStatus::None
} else {
DeadKeyStatus::Composing(inner.ime_text.clone())
};
inner
.events
.dispatch(WindowEvent::AdviseDeadKeyStatus(status));
return;
}
}