1use anyhow::{format_err, Result};
6use async_trait::async_trait;
7use futures::stream::{self, StreamExt, TryStreamExt};
8use futures::FutureExt;
9use {
10 fidl_fuchsia_input as input, fidl_fuchsia_ui_input as ui_input,
11 fidl_fuchsia_ui_input3 as ui_input3,
12};
13
14pub fn default_state() -> ui_input::TextInputState {
15 ui_input::TextInputState {
16 revision: 1,
17 text: "".to_string(),
18 selection: ui_input::TextSelection {
19 base: 0,
20 extent: 0,
21 affinity: ui_input::TextAffinity::Upstream,
22 },
23 composing: ui_input::TextRange { start: -1, end: -1 },
24 }
25}
26
27pub fn measure_utf16(s: &str) -> usize {
29 s.chars().map(|c| c.len_utf16()).sum::<usize>()
30}
31
32pub async fn setup_ime(
34 ime: &ui_input::InputMethodEditorProxy,
35 text: &str,
36 base: i64,
37 extent: i64,
38) -> Result<()> {
39 let mut state = default_state();
40 state.text = text.to_string();
41 state.selection.base = base;
42 state.selection.extent = extent;
43
44 ime.set_state(&state).map_err(Into::into)
45}
46
47pub fn bind_editor(
49 ime_service: &ui_input::ImeServiceProxy,
50) -> Result<(ui_input::InputMethodEditorProxy, ui_input::InputMethodEditorClientRequestStream)> {
51 let (ime, ime_server_end) =
52 fidl::endpoints::create_proxy::<ui_input::InputMethodEditorMarker>();
53 let (editor_client_end, editor_request_stream) = fidl::endpoints::create_request_stream();
54 ime_service.get_input_method_editor(
55 ui_input::KeyboardType::Text,
56 ui_input::InputMethodAction::Done,
57 &default_state(),
58 editor_client_end,
59 ime_server_end,
60 )?;
61
62 Ok((ime, editor_request_stream))
63}
64
65#[async_trait]
68pub trait KeyDispatcher {
69 async fn dispatch(&self, event: ui_input3::KeyEvent) -> Result<bool>;
70}
71
72pub struct InputMethodEditorDispatcher<'a> {
74 pub ime: &'a ui_input::InputMethodEditorProxy,
75}
76
77#[async_trait]
78impl<'a> KeyDispatcher for InputMethodEditorDispatcher<'a> {
79 async fn dispatch(&self, event: ui_input3::KeyEvent) -> Result<bool> {
80 Ok(self.ime.dispatch_key3(&event).await?)
81 }
82}
83
84pub struct KeyEventInjectorDispatcher<'a> {
86 pub key_event_injector: &'a ui_input3::KeyEventInjectorProxy,
87}
88
89#[async_trait]
90impl<'a> KeyDispatcher for KeyEventInjectorDispatcher<'a> {
91 async fn dispatch(&self, event: ui_input3::KeyEvent) -> Result<bool> {
92 Ok(self.key_event_injector.inject(&event).await? == ui_input3::KeyEventStatus::Handled)
93 }
94}
95
96pub struct KeySimulator<'a> {
110 dispatcher: &'a dyn KeyDispatcher,
111}
112
113impl<'a> KeySimulator<'a> {
114 pub fn new(dispatcher: &'a dyn KeyDispatcher) -> Self {
115 KeySimulator { dispatcher }
116 }
117
118 pub async fn dispatch(&self, event: ui_input3::KeyEvent) -> Result<bool> {
119 self.dispatcher.dispatch(event).await
120 }
121
122 async fn simulate_keypress(&self, key: input::Key) -> Result<()> {
124 self.dispatch(ui_input3::KeyEvent {
125 timestamp: Some(0),
126 type_: Some(ui_input3::KeyEventType::Pressed),
127 key: Some(key),
128 ..Default::default()
129 })
130 .await?;
131 self.dispatch(ui_input3::KeyEvent {
132 timestamp: Some(0),
133 type_: Some(ui_input3::KeyEventType::Released),
134 key: Some(key),
135 ..Default::default()
136 })
137 .await?;
138 Ok(())
139 }
140
141 async fn simulate_ime_keypress_with_held_keys(
143 &self,
144 key: input::Key,
145 held_keys: Vec<input::Key>,
146 ) {
147 let held_keys_down =
148 held_keys.iter().map(|k| (ui_input3::KeyEventType::Pressed, *k)).into_iter();
149 let held_keys_up =
150 held_keys.iter().map(|k| (ui_input3::KeyEventType::Released, *k)).into_iter();
151 let key_press_and_release =
152 vec![(ui_input3::KeyEventType::Pressed, key), (ui_input3::KeyEventType::Released, key)]
153 .into_iter();
154 let sequence = held_keys_down.chain(key_press_and_release).chain(held_keys_up);
155 stream::iter(sequence)
156 .for_each(|(type_, key)| {
157 self.dispatch(ui_input3::KeyEvent {
158 timestamp: Some(0),
159 type_: Some(type_),
160 key: Some(key),
161 ..Default::default()
162 })
163 .map(|_| ())
164 })
165 .await;
166 }
167}
168
169pub async fn simulate_keypress(
171 key_event_injector: &ui_input3::KeyEventInjectorProxy,
172 key: input::Key,
173) -> Result<()> {
174 let key_dispatcher = KeyEventInjectorDispatcher { key_event_injector: &key_event_injector };
175 let key_simulator = KeySimulator::new(&key_dispatcher);
176 key_simulator.simulate_keypress(key).await
177}
178
179pub async fn simulate_ime_keypress(ime: &ui_input::InputMethodEditorProxy, key: input::Key) {
181 simulate_ime_keypress_with_held_keys(ime, key, Vec::new()).await
182}
183
184pub async fn simulate_ime_keypress_with_held_keys(
186 ime: &ui_input::InputMethodEditorProxy,
187 key: input::Key,
188 held_keys: Vec<input::Key>,
189) {
190 let key_dispatcher = InputMethodEditorDispatcher { ime: &ime };
191 let key_simulator = KeySimulator::new(&key_dispatcher);
192 key_simulator.simulate_ime_keypress_with_held_keys(key, held_keys).await
193}
194
195pub async fn get_state_update(
197 editor_stream: &mut ui_input::InputMethodEditorClientRequestStream,
198) -> Result<(ui_input::TextInputState, Option<ui_input::KeyboardEvent>)> {
199 editor_stream
200 .map(|request| match request {
201 Ok(ui_input::InputMethodEditorClientRequest::DidUpdateState {
202 state, event, ..
203 }) => {
204 let keyboard_event = event.map(|e| {
205 if let ui_input::InputEvent::Keyboard(keyboard_event) = *e {
206 keyboard_event
207 } else {
208 panic!("expected DidUpdateState to only send Keyboard events");
209 }
210 });
211 Ok((state, keyboard_event))
212 }
213 Ok(msg) => Err(format_err!("request should be DidUpdateState, got {:?}", msg)),
214 Err(err) => Err(Into::into(err)),
215 })
216 .try_next()
217 .await
218 .map(|maybe_msg| maybe_msg.ok_or(format_err!("ime should have sent message")))?
219}
220
221pub async fn get_action(
223 editor_stream: &mut ui_input::InputMethodEditorClientRequestStream,
224) -> Result<ui_input::InputMethodAction> {
225 editor_stream
226 .map(|request| match request {
227 Ok(ui_input::InputMethodEditorClientRequest::OnAction { action, .. }) => Ok(action),
228 Ok(msg) => Err(format_err!("request should be OnAction, got {:?}", msg)),
229 Err(err) => Err(Into::into(err)),
230 })
231 .try_next()
232 .await
233 .map(|maybe_msg| maybe_msg.ok_or(format_err!("ime should have sent message")))?
234}
235
236pub struct KeyMeaningWrapper(Option<ui_input3::KeyMeaning>);
238
239impl From<ui_input3::KeyMeaning> for KeyMeaningWrapper {
240 fn from(src: ui_input3::KeyMeaning) -> Self {
241 KeyMeaningWrapper(src.into())
242 }
243}
244
245impl From<Option<ui_input3::KeyMeaning>> for KeyMeaningWrapper {
246 fn from(src: Option<ui_input3::KeyMeaning>) -> Self {
247 KeyMeaningWrapper(src)
248 }
249}
250
251impl From<KeyMeaningWrapper> for Option<ui_input3::KeyMeaning> {
252 fn from(src: KeyMeaningWrapper) -> Self {
253 src.0
254 }
255}
256
257impl From<char> for KeyMeaningWrapper {
258 fn from(src: char) -> Self {
259 Some(ui_input3::KeyMeaning::Codepoint(src as u32)).into()
260 }
261}
262
263impl From<ui_input3::NonPrintableKey> for KeyMeaningWrapper {
264 fn from(src: ui_input3::NonPrintableKey) -> Self {
265 Some(ui_input3::KeyMeaning::NonPrintableKey(src)).into()
266 }
267}
268
269pub fn create_key_event(
271 timestamp: zx::MonotonicInstant,
272 event_type: ui_input3::KeyEventType,
273 key: impl Into<Option<input::Key>>,
274 modifiers: impl Into<Option<ui_input3::Modifiers>>,
275 key_meaning: impl Into<KeyMeaningWrapper>,
276) -> ui_input3::KeyEvent {
277 let key_meaning: KeyMeaningWrapper = key_meaning.into();
278 ui_input3::KeyEvent {
279 timestamp: Some(timestamp.into_nanos()),
280 type_: Some(event_type),
281 key: key.into(),
282 modifiers: modifiers.into(),
283 key_meaning: key_meaning.into(),
284 ..Default::default()
285 }
286}