Revert "Add composition event on macOS (#1979)" (#2119)

This reverts commit 8afeb910bd.

Reverting because this change made Pinyin input unusable
(only latin characters showed even after selecting the
desired Chinese character)
This commit is contained in:
Artúr Kovács 2022-01-02 22:01:51 +01:00 committed by GitHub
parent 5331397c6c
commit 6b250a74f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 31 additions and 121 deletions

View file

@ -1,6 +1,7 @@
# Unreleased # Unreleased
- On X11, add mappings for numpad comma, numpad enter, numlock and pause. - On X11, add mappings for numpad comma, numpad enter, numlock and pause.
- On macOS, fix Pinyin IME input by reverting a change that intended to improve IME.
# 0.26.0 (2021-12-01) # 0.26.0 (2021-12-01)

View file

@ -48,7 +48,6 @@ cocoa = "0.24"
core-foundation = "0.9" core-foundation = "0.9"
core-graphics = "0.22" core-graphics = "0.22"
dispatch = "0.2.0" dispatch = "0.2.0"
block = "0.1"
[target.'cfg(target_os = "macos")'.dependencies.core-video-sys] [target.'cfg(target_os = "macos")'.dependencies.core-video-sys]
version = "0.1.4" version = "0.1.4"

View file

@ -118,8 +118,6 @@ pub enum NSWindowLevel {
NSScreenSaverWindowLevel = kCGScreenSaverWindowLevelKey as _, NSScreenSaverWindowLevel = kCGScreenSaverWindowLevelKey as _,
} }
pub const NSStringEnumerationByComposedCharacterSequences: NSUInteger = 2;
pub type CGDisplayFadeInterval = f32; pub type CGDisplayFadeInterval = f32;
pub type CGDisplayReservationInterval = f32; pub type CGDisplayReservationInterval = f32;
pub type CGDisplayBlendFraction = f32; pub type CGDisplayBlendFraction = f32;

View file

