use std::default::Default; use x11rb::protocol::{xproto, Event}; use xim::{AHashMap, AttributeName, Client, ClientError, ClientHandler, InputStyle}; pub enum XimCallbackEvent { XimXEvent(x11rb::protocol::Event), XimPreeditEvent(xproto::Window, String), XimCommitEvent(xproto::Window, String), } pub struct XimHandler { pub im_id: u16, pub ic_id: u16, pub connected: bool, pub window: xproto::Window, pub last_callback_event: Option, } impl XimHandler { pub fn new() -> Self { Self { im_id: Default::default(), ic_id: Default::default(), connected: false, window: Default::default(), last_callback_event: None, } } } impl> ClientHandler for XimHandler { fn handle_connect(&mut self, client: &mut C) -> Result<(), ClientError> { client.open("C") } fn handle_open(&mut self, client: &mut C, input_method_id: u16) -> Result<(), ClientError> { 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>, ) -> Result<(), ClientError> { let ic_attributes = client .build_ic_attributes() .push(AttributeName::InputStyle, InputStyle::PREEDIT_CALLBACKS) .push(AttributeName::ClientWindow, self.window) .push(AttributeName::FocusWindow, self.window) .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; Ok(()) } fn handle_commit( &mut self, _client: &mut C, _input_method_id: u16, _input_context_id: u16, text: &str, ) -> Result<(), ClientError> { self.last_callback_event = Some(XimCallbackEvent::XimCommitEvent( self.window, String::from(text), )); Ok(()) } fn handle_forward_event( &mut self, _client: &mut C, _input_method_id: u16, _input_context_id: u16, _flag: xim::ForwardEventFlag, xev: C::XEvent, ) -> Result<(), ClientError> { match xev.response_type { x11rb::protocol::xproto::KEY_PRESS_EVENT => { self.last_callback_event = Some(XimCallbackEvent::XimXEvent(Event::KeyPress(xev))); } x11rb::protocol::xproto::KEY_RELEASE_EVENT => { self.last_callback_event = Some(XimCallbackEvent::XimXEvent(Event::KeyRelease(xev))); } _ => {} } Ok(()) } fn handle_close(&mut self, client: &mut C, _input_method_id: u16) -> Result<(), ClientError> { client.disconnect() } 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, ) -> Result<(), ClientError> { // XIMReverse: 1, XIMPrimary: 8, XIMTertiary: 32: selected text // XIMUnderline: 2, XIMSecondary: 16: underlined text // XIMHighlight: 4: normal text // XIMVisibleToForward: 64, XIMVisibleToBackward: 128, XIMVisibleCenter: 256: text align position // XIMPrimary, XIMHighlight, XIMSecondary, XIMTertiary are not specified, // but interchangeable as above // Currently there's no way to support these. self.last_callback_event = Some(XimCallbackEvent::XimPreeditEvent( self.window, String::from(preedit_string), )); Ok(()) } }