mirror of
https://github.com/wezterm/wezterm.git
synced 2026-11-08 01:21:45 +08:00
macos: fix dictation support, with new configs for preview text (#7453)
closes: #4592 & #5180
This commit is contained in:
parent
016b96272b
commit
2658f629cd
@ -52,6 +52,8 @@
|
||||
<string>An application launched via WezTerm would like to access your location information while active.</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>An application launched via WezTerm would like to access your microphone.</string>
|
||||
<key>NSSpeechRecognitionUsageDescription</key>
|
||||
<string>An application launched via WezTerm would like to use speech recognition.</string>
|
||||
<key>NSRemindersUsageDescription</key>
|
||||
<string>An application launched via WezTerm would like to access your reminders.</string>
|
||||
<key>NSDocumentsFolderUsageDescription</key>
|
||||
|
||||
@ -160,6 +160,10 @@ pub struct Palette {
|
||||
pub visual_bell: Option<RgbaColor>,
|
||||
/// The color to use for the cursor when a dead key or leader state is active
|
||||
pub compose_cursor: Option<RgbaColor>,
|
||||
/// The foreground color for composition/IME preview text (e.g., dictation)
|
||||
pub compose_fg: Option<RgbaColor>,
|
||||
/// The background color for composition/IME preview text (e.g., dictation)
|
||||
pub compose_bg: Option<RgbaColor>,
|
||||
|
||||
pub copy_mode_active_highlight_fg: Option<ColorSpec>,
|
||||
pub copy_mode_active_highlight_bg: Option<ColorSpec>,
|
||||
@ -217,6 +221,8 @@ impl Palette {
|
||||
split: overlay!(split),
|
||||
visual_bell: overlay!(visual_bell),
|
||||
compose_cursor: overlay!(compose_cursor),
|
||||
compose_fg: overlay!(compose_fg),
|
||||
compose_bg: overlay!(compose_bg),
|
||||
copy_mode_active_highlight_fg: overlay!(copy_mode_active_highlight_fg),
|
||||
copy_mode_active_highlight_bg: overlay!(copy_mode_active_highlight_bg),
|
||||
copy_mode_inactive_highlight_fg: overlay!(copy_mode_inactive_highlight_fg),
|
||||
|
||||
@ -112,6 +112,15 @@ config.colors = {
|
||||
-- to this color to give a visual cue about the compose state.
|
||||
compose_cursor = 'orange',
|
||||
|
||||
-- Override the foreground color for composition/IME preview text,
|
||||
-- such as text being dictated via macOS dictation or composed via
|
||||
-- a dead key sequence. Falls back to the cursor foreground color.
|
||||
compose_fg = '#1e1e2e', -- {{since('nightly', inline=True)}}
|
||||
|
||||
-- Override the background color for composition/IME preview text.
|
||||
-- Falls back to the cursor background color.
|
||||
compose_bg = '#f5c2e7', -- {{since('nightly', inline=True)}}
|
||||
|
||||
-- Colors for copy_mode and quick_select
|
||||
-- available since: 20220807-113146-c2fee766
|
||||
-- In copy_mode, the color of the active text is:
|
||||
|
||||
@ -570,11 +570,32 @@ impl crate::TermWindow {
|
||||
self.dead_key_status != DeadKeyStatus::None || self.leader_is_active();
|
||||
|
||||
if dead_key_or_leader && params.is_active_pane {
|
||||
let (fg_color, bg_color) = if self.use_reverse_video_cursor(¶ms) {
|
||||
(params.bg_color, params.fg_color)
|
||||
} else {
|
||||
(params.cursor_fg, params.cursor_bg)
|
||||
};
|
||||
let (fg_color, bg_color) = (
|
||||
params
|
||||
.config
|
||||
.resolved_palette
|
||||
.compose_fg
|
||||
.map(|c| c.to_linear())
|
||||
.unwrap_or_else(|| {
|
||||
if self.use_reverse_video_cursor(¶ms) {
|
||||
params.bg_color
|
||||
} else {
|
||||
params.cursor_fg
|
||||
}
|
||||
}),
|
||||
params
|
||||
.config
|
||||
.resolved_palette
|
||||
.compose_bg
|
||||
.map(|c| c.to_linear())
|
||||
.unwrap_or_else(|| {
|
||||
if self.use_reverse_video_cursor(¶ms) {
|
||||
params.fg_color
|
||||
} else {
|
||||
params.cursor_bg
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
let fg_color = self.ensure_min_contrast(fg_color, bg_color);
|
||||
|
||||
|
||||
@ -303,6 +303,23 @@ impl crate::TermWindow {
|
||||
0.0..0.0
|
||||
};
|
||||
|
||||
// Render composition/IME preview background
|
||||
if composition_width > 0 {
|
||||
if let Some(compose_bg) = ¶ms.config.resolved_palette.compose_bg {
|
||||
let start = params.left_pixel_x + (params.cursor.x as f32 * cell_width);
|
||||
let width = composition_width as f32 * cell_width;
|
||||
let mut quad = self
|
||||
.filled_rectangle(
|
||||
layers,
|
||||
0,
|
||||
euclid::rect(start, params.top_pixel_y, width, cell_height),
|
||||
compose_bg.to_linear(),
|
||||
)
|
||||
.context("filled_rectangle")?;
|
||||
quad.set_hsv(hsv);
|
||||
}
|
||||
}
|
||||
|
||||
// Consider cursor
|
||||
if !cursor_range.is_empty() {
|
||||
let (fg_color, bg_color) = if let Some(c) = &cursor_cell {
|
||||
@ -736,7 +753,14 @@ impl crate::TermWindow {
|
||||
// Create an updated line with the composition overlaid
|
||||
let mut line = params.line.clone();
|
||||
let seqno = line.current_seqno();
|
||||
line.overlay_text_with_attribute(*cursor_x, &composing, CellAttributes::blank(), seqno);
|
||||
|
||||
let mut compose_attrs = CellAttributes::blank();
|
||||
if let Some(fg) = ¶ms.config.resolved_palette.compose_fg {
|
||||
compose_attrs
|
||||
.set_foreground(ColorAttribute::TrueColorWithDefaultFallback((*fg).into()));
|
||||
}
|
||||
|
||||
line.overlay_text_with_attribute(*cursor_x, &composing, compose_attrs, seqno);
|
||||
line.cluster(bidi_hint)
|
||||
} else {
|
||||
params.line.cluster(bidi_hint)
|
||||
|
||||
@ -2050,7 +2050,15 @@ impl WindowView {
|
||||
}
|
||||
|
||||
extern "C" fn selected_range(_this: &mut Object, _sel: Sel) -> NSRange {
|
||||
NSRange::new(NSNotFound as _, 0)
|
||||
// Return an empty range at position 0 rather than {NSNotFound, 0}.
|
||||
// NSTextInputClient expects character indices into a text storage
|
||||
// buffer, but as a terminal emulator we don't maintain one—input
|
||||
// is handled through insert_text/set_marked_text callbacks instead.
|
||||
// Returning NSNotFound causes macOS dictation to silently bail out
|
||||
// because it has no valid insertion point. An empty selection at 0
|
||||
// satisfies the protocol and enables dictation. This is the same
|
||||
// workaround used by kitty and Emacs. See #4592
|
||||
NSRange::new(0, 0)
|
||||
}
|
||||
|
||||
// Called by the IME when inserting composed text and/or emoji
|
||||
@ -2110,22 +2118,16 @@ impl WindowView {
|
||||
let mut inner = myself.inner.borrow_mut();
|
||||
inner.ime_text = s.to_string();
|
||||
|
||||
/*
|
||||
let key_is_down = inner.key_is_down.take().unwrap_or(true);
|
||||
// Show composition preview for dictation; see #4592
|
||||
let status = if s.is_empty() {
|
||||
DeadKeyStatus::None
|
||||
} else {
|
||||
DeadKeyStatus::Composing(s.to_string())
|
||||
};
|
||||
inner
|
||||
.events
|
||||
.dispatch(WindowEvent::AdviseDeadKeyStatus(status));
|
||||
|
||||
let key = KeyCode::composed(s);
|
||||
|
||||
let event = KeyEvent {
|
||||
key,
|
||||
modifiers: Modifiers::NONE,
|
||||
repeat_count: 1,
|
||||
key_is_down,
|
||||
}
|
||||
.normalize_shift();
|
||||
|
||||
inner.ime_last_event.replace(event.clone());
|
||||
inner.events.dispatch(WindowEvent::KeyEvent(event));
|
||||
*/
|
||||
inner.ime_last_event.take();
|
||||
inner.ime_state = ImeDisposition::Acted;
|
||||
}
|
||||
@ -2141,6 +2143,9 @@ impl WindowView {
|
||||
inner.ime_text.clear();
|
||||
inner.ime_last_event.take();
|
||||
inner.ime_state = ImeDisposition::Acted;
|
||||
inner
|
||||
.events
|
||||
.dispatch(WindowEvent::AdviseDeadKeyStatus(DeadKeyStatus::None));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user