Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
a9f5400
Add composition event support
garasubo Mar 6, 2020
12dfeda
Rename CompostionEvent to IME
kchibisov Jan 16, 2022
5042d9a
Add new IME event support for Wayland
kchibisov Jan 21, 2022
08b4032
initial implementation for web IME support
KentaTheBugMaker Jan 24, 2022
5b00b46
initial set_ime_position implementation for web
KentaTheBugMaker Jan 26, 2022
e562be8
install Input to body.
KentaTheBugMaker Jan 29, 2022
b11dd9a
set_ime_position implementation finished.
KentaTheBugMaker Jan 29, 2022
8df9ad8
testing more correct handling.
KentaTheBugMaker Jan 29, 2022
7ad799a
fixed double input
KentaTheBugMaker Jan 30, 2022
cccaace
fixed backspace not working
KentaTheBugMaker Jan 30, 2022
875cdca
Update CHANGELOG.md
KentaTheBugMaker Jan 30, 2022
327224f
add platform specific behavior notes for `set_ime_position`
KentaTheBugMaker Jan 30, 2022
7b5f167
do not separate Desktop and Mobile device behavior
KentaTheBugMaker Feb 4, 2022
2f69107
trying to fix WebkitGTK bug
KentaTheBugMaker Feb 5, 2022
ef99d29
insert logging to which event fired to winit
KentaTheBugMaker Feb 5, 2022
d2e8bdc
do not fire IME::Enabled many times.
KentaTheBugMaker Feb 5, 2022
b200222
multi window support for IME
KentaTheBugMaker Feb 7, 2022
d02cbbd
fmt
KentaTheBugMaker Feb 7, 2022
044c973
more correct DOM attach and detach
KentaTheBugMaker Feb 7, 2022
abd8824
more correct DOM attach and detach
KentaTheBugMaker Feb 7, 2022
4e828ca
more correct DOM attach and detach
KentaTheBugMaker Feb 7, 2022
053e267
fix
KentaTheBugMaker Feb 7, 2022
8814eaf
do not emit ReceivedCharacter when paste performed
KentaTheBugMaker Feb 7, 2022
645f52d
revert windows clippy fix
KentaTheBugMaker Feb 8, 2022
c21ce98
small doc fix
KentaTheBugMaker Feb 8, 2022
7b390ed
remove unused web_sys features
KentaTheBugMaker Feb 8, 2022
1f89490
fmt
KentaTheBugMaker Feb 8, 2022
36e6093
trying to fix ReceivedCharacter not fired on some cases.
KentaTheBugMaker Feb 8, 2022
f14fb5c
trying to fix mobile virtual keyboard KeyboardEvent.code() = "" causi…
KentaTheBugMaker Feb 12, 2022
a040d07
don't use keypress
KentaTheBugMaker Feb 12, 2022
6d99b05
fmt and fix
KentaTheBugMaker Feb 12, 2022
dde1ebf
fix blocking order
KentaTheBugMaker Feb 12, 2022
20d38c9
fix first char after IME::Commit not appear to ReceivedCharacter in b…
KentaTheBugMaker Feb 15, 2022
aa5b966
fmt
KentaTheBugMaker Feb 15, 2022
ef32368
try to remove composing
KentaTheBugMaker Feb 15, 2022
3e83dfe
more egui like handling
KentaTheBugMaker Feb 15, 2022
5db61c1
Add new `IME` event for desktop platforms
kchibisov Apr 6, 2022
068dbd2
merge upstream
KentaTheBugMaker Apr 9, 2022
411497a
fix CHANGELOG.md
KentaTheBugMaker Apr 9, 2022
79e473b
fix CHANGELOG.md and fmt
KentaTheBugMaker Apr 9, 2022
cb57b49
remove untouched change
KentaTheBugMaker Apr 9, 2022
a90407a
Add new `IME` event for desktop platforms
kchibisov Apr 6, 2022
d7db8da
Merge branch 'composition-event' of https://github.com/rust-windowing…
KentaTheBugMaker Apr 15, 2022
4366881
Merge branch 'rw-composition-event' into composition-event
KentaTheBugMaker Apr 15, 2022
1502b77
remove untouched change
KentaTheBugMaker Apr 15, 2022
6b8c242
remove untouched change
KentaTheBugMaker Apr 15, 2022
3c0a180
Add new `IME` event for desktop platforms
kchibisov Apr 6, 2022
839f04a
remove untouched change
KentaTheBugMaker Apr 15, 2022
7d651d5
Merge branch 'composition-event' into composition-event
KentaTheBugMaker Apr 15, 2022
20a07a8
fmt
KentaTheBugMaker Apr 15, 2022
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ And please only add new entries to the top of this list, right below the `# Unre

# Unreleased


- On Web, implement IME support. please not create DOM element with `id='winit_input_agent'`
- On Web, `Window::set_ime_position` now works. you need to use to support IME on web because we don't have good way to get ime enabled.
- On macOS, Windows, and Wayland, add `set_cursor_hittest` to let the window ignore mouse events.
- On Windows, added `WindowExtWindows::set_skip_taskbar` and `WindowBuilderExtWindows::with_skip_taskbar`.
- On Windows, added `EventLoopBuilderExtWindows::with_msg_hook`.
Expand Down Expand Up @@ -38,6 +41,10 @@ And please only add new entries to the top of this list, right below the `# Unre
sent a cancel or frame event.
- On iOS, send `RedrawEventsCleared` even if there are no redraw events, consistent with other platforms.

