diff --git a/winit-appkit/Cargo.toml b/winit-appkit/Cargo.toml index a4f590ea29..2a21b1819d 100644 --- a/winit-appkit/Cargo.toml +++ b/winit-appkit/Cargo.toml @@ -9,6 +9,9 @@ rust-version.workspace = true version.workspace = true [features] +#TODO remove from default before merging +default = ["experimental_ime_rewrite"] +experimental_ime_rewrite = [] serde = ["dep:serde", "bitflags/serde", "smol_str/serde", "dpi/serde"] [dependencies] diff --git a/winit-appkit/src/view.rs b/winit-appkit/src/view.rs index 056ec93a2d..dbb0b237f0 100644 --- a/winit-appkit/src/view.rs +++ b/winit-appkit/src/view.rs @@ -22,7 +22,7 @@ use winit_core::event::{ PointerKind, PointerSource, TouchPhase, WindowEvent, }; use winit_core::keyboard::{Key, KeyCode, KeyLocation, ModifiersState, NamedKey}; -use winit_core::window::ImeCapabilities; +use winit_core::window::{ImeCapabilities, ImeSurroundingText}; use super::app_state::AppState; use super::cursor::{default_cursor, invisible_cursor}; @@ -44,7 +44,7 @@ impl Default for CursorState { Self { visible: true, cursor: default_cursor() } } } - +#[cfg(not(feature = "experimental_ime_rewrite"))] #[derive(Debug, Eq, PartialEq, Clone, Copy, Default)] enum ImeState { #[default] @@ -120,18 +120,19 @@ pub struct ViewState { modifiers: Cell, phys_modifiers: RefCell>, tracking_rect: Cell>, - ime_state: Cell, input_source: RefCell, - /// True iff the application wants IME events. - /// - /// Can be set using `set_ime_allowed` + /// Some(caps) iff the application wants IME events. ime_capabilities: Cell>, + #[cfg(not(feature = "experimental_ime_rewrite"))] + ime_state: Cell, + ime_current_surroundings: RefCell>, /// True if the current key event should be forwarded /// to the application, even during IME + #[cfg(not(feature = "experimental_ime_rewrite"))] forward_key_to_app: Cell, - + #[cfg(not(feature = "experimental_ime_rewrite"))] marked_text: RefCell>, accepts_first_mouse: bool, @@ -235,7 +236,90 @@ define_class!( } } } + unsafe impl NSTextInputClient for WinitView { + #[unsafe(method(hasMarkedText))] + fn has_marked_text(&self) -> bool { + trace_scope!("hasMarkedText"); + todo!() + } + #[unsafe(method(markedRange))] + fn marked_range(&self) -> NSRange { + trace_scope!("markedRange"); + todo!() + } + + #[unsafe(method(selectedRange))] + fn selected_range(&self) -> NSRange { + trace_scope!("selectedRange"); + // Documented to return `{NSNotFound, 0}` if there is no selection. + NSRange::new(NSNotFound as NSUInteger, 0) + } + + #[unsafe(method(setMarkedText:selectedRange:replacementRange:))] + fn set_marked_text( + &self, + string: &NSObject, + selected_range: NSRange, + _replacement_range: NSRange, + ) { + // TODO: Use _replacement_range, requires changing the event to report surrounding text. + trace_scope!("setMarkedText:selectedRange:replacementRange:"); + todo!() + } + + #[unsafe(method(unmarkText))] + fn unmark_text(&self) { + trace_scope!("unmarkText"); + } + + #[unsafe(method_id(validAttributesForMarkedText))] + fn valid_attributes_for_marked_text(&self) -> Retained> { + trace_scope!("validAttributesForMarkedText"); + NSArray::new() + } + + #[unsafe(method_id(attributedSubstringForProposedRange:actualRange:))] + fn attributed_substring_for_proposed_range( + &self, + _range: NSRange, + _actual_range: *mut NSRange, + ) -> Option> { + trace_scope!("attributedSubstringForProposedRange:actualRange:"); + None + } + + #[unsafe(method(characterIndexForPoint:))] + fn character_index_for_point(&self, _point: NSPoint) -> NSUInteger { + trace_scope!("characterIndexForPoint:"); + 0 + } + + #[unsafe(method(firstRectForCharacterRange:actualRange:))] + fn first_rect_for_character_range( + &self, + _range: NSRange, + _actual_range: *mut NSRange, + ) -> NSRect { + trace_scope!("firstRectForCharacterRange:actualRange:"); + todo!() + } + + #[unsafe(method(insertText:replacementRange:))] + fn insert_text(&self, string: &NSObject, _replacement_range: NSRange) { + // TODO: Use _replacement_range, requires changing the event to report surrounding text. + trace_scope!("insertText:replacementRange:"); + } + + // Basically, we're sent this message whenever a keyboard event that doesn't generate a + // "human readable" character happens, i.e. newlines, tabs, and Ctrl+C. + #[unsafe(method(doCommandBySelector:))] + fn do_command_by_selector(&self, command: Sel) { + trace_scope!("doCommandBySelector:"); + todo!() + } + } + #[cfg(not(feature = "experimental_ime_rewrite"))] unsafe impl NSTextInputClient for WinitView { #[unsafe(method(hasMarkedText))] fn has_marked_text(&self) -> bool { @@ -272,16 +356,15 @@ define_class!( // TODO: Use _replacement_range, requires changing the event to report surrounding text. trace_scope!("setMarkedText:selectedRange:replacementRange:"); - let (marked_text, string) = if let Some(string) = - string.downcast_ref::() - { - (NSMutableAttributedString::from_attributed_nsstring(string), string.string()) - } else if let Some(string) = string.downcast_ref::() { - (NSMutableAttributedString::from_nsstring(string), string.copy()) - } else { - // This method is guaranteed to get either a `NSString` or a `NSAttributedString`. - panic!("unexpected text {string:?}") - }; + let (marked_text, string) = + if let Some(string) = string.downcast_ref::() { + (NSMutableAttributedString::from_attributed_nsstring(string), string.string()) + } else if let Some(string) = string.downcast_ref::() { + (NSMutableAttributedString::from_nsstring(string), string.copy()) + } else { + // This method is guaranteed to get either a `NSString` or a `NSAttributedString`. + panic!("unexpected text {string:?}") + }; // Update marked text. *self.ivars().marked_text.borrow_mut() = marked_text; @@ -445,6 +528,7 @@ define_class!( /// This documentation attribute makes rustfmt work for some reason? impl WinitView { + #[cfg(not(feature = "experimental_ime_rewrite"))] #[unsafe(method(keyDown:))] fn key_down(&self, event: &NSEvent) { trace_scope!("keyDown:"); @@ -503,7 +587,14 @@ define_class!( }); } } + #[cfg(feature = "experimental_ime_rewrite")] + #[unsafe(method(keyDown:))] + fn key_down(&self, event: &NSEvent) { + trace_scope!("keyDown:"); + todo!() + } + #[cfg(not(feature = "experimental_ime_rewrite"))] #[unsafe(method(keyUp:))] fn key_up(&self, event: &NSEvent) { trace_scope!("keyUp:"); @@ -520,7 +611,12 @@ define_class!( }); } } - + #[cfg(feature = "experimental_ime_rewrite")] + #[unsafe(method(keyUp:))] + fn key_up(&self, event: &NSEvent) { + trace_scope!("keyUp:"); + todo!() + } #[unsafe(method(flagsChanged:))] fn flags_changed(&self, event: &NSEvent) { trace_scope!("flagsChanged:"); @@ -809,10 +905,13 @@ impl WinitView { modifiers: Default::default(), phys_modifiers: Default::default(), tracking_rect: Default::default(), + #[cfg(not(feature = "experimental_ime_rewrite"))] ime_state: Default::default(), input_source: Default::default(), ime_capabilities: Default::default(), + #[cfg(not(feature = "experimental_ime_rewrite"))] forward_key_to_app: Default::default(), + #[cfg(not(feature = "experimental_ime_rewrite"))] marked_text: Default::default(), accepts_first_mouse, option_as_alt: Cell::new(option_as_alt), @@ -838,7 +937,7 @@ impl WinitView { fn scale_factor(&self) -> f64 { self.window().backingScaleFactor() as f64 } - + #[cfg(not(feature = "experimental_ime_rewrite"))] fn is_ime_enabled(&self) -> bool { !matches!(self.ivars().ime_state.get(), ImeState::Disabled) } @@ -872,6 +971,7 @@ impl WinitView { false } } + #[cfg(not(feature = "experimental_ime_rewrite"))] pub(super) fn enable_ime(&self, capabilities: ImeCapabilities) { // This seems reasonable but the prior behavior of `set_ime_allowed` doesn't do this // (it was also broken but let's not break things worse) @@ -889,6 +989,12 @@ impl WinitView { self.ivars().ime_capabilities.set(Some(capabilities)); *self.ivars().marked_text.borrow_mut() = NSMutableAttributedString::new(); } + #[cfg(feature = "experimental_ime_rewrite")] + pub(super) fn enable_ime(&self, capabilities: ImeCapabilities) { + todo!(); + } + + #[cfg(not(feature = "experimental_ime_rewrite"))] pub(super) fn disable_ime(&self) { // see above self.ivars().ime_capabilities.set(None); @@ -900,6 +1006,10 @@ impl WinitView { // `set_ime_allowed` *self.ivars().marked_text.borrow_mut() = NSMutableAttributedString::new(); } + #[cfg(feature = "experimental_ime_rewrite")] + pub(super) fn disable_ime(&self) { + todo!() + } pub(super) fn ime_capabilities(&self) -> Option { self.ivars().ime_capabilities.get()