Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions winit-appkit/src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ pub struct ViewState {
ime_state: Cell<ImeState>,
input_source: RefCell<String>,

/// True if this view was in a preedit session that will result in a commit.
pending_commit: Cell<bool>,

/// True iff the application wants IME events.
///
/// Can be set using `set_ime_allowed`
Expand Down Expand Up @@ -292,6 +295,7 @@ define_class!(
// In case the preedit was cleared, set IME into the Ground state.
self.ivars().ime_state.set(ImeState::Ground);
}
self.ivars().pending_commit.set(true);

let string = string.to_string();
let cursor_range = if string.is_empty() {
Expand Down Expand Up @@ -335,7 +339,9 @@ define_class!(
#[unsafe(method_id(validAttributesForMarkedText))]
fn valid_attributes_for_marked_text(&self) -> Retained<NSArray<NSAttributedStringKey>> {
let _entered = trace_span!("validAttributesForMarkedText").entered();
NSArray::new()
let underline_style = NSString::from_str("NSUnderlineStyle");
let marked_clause = NSString::from_str("NSMarkedClauseSegment");
NSArray::from_slice(&[&*underline_style, &*marked_clause])
}

#[unsafe(method_id(attributedSubstringForProposedRange:actualRange:))]
Expand Down Expand Up @@ -389,10 +395,20 @@ define_class!(
};

let is_control = string.chars().next().is_some_and(|c| c.is_control());
let has_marked = self.hasMarkedText();
let pending_commit = self.ivars().pending_commit.get();
let ime_enabled = self.is_ime_enabled();

// Commit only if we have marked text.
if self.hasMarkedText() && self.is_ime_enabled() && !is_control {
// Clear preedit if there is marked text.
if has_marked {
self.queue_event(WindowEvent::Ime(Ime::Preedit(String::new(), None)));
}

// Only commit via IME if there was a real composition session.
// Some IMEs send insertText for all typing (e.g. spaces, English chars)
// which should go through keyboard input instead of paste.
if pending_commit && ime_enabled && !is_control {
self.ivars().pending_commit.set(false);
self.queue_event(WindowEvent::Ime(Ime::Commit(string)));
self.ivars().ime_state.set(ImeState::Committed);
}
Expand Down Expand Up @@ -816,6 +832,7 @@ impl WinitView {
phys_modifiers: Default::default(),
ime_state: Default::default(),
input_source: Default::default(),
pending_commit: Default::default(),
ime_capabilities: Default::default(),
forward_key_to_app: Default::default(),
marked_text: Default::default(),
Expand Down Expand Up @@ -971,6 +988,7 @@ impl WinitView {
}
self.ivars().ime_capabilities.set(Some(capabilities));
*self.ivars().marked_text.borrow_mut() = NSMutableAttributedString::new();
self.ivars().pending_commit.set(false);
}
pub(super) fn disable_ime(&self) {
// see above
Expand All @@ -982,6 +1000,7 @@ impl WinitView {
// we probably don't need to do this, but again this mirrors the prior behavior of
// `set_ime_allowed`
*self.ivars().marked_text.borrow_mut() = NSMutableAttributedString::new();
self.ivars().pending_commit.set(false);
}

pub(super) fn ime_capabilities(&self) -> Option<ImeCapabilities> {
Expand Down