1mod attribute_builder;
2
3pub use self::attribute_builder::AttributeBuilder;
4use crate::AHashMap;
5use xim_parser::{
6 Attr, Attribute, AttributeName, CaretDirection, CaretStyle, CommitData, Extension, Feedback,
7 ForwardEventFlag, PreeditDrawStatus, Request,
8};
9
10use alloc::string::String;
11use alloc::vec;
12use alloc::vec::Vec;
13use core::fmt;
14
15#[derive(Debug)]
16#[non_exhaustive]
17pub enum ClientError {
18 ReadProtocol(xim_parser::ReadError),
19 XimError(xim_parser::ErrorCode, String),
20 UnsupportedTransport,
21 InvalidReply,
22 NoXimServer,
23 #[cfg(feature = "std")]
24 Other(alloc::boxed::Box<dyn std::error::Error + Send + Sync>),
25}
26
27impl From<xim_parser::ReadError> for ClientError {
28 fn from(e: xim_parser::ReadError) -> Self {
29 Self::ReadProtocol(e)
30 }
31}
32
33impl fmt::Display for ClientError {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 match self {
36 ClientError::ReadProtocol(e) => write!(f, "Can't read xim message: {}", e),
37 ClientError::XimError(code, detail) => {
38 write!(f, "Server send error code: {:?}, detail: {}", code, detail)
39 }
40 ClientError::UnsupportedTransport => write!(f, "Server Transport is not supported"),
41 ClientError::InvalidReply => write!(f, "Invalid reply from server"),
42 ClientError::NoXimServer => write!(f, "Can't connect xim server"),
43 #[cfg(feature = "std")]
44 ClientError::Other(e) => write!(f, "Other error: {}", e),
45 }
46 }
47}
48
49#[cfg(feature = "std")]
50impl std::error::Error for ClientError {}
51
52pub fn handle_request<C: ClientCore>(
53 client: &mut C,
54 handler: &mut impl ClientHandler<C>,
55 req: Request,
56) -> Result<(), ClientError> {
57 if log::log_enabled!(log::Level::Trace) {
58 log::trace!("<-: {:?}", req);
59 } else {
60 log::debug!("<-: {}", req.name());
61 }
62
63 match req {
64 Request::ConnectReply {
65 server_major_protocol_version: _,
66 server_minor_protocol_version: _,
67 } => handler.handle_connect(client),
68 Request::OpenReply {
69 input_method_id,
70 im_attrs,
71 ic_attrs,
72 } => {
73 log::debug!("im_attrs: {:#?}", im_attrs);
74 log::debug!("ic_attrs: {:#?}", ic_attrs);
75 client.set_attrs(im_attrs, ic_attrs);
76 client.send_req(Request::EncodingNegotiation {
78 encodings: vec!["COMPOUND_TEXT".into()],
79 encoding_infos: vec![],
80 input_method_id,
81 })
82 }
83 Request::EncodingNegotiationReply {
84 input_method_id,
85 index: _,
86 category: _,
87 } => handler.handle_open(client, input_method_id),
88 Request::QueryExtensionReply {
89 input_method_id: _,
90 extensions,
91 } => handler.handle_query_extension(client, &extensions),
92 Request::GetImValuesReply {
93 input_method_id,
94 im_attributes,
95 } => handler.handle_get_im_values(
96 client,
97 input_method_id,
98 im_attributes
99 .into_iter()
100 .filter_map(|attr| {
101 client
102 .im_attributes()
103 .iter()
104 .find(|(_, v)| **v == attr.id)
105 .map(|(n, _)| (*n, attr.value))
106 })
107 .collect(),
108 ),
109 Request::SetIcValuesReply {
110 input_method_id,
111 input_context_id,
112 } => handler.handle_set_ic_values(client, input_method_id, input_context_id),
113 Request::CreateIcReply {
114 input_method_id,
115 input_context_id,
116 } => handler.handle_create_ic(client, input_method_id, input_context_id),
117 Request::DestroyIcReply {
118 input_method_id,
119 input_context_id,
120 } => handler.handle_destroy_ic(client, input_method_id, input_context_id),
121 Request::SetEventMask {
122 input_method_id,
123 input_context_id,
124 forward_event_mask,
125 synchronous_event_mask,
126 } => handler.handle_set_event_mask(
127 client,
128 input_method_id,
129 input_context_id,
130 forward_event_mask,
131 synchronous_event_mask,
132 ),
133 Request::CloseReply { input_method_id } => handler.handle_close(client, input_method_id),
134 Request::DisconnectReply {} => {
135 handler.handle_disconnect();
136 Ok(())
137 }
138 Request::ResetIcReply {
139 input_method_id,
140 input_context_id,
141 preedit_string,
142 } => {
143 let preedit_string =
144 xim_ctext::compound_text_to_utf8(&preedit_string).expect("Encoding error");
145 handler.handle_reset_ic(client, input_method_id, input_context_id, &preedit_string);
146 Ok(())
147 }
148 Request::Error { code, detail, .. } => Err(ClientError::XimError(code, detail)),
149 Request::ForwardEvent {
150 xev,
151 input_method_id,
152 input_context_id,
153 flag,
154 ..
155 } => {
156 handler.handle_forward_event(
157 client,
158 input_method_id,
159 input_context_id,
160 flag,
161 client.deserialize_event(&xev),
162 )?;
163
164 if flag.contains(ForwardEventFlag::SYNCHRONOUS) {
165 client.send_req(Request::SyncReply {
166 input_method_id,
167 input_context_id,
168 })?;
169 }
170
171 Ok(())
172 }
173 Request::Commit {
174 input_method_id,
175 input_context_id,
176 data,
177 } => match data {
178 CommitData::Keysym { keysym: _, .. } => {
179 log::warn!("Keysym commit is not supported");
180 Ok(())
181 }
182 CommitData::Chars {
183 commited,
184 syncronous,
185 } => {
186 handler.handle_commit(
187 client,
188 input_method_id,
189 input_context_id,
190 &xim_ctext::compound_text_to_utf8(&commited).expect("Encoding Error"),
191 )?;
192
193 if syncronous {
194 client.send_req(Request::SyncReply {
195 input_method_id,
196 input_context_id,
197 })?;
198 }
199
200 Ok(())
201 }
202 CommitData::Both { .. } => {
203 log::warn!("Both commit data is not supported");
204 Ok(())
205 }
206 },
207 Request::Sync {
208 input_method_id,
209 input_context_id,
210 } => client.send_req(Request::SyncReply {
211 input_method_id,
212 input_context_id,
213 }),
214 Request::SyncReply { .. } => {
215 Ok(())
217 }
218 Request::PreeditStart {
219 input_method_id,
220 input_context_id,
221 } => handler.handle_preedit_start(client, input_method_id, input_context_id),
222 Request::PreeditDone {
223 input_method_id,
224 input_context_id,
225 } => handler.handle_preedit_done(client, input_method_id, input_context_id),
226 Request::PreeditDraw {
227 input_method_id,
228 input_context_id,
229 caret,
230 chg_first,
231 chg_length,
232 preedit_string,
233 status,
234 feedbacks,
235 } => {
236 let preedit_string =
237 xim_ctext::compound_text_to_utf8(&preedit_string).expect("Encoding Error");
238 handler.handle_preedit_draw(
239 client,
240 input_method_id,
241 input_context_id,
242 caret,
243 chg_first,
244 chg_length,
245 status,
246 &preedit_string,
247 feedbacks,
248 )
249 }
250 Request::PreeditCaret {
251 input_method_id,
252 input_context_id,
253 mut position,
254 direction,
255 style,
256 } => {
257 handler.handle_preedit_caret(
259 client,
260 input_method_id,
261 input_context_id,
262 &mut position,
263 direction,
264 style,
265 )?;
266
267 client.send_req(Request::PreeditCaretReply {
269 input_method_id,
270 input_context_id,
271 position,
272 })
273 }
274 _ => {
275 log::warn!("Unknown request {:?}", req);
276 Ok(())
277 }
278 }
279}
280
281pub trait ClientCore {
282 type XEvent;
283
284 fn set_attrs(&mut self, ic_attrs: Vec<Attr>, im_attrs: Vec<Attr>);
285 fn ic_attributes(&self) -> &AHashMap<AttributeName, u16>;
286 fn im_attributes(&self) -> &AHashMap<AttributeName, u16>;
287 fn serialize_event(&self, xev: &Self::XEvent) -> xim_parser::XEvent;
288 fn deserialize_event(&self, xev: &xim_parser::XEvent) -> Self::XEvent;
289 fn send_req(&mut self, req: Request) -> Result<(), ClientError>;
290}
291
292pub trait Client {
293 type XEvent;
294
295 fn build_ic_attributes(&self) -> AttributeBuilder;
296 fn build_im_attributes(&self) -> AttributeBuilder;
297
298 fn disconnect(&mut self) -> Result<(), ClientError>;
299 fn open(&mut self, locale: &str) -> Result<(), ClientError>;
300 fn close(&mut self, input_method_id: u16) -> Result<(), ClientError>;
301 fn quert_extension(
302 &mut self,
303 input_method_id: u16,
304 extensions: &[&str],
305 ) -> Result<(), ClientError>;
306 fn get_im_values(
307 &mut self,
308 input_method_id: u16,
309 names: &[AttributeName],
310 ) -> Result<(), ClientError>;
311 fn set_ic_values(
312 &mut self,
313 input_method_id: u16,
314 input_context_id: u16,
315 ic_attributes: Vec<Attribute>,
316 ) -> Result<(), ClientError>;
317 fn create_ic(
318 &mut self,
319 input_method_id: u16,
320 ic_attributes: Vec<Attribute>,
321 ) -> Result<(), ClientError>;
322 fn destroy_ic(
323 &mut self,
324 input_method_id: u16,
325 input_context_id: u16,
326 ) -> Result<(), ClientError>;
327 fn forward_event(
328 &mut self,
329 input_method_id: u16,
330 input_context_id: u16,
331 flag: ForwardEventFlag,
332 xev: &Self::XEvent,
333 ) -> Result<(), ClientError>;
334 fn set_focus(&mut self, input_method_id: u16, input_context_id: u16)
335 -> Result<(), ClientError>;
336 fn unset_focus(
337 &mut self,
338 input_method_id: u16,
339 input_context_id: u16,
340 ) -> Result<(), ClientError>;
341 fn reset_ic(&mut self, input_method_id: u16, input_context_id: u16) -> Result<(), ClientError>;
342}
343
344impl<C> Client for C
345where
346 C: ClientCore,
347{
348 type XEvent = C::XEvent;
349
350 fn build_ic_attributes(&self) -> AttributeBuilder {
351 AttributeBuilder::new(self.ic_attributes())
352 }
353
354 fn build_im_attributes(&self) -> AttributeBuilder {
355 AttributeBuilder::new(self.im_attributes())
356 }
357
358 fn open(&mut self, locale: &str) -> Result<(), ClientError> {
359 self.send_req(Request::Open {
360 locale: locale.into(),
361 })
362 }
363
364 fn quert_extension(
365 &mut self,
366 input_method_id: u16,
367 extensions: &[&str],
368 ) -> Result<(), ClientError> {
369 self.send_req(Request::QueryExtension {
370 input_method_id,
371 extensions: extensions.iter().map(|&e| e.into()).collect(),
372 })
373 }
374
375 fn get_im_values(
376 &mut self,
377 input_method_id: u16,
378 names: &[AttributeName],
379 ) -> Result<(), ClientError> {
380 self.send_req(Request::GetImValues {
381 input_method_id,
382 im_attributes: names
383 .iter()
384 .filter_map(|name| self.im_attributes().get(name).copied())
385 .collect(),
386 })
387 }
388
389 fn set_ic_values(
390 &mut self,
391 input_method_id: u16,
392 input_context_id: u16,
393 ic_attributes: Vec<Attribute>,
394 ) -> Result<(), ClientError> {
395 self.send_req(Request::SetIcValues {
396 input_method_id,
397 input_context_id,
398 ic_attributes,
399 })
400 }
401
402 fn create_ic(
403 &mut self,
404 input_method_id: u16,
405 ic_attributes: Vec<Attribute>,
406 ) -> Result<(), ClientError> {
407 self.send_req(Request::CreateIc {
408 input_method_id,
409 ic_attributes,
410 })
411 }
412
413 fn forward_event(
414 &mut self,
415 input_method_id: u16,
416 input_context_id: u16,
417 flag: ForwardEventFlag,
418 xev: &Self::XEvent,
419 ) -> Result<(), ClientError> {
420 let ev = self.serialize_event(xev);
421 self.send_req(Request::ForwardEvent {
422 input_method_id,
423 input_context_id,
424 flag,
425 serial_number: ev.sequence,
426 xev: ev,
427 })
428 }
429
430 fn disconnect(&mut self) -> Result<(), ClientError> {
431 self.send_req(Request::Disconnect {})
432 }
433
434 fn close(&mut self, input_method_id: u16) -> Result<(), ClientError> {
435 self.send_req(Request::Close { input_method_id })
436 }
437
438 fn destroy_ic(
439 &mut self,
440 input_method_id: u16,
441 input_context_id: u16,
442 ) -> Result<(), ClientError> {
443 self.send_req(Request::DestroyIc {
444 input_method_id,
445 input_context_id,
446 })
447 }
448
449 fn set_focus(
450 &mut self,
451 input_method_id: u16,
452 input_context_id: u16,
453 ) -> Result<(), ClientError> {
454 self.send_req(Request::SetIcFocus {
455 input_method_id,
456 input_context_id,
457 })
458 }
459 fn unset_focus(
460 &mut self,
461 input_method_id: u16,
462 input_context_id: u16,
463 ) -> Result<(), ClientError> {
464 self.send_req(Request::UnsetIcFocus {
465 input_method_id,
466 input_context_id,
467 })
468 }
469 fn reset_ic(&mut self, input_method_id: u16, input_context_id: u16) -> Result<(), ClientError> {
470 self.send_req(Request::ResetIc {
471 input_method_id,
472 input_context_id,
473 })
474 }
475}
476
477#[allow(unused_variables)]
478pub trait ClientHandler<C: Client> {
479 fn handle_connect(&mut self, client: &mut C) -> Result<(), ClientError> {
480 Ok(())
481 }
482 fn handle_disconnect(&mut self) {}
483 fn handle_open(&mut self, client: &mut C, input_method_id: u16) -> Result<(), ClientError> {
484 Ok(())
485 }
486 fn handle_close(&mut self, client: &mut C, input_method_id: u16) -> Result<(), ClientError> {
487 Ok(())
488 }
489 fn handle_query_extension(
490 &mut self,
491 client: &mut C,
492 extensions: &[Extension],
493 ) -> Result<(), ClientError> {
494 Ok(())
495 }
496 fn handle_get_im_values(
497 &mut self,
498 client: &mut C,
499 input_method_id: u16,
500 attributes: AHashMap<AttributeName, Vec<u8>>,
501 ) -> Result<(), ClientError> {
502 Ok(())
503 }
504 fn handle_set_ic_values(
505 &mut self,
506 client: &mut C,
507 input_method_id: u16,
508 input_context_id: u16,
509 ) -> Result<(), ClientError> {
510 Ok(())
511 }
512 fn handle_create_ic(
513 &mut self,
514 client: &mut C,
515 input_method_id: u16,
516 input_context_id: u16,
517 ) -> Result<(), ClientError> {
518 Ok(())
519 }
520 fn handle_destroy_ic(
521 &mut self,
522 client: &mut C,
523 input_method_id: u16,
524 input_context_id: u16,
525 ) -> Result<(), ClientError> {
526 Ok(())
527 }
528 fn handle_commit(
529 &mut self,
530 client: &mut C,
531 input_method_id: u16,
532 input_context_id: u16,
533 text: &str,
534 ) -> Result<(), ClientError> {
535 Ok(())
536 }
537 fn handle_forward_event(
538 &mut self,
539 client: &mut C,
540 input_method_id: u16,
541 input_context_id: u16,
542 flag: ForwardEventFlag,
543 xev: C::XEvent,
544 ) -> Result<(), ClientError> {
545 Ok(())
546 }
547 fn handle_set_event_mask(
548 &mut self,
549 client: &mut C,
550 input_method_id: u16,
551 input_context_id: u16,
552 forward_event_mask: u32,
553 synchronous_event_mask: u32,
554 ) -> Result<(), ClientError> {
555 Ok(())
556 }
557 fn handle_preedit_start(
558 &mut self,
559 client: &mut C,
560 input_method_id: u16,
561 input_context_id: u16,
562 ) -> Result<(), ClientError> {
563 Ok(())
564 }
565 fn handle_preedit_draw(
566 &mut self,
567 client: &mut C,
568 input_method_id: u16,
569 input_context_id: u16,
570 caret: i32,
571 chg_first: i32,
572 chg_len: i32,
573 status: PreeditDrawStatus,
574 preedit_string: &str,
575 feedbacks: Vec<Feedback>,
576 ) -> Result<(), ClientError> {
577 Ok(())
578 }
579 fn handle_preedit_caret(
580 &mut self,
581 client: &mut C,
582 input_method_id: u16,
583 input_context_id: u16,
584 position: &mut i32,
585 direction: CaretDirection,
586 style: CaretStyle,
587 ) -> Result<(), ClientError> {
588 Ok(())
589 }
590 fn handle_preedit_done(
591 &mut self,
592 client: &mut C,
593 input_method_id: u16,
594 input_context_id: u16,
595 ) -> Result<(), ClientError> {
596 Ok(())
597 }
598 fn handle_reset_ic(
599 &mut self,
600 client: &mut C,
601 input_method_id: u16,
602 input_context_id: u16,
603 preedit_text: &str,
604 ) -> Result<(), ClientError> {
605 Ok(())
606 }
607}