mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 21:32:13 +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:
parent
71dae34b75
commit
0d6fbc1aa2
@ -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)),
|
||||
|
@ -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, ¶ms)?;
|
||||
&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, ¶ms)?;
|
||||
&local_shaped
|
||||
} else {
|
||||
params.pre_shaped.unwrap()
|
||||
};
|
||||
|
||||
let bounding_rect = euclid::rect(
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user