- **Breaking:** Added new `WindowEvent::IME` supported on desktop platforms.
- Added `Window::set_ime_allowed` supported on desktop platforms.
- **Breaking:** IME input on desktop platforms won't be received unless it's explicitly allowed via `Window::set_ime_allowed` and new `WindowEvent::IME` events are handled.

# 0.26.1 (2022-01-05)

- Fix linking to the `ColorSync` framework on macOS 10.7, and in newer Rust versions.
Expand Down
10 changes: 7 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ features = [
]

[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
wayland-client = { version = "0.29", default_features = false, features = ["use_system_lib"], optional = true }
wayland-protocols = { version = "0.29", features = [ "staging_protocols"], optional = true }
wayland-client = { version = "0.29.4", default_features = false, features = ["use_system_lib"], optional = true }
wayland-protocols = { version = "0.29.4", features = [ "staging_protocols"], optional = true }
sctk = { package = "smithay-client-toolkit", version = "0.15.4", default_features = false, features = ["calloop"], optional = true }
mio = { version = "0.8", features = ["os-ext"], optional = true }
x11-dl = { version = "2.18.5", optional = true }
Expand All @@ -101,8 +101,9 @@ package = "web-sys"
version = "0.3.22"
features = [
'console',
"AddEventListenerOptions",
'AddEventListenerOptions',
'CssStyleDeclaration',
'CompositionEvent',
'BeforeUnloadEvent',
'Document',
'DomRect',
Expand All @@ -111,11 +112,14 @@ features = [
'EventTarget',
'FocusEvent',
'HtmlCanvasElement',
'HtmlInputElement',
'HtmlElement',
'InputEvent',
'KeyboardEvent',
'MediaQueryList',
'MediaQueryListEvent',
'MouseEvent',
'Navigator',
'Node',
'PointerEvent',
'Window',
Expand Down
97 changes: 97 additions & 0 deletions examples/ime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use log::LevelFilter;
use simple_logger::SimpleLogger;
use winit::{
dpi::PhysicalPosition,
event::{ElementState, Event, VirtualKeyCode, WindowEvent, IME},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};

fn main() {
SimpleLogger::new()
.with_level(LevelFilter::Trace)
.init()
.unwrap();

println!("Ime position will system default");
println!("Click to set ime position to cursor's");
println!("Press F2 to toggle IME. See the documentation of `set_ime_allowed` for more info");

let event_loop = EventLoop::new();

let window = WindowBuilder::new()
.with_inner_size(winit::dpi::LogicalSize::new(256f64, 128f64))
.build(&event_loop)
.unwrap();

let mut ime_allowed = true;
window.set_ime_allowed(ime_allowed);

let mut may_show_ime = false;
let mut cursor_position = PhysicalPosition::new(0.0, 0.0);
let mut ime_pos = PhysicalPosition::new(0.0, 0.0);

event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => *control_flow = ControlFlow::Exit,
Event::WindowEvent {
event: WindowEvent::CursorMoved { position, .. },
..
} => {
cursor_position = position;
}
Event::WindowEvent {
event:
WindowEvent::MouseInput {
state: ElementState::Released,
..
},
..
} => {
println!(
"Setting ime position to {}, {}",
cursor_position.x, cursor_position.y
);
ime_pos = cursor_position;
if may_show_ime {
window.set_ime_position(ime_pos);
}
}
Event::WindowEvent {
event: WindowEvent::IME(event),
..
} => {
println!("{:?}", event);
may_show_ime = event != IME::Disabled;
if may_show_ime {
window.set_ime_position(ime_pos);
}
}
Event::WindowEvent {
event: WindowEvent::ReceivedCharacter(ch),
..
} => {
println!("ch: {:?}", ch);
}
Event::WindowEvent {
event: WindowEvent::KeyboardInput { input, .. },
..
} => {
println!("key: {:?}", input);

if input.state == ElementState::Pressed
&& input.virtual_keycode == Some(VirtualKeyCode::F2)
{
ime_allowed = !ime_allowed;
window.set_ime_allowed(ime_allowed);
println!("\nIME: {}\n", ime_allowed);
}
}
_ => (),
}
});
}
53 changes: 0 additions & 53 deletions examples/set_ime_position.rs

