gpui: Introduce PlatformKeyboardLayout trait for human-friendly keyboard layout names (#29049)
This PR adds a new `PlatformKeyboardLayout` trait with two methods: `id(&self) -> &str` and `name(&self) -> &str`. The `id()` method returns a unique identifier for the keyboard layout, while `name()` provides a human-readable name. This distinction is especially important on Windows, where the `id` and `name` can be quite different. For example, the French layout has an `id` of `0000040C`, which is not human-readable, whereas the `name` would simply be `French`. Currently, the existing `keyboard_layout()` method returns what's essentially the same as `id()` in this new design. This PR implements the `name()` method for both Windows and macOS. On Linux, for now, `name()` still returns the same value as `id()`. Release Notes: - N/A
This commit is contained in:
@@ -9,7 +9,8 @@ use util::ResultExt;
|
||||
use crate::platform::linux::LinuxClient;
|
||||
use crate::platform::{LinuxCommon, PlatformWindow};
|
||||
use crate::{
|
||||
AnyWindowHandle, CursorStyle, DisplayId, PlatformDisplay, ScreenCaptureSource, WindowParams,
|
||||
AnyWindowHandle, CursorStyle, DisplayId, LinuxKeyboardLayout, PlatformDisplay,
|
||||
PlatformKeyboardLayout, ScreenCaptureSource, WindowParams,
|
||||
};
|
||||
|
||||
pub struct HeadlessClientState {
|
||||
@@ -50,8 +51,8 @@ impl LinuxClient for HeadlessClient {
|
||||
f(&mut self.0.borrow_mut().common)
|
||||
}
|
||||
|
||||
fn keyboard_layout(&self) -> String {
|
||||
"unknown".to_string()
|
||||
fn keyboard_layout(&self) -> Box<dyn PlatformKeyboardLayout> {
|
||||
Box::new(LinuxKeyboardLayout::new("unknown".to_string()))
|
||||
}
|
||||
|
||||
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
|
||||
|
||||
@@ -25,8 +25,8 @@ use xkbcommon::xkb::{self, Keycode, Keysym, State};
|
||||
use crate::{
|
||||
Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId,
|
||||
ForegroundExecutor, Keymap, LinuxDispatcher, Menu, MenuItem, OwnedMenu, PathPromptOptions,
|
||||
Pixels, Platform, PlatformDisplay, PlatformTextSystem, PlatformWindow, Point, Result,
|
||||
ScreenCaptureSource, Task, WindowAppearance, WindowParams, px,
|
||||
Pixels, Platform, PlatformDisplay, PlatformKeyboardLayout, PlatformTextSystem, PlatformWindow,
|
||||
Point, Result, ScreenCaptureSource, Task, WindowAppearance, WindowParams, px,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "wayland", feature = "x11"))]
|
||||
@@ -46,7 +46,7 @@ const FILE_PICKER_PORTAL_MISSING: &str =
|
||||
pub trait LinuxClient {
|
||||
fn compositor_name(&self) -> &'static str;
|
||||
fn with_common<R>(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R;
|
||||
fn keyboard_layout(&self) -> String;
|
||||
fn keyboard_layout(&self) -> Box<dyn PlatformKeyboardLayout>;
|
||||
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>>;
|
||||
#[allow(unused)]
|
||||
fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>>;
|
||||
@@ -138,7 +138,7 @@ impl<P: LinuxClient + 'static> Platform for P {
|
||||
self.with_common(|common| common.text_system.clone())
|
||||
}
|
||||
|
||||
fn keyboard_layout(&self) -> String {
|
||||
fn keyboard_layout(&self) -> Box<dyn PlatformKeyboardLayout> {
|
||||
self.keyboard_layout()
|
||||
}
|
||||
|
||||
@@ -858,6 +858,26 @@ impl crate::Modifiers {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct LinuxKeyboardLayout {
|
||||
id: String,
|
||||
}
|
||||
|
||||
impl PlatformKeyboardLayout for LinuxKeyboardLayout {
|
||||
fn id(&self) -> &str {
|
||||
&self.id
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl LinuxKeyboardLayout {
|
||||
pub(crate) fn new(id: String) -> Self {
|
||||
Self { id }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -66,8 +66,10 @@ use wayland_protocols_plasma::blur::client::{org_kde_kwin_blur, org_kde_kwin_blu
|
||||
use xkbcommon::xkb::ffi::XKB_KEYMAP_FORMAT_TEXT_V1;
|
||||
use xkbcommon::xkb::{self, KEYMAP_COMPILE_NO_FLAGS, Keycode};
|
||||
|
||||
use super::display::WaylandDisplay;
|
||||
use super::window::{ImeInput, WaylandWindowStatePtr};
|
||||
use super::{
|
||||
display::WaylandDisplay,
|
||||
window::{ImeInput, WaylandWindowStatePtr},
|
||||
};
|
||||
|
||||
use crate::platform::linux::{
|
||||
LinuxClient, get_xkb_compose_state, is_within_click_distance, open_uri_internal, read_fd,
|
||||
@@ -83,11 +85,11 @@ use crate::platform::linux::{
|
||||
use crate::platform::{PlatformWindow, blade::BladeContext};
|
||||
use crate::{
|
||||
AnyWindowHandle, Bounds, CursorStyle, DOUBLE_CLICK_INTERVAL, DevicePixels, DisplayId,
|
||||
FileDropEvent, ForegroundExecutor, KeyDownEvent, KeyUpEvent, Keystroke, LinuxCommon, Modifiers,
|
||||
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseExitEvent, MouseMoveEvent,
|
||||
MouseUpEvent, NavigationDirection, Pixels, PlatformDisplay, PlatformInput, Point, SCROLL_LINES,
|
||||
ScaledPixels, ScreenCaptureSource, ScrollDelta, ScrollWheelEvent, Size, TouchPhase,
|
||||
WindowParams, point, px, size,
|
||||
FileDropEvent, ForegroundExecutor, KeyDownEvent, KeyUpEvent, Keystroke, LinuxCommon,
|
||||
LinuxKeyboardLayout, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent,
|
||||
MouseExitEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection, Pixels, PlatformDisplay,
|
||||
PlatformInput, PlatformKeyboardLayout, Point, SCROLL_LINES, ScaledPixels, ScreenCaptureSource,
|
||||
ScrollDelta, ScrollWheelEvent, Size, TouchPhase, WindowParams, point, px, size,
|
||||
};
|
||||
|
||||
/// Used to convert evdev scancode to xkb scancode
|
||||
@@ -587,9 +589,9 @@ impl WaylandClient {
|
||||
}
|
||||
|
||||
impl LinuxClient for WaylandClient {
|
||||
fn keyboard_layout(&self) -> String {
|
||||
fn keyboard_layout(&self) -> Box<dyn PlatformKeyboardLayout> {
|
||||
let state = self.0.borrow();
|
||||
if let Some(keymap_state) = &state.keymap_state {
|
||||
let id = if let Some(keymap_state) = &state.keymap_state {
|
||||
let layout_idx = keymap_state.serialize_layout(xkbcommon::xkb::STATE_LAYOUT_EFFECTIVE);
|
||||
keymap_state
|
||||
.get_keymap()
|
||||
@@ -597,7 +599,8 @@ impl LinuxClient for WaylandClient {
|
||||
.to_string()
|
||||
} else {
|
||||
"unknown".to_string()
|
||||
}
|
||||
};
|
||||
Box::new(LinuxKeyboardLayout::new(id))
|
||||
}
|
||||
|
||||
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
|
||||
|
||||
@@ -59,9 +59,10 @@ use crate::platform::{
|
||||
};
|
||||
use crate::{
|
||||
AnyWindowHandle, Bounds, ClipboardItem, CursorStyle, DisplayId, FileDropEvent, Keystroke,
|
||||
Modifiers, ModifiersChangedEvent, MouseButton, Pixels, Platform, PlatformDisplay,
|
||||
PlatformInput, Point, RequestFrameOptions, ScaledPixels, ScreenCaptureSource, ScrollDelta,
|
||||
Size, TouchPhase, WindowParams, X11Window, modifiers_from_xinput_info, point, px,
|
||||
LinuxKeyboardLayout, Modifiers, ModifiersChangedEvent, MouseButton, Pixels, Platform,
|
||||
PlatformDisplay, PlatformInput, PlatformKeyboardLayout, Point, RequestFrameOptions,
|
||||
ScaledPixels, ScreenCaptureSource, ScrollDelta, Size, TouchPhase, WindowParams, X11Window,
|
||||
modifiers_from_xinput_info, point, px,
|
||||
};
|
||||
|
||||
/// Value for DeviceId parameters which selects all devices.
|
||||
@@ -1282,14 +1283,16 @@ impl LinuxClient for X11Client {
|
||||
f(&mut self.0.borrow_mut().common)
|
||||
}
|
||||
|
||||
fn keyboard_layout(&self) -> String {
|
||||
fn keyboard_layout(&self) -> Box<dyn PlatformKeyboardLayout> {
|
||||
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()
|
||||
Box::new(LinuxKeyboardLayout::new(
|
||||
state
|
||||
.xkb
|
||||
.get_keymap()
|
||||
.layout_get_name(layout_idx)
|
||||
.to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
|
||||
|
||||
Reference in New Issue
Block a user