This commit is contained in:
Smit Barmase 2025-08-09 02:14:07 +05:30
parent f2435f7284
commit 79a9669f46
No known key found for this signature in database
3 changed files with 107 additions and 12 deletions

View file

@ -631,42 +631,54 @@ impl X11Client {
for event in events.into_iter() { for event in events.into_iter() {
let mut state = self.0.borrow_mut(); let mut state = self.0.borrow_mut();
if !state.has_xim() { if !state.has_xim() {
dbg!("XIM: no XIM available for key event");
drop(state); drop(state);
self.handle_event(event); self.handle_event(event);
continue; continue;
} }
let Some((mut ximc, mut xim_handler)) = state.take_xim() else { let Some((mut ximc, mut xim_handler)) = state.take_xim() else {
dbg!("XIM: failed to take XIM for key event");
continue; continue;
}; };
let xim_connected = xim_handler.connected; let xim_connected = xim_handler.connected;
dbg!("XIM: processing key event", xim_connected);
drop(state); drop(state);
let xim_filtered = match ximc.filter_event(&event, &mut xim_handler) { let xim_filtered = match ximc.filter_event(&event, &mut xim_handler) {
Ok(handled) => handled, Ok(handled) => {
dbg!("XIM: filter_event result", handled);
handled
},
Err(err) => { Err(err) => {
dbg!("XIM: filter_event error", &err);
log::error!("XIMClientError: {}", err); log::error!("XIMClientError: {}", err);
false false
} }
}; };
let xim_callback_event = xim_handler.last_callback_event.take(); let xim_callback_event = xim_handler.last_callback_event.take();
dbg!("XIM: callback event present", xim_callback_event.is_some());
let mut state = self.0.borrow_mut(); let mut state = self.0.borrow_mut();
state.restore_xim(ximc, xim_handler); state.restore_xim(ximc, xim_handler);
drop(state); drop(state);
if let Some(event) = xim_callback_event { if let Some(event) = xim_callback_event {
dbg!("XIM: handling callback event");
self.handle_xim_callback_event(event); self.handle_xim_callback_event(event);
} }
if xim_filtered { if xim_filtered {
dbg!("XIM: event was filtered, not processing further");
continue; continue;
} }
if xim_connected { if xim_connected {
dbg!("XIM: forwarding event to XIM");
self.xim_handle_event(event); self.xim_handle_event(event);
} else { } else {
self.handle_event(event); self.handle_event(event);
dbg!("XIM: not connected, skipping XIM event handling");
} }
} }
} }
@ -1273,22 +1285,28 @@ impl X11Client {
} }
fn handle_xim_callback_event(&self, event: XimCallbackEvent) { fn handle_xim_callback_event(&self, event: XimCallbackEvent) {
dbg!("XIM: handle_xim_callback_event called");
match event { match event {
XimCallbackEvent::XimXEvent(event) => { XimCallbackEvent::XimXEvent(event) => {
dbg!("XIM: handling forwarded X event");
self.handle_event(event); self.handle_event(event);
} }
XimCallbackEvent::XimCommitEvent(window, text) => { XimCallbackEvent::XimCommitEvent(window, text) => {
dbg!("XIM: handling commit event", window, &text);
self.xim_handle_commit(window, text); self.xim_handle_commit(window, text);
} }
XimCallbackEvent::XimPreeditEvent(window, text) => { XimCallbackEvent::XimPreeditEvent(window, text) => {
dbg!("XIM: handling preedit event", window, &text);
self.xim_handle_preedit(window, text); self.xim_handle_preedit(window, text);
} }
}; };
} }
fn xim_handle_event(&self, event: Event) -> Option<()> { fn xim_handle_event(&self, event: Event) -> Option<()> {
dbg!("XIM: xim_handle_event called");
match event { match event {
Event::KeyPress(event) | Event::KeyRelease(event) => { Event::KeyPress(event) | Event::KeyRelease(event) => {
dbg!("XIM: handling key press/release event", event.event);
let mut state = self.0.borrow_mut(); let mut state = self.0.borrow_mut();
state.pre_key_char_down = Some(Keystroke::from_xkb( state.pre_key_char_down = Some(Keystroke::from_xkb(
&state.xkb, &state.xkb,
@ -1298,19 +1316,25 @@ impl X11Client {
let (mut ximc, mut xim_handler) = state.take_xim()?; let (mut ximc, mut xim_handler) = state.take_xim()?;
drop(state); drop(state);
xim_handler.window = event.event; xim_handler.window = event.event;
ximc.forward_event( dbg!("XIM: forwarding event to XIM server", event.event, xim_handler.im_id, xim_handler.ic_id);
let result = ximc.forward_event(
xim_handler.im_id, xim_handler.im_id,
xim_handler.ic_id, xim_handler.ic_id,
xim::ForwardEventFlag::empty(), xim::ForwardEventFlag::empty(),
&event, &event,
) );
.context("X11: Failed to forward XIM event") if let Err(ref error) = result {
.log_err(); dbg!("XIM: forward_event error", error);
}
result
.context("X11: Failed to forward XIM event")
.log_err();
let mut state = self.0.borrow_mut(); let mut state = self.0.borrow_mut();
state.restore_xim(ximc, xim_handler); state.restore_xim(ximc, xim_handler);
drop(state); drop(state);
} }
event => { event => {
dbg!("XIM: forwarding non-key event to normal handler");
self.handle_event(event); self.handle_event(event);
} }
} }
@ -1318,27 +1342,35 @@ impl X11Client {
} }
fn xim_handle_commit(&self, window: xproto::Window, text: String) -> Option<()> { fn xim_handle_commit(&self, window: xproto::Window, text: String) -> Option<()> {
dbg!("XIM: xim_handle_commit called", window, &text);
let Some(window) = self.get_window(window) else { let Some(window) = self.get_window(window) else {
dbg!("XIM: bug: Failed to get window for XIM commit", window);
log::error!("bug: Failed to get window for XIM commit"); log::error!("bug: Failed to get window for XIM commit");
return None; return None;
}; };
let mut state = self.0.borrow_mut(); let mut state = self.0.borrow_mut();
let keystroke = state.pre_key_char_down.take(); let keystroke = state.pre_key_char_down.take();
state.composing = false; state.composing = false;
dbg!("XIM: setting composing to false, keystroke present", keystroke.is_some());
drop(state); drop(state);
if let Some(mut keystroke) = keystroke { if let Some(mut keystroke) = keystroke {
keystroke.key_char = Some(text.clone()); keystroke.key_char = Some(text.clone());
dbg!("XIM: calling window.handle_input with keystroke");
window.handle_input(PlatformInput::KeyDown(crate::KeyDownEvent { window.handle_input(PlatformInput::KeyDown(crate::KeyDownEvent {
keystroke, keystroke,
is_held: false, is_held: false,
})); }));
} else {
dbg!("XIM: no keystroke available for commit");
} }
Some(()) Some(())
} }
fn xim_handle_preedit(&self, window: xproto::Window, text: String) -> Option<()> { fn xim_handle_preedit(&self, window: xproto::Window, text: String) -> Option<()> {
dbg!("XIM: xim_handle_preedit called", window, &text);
let Some(window) = self.get_window(window) else { let Some(window) = self.get_window(window) else {
dbg!("XIM: bug: Failed to get window for XIM preedit", window);
log::error!("bug: Failed to get window for XIM preedit"); log::error!("bug: Failed to get window for XIM preedit");
return None; return None;
}; };
@ -1346,10 +1378,13 @@ impl X11Client {
let mut state = self.0.borrow_mut(); let mut state = self.0.borrow_mut();
let (mut ximc, mut xim_handler) = state.take_xim()?; let (mut ximc, mut xim_handler) = state.take_xim()?;
state.composing = !text.is_empty(); state.composing = !text.is_empty();
dbg!("XIM: setting composing state", state.composing);
drop(state); drop(state);
dbg!("XIM: calling window.handle_ime_preedit");
window.handle_ime_preedit(text); window.handle_ime_preedit(text);
if let Some(area) = window.get_ime_area() { if let Some(area) = window.get_ime_area() {
dbg!("XIM: got IME area, updating spot location", area);
let ic_attributes = ximc let ic_attributes = ximc
.build_ic_attributes() .build_ic_attributes()
.push( .push(
@ -1368,8 +1403,10 @@ impl X11Client {
); );
}) })
.build(); .build();
ximc.set_ic_values(xim_handler.im_id, xim_handler.ic_id, ic_attributes) let result = ximc.set_ic_values(xim_handler.im_id, xim_handler.ic_id, ic_attributes);
.ok(); dbg!("XIM: set_ic_values result for preedit", result.is_ok());
} else {
dbg!("XIM: no IME area available");
} }
let mut state = self.0.borrow_mut(); let mut state = self.0.borrow_mut();
state.restore_xim(ximc, xim_handler); state.restore_xim(ximc, xim_handler);

View file

@ -956,79 +956,111 @@ impl X11WindowStatePtr {
} }
pub fn handle_input(&self, input: PlatformInput) { pub fn handle_input(&self, input: PlatformInput) {
dbg!("Window: handle_input called", &input);
if let Some(ref mut fun) = self.callbacks.borrow_mut().input { if let Some(ref mut fun) = self.callbacks.borrow_mut().input {
if !fun(input.clone()).propagate { let result = fun(input.clone());
dbg!("Window: input callback result", result.propagate);
if !result.propagate {
return; return;
} }
} }
if let PlatformInput::KeyDown(event) = input { if let PlatformInput::KeyDown(event) = input {
dbg!("Window: handling KeyDown event", &event.keystroke);
// only allow shift modifier when inserting text // only allow shift modifier when inserting text
if event.keystroke.modifiers.is_subset_of(&Modifiers::shift()) { if event.keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
dbg!("Window: modifiers subset of shift, checking for key_char");
let mut state = self.state.borrow_mut(); let mut state = self.state.borrow_mut();
if let Some(mut input_handler) = state.input_handler.take() { if let Some(mut input_handler) = state.input_handler.take() {
if let Some(key_char) = &event.keystroke.key_char { if let Some(key_char) = &event.keystroke.key_char {
dbg!("Window: inserting key_char directly", key_char);
drop(state); drop(state);
input_handler.replace_text_in_range(None, key_char); input_handler.replace_text_in_range(None, key_char);
state = self.state.borrow_mut(); state = self.state.borrow_mut();
} }
state.input_handler = Some(input_handler); state.input_handler = Some(input_handler);
} }
} else {
dbg!("Window: modifiers not subset of shift, ignoring key_char insertion");
} }
} }
} }
pub fn handle_ime_commit(&self, text: String) { pub fn handle_ime_commit(&self, text: String) {
dbg!("Window: handle_ime_commit called", &text);
let mut state = self.state.borrow_mut(); let mut state = self.state.borrow_mut();
if let Some(mut input_handler) = state.input_handler.take() { if let Some(mut input_handler) = state.input_handler.take() {
dbg!("Window: got input handler, calling replace_text_in_range");
drop(state); drop(state);
input_handler.replace_text_in_range(None, &text); input_handler.replace_text_in_range(None, &text);
let mut state = self.state.borrow_mut(); let mut state = self.state.borrow_mut();
state.input_handler = Some(input_handler); state.input_handler = Some(input_handler);
} else {
dbg!("Window: no input handler available for IME commit");
} }
} }
pub fn handle_ime_preedit(&self, text: String) { pub fn handle_ime_preedit(&self, text: String) {
dbg!("Window: handle_ime_preedit called", &text);
let mut state = self.state.borrow_mut(); let mut state = self.state.borrow_mut();
if let Some(mut input_handler) = state.input_handler.take() { if let Some(mut input_handler) = state.input_handler.take() {
dbg!("Window: got input handler, calling replace_and_mark_text_in_range");
drop(state); drop(state);
input_handler.replace_and_mark_text_in_range(None, &text, None); input_handler.replace_and_mark_text_in_range(None, &text, None);
let mut state = self.state.borrow_mut(); let mut state = self.state.borrow_mut();
state.input_handler = Some(input_handler); state.input_handler = Some(input_handler);
} else {
dbg!("Window: no input handler available for IME preedit");
} }
} }
pub fn handle_ime_unmark(&self) { pub fn handle_ime_unmark(&self) {
dbg!("Window: handle_ime_unmark called");
let mut state = self.state.borrow_mut(); let mut state = self.state.borrow_mut();
if let Some(mut input_handler) = state.input_handler.take() { if let Some(mut input_handler) = state.input_handler.take() {
dbg!("Window: got input handler, calling unmark_text");
drop(state); drop(state);
input_handler.unmark_text(); input_handler.unmark_text();
let mut state = self.state.borrow_mut(); let mut state = self.state.borrow_mut();
state.input_handler = Some(input_handler); state.input_handler = Some(input_handler);
} else {
dbg!("Window: no input handler available for IME unmark");
} }
} }
pub fn handle_ime_delete(&self) { pub fn handle_ime_delete(&self) {
dbg!("Window: handle_ime_delete called");
let mut state = self.state.borrow_mut(); let mut state = self.state.borrow_mut();
if let Some(mut input_handler) = state.input_handler.take() { if let Some(mut input_handler) = state.input_handler.take() {
drop(state); drop(state);
if let Some(marked) = input_handler.marked_text_range() { if let Some(marked) = input_handler.marked_text_range() {
dbg!("Window: found marked text range, deleting", &marked);
input_handler.replace_text_in_range(Some(marked), ""); input_handler.replace_text_in_range(Some(marked), "");
} else {
dbg!("Window: no marked text range to delete");
} }
let mut state = self.state.borrow_mut(); let mut state = self.state.borrow_mut();
state.input_handler = Some(input_handler); state.input_handler = Some(input_handler);
} else {
dbg!("Window: no input handler available for IME delete");
} }
} }
pub fn get_ime_area(&self) -> Option<Bounds<Pixels>> { pub fn get_ime_area(&self) -> Option<Bounds<Pixels>> {
dbg!("Window: get_ime_area called");
let mut state = self.state.borrow_mut(); let mut state = self.state.borrow_mut();
let mut bounds: Option<Bounds<Pixels>> = None; let mut bounds: Option<Bounds<Pixels>> = None;
if let Some(mut input_handler) = state.input_handler.take() { if let Some(mut input_handler) = state.input_handler.take() {
drop(state); drop(state);
if let Some(selection) = input_handler.selected_text_range(true) { if let Some(selection) = input_handler.selected_text_range(true) {
bounds = input_handler.bounds_for_range(selection.range); bounds = input_handler.bounds_for_range(selection.range);
dbg!("Window: got IME area bounds", bounds);
} else {
dbg!("Window: no selected text range for IME area");
} }
let mut state = self.state.borrow_mut(); let mut state = self.state.borrow_mut();
state.input_handler = Some(input_handler); state.input_handler = Some(input_handler);
} else {
dbg!("Window: no input handler available for IME area");
}; };
bounds bounds
} }

View file

@ -31,13 +31,19 @@ impl XimHandler {
impl<C: Client<XEvent = xproto::KeyPressEvent>> ClientHandler<C> for XimHandler { impl<C: Client<XEvent = xproto::KeyPressEvent>> ClientHandler<C> for XimHandler {
fn handle_connect(&mut self, client: &mut C) -> Result<(), ClientError> { fn handle_connect(&mut self, client: &mut C) -> Result<(), ClientError> {
client.open("C") dbg!("XIM: handle_connect called");
let result = client.open("C");
dbg!("XIM: handle_connect result", &result);
result
} }
fn handle_open(&mut self, client: &mut C, input_method_id: u16) -> Result<(), ClientError> { fn handle_open(&mut self, client: &mut C, input_method_id: u16) -> Result<(), ClientError> {
dbg!("XIM: handle_open called", input_method_id);
self.im_id = input_method_id; self.im_id = input_method_id;
client.get_im_values(input_method_id, &[AttributeName::QueryInputStyle]) let result = client.get_im_values(input_method_id, &[AttributeName::QueryInputStyle]);
dbg!("XIM: handle_open result", &result);
result
} }
fn handle_get_im_values( fn handle_get_im_values(
@ -61,8 +67,10 @@ impl<C: Client<XEvent = xproto::KeyPressEvent>> ClientHandler<C> for XimHandler
_input_method_id: u16, _input_method_id: u16,
input_context_id: u16, input_context_id: u16,
) -> Result<(), ClientError> { ) -> Result<(), ClientError> {
dbg!("XIM: handle_create_ic called", input_context_id);
self.connected = true; self.connected = true;
self.ic_id = input_context_id; self.ic_id = input_context_id;
dbg!("XIM: connection established", self.connected, self.ic_id);
Ok(()) Ok(())
} }
@ -73,6 +81,7 @@ impl<C: Client<XEvent = xproto::KeyPressEvent>> ClientHandler<C> for XimHandler
_input_context_id: u16, _input_context_id: u16,
text: &str, text: &str,
) -> Result<(), ClientError> { ) -> Result<(), ClientError> {
dbg!("XIM: handle_commit called", text, self.window);
self.last_callback_event = Some(XimCallbackEvent::XimCommitEvent( self.last_callback_event = Some(XimCallbackEvent::XimCommitEvent(
self.window, self.window,
String::from(text), String::from(text),
@ -88,21 +97,30 @@ impl<C: Client<XEvent = xproto::KeyPressEvent>> ClientHandler<C> for XimHandler
_flag: xim::ForwardEventFlag, _flag: xim::ForwardEventFlag,
xev: C::XEvent, xev: C::XEvent,
) -> Result<(), ClientError> { ) -> Result<(), ClientError> {
dbg!("XIM: handle_forward_event called", xev.response_type);
match xev.response_type { match xev.response_type {
x11rb::protocol::xproto::KEY_PRESS_EVENT => { x11rb::protocol::xproto::KEY_PRESS_EVENT => {
dbg!("XIM: forwarding key press event");
self.last_callback_event = Some(XimCallbackEvent::XimXEvent(Event::KeyPress(xev))); self.last_callback_event = Some(XimCallbackEvent::XimXEvent(Event::KeyPress(xev)));
} }
x11rb::protocol::xproto::KEY_RELEASE_EVENT => { x11rb::protocol::xproto::KEY_RELEASE_EVENT => {
dbg!("XIM: forwarding key release event");
self.last_callback_event = self.last_callback_event =
Some(XimCallbackEvent::XimXEvent(Event::KeyRelease(xev))); Some(XimCallbackEvent::XimXEvent(Event::KeyRelease(xev)));
} }
_ => {} _ => {
dbg!("XIM: ignoring event type", xev.response_type);
}
} }
Ok(()) Ok(())
} }
fn handle_close(&mut self, client: &mut C, _input_method_id: u16) -> Result<(), ClientError> { fn handle_close(&mut self, client: &mut C, _input_method_id: u16) -> Result<(), ClientError> {
client.disconnect() dbg!("XIM: handle_close called");
// self.connected = false;
let result = client.disconnect();
dbg!("XIM: disconnect result", &result);
result
} }
fn handle_preedit_draw( fn handle_preedit_draw(
@ -117,6 +135,14 @@ impl<C: Client<XEvent = xproto::KeyPressEvent>> ClientHandler<C> for XimHandler
preedit_string: &str, preedit_string: &str,
_feedbacks: Vec<xim::Feedback>, _feedbacks: Vec<xim::Feedback>,
) -> Result<(), ClientError> { ) -> Result<(), ClientError> {
dbg!(
"XIM: handle_preedit_draw called",
preedit_string,
self.window,
_caret,
_chg_first,
_chg_len
);
// XIMReverse: 1, XIMPrimary: 8, XIMTertiary: 32: selected text // XIMReverse: 1, XIMPrimary: 8, XIMTertiary: 32: selected text
// XIMUnderline: 2, XIMSecondary: 16: underlined text // XIMUnderline: 2, XIMSecondary: 16: underlined text
// XIMHighlight: 4: normal text // XIMHighlight: 4: normal text