zed_xim/
client.rs

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            // Require for uim
77            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            // Nothing to do
216            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            // Handle the request.
258            handler.handle_preedit_caret(
259                client,
260                input_method_id,
261                input_context_id,
262                &mut position,
263                direction,
264                style,
265            )?;
266
267            // Send the reply.
268            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}