Restructure IME composition to not follow Chromium so closely
This commit is contained in:
parent
b02681ee8a
commit
481078ae22
1 changed files with 48 additions and 97 deletions
|
@ -37,7 +37,6 @@ use smol::Timer;
|
|||
use std::{
|
||||
any::Any,
|
||||
cell::{Cell, RefCell},
|
||||
cmp,
|
||||
convert::TryInto,
|
||||
ffi::{c_void, CStr},
|
||||
mem,
|
||||
|
@ -274,7 +273,7 @@ struct WindowState {
|
|||
should_close_callback: Option<Box<dyn FnMut() -> bool>>,
|
||||
close_callback: Option<Box<dyn FnOnce()>>,
|
||||
input_handler: Option<Box<dyn InputHandler>>,
|
||||
pending_key_event: Option<PendingKeyEvent>,
|
||||
pending_keydown_event: Option<KeyDownEvent>,
|
||||
synthetic_drag_counter: usize,
|
||||
executor: Rc<executor::Foreground>,
|
||||
scene_to_render: Option<Scene>,
|
||||
|
@ -286,13 +285,6 @@ struct WindowState {
|
|||
previous_modifiers_changed_event: Option<Event>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct PendingKeyEvent {
|
||||
set_marked_text: Option<(String, Option<Range<usize>>, Option<Range<usize>>)>,
|
||||
unmark_text: bool,
|
||||
insert_text: Option<String>,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
pub fn open(
|
||||
id: usize,
|
||||
|
@ -369,7 +361,7 @@ impl Window {
|
|||
close_callback: None,
|
||||
activate_callback: None,
|
||||
input_handler: None,
|
||||
pending_key_event: None,
|
||||
pending_keydown_event: None,
|
||||
synthetic_drag_counter: 0,
|
||||
executor,
|
||||
scene_to_render: Default::default(),
|
||||
|
@ -705,7 +697,7 @@ extern "C" fn handle_key_equivalent(this: &Object, _: Sel, native_event: id) ->
|
|||
|
||||
let event = unsafe { Event::from_native(native_event, Some(window_state_borrow.size().y())) };
|
||||
if let Some(event) = event {
|
||||
let mut event = match event {
|
||||
window_state_borrow.pending_keydown_event = match event {
|
||||
Event::KeyDown(event) => {
|
||||
let keydown = (event.keystroke.clone(), event.input.clone());
|
||||
// Ignore events from held-down keys after some of the initially-pressed keys
|
||||
|
@ -718,97 +710,30 @@ extern "C" fn handle_key_equivalent(this: &Object, _: Sel, native_event: id) ->
|
|||
window_state_borrow.last_fresh_keydown = Some(keydown);
|
||||
}
|
||||
|
||||
event
|
||||
Some(event)
|
||||
}
|
||||
_ => return NO,
|
||||
};
|
||||
|
||||
// TODO: handle "live conversion"
|
||||
window_state_borrow.pending_key_event = Some(Default::default());
|
||||
drop(window_state_borrow);
|
||||
let had_marked_text =
|
||||
with_input_handler(this, |input_handler| input_handler.marked_text_range())
|
||||
.flatten()
|
||||
.is_some();
|
||||
|
||||
// TODO:
|
||||
// Since Mac Eisu Kana keys cannot be handled by interpretKeyEvents to enable/
|
||||
// disable an IME, we need to pass the event to processInputKeyBindings.
|
||||
// processInputKeyBindings is available at least on 10.11-11.0.
|
||||
// if (keyCode == kVK_JIS_Eisu || keyCode == kVK_JIS_Kana) {
|
||||
// if ([NSTextInputContext
|
||||
// respondsToSelector:@selector(processInputKeyBindings:)]) {
|
||||
// [NSTextInputContext performSelector:@selector(processInputKeyBindings:)
|
||||
// withObject:theEvent];
|
||||
// }
|
||||
// } else {
|
||||
unsafe {
|
||||
let input_context: id = msg_send![this, inputContext];
|
||||
let _: BOOL = msg_send![input_context, handleEvent: native_event];
|
||||
}
|
||||
// }
|
||||
|
||||
let pending_event = window_state.borrow_mut().pending_key_event.take().unwrap();
|
||||
|
||||
dbg!(&pending_event);
|
||||
|
||||
let mut inserted_text = false;
|
||||
let has_marked_text = pending_event.set_marked_text.is_some()
|
||||
|| with_input_handler(this, |input_handler| input_handler.marked_text_range())
|
||||
.flatten()
|
||||
.is_some();
|
||||
if let Some(text) = pending_event.insert_text.as_ref() {
|
||||
if !text.is_empty() {
|
||||
with_input_handler(this, |input_handler| {
|
||||
input_handler.replace_text_in_range(None, &text)
|
||||
});
|
||||
inserted_text = true;
|
||||
}
|
||||
}
|
||||
|
||||
with_input_handler(this, |input_handler| {
|
||||
if let Some((text, new_selected_range, replacement_range)) =
|
||||
pending_event.set_marked_text
|
||||
{
|
||||
input_handler.replace_and_mark_text_in_range(
|
||||
replacement_range,
|
||||
&text,
|
||||
new_selected_range,
|
||||
)
|
||||
} else if had_marked_text && !has_marked_text && !inserted_text {
|
||||
if pending_event.unmark_text {
|
||||
input_handler.finish_composition();
|
||||
} else {
|
||||
input_handler.cancel_composition();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if has_marked_text {
|
||||
YES
|
||||
} else {
|
||||
let mut handled = false;
|
||||
let mut window_state_borrow = window_state.borrow_mut();
|
||||
let mut handled = false;
|
||||
let mut window_state_borrow = window_state.borrow_mut();
|
||||
if let Some(event) = window_state_borrow.pending_keydown_event.take() {
|
||||
if let Some(mut callback) = window_state_borrow.event_callback.take() {
|
||||
drop(window_state_borrow);
|
||||
|
||||
if inserted_text {
|
||||
handled = true;
|
||||
} else {
|
||||
if let Some(text) = pending_event.insert_text {
|
||||
if text.chars().count() == 1 {
|
||||
event.keystroke.key = text;
|
||||
}
|
||||
}
|
||||
|
||||
handled = callback(Event::KeyDown(event.clone()));
|
||||
}
|
||||
|
||||
handled = callback(Event::KeyDown(event.clone()));
|
||||
window_state.borrow_mut().event_callback = Some(callback);
|
||||
}
|
||||
|
||||
handled as BOOL
|
||||
} else {
|
||||
handled = true;
|
||||
}
|
||||
|
||||
handled as BOOL
|
||||
} else {
|
||||
NO
|
||||
}
|
||||
|
@ -1090,6 +1015,11 @@ extern "C" fn first_rect_for_character_range(_: &Object, _: Sel, _: NSRange, _:
|
|||
|
||||
extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NSRange) {
|
||||
unsafe {
|
||||
let window_state = get_window_state(this);
|
||||
let mut window_state_borrow = window_state.borrow_mut();
|
||||
let pending_keydown_event = window_state_borrow.pending_keydown_event.take();
|
||||
drop(window_state_borrow);
|
||||
|
||||
let is_attributed_string: BOOL =
|
||||
msg_send![text, isKindOfClass: [class!(NSAttributedString)]];
|
||||
let text: id = if is_attributed_string == YES {
|
||||
|
@ -1100,20 +1030,36 @@ extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NS
|
|||
let text = CStr::from_ptr(text.UTF8String() as *mut c_char)
|
||||
.to_str()
|
||||
.unwrap();
|
||||
let replacement_range = replacement_range.to_range();
|
||||
|
||||
let window_state = get_window_state(this);
|
||||
let mut window_state = window_state.borrow_mut();
|
||||
if window_state.pending_key_event.is_some() && !replacement_range.is_valid() {
|
||||
window_state.pending_key_event.as_mut().unwrap().insert_text = Some(text.to_string());
|
||||
drop(window_state);
|
||||
} else {
|
||||
drop(window_state);
|
||||
let is_composing =
|
||||
with_input_handler(this, |input_handler| input_handler.marked_text_range())
|
||||
.flatten()
|
||||
.is_some();
|
||||
|
||||
if is_composing || text.chars().count() > 1 || pending_keydown_event.is_none() {
|
||||
with_input_handler(this, |input_handler| {
|
||||
input_handler.replace_text_in_range(replacement_range.to_range(), text);
|
||||
input_handler.replace_text_in_range(replacement_range, text)
|
||||
});
|
||||
}
|
||||
} else {
|
||||
let mut pending_keydown_event = pending_keydown_event.unwrap();
|
||||
pending_keydown_event.keystroke.key = text.into();
|
||||
let mut window_state_borrow = window_state.borrow_mut();
|
||||
let event_callback = window_state_borrow.event_callback.take();
|
||||
drop(window_state_borrow);
|
||||
|
||||
with_input_handler(this, |input_handler| input_handler.unmark_text());
|
||||
let mut handled = false;
|
||||
if let Some(mut event_callback) = event_callback {
|
||||
handled = event_callback(Event::KeyDown(pending_keydown_event));
|
||||
window_state.borrow_mut().event_callback = Some(event_callback);
|
||||
}
|
||||
|
||||
if !handled {
|
||||
with_input_handler(this, |input_handler| {
|
||||
input_handler.replace_text_in_range(replacement_range, text)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1126,6 +1072,11 @@ extern "C" fn set_marked_text(
|
|||
) {
|
||||
println!("set_marked_text");
|
||||
unsafe {
|
||||
get_window_state(this)
|
||||
.borrow_mut()
|
||||
.pending_keydown_event
|
||||
.take();
|
||||
|
||||
let is_attributed_string: BOOL =
|
||||
msg_send![text, isKindOfClass: [class!(NSAttributedString)]];
|
||||
let text: id = if is_attributed_string == YES {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue