Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ wayland-client = { version = "0.23.0", features = [ "dlopen", "egl", "cursor", "
mio = "0.6"
mio-extras = "2.0"
smithay-client-toolkit = "^0.6.6"
x11-dl = "2.18.3"
x11-dl = "2.18.5"
percent-encoding = "2.0"

[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "windows"))'.dependencies.parking_lot]
Expand Down
12 changes: 12 additions & 0 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ pub enum WindowEvent<'a> {
is_synthetic: bool,
},

/// An event from IME
Composition(CompositionEvent),

/// The cursor has moved on the window.
CursorMoved {
device_id: DeviceId,
Expand Down Expand Up @@ -341,6 +344,7 @@ impl<'a> WindowEvent<'a> {
input,
is_synthetic,
}),
Composition(event) => Some(Composition(event)),
#[allow(deprecated)]
CursorMoved {
device_id,
Expand Down Expand Up @@ -506,6 +510,14 @@ pub struct KeyboardInput {
pub modifiers: ModifiersState,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum CompositionEvent {
CompositionStart(String),
CompositionUpdate(String, usize),
CompositionEnd(String),
}

/// Describes touch-screen input state.
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
Expand Down
45 changes: 44 additions & 1 deletion src/platform_impl/linux/x11/event_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,20 @@ use super::{

use util::modifiers::{ModifierKeyState, ModifierKeymap};

use crate::platform_impl::platform::x11::ime::{ImeEvent, ImeEventReceiver};
use crate::{
dpi::{PhysicalPosition, PhysicalSize},
event::{
DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, TouchPhase, WindowEvent,
CompositionEvent, DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState,
TouchPhase, WindowEvent,
},
event_loop::EventLoopWindowTarget as RootELW,
};

pub(super) struct EventProcessor<T: 'static> {
pub(super) dnd: Dnd,
pub(super) ime_receiver: ImeReceiver,
pub(super) ime_event_receiver: ImeEventReceiver,
pub(super) randr_event_offset: c_int,
pub(super) devices: RefCell<HashMap<DeviceId, Device>>,
pub(super) xi2ext: XExtension,
Expand All @@ -32,6 +35,8 @@ pub(super) struct EventProcessor<T: 'static> {
// Number of touch events currently in progress
pub(super) num_touch: u32,
pub(super) first_touch: Option<u64>,
pub(super) is_composing: bool,
pub(super) composed_text: Option<String>,
}

impl<T: 'static> EventProcessor<T> {
Expand Down Expand Up @@ -603,6 +608,10 @@ impl<T: 'static> EventProcessor<T> {
};
callback(event);
}
if self.is_composing && !written.is_empty() {
self.composed_text = Some(written);
self.is_composing = false;
}
}
}

Expand Down Expand Up @@ -1188,6 +1197,40 @@ impl<T: 'static> EventProcessor<T> {
}
Err(_) => (),
}
match self.ime_event_receiver.try_recv() {
Copy link
Contributor

@kaiwk kaiwk Sep 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @garasubo and @murarth , I'm implementing this for Mac, should I handle both WindowEvent::ReceivedCharacter and CompositionEvent::End at the same time, or just ignore WindowEvent::ReceivedCharacter during composing?

I'm not sure how XIM work, but looks like here, in process_event, both x event and ime event are handled?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for get interested in this work. I don't have Mac dev environment, so that would be great.

I think we should handle both to keep compatibility, so in my implementation, both events are handled.
In XIM, IME events and receiving characters events are independent. So, I didn't touch any logic related to ReceivedCharacter event.

Ok((window, event)) => match event {
ImeEvent::Start => {
self.is_composing = true;
self.composed_text = None;
callback(Event::WindowEvent {
window_id: mkwid(window),
event: WindowEvent::Composition(CompositionEvent::CompositionStart(
"".to_owned(),
)),
});
}
ImeEvent::Update(text, position) => {
if self.is_composing {
callback(Event::WindowEvent {
window_id: mkwid(window),
event: WindowEvent::Composition(CompositionEvent::CompositionUpdate(
text, position,
)),
});
}
}
ImeEvent::End => {
self.is_composing = false;
callback(Event::WindowEvent {
window_id: mkwid(window),
event: WindowEvent::Composition(CompositionEvent::CompositionEnd(
self.composed_text.take().unwrap_or("".to_owned()),
)),
});
}
},
Err(_) => (),
}
}

fn handle_pressed_keys<F>(
Expand Down
8 changes: 7 additions & 1 deletion src/platform_impl/linux/x11/ime/callbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,13 @@ unsafe fn replace_im(inner: *mut ImeInner) -> Result<(), ReplaceImError> {
for (window, old_context) in (*inner).contexts.iter() {
let spot = old_context.as_ref().map(|old_context| old_context.ic_spot);
let new_context = {
let result = ImeContext::new(xconn, new_im.im, *window, spot);
let result = ImeContext::new(
xconn,
new_im.im,
*window,
spot,
(*inner).event_sender.clone(),
);
if result.is_err() {
let _ = close_im(xconn, new_im.im);
}
Expand Down
Loading