linux: Add keyboard_layout and on_keyboard_layout_change support (#22736)

No issue, as the functionality is currently not being used in Zed. This
is more of a GPUI improvement.

Currently, `keyboard_layout` and `on_keyboard_layout_change` are already
handled on macOS. This PR implements the same for X11 and Wayland.

Linux supports up to 4 keyboard layout groups (e.g., Group 0: English
US, Group 1: Bulgarian, etc). On X11 and Wayland, `event` provides a new
active group, which maps to the `layout_index`. We already store keymap
state from where we can get the current `layout_index`. By comparing
them, we determine if the layout has changed.

X11:
<img
src="https://github.com/user-attachments/assets/b528db77-1ff2-4f17-aac5-7654837edeb9"
alt="x11" width="300px" />

Wayland:
<img
src="https://github.com/user-attachments/assets/2b4e2a30-b0f4-495c-96bb-7bca41365d56"
alt="wayland" width="300px" />

Release Notes:

- N/A
This commit is contained in:
tims 2025-01-07 05:40:00 +05:30 committed by GitHub
parent 76d18f3cd2
commit d2d1779e0d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 65 additions and 4 deletions

View file

@ -37,7 +37,7 @@ use x11rb::{
};
use xim::{x11rb::X11rbClient, AttributeName, Client, InputStyle};
use xkbc::x11::ffi::{XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION};
use xkbcommon::xkb::{self as xkbc, LayoutIndex, ModMask};
use xkbcommon::xkb::{self as xkbc, LayoutIndex, ModMask, STATE_LAYOUT_EFFECTIVE};
use super::{
button_or_scroll_from_event_detail, get_valuator_axis_index, modifiers_from_state,
@ -840,6 +840,8 @@ impl X11Client {
}
Event::XkbStateNotify(event) => {
let mut state = self.0.borrow_mut();
let old_layout = state.xkb.serialize_layout(STATE_LAYOUT_EFFECTIVE);
let new_layout = u32::from(event.group);
state.xkb.update_mask(
event.base_mods.into(),
event.latched_mods.into(),
@ -853,6 +855,17 @@ impl X11Client {
latched_layout: event.latched_group as u32,
locked_layout: event.locked_group.into(),
};
if new_layout != old_layout {
if let Some(mut callback) = state.common.callbacks.keyboard_layout_change.take()
{
drop(state);
callback();
state = self.0.borrow_mut();
state.common.callbacks.keyboard_layout_change = Some(callback);
}
}
let modifiers = Modifiers::from_xkb(&state.xkb);
if state.modifiers == modifiers {
drop(state);
@ -1265,6 +1278,16 @@ impl LinuxClient for X11Client {
f(&mut self.0.borrow_mut().common)
}
fn keyboard_layout(&self) -> String {
let state = self.0.borrow();
let layout_idx = state.xkb.serialize_layout(STATE_LAYOUT_EFFECTIVE);
state
.xkb
.get_keymap()
.layout_get_name(layout_idx)
.to_string()
}
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
let state = self.0.borrow();
let setup = state.xcb_connection.setup();