This file was deleted.

31 changes: 30 additions & 1 deletion src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,12 @@ pub enum WindowEvent<'a> {
/// issue, and it should get fixed - but it's the current state of the API.
ModifiersChanged(ModifiersState),

/// An event from input method.
///
/// Platform-specific behavior:
/// - **iOS / Android / Web :** Unsupported.
IME(IME),

/// The cursor has moved on the window.
CursorMoved {
device_id: DeviceId,
Expand Down Expand Up @@ -376,7 +382,7 @@ impl Clone for WindowEvent<'static> {
input: *input,
is_synthetic: *is_synthetic,
},

IME(preedit_state) => IME(preedit_state.clone()),
ModifiersChanged(modifiers) => ModifiersChanged(*modifiers),
#[allow(deprecated)]
CursorMoved {
Expand Down Expand Up @@ -468,6 +474,7 @@ impl<'a> WindowEvent<'a> {
is_synthetic,
}),
ModifiersChanged(modifiers) => Some(ModifiersChanged(modifiers)),
IME(event) => Some(IME(event)),
#[allow(deprecated)]
CursorMoved {
device_id,
Expand Down Expand Up @@ -627,6 +634,28 @@ pub struct KeyboardInput {
pub modifiers: ModifiersState,
}

/// Describes an event from input method.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum IME {
/// Notifies when the IME was enabled.
Enabled,

/// Notifies when a new composing text should be set at the cursor position.
///
/// The value represents a pair of the preedit string and the cursor begin position and end
/// position. When both indices are `None`, the cursor should be hidden.
///
/// The cursor position is byte-wise indexed.
Preedit(String, Option<usize>, Option<usize>),

/// Notifies when text should be inserted into the editor widget.
Commit(String),

/// Notifies when the IME was disabled.
Disabled,
}