@ -3,13 +3,8 @@ mod cursor;
pub use self::{cursor::*, r#async::*}; pub use self::{cursor::*, r#async::*};
use std::{ use std::ops::{BitAnd, Deref};
cell::Cell,
ops::{BitAnd, Deref},
rc::Rc,
};
use block::ConcreteBlock;
use cocoa::{ use cocoa::{
appkit::{NSApp, NSWindowStyleMask}, appkit::{NSApp, NSWindowStyleMask},
base::{id, nil}, base::{id, nil},
@ -18,12 +13,8 @@ use cocoa::{
use core_graphics::display::CGDisplay; use core_graphics::display::CGDisplay;
use objc::runtime::{Class, Object, Sel, BOOL, YES}; use objc::runtime::{Class, Object, Sel, BOOL, YES};
use crate::{ use crate::dpi::LogicalPosition;
dpi::LogicalPosition, use crate::platform_impl::platform::ffi;
platform_impl::platform::ffi::{
self, NSRange, NSStringEnumerationByComposedCharacterSequences,
},
};
// Replace with `!` once stable // Replace with `!` once stable
#[derive(Debug)] #[derive(Debug)]
@ -113,31 +104,6 @@ pub unsafe fn ns_string_id_ref(s: &str) -> IdRef {
IdRef::new(NSString::alloc(nil).init_str(s)) IdRef::new(NSString::alloc(nil).init_str(s))
} }
/// Returns the number of characters in a string.
/// (A single character may consist of multiple UTF-32 code units.
/// This is possible when long sequences of composing characters are present)
///
/// Unsafe because assumes that the `string` is an `NSString` object
pub unsafe fn ns_string_char_count(string: id) -> usize {
let length: NSUInteger = msg_send![string, length];
let range = NSRange {
location: 0,
length,
};
let char_count = Rc::new(Cell::new(0));
let block = {
let char_count = char_count.clone();
ConcreteBlock::new(move || char_count.set(char_count.get() + 1)).copy()
};
let block = &*block;
let () = msg_send![string,
enumerateSubstringsInRange:range
options:NSStringEnumerationByComposedCharacterSequences
usingBlock:block
];
char_count.get()
}
#[allow(dead_code)] // In case we want to use this function in the future #[allow(dead_code)] // In case we want to use this function in the future
pub unsafe fn app_name() -> Option<id> { pub unsafe fn app_name() -> Option<id> {
let bundle: id = msg_send![class!(NSBundle), mainBundle]; let bundle: id = msg_send![class!(NSBundle), mainBundle];

View file

@ -29,7 +29,7 @@ use crate::{
scancode_to_keycode, EventWrapper, scancode_to_keycode, EventWrapper,
}, },
ffi::*, ffi::*,
util::{self, ns_string_char_count, IdRef}, util::{self, IdRef},
window::get_window_id, window::get_window_id,
DEVICE_ID, DEVICE_ID,
}, },
@ -57,8 +57,6 @@ pub(super) struct ViewState {
raw_characters: Option<String>, raw_characters: Option<String>,
pub(super) modifiers: ModifiersState, pub(super) modifiers: ModifiersState,
tracking_rect: Option<NSInteger>, tracking_rect: Option<NSInteger>,
is_ime_activated: bool,
marked_text: id,
} }
impl ViewState { impl ViewState {
@ -70,8 +68,6 @@ impl ViewState {
pub fn new_view(ns_window: id) -> (IdRef, Weak<Mutex<CursorState>>) { pub fn new_view(ns_window: id) -> (IdRef, Weak<Mutex<CursorState>>) {
let cursor_state = Default::default(); let cursor_state = Default::default();
let cursor_access = Arc::downgrade(&cursor_state); let cursor_access = Arc::downgrade(&cursor_state);
let marked_text =
unsafe { <id as NSMutableAttributedString>::init(NSMutableAttributedString::alloc(nil)) };
let state = ViewState { let state = ViewState {
ns_window, ns_window,
cursor_state, cursor_state,
@ -79,8 +75,6 @@ pub fn new_view(ns_window: id) -> (IdRef, Weak<Mutex<CursorState>>) {
raw_characters: None, raw_characters: None,
modifiers: Default::default(), modifiers: Default::default(),
tracking_rect: None, tracking_rect: None,
is_ime_activated: false,
marked_text,
}; };
unsafe { unsafe {
// This is free'd in `dealloc` // This is free'd in `dealloc`
@ -153,10 +147,7 @@ lazy_static! {
sel!(setMarkedText:selectedRange:replacementRange:), sel!(setMarkedText:selectedRange:replacementRange:),
set_marked_text as extern "C" fn(&mut Object, Sel, id, NSRange, NSRange), set_marked_text as extern "C" fn(&mut Object, Sel, id, NSRange, NSRange),
); );
decl.add_method( decl.add_method(sel!(unmarkText), unmark_text as extern "C" fn(&Object, Sel));
sel!(unmarkText),
unmark_text as extern "C" fn(&mut Object, Sel),
);
decl.add_method( decl.add_method(
sel!(validAttributesForMarkedText), sel!(validAttributesForMarkedText),
valid_attributes_for_marked_text as extern "C" fn(&Object, Sel) -> id, valid_attributes_for_marked_text as extern "C" fn(&Object, Sel) -> id,
@ -168,7 +159,7 @@ lazy_static! {
); );
decl.add_method( decl.add_method(
sel!(insertText:replacementRange:), sel!(insertText:replacementRange:),
insert_text as extern "C" fn(&mut Object, Sel, id, NSRange), insert_text as extern "C" fn(&Object, Sel, id, NSRange),
); );
decl.add_method( decl.add_method(
sel!(characterIndexForPoint:), sel!(characterIndexForPoint:),
@ -267,6 +258,7 @@ lazy_static! {
accepts_first_mouse as extern "C" fn(&Object, Sel, id) -> BOOL, accepts_first_mouse as extern "C" fn(&Object, Sel, id) -> BOOL,
); );
decl.add_ivar::<*mut c_void>("winitState"); decl.add_ivar::<*mut c_void>("winitState");
decl.add_ivar::<id>("markedText");
let protocol = Protocol::get("NSTextInputClient").unwrap(); let protocol = Protocol::get("NSTextInputClient").unwrap();
decl.add_protocol(&protocol); decl.add_protocol(&protocol);
ViewClass(decl.register()) ViewClass(decl.register())
@ -276,9 +268,9 @@ lazy_static! {
extern "C" fn dealloc(this: &Object, _sel: Sel) { extern "C" fn dealloc(this: &Object, _sel: Sel) {
unsafe { unsafe {
let state: *mut c_void = *this.get_ivar("winitState"); let state: *mut c_void = *this.get_ivar("winitState");
let state = state as *mut ViewState; let marked_text: id = *this.get_ivar("markedText");
let _: () = msg_send![(*state).marked_text, release]; let _: () = msg_send![marked_text, release];
Box::from_raw(state); Box::from_raw(state as *mut ViewState);
} }
} }
@ -287,6 +279,9 @@ extern "C" fn init_with_winit(this: &Object, _sel: Sel, state: *mut c_void) -> i
let this: id = msg_send![this, init]; let this: id = msg_send![this, init];
if this != nil { if this != nil {
(*this).set_ivar("winitState", state); (*this).set_ivar("winitState", state);
let marked_text =
<id as NSMutableAttributedString>::init(NSMutableAttributedString::alloc(nil));
(*this).set_ivar("markedText", marked_text);
let _: () = msg_send![this, setPostsFrameChangedNotifications: YES]; let _: () = msg_send![this, setPostsFrameChangedNotifications: YES];
let notification_center: &Object = let notification_center: &Object =
@ -393,20 +388,17 @@ extern "C" fn reset_cursor_rects(this: &Object, _sel: Sel) {
extern "C" fn has_marked_text(this: &Object, _sel: Sel) -> BOOL { extern "C" fn has_marked_text(this: &Object, _sel: Sel) -> BOOL {
unsafe { unsafe {
trace!("Triggered `hasMarkedText`"); trace!("Triggered `hasMarkedText`");
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let marked_text: id = *this.get_ivar("markedText");
let state = &mut *(state_ptr as *mut ViewState);
let retval = (state.marked_text.length() > 0) as BOOL;
trace!("Completed `hasMarkedText`"); trace!("Completed `hasMarkedText`");
retval (marked_text.length() > 0) as BOOL
} }
} }
extern "C" fn marked_range(this: &Object, _sel: Sel) -> NSRange { extern "C" fn marked_range(this: &Object, _sel: Sel) -> NSRange {
unsafe { unsafe {
trace!("Triggered `markedRange`"); trace!("Triggered `markedRange`");
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let marked_text: id = *this.get_ivar("markedText");
let state = &mut *(state_ptr as *mut ViewState); let length = marked_text.length();
let length = state.marked_text.length();
trace!("Completed `markedRange`"); trace!("Completed `markedRange`");
if length > 0 { if length > 0 {
NSRange::new(0, length - 1) NSRange::new(0, length - 1)
@ -431,60 +423,30 @@ extern "C" fn set_marked_text(
) { ) {
trace!("Triggered `setMarkedText`"); trace!("Triggered `setMarkedText`");
unsafe { unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let marked_text_ref: &mut id = this.get_mut_ivar("markedText");
let state = &mut *(state_ptr as *mut ViewState); let _: () = msg_send![(*marked_text_ref), release];
let marked_text = NSMutableAttributedString::alloc(nil);
// Delete previous marked text
let char_count = ns_string_char_count(state.marked_text.string());
delete_marked_text(state, char_count);
state.is_ime_activated = true;
let _: () = msg_send![state.marked_text, release];
state.marked_text = NSMutableAttributedString::alloc(nil);
let has_attr = msg_send![string, isKindOfClass: class!(NSAttributedString)]; let has_attr = msg_send![string, isKindOfClass: class!(NSAttributedString)];
if has_attr { if has_attr {
state.marked_text.initWithAttributedString(string); marked_text.initWithAttributedString(string);
} else { } else {
state.marked_text.initWithString(string); marked_text.initWithString(string);
}; };
*marked_text_ref = marked_text;
let text_ns_str = state.marked_text.string();
let slice = slice::from_raw_parts(
text_ns_str.UTF8String() as *const c_uchar,
text_ns_str.len(),
);
let text_str = str::from_utf8_unchecked(slice);
for character in text_str.chars() {
AppState::queue_event(EventWrapper::StaticEvent(Event::WindowEvent {
window_id: WindowId(get_window_id(state.ns_window)),
event: WindowEvent::ReceivedCharacter(character),
}));
}
} }
trace!("Completed `setMarkedText`"); trace!("Completed `setMarkedText`");
} }
extern "C" fn unmark_text(this: &mut Object, _sel: Sel) { extern "C" fn unmark_text(this: &Object, _sel: Sel) {
trace!("Triggered `unmarkText`"); trace!("Triggered `unmarkText`");
unsafe { unsafe {
clear_marked_text(this); let marked_text: id = *this.get_ivar("markedText");
} let mutable_string = marked_text.mutableString();
trace!("Completed `unmarkText`"); let _: () = msg_send![mutable_string, setString:""];
}
/// Unsafe because assumes that `this` is an instance of the `WinitView` class that we declare
/// programmatically
unsafe fn clear_marked_text(this: &mut Object) {
let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState);
let _: () = msg_send![state.marked_text, release];
state.marked_text = NSMutableAttributedString::alloc(nil);
let input_context: id = msg_send![this, inputContext]; let input_context: id = msg_send![this, inputContext];
let _: () = msg_send![input_context, discardMarkedText]; let _: () = msg_send![input_context, discardMarkedText];
}
trace!("Completed `unmarkText`");
} }
extern "C" fn valid_attributes_for_marked_text(_this: &Object, _sel: Sel) -> id { extern "C" fn valid_attributes_for_marked_text(_this: &Object, _sel: Sel) -> id {
@ -534,19 +496,12 @@ extern "C" fn first_rect_for_character_range(
} }
} }
extern "C" fn insert_text(this: &mut Object, _sel: Sel, string: id, _replacement_range: NSRange) { extern "C" fn insert_text(this: &Object, _sel: Sel, string: id, _replacement_range: NSRange) {
trace!("Triggered `insertText`"); trace!("Triggered `insertText`");
unsafe { unsafe {
let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state_ptr: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state_ptr as *mut ViewState); let state = &mut *(state_ptr as *mut ViewState);
let is_ime_activated: bool = state.is_ime_activated;
if is_ime_activated {
clear_marked_text(this);
state.is_ime_activated = false;
return;
}
let has_attr = msg_send![string, isKindOfClass: class!(NSAttributedString)]; let has_attr = msg_send![string, isKindOfClass: class!(NSAttributedString)];
let characters = if has_attr { let characters = if has_attr {
// This is a *mut NSAttributedString // This is a *mut NSAttributedString
@ -613,15 +568,6 @@ extern "C" fn do_command_by_selector(this: &Object, _sel: Sel, command: Sel) {
trace!("Completed `doCommandBySelector`"); trace!("Completed `doCommandBySelector`");
} }
fn delete_marked_text(state: &mut ViewState, count: usize) {
for _ in 0..count {
AppState::queue_event(EventWrapper::StaticEvent(Event::WindowEvent {
window_id: WindowId(get_window_id(state.ns_window)),
event: WindowEvent::ReceivedCharacter('\u{7f}'), // fire DELETE
}));
}
}
fn get_characters(event: id, ignore_modifiers: bool) -> String { fn get_characters(event: id, ignore_modifiers: bool) -> String {
unsafe { unsafe {
let characters: id = if ignore_modifiers { let characters: id = if ignore_modifiers {