xim_handler.rs

  1use std::default::Default;
  2
  3use x11rb::protocol::{Event, xproto};
  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        dbg!("XIM: handle_connect called");
 35        let result = client.open("C");
 36        dbg!("XIM: handle_connect result", &result);
 37        result
 38    }
 39
 40    fn handle_open(&mut self, client: &mut C, input_method_id: u16) -> Result<(), ClientError> {
 41        dbg!("XIM: handle_open called", input_method_id);
 42        self.im_id = input_method_id;
 43
 44        let result = client.get_im_values(input_method_id, &[AttributeName::QueryInputStyle]);
 45        dbg!("XIM: handle_open result", &result);
 46        result
 47    }
 48
 49    fn handle_get_im_values(
 50        &mut self,
 51        client: &mut C,
 52        input_method_id: u16,
 53        _attributes: AHashMap<AttributeName, Vec<u8>>,
 54    ) -> Result<(), ClientError> {
 55        let ic_attributes = client
 56            .build_ic_attributes()
 57            .push(AttributeName::InputStyle, InputStyle::PREEDIT_CALLBACKS)
 58            .push(AttributeName::ClientWindow, self.window)
 59            .push(AttributeName::FocusWindow, self.window)
 60            .build();
 61        client.create_ic(input_method_id, ic_attributes)
 62    }
 63
 64    fn handle_create_ic(
 65        &mut self,
 66        _client: &mut C,
 67        _input_method_id: u16,
 68        input_context_id: u16,
 69    ) -> Result<(), ClientError> {
 70        dbg!("XIM: handle_create_ic called", input_context_id);
 71        self.connected = true;
 72        self.ic_id = input_context_id;
 73        dbg!("XIM: connection established", self.connected, self.ic_id);
 74        Ok(())
 75    }
 76
 77    fn handle_commit(
 78        &mut self,
 79        _client: &mut C,
 80        _input_method_id: u16,
 81        _input_context_id: u16,
 82        text: &str,
 83    ) -> Result<(), ClientError> {
 84        dbg!("XIM: handle_commit called", text, self.window);
 85        self.last_callback_event = Some(XimCallbackEvent::XimCommitEvent(
 86            self.window,
 87            String::from(text),
 88        ));
 89        Ok(())
 90    }
 91
 92    fn handle_forward_event(
 93        &mut self,
 94        _client: &mut C,
 95        _input_method_id: u16,
 96        _input_context_id: u16,
 97        _flag: xim::ForwardEventFlag,
 98        xev: C::XEvent,
 99    ) -> Result<(), ClientError> {
100        dbg!("XIM: handle_forward_event called", xev.response_type);
101        match xev.response_type {
102            x11rb::protocol::xproto::KEY_PRESS_EVENT => {
103                dbg!("XIM: forwarding key press event");
104                self.last_callback_event = Some(XimCallbackEvent::XimXEvent(Event::KeyPress(xev)));
105            }
106            x11rb::protocol::xproto::KEY_RELEASE_EVENT => {
107                dbg!("XIM: forwarding key release event");
108                self.last_callback_event =
109                    Some(XimCallbackEvent::XimXEvent(Event::KeyRelease(xev)));
110            }
111            _ => {
112                dbg!("XIM: ignoring event type", xev.response_type);
113            }
114        }
115        Ok(())
116    }
117
118    fn handle_close(&mut self, client: &mut C, _input_method_id: u16) -> Result<(), ClientError> {
119        dbg!("XIM: handle_close called");
120        // self.connected = false;
121        let result = client.disconnect();
122        dbg!("XIM: disconnect result", &result);
123        result
124    }
125
126    fn handle_preedit_draw(
127        &mut self,
128        _client: &mut C,
129        _input_method_id: u16,
130        _input_context_id: u16,
131        _caret: i32,
132        _chg_first: i32,
133        _chg_len: i32,
134        _status: xim::PreeditDrawStatus,
135        preedit_string: &str,
136        _feedbacks: Vec<xim::Feedback>,
137    ) -> Result<(), ClientError> {
138        dbg!(
139            "XIM: handle_preedit_draw called",
140            preedit_string,
141            self.window,
142            _caret,
143            _chg_first,
144            _chg_len
145        );
146        // XIMReverse: 1, XIMPrimary: 8, XIMTertiary: 32: selected text
147        // XIMUnderline: 2, XIMSecondary: 16: underlined text
148        // XIMHighlight: 4: normal text
149        // XIMVisibleToForward: 64, XIMVisibleToBackward: 128, XIMVisibleCenter: 256: text align position
150        // XIMPrimary, XIMHighlight, XIMSecondary, XIMTertiary are not specified,
151        // but interchangeable as above
152        // Currently there's no way to support these.
153        self.last_callback_event = Some(XimCallbackEvent::XimPreeditEvent(
154            self.window,
155            String::from(preedit_string),
156        ));
157        Ok(())
158    }
159}