/// Describes touch-screen input state.
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
Expand Down
2 changes: 2 additions & 0 deletions src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,8 @@ impl Window {

pub fn set_ime_position(&self, _position: Position) {}

pub fn set_ime_allowed(&self, _allowed: bool) {}

pub fn focus_window(&self) {}

pub fn request_user_attention(&self, _request_type: Option<window::UserAttentionType>) {}
Expand Down
4 changes: 4 additions & 0 deletions src/platform_impl/ios/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,10 @@ impl Inner {
warn!("`Window::set_ime_position` is ignored on iOS")
}

pub fn set_ime_allowed(&self, _allowed: bool) {
warn!("`Window::set_ime_allowed` is ignored on iOS")
}

pub fn focus_window(&self) {
warn!("`Window::set_focus` is ignored on iOS")
}
Expand Down
5 changes: 5 additions & 0 deletions src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,11 @@ impl Window {
x11_or_wayland!(match self; Window(w) => w.set_ime_position(position))
}

#[inline]
pub fn set_ime_allowed(&self, allowed: bool) {
x11_or_wayland!(match self; Window(w) => w.set_ime_allowed(allowed))
}

#[inline]
pub fn focus_window(&self) {
match self {
Expand Down
3 changes: 1 addition & 2 deletions src/platform_impl/linux/wayland/event_loop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,9 @@ mod sink;
mod state;

pub use proxy::EventLoopProxy;
pub use sink::EventSink;
pub use state::WinitState;

use sink::EventSink;

type WinitDispatcher = calloop::Dispatcher<'static, WaylandSource, WinitState>;

pub struct EventLoopWindowTarget<T> {
Expand Down
45 changes: 35 additions & 10 deletions src/platform_impl/linux/wayland/seat/text_input/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use sctk::reexports::protocols::unstable::text_input::v3::client::zwp_text_input
Event as TextInputEvent, ZwpTextInputV3,
};

use crate::event::WindowEvent;
use crate::event::{WindowEvent, IME};
use crate::platform_impl::wayland;
use crate::platform_impl::wayland::event_loop::WinitState;

use super::{TextInputHandler, TextInputInner};
use super::{Preedit, TextInputHandler, TextInputInner};

#[inline]
pub(super) fn handle_text_input(
Expand All @@ -30,8 +30,11 @@ pub(super) fn handle_text_input(
inner.target_window_id = Some(window_id);

// Enable text input on that surface.
text_input.enable();
text_input.commit();
if window_handle.ime_allowed.get() {
text_input.enable();
text_input.commit();
event_sink.push_window_event(WindowEvent::IME(IME::Enabled), window_id);
}

// Notify a window we're currently over about text input handler.
let text_input_handler = TextInputHandler {
Expand All @@ -58,19 +61,41 @@ pub(super) fn handle_text_input(
text_input: text_input.detach(),
};
window_handle.text_input_left(text_input_handler);
event_sink.push_window_event(WindowEvent::IME(IME::Disabled), window_id);
}
TextInputEvent::PreeditString {
text,
cursor_begin,
cursor_end,
} => {
let cursor_begin = usize::try_from(cursor_begin).ok();
let cursor_end = usize::try_from(cursor_end).ok();
let text = text.unwrap_or_default();
inner.pending_preedit = Some(Preedit {
text,
cursor_begin,
cursor_end,
});
}
TextInputEvent::CommitString { text } => {
// Update currenly commited string.
inner.commit_string = text;
// Update currenly commited string and reset previous preedit.
inner.pending_preedit = None;
inner.pending_commit = Some(text.unwrap_or_default());
}
TextInputEvent::Done { .. } => {
let (window_id, text) = match (inner.target_window_id, inner.commit_string.take()) {
(Some(window_id), Some(text)) => (window_id, text),
let window_id = match inner.target_window_id {
Some(window_id) => window_id,
_ => return,
};

for ch in text.chars() {
event_sink.push_window_event(WindowEvent::ReceivedCharacter(ch), window_id);
if let Some(text) = inner.pending_commit.take() {
event_sink.push_window_event(WindowEvent::IME(IME::Commit(text)), window_id);
}

// Push preedit string we've got after latest commit.
if let Some(preedit) = inner.pending_preedit.take() {
let event = IME::Preedit(preedit.text, preedit.cursor_begin, preedit.cursor_end);
event_sink.push_window_event(WindowEvent::IME(event), window_id);
}
}
_ => (),
Expand Down
Loading