xim 0.5.0

XIM protocol parser, handler
Documentation
use std::convert::TryInto;

use xim::{AHashMap, Client, ClientCore, ClientError, ClientHandler};
use xim_parser::{AttributeName, InputStyle, Point};

#[derive(Default)]
pub struct ExampleHandler {
    pub im_id: u16,
    pub ic_id: u16,
    pub connected: bool,
    pub window: u32,
}

impl<T, C: Client<XEvent = T> + ClientCore<XEvent = T>> ClientHandler<C> for ExampleHandler {
    fn handle_connect(&mut self, client: &mut C) -> Result<(), ClientError> {
        log::trace!("Connected");
        client.open("en_US")
    }

    fn handle_open(&mut self, client: &mut C, input_method_id: u16) -> Result<(), ClientError> {
        log::trace!("Opened");
        self.im_id = input_method_id;

        client.get_im_values(input_method_id, &[AttributeName::QueryInputStyle])
    }

    fn handle_get_im_values(
        &mut self,
        client: &mut C,
        input_method_id: u16,
        _attributes: AHashMap<AttributeName, Vec<u8>>,
    ) -> Result<(), ClientError> {
        let ic_attributes = client
            .build_ic_attributes()
            .push(
                AttributeName::InputStyle,
                InputStyle::PREEDIT_CALLBACKS | InputStyle::STATUS_NOTHING,
            )
            .push(AttributeName::ClientWindow, self.window)
            .push(AttributeName::FocusWindow, self.window)
            .nested_list(AttributeName::PreeditAttributes, |b| {
                b.push(AttributeName::SpotLocation, Point { x: 0, y: 0 });
            })
            .build();
        client.create_ic(input_method_id, ic_attributes)
    }

    fn handle_create_ic(
        &mut self,
        _client: &mut C,
        input_method_id: u16,
        input_context_id: u16,
    ) -> Result<(), ClientError> {
        self.connected = true;
        self.ic_id = input_context_id;
        log::info!("IC created {}, {}", input_method_id, input_context_id);
        Ok(())
    }

    fn handle_forward_event(
        &mut self,
        client: &mut C,
        _input_method_id: u16,
        _input_context_id: u16,
        flag: xim::ForwardEventFlag,
        xev: T,
    ) -> Result<(), ClientError> {
        let xev = client.serialize_event(&xev);
        log::info!("Handle forward event {:?}, {}", flag, xev.detail);

        Ok(())
    }

    fn handle_commit(
        &mut self,
        _client: &mut C,
        _input_method_id: u16,
        _input_context_id: u16,
        text: &str,
    ) -> Result<(), ClientError> {
        log::info!("Commited {}", text);
        Ok(())
    }

    fn handle_disconnect(&mut self) {
        log::info!("disconnected");
    }

    fn handle_close(&mut self, client: &mut C, _input_method_id: u16) -> Result<(), ClientError> {
        log::info!("closed");
        client.disconnect()
    }

    fn handle_destroy_ic(
        &mut self,
        client: &mut C,
        input_method_id: u16,
        _input_context_id: u16,
    ) -> Result<(), ClientError> {
        client.close(input_method_id)
    }

    fn handle_set_event_mask(
        &mut self,
        _client: &mut C,
        input_method_id: u16,
        input_context_id: u16,
        forward_event_mask: u32,
        synchronous_event_mask: u32,
    ) -> Result<(), ClientError> {
        log::info!(
            "Set event mask {}, {}, {}, {}",
            input_method_id,
            input_context_id,
            forward_event_mask,
            synchronous_event_mask
        );
        Ok(())
    }

    fn handle_preedit_start(
        &mut self,
        _client: &mut C,
        input_method_id: u16,
        input_context_id: u16,
    ) -> Result<(), ClientError> {
        log::info!("Preedit start {}, {}", input_method_id, input_context_id);
        Ok(())
    }

    fn handle_preedit_done(
        &mut self,
        _client: &mut C,
        input_method_id: u16,
        input_context_id: u16,
    ) -> Result<(), ClientError> {
        log::info!("Preedit done {}, {}", input_method_id, input_context_id);
        Ok(())
    }

    fn handle_preedit_draw(
        &mut self,
        _client: &mut C,
        _input_method_id: u16,
        _input_context_id: u16,
        caret: i32,
        _chg_first: i32,
        _chg_len: i32,
        _status: xim::PreeditDrawStatus,
        preedit_string: &str,
        feedbacks: Vec<xim::Feedback>,
    ) -> Result<(), ClientError> {
        let mut caret_string = String::new();

        let mut chars = preedit_string.chars();

        caret_string.extend(chars.by_ref().take(caret.try_into().unwrap_or_default()));
        caret_string.push('|');
        caret_string.extend(chars);

        log::info!("Preedit {}({:?})", caret_string, feedbacks);

        Ok(())
    }
}