X11: Implement missing XKB Compose (#12150)
Release Notes: - N/A We have implemented XKB Compose for Wayland, but we forgot to implement it for X11. Fixed #12089
This commit is contained in:
parent
57d570c281
commit
3b14115c2f
1 changed files with 53 additions and 4 deletions
|
@ -1,4 +1,5 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::ffi::OsString;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
@ -29,8 +30,8 @@ use crate::platform::linux::LinuxClient;
|
||||||
use crate::platform::{LinuxCommon, PlatformWindow};
|
use crate::platform::{LinuxCommon, PlatformWindow};
|
||||||
use crate::{
|
use crate::{
|
||||||
modifiers_from_xinput_info, point, px, AnyWindowHandle, Bounds, CursorStyle, DisplayId,
|
modifiers_from_xinput_info, point, px, AnyWindowHandle, Bounds, CursorStyle, DisplayId,
|
||||||
Modifiers, ModifiersChangedEvent, Pixels, PlatformDisplay, PlatformInput, Point, ScrollDelta,
|
Keystroke, Modifiers, ModifiersChangedEvent, Pixels, PlatformDisplay, PlatformInput, Point,
|
||||||
Size, TouchPhase, WindowParams, X11Window,
|
ScrollDelta, Size, TouchPhase, WindowParams, X11Window,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -105,6 +106,8 @@ pub struct X11ClientState {
|
||||||
pub(crate) ximc: Option<X11rbClient<Rc<XCBConnection>>>,
|
pub(crate) ximc: Option<X11rbClient<Rc<XCBConnection>>>,
|
||||||
pub(crate) xim_handler: Option<XimHandler>,
|
pub(crate) xim_handler: Option<XimHandler>,
|
||||||
|
|
||||||
|
pub(crate) compose_state: xkbc::compose::State,
|
||||||
|
pub(crate) pre_edit_text: Option<String>,
|
||||||
pub(crate) cursor_handle: cursor::Handle,
|
pub(crate) cursor_handle: cursor::Handle,
|
||||||
pub(crate) cursor_styles: HashMap<xproto::Window, CursorStyle>,
|
pub(crate) cursor_styles: HashMap<xproto::Window, CursorStyle>,
|
||||||
pub(crate) cursor_cache: HashMap<CursorStyle, xproto::Cursor>,
|
pub(crate) cursor_cache: HashMap<CursorStyle, xproto::Cursor>,
|
||||||
|
@ -215,8 +218,8 @@ impl X11Client {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(xkb.supported);
|
assert!(xkb.supported);
|
||||||
|
|
||||||
|
let xkb_context = xkbc::Context::new(xkbc::CONTEXT_NO_FLAGS);
|
||||||
let xkb_state = {
|
let xkb_state = {
|
||||||
let xkb_context = xkbc::Context::new(xkbc::CONTEXT_NO_FLAGS);
|
|
||||||
let xkb_device_id = xkbc::x11::get_core_keyboard_device_id(&xcb_connection);
|
let xkb_device_id = xkbc::x11::get_core_keyboard_device_id(&xcb_connection);
|
||||||
let xkb_keymap = xkbc::x11::keymap_new_from_device(
|
let xkb_keymap = xkbc::x11::keymap_new_from_device(
|
||||||
&xkb_context,
|
&xkb_context,
|
||||||
|
@ -226,6 +229,17 @@ impl X11Client {
|
||||||
);
|
);
|
||||||
xkbc::x11::state_new_from_device(&xkb_keymap, &xcb_connection, xkb_device_id)
|
xkbc::x11::state_new_from_device(&xkb_keymap, &xcb_connection, xkb_device_id)
|
||||||
};
|
};
|
||||||
|
let compose_state = {
|
||||||
|
let locale = std::env::var_os("LC_CTYPE").unwrap_or(OsString::from("C"));
|
||||||
|
let table = xkbc::compose::Table::new_from_locale(
|
||||||
|
&xkb_context,
|
||||||
|
&locale,
|
||||||
|
xkbc::compose::COMPILE_NO_FLAGS,
|
||||||
|
)
|
||||||
|
.log_err()
|
||||||
|
.unwrap();
|
||||||
|
xkbc::compose::State::new(&table, xkbc::compose::STATE_NO_FLAGS)
|
||||||
|
};
|
||||||
|
|
||||||
let screen = xcb_connection.setup().roots.get(x_root_index).unwrap();
|
let screen = xcb_connection.setup().roots.get(x_root_index).unwrap();
|
||||||
|
|
||||||
|
@ -361,6 +375,9 @@ impl X11Client {
|
||||||
ximc,
|
ximc,
|
||||||
xim_handler,
|
xim_handler,
|
||||||
|
|
||||||
|
compose_state: compose_state,
|
||||||
|
pre_edit_text: None,
|
||||||
|
|
||||||
cursor_handle,
|
cursor_handle,
|
||||||
cursor_styles: HashMap::default(),
|
cursor_styles: HashMap::default(),
|
||||||
cursor_cache: HashMap::default(),
|
cursor_cache: HashMap::default(),
|
||||||
|
@ -452,12 +469,44 @@ impl X11Client {
|
||||||
let modifiers = modifiers_from_state(event.state);
|
let modifiers = modifiers_from_state(event.state);
|
||||||
let keystroke = {
|
let keystroke = {
|
||||||
let code = event.detail.into();
|
let code = event.detail.into();
|
||||||
let keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code);
|
let mut keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code);
|
||||||
state.xkb.update_key(code, xkbc::KeyDirection::Down);
|
state.xkb.update_key(code, xkbc::KeyDirection::Down);
|
||||||
let keysym = state.xkb.key_get_one_sym(code);
|
let keysym = state.xkb.key_get_one_sym(code);
|
||||||
if keysym.is_modifier_key() {
|
if keysym.is_modifier_key() {
|
||||||
return Some(());
|
return Some(());
|
||||||
}
|
}
|
||||||
|
state.compose_state.feed(keysym);
|
||||||
|
match state.compose_state.status() {
|
||||||
|
xkbc::Status::Composed => {
|
||||||
|
state.pre_edit_text.take();
|
||||||
|
keystroke.ime_key = state.compose_state.utf8();
|
||||||
|
keystroke.key =
|
||||||
|
xkbc::keysym_get_name(state.compose_state.keysym().unwrap());
|
||||||
|
}
|
||||||
|
xkbc::Status::Composing => {
|
||||||
|
state.pre_edit_text = state
|
||||||
|
.compose_state
|
||||||
|
.utf8()
|
||||||
|
.or(crate::Keystroke::underlying_dead_key(keysym));
|
||||||
|
let pre_edit = state.pre_edit_text.clone().unwrap_or(String::default());
|
||||||
|
drop(state);
|
||||||
|
window.handle_ime_preedit(pre_edit);
|
||||||
|
state = self.0.borrow_mut();
|
||||||
|
}
|
||||||
|
xkbc::Status::Cancelled => {
|
||||||
|
let pre_edit = state.pre_edit_text.take();
|
||||||
|
drop(state);
|
||||||
|
if let Some(pre_edit) = pre_edit {
|
||||||
|
window.handle_ime_commit(pre_edit);
|
||||||
|
}
|
||||||
|
if let Some(current_key) = Keystroke::underlying_dead_key(keysym) {
|
||||||
|
window.handle_ime_preedit(current_key);
|
||||||
|
}
|
||||||
|
state = self.0.borrow_mut();
|
||||||
|
state.compose_state.feed(keysym);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
keystroke
|
keystroke
|
||||||
};
|
};
|
||||||
drop(state);
|
drop(state);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue