xim_handler.rs

  1use std::default::Default;
  2
  3use x11rb::protocol::{xproto, Event};
  4use xim::{AHashMap, AttributeName, Client, ClientError, ClientHandler, InputStyle};
  5
  6pub enum XimCallbackEvent {
  7    XimXEvent(x11rb::protocol::Event),
  8    XimPreeditEvent(xproto::Window, String),
  9    XimCommitEvent(xproto::Window, String),
 10}
 11
 12pub struct XimHandler {
 13    pub im_id: u16,
 14    pub ic_id: u16,
 15    pub connected: bool,
 16    pub window: xproto::Window,
 17    pub last_callback_event: Option<XimCallbackEvent>,
 18}
 19
 20impl XimHandler {
 21    pub fn new() -> Self {
 22        Self {
 23            im_id: Default::default(),
 24            ic_id: Default::default(),
 25            connected: false,
 26            window: Default::default(),
 27            last_callback_event: None,
 28        }
 29    }
 30}
 31
 32impl<C: Client<XEvent = xproto::KeyPressEvent>> ClientHandler<C> for XimHandler {
 33    fn handle_connect(&mut self, client: &mut C) -> Result<(), ClientError> {
 34        client.open("C")
 35    }
 36
 37    fn handle_open(&mut self, client: &mut C, input_method_id: u16) -> Result<(), ClientError> {
 38        self.im_id = input_method_id;
 39
 40        client.get_im_values(input_method_id, &[AttributeName::QueryInputStyle])
 41    }
 42
 43    fn handle_get_im_values(
 44        &mut self,
 45        client: &mut C,
 46        input_method_id: u16,
 47        _attributes: AHashMap<AttributeName, Vec<u8>>,
 48    ) -> Result<(), ClientError> {
 49        let ic_attributes = client
 50            .build_ic_attributes()
 51            .push(
 52                AttributeName::InputStyle,
 53                InputStyle::PREEDIT_CALLBACKS
 54                    | InputStyle::STATUS_NOTHING
 55                    | InputStyle::PREEDIT_NONE,
 56            )
 57            .push(AttributeName::ClientWindow, self.window)
 58            .push(AttributeName::FocusWindow, self.window)
 59            .build();
 60        client.create_ic(input_method_id, ic_attributes)
 61    }
 62
 63    fn handle_create_ic(
 64        &mut self,
 65        _client: &mut C,
 66        _input_method_id: u16,
 67        input_context_id: u16,
 68    ) -> Result<(), ClientError> {
 69        self.connected = true;
 70        self.ic_id = input_context_id;
 71        Ok(())
 72    }
 73
 74    fn handle_commit(
 75        &mut self,
 76        _client: &mut C,
 77        _input_method_id: u16,
 78        _input_context_id: u16,
 79        text: &str,
 80    ) -> Result<(), ClientError> {
 81        self.last_callback_event = Some(XimCallbackEvent::XimCommitEvent(
 82            self.window,
 83            String::from(text),
 84        ));
 85        Ok(())
 86    }
 87
 88    fn handle_forward_event(
 89        &mut self,
 90        _client: &mut C,
 91        _input_method_id: u16,
 92        _input_context_id: u16,
 93        _flag: xim::ForwardEventFlag,
 94        xev: C::XEvent,
 95    ) -> Result<(), ClientError> {
 96        match xev.response_type {
 97            x11rb::protocol::xproto::KEY_PRESS_EVENT => {
 98                self.last_callback_event = Some(XimCallbackEvent::XimXEvent(Event::KeyPress(xev)));
 99            }
100            x11rb::protocol::xproto::KEY_RELEASE_EVENT => {
101                self.last_callback_event =
102                    Some(XimCallbackEvent::XimXEvent(Event::KeyRelease(xev)));
103            }
104            _ => {}
105        }
106        Ok(())
107    }
108
109    fn handle_close(&mut self, client: &mut C, _input_method_id: u16) -> Result<(), ClientError> {
110        client.disconnect()
111    }
112
113    fn handle_destroy_ic(
114        &mut self,
115        client: &mut C,
116        input_method_id: u16,
117        _input_context_id: u16,
118    ) -> Result<(), ClientError> {
119        client.close(input_method_id)
120    }
121
122    fn handle_preedit_draw(
123        &mut self,
124        _client: &mut C,
125        _input_method_id: u16,
126        _input_context_id: u16,
127        _caret: i32,
128        _chg_first: i32,
129        _chg_len: i32,
130        _status: xim::PreeditDrawStatus,
131        preedit_string: &str,
132        _feedbacks: Vec<xim::Feedback>,
133    ) -> Result<(), ClientError> {
134        // XIMReverse: 1, XIMPrimary: 8, XIMTertiary: 32: selected text
135        // XIMUnderline: 2, XIMSecondary: 16: underlined text
136        // XIMHighlight: 4: normal text
137        // XIMVisibleToForward: 64, XIMVisibleToBackward: 128, XIMVisibleCenter: 256: text align position
138        // XIMPrimary, XIMHighlight, XIMSecondary, XIMTertiary are not specified,
139        // but interchangeable as above
140        // Currently there's no way to support these.
141        self.last_callback_event = Some(XimCallbackEvent::XimPreeditEvent(
142            self.window,
143            String::from(preedit_string),
144        ));
145        Ok(())
146    }
147}