gpui: Refactor `PlatformKeyboardLayout` (#29653)

张小白 created

Release Notes:

- N/A

Change summary

crates/gpui/src/platform.rs                  | 10 ---
crates/gpui/src/platform/keyboard.rs         |  7 +++
crates/gpui/src/platform/linux.rs            |  2 
crates/gpui/src/platform/linux/keyboard.rs   | 21 +++++++++
crates/gpui/src/platform/linux/platform.rs   | 20 --------
crates/gpui/src/platform/mac.rs              |  2 
crates/gpui/src/platform/mac/keyboard.rs     | 49 ++++++++++++++++++++++
crates/gpui/src/platform/mac/platform.rs     | 41 -----------------
crates/gpui/src/platform/windows.rs          |  2 
crates/gpui/src/platform/windows/keyboard.rs | 43 +++++++++++++++++++
crates/gpui/src/platform/windows/platform.rs | 40 -----------------
11 files changed, 131 insertions(+), 106 deletions(-)

Detailed changes

crates/gpui/src/platform.rs 🔗

@@ -1,4 +1,5 @@
 mod app_menu;
+mod keyboard;
 mod keystroke;
 
 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
@@ -63,6 +64,7 @@ use strum::EnumIter;
 use uuid::Uuid;
 
 pub use app_menu::*;
+pub use keyboard::*;
 pub use keystroke::*;
 
 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
@@ -1679,11 +1681,3 @@ impl From<String> for ClipboardString {
         }
     }
 }
-
-/// A trait for platform-specific keyboard layouts
-pub trait PlatformKeyboardLayout {
-    /// Get the keyboard layout ID, which should be unique to the layout
-    fn id(&self) -> &str;
-    /// Get the keyboard layout display name
-    fn name(&self) -> &str;
-}

crates/gpui/src/platform/keyboard.rs 🔗

@@ -0,0 +1,7 @@
+/// A trait for platform-specific keyboard layouts
+pub trait PlatformKeyboardLayout {
+    /// Get the keyboard layout ID, which should be unique to the layout
+    fn id(&self) -> &str;
+    /// Get the keyboard layout display name
+    fn name(&self) -> &str;
+}

crates/gpui/src/platform/linux.rs 🔗

@@ -1,5 +1,6 @@
 mod dispatcher;
 mod headless;
+mod keyboard;
 mod platform;
 #[cfg(any(feature = "wayland", feature = "x11"))]
 mod text_system;
@@ -13,6 +14,7 @@ mod xdg_desktop_portal;
 
 pub(crate) use dispatcher::*;
 pub(crate) use headless::*;
+pub(crate) use keyboard::*;
 pub(crate) use platform::*;
 #[cfg(any(feature = "wayland", feature = "x11"))]
 pub(crate) use text_system::*;

crates/gpui/src/platform/linux/keyboard.rs 🔗

@@ -0,0 +1,21 @@
+use crate::PlatformKeyboardLayout;
+
+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 }
+    }
+}

crates/gpui/src/platform/linux/platform.rs 🔗

@@ -858,26 +858,6 @@ 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::*;

crates/gpui/src/platform/mac.rs 🔗

@@ -4,6 +4,7 @@ mod dispatcher;
 mod display;
 mod display_link;
 mod events;
+mod keyboard;
 mod screen_capture;
 
 #[cfg(not(feature = "macos-blade"))]
@@ -45,6 +46,7 @@ use std::{
 pub(crate) use dispatcher::*;
 pub(crate) use display::*;
 pub(crate) use display_link::*;
+pub(crate) use keyboard::*;
 pub(crate) use platform::*;
 pub(crate) use window::*;
 

crates/gpui/src/platform/mac/keyboard.rs 🔗

@@ -0,0 +1,49 @@
+use std::ffi::{CStr, c_void};
+
+use objc::{msg_send, runtime::Object, sel, sel_impl};
+
+use crate::PlatformKeyboardLayout;
+
+use super::{
+    TISCopyCurrentKeyboardLayoutInputSource, TISGetInputSourceProperty, kTISPropertyInputSourceID,
+    kTISPropertyLocalizedName,
+};
+
+pub(crate) struct MacKeyboardLayout {
+    id: String,
+    name: String,
+}
+
+impl PlatformKeyboardLayout for MacKeyboardLayout {
+    fn id(&self) -> &str {
+        &self.id
+    }
+
+    fn name(&self) -> &str {
+        &self.name
+    }
+}
+
+impl MacKeyboardLayout {
+    pub(crate) fn new() -> Self {
+        unsafe {
+            let current_keyboard = TISCopyCurrentKeyboardLayoutInputSource();
+
+            let id: *mut Object = TISGetInputSourceProperty(
+                current_keyboard,
+                kTISPropertyInputSourceID as *const c_void,
+            );
+            let id: *const std::os::raw::c_char = msg_send![id, UTF8String];
+            let id = CStr::from_ptr(id).to_str().unwrap().to_string();
+
+            let name: *mut Object = TISGetInputSourceProperty(
+                current_keyboard,
+                kTISPropertyLocalizedName as *const c_void,
+            );
+            let name: *const std::os::raw::c_char = msg_send![name, UTF8String];
+            let name = CStr::from_ptr(name).to_str().unwrap().to_string();
+
+            Self { id, name }
+        }
+    }
+}

crates/gpui/src/platform/mac/platform.rs 🔗

@@ -1,5 +1,5 @@
 use super::{
-    BoolExt,
+    BoolExt, MacKeyboardLayout,
     attributed_string::{NSAttributedString, NSMutableAttributedString},
     events::key_to_native,
     is_macos_version_at_least, renderer, screen_capture,
@@ -1579,45 +1579,6 @@ impl UTType {
     }
 }
 
-struct MacKeyboardLayout {
-    id: String,
-    name: String,
-}
-
-impl PlatformKeyboardLayout for MacKeyboardLayout {
-    fn id(&self) -> &str {
-        &self.id
-    }
-
-    fn name(&self) -> &str {
-        &self.name
-    }
-}
-
-impl MacKeyboardLayout {
-    fn new() -> Self {
-        unsafe {
-            let current_keyboard = TISCopyCurrentKeyboardLayoutInputSource();
-
-            let id: *mut Object = TISGetInputSourceProperty(
-                current_keyboard,
-                kTISPropertyInputSourceID as *const c_void,
-            );
-            let id: *const std::os::raw::c_char = msg_send![id, UTF8String];
-            let id = CStr::from_ptr(id).to_str().unwrap().to_string();
-
-            let name: *mut Object = TISGetInputSourceProperty(
-                current_keyboard,
-                kTISPropertyLocalizedName as *const c_void,
-            );
-            let name: *const std::os::raw::c_char = msg_send![name, UTF8String];
-            let name = CStr::from_ptr(name).to_str().unwrap().to_string();
-
-            Self { id, name }
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use crate::ClipboardItem;

crates/gpui/src/platform/windows.rs 🔗

@@ -4,6 +4,7 @@ mod direct_write;
 mod dispatcher;
 mod display;
 mod events;
+mod keyboard;
 mod platform;
 mod system_settings;
 mod util;
@@ -16,6 +17,7 @@ pub(crate) use direct_write::*;
 pub(crate) use dispatcher::*;
 pub(crate) use display::*;
 pub(crate) use events::*;
+pub(crate) use keyboard::*;
 pub(crate) use platform::*;
 pub(crate) use system_settings::*;
 pub(crate) use util::*;

crates/gpui/src/platform/windows/keyboard.rs 🔗

@@ -0,0 +1,43 @@
+use anyhow::Result;
+use windows::Win32::UI::{
+    Input::KeyboardAndMouse::GetKeyboardLayoutNameW, WindowsAndMessaging::KL_NAMELENGTH,
+};
+use windows_core::HSTRING;
+
+use crate::PlatformKeyboardLayout;
+
+pub(crate) struct WindowsKeyboardLayout {
+    id: String,
+    name: String,
+}
+
+impl PlatformKeyboardLayout for WindowsKeyboardLayout {
+    fn id(&self) -> &str {
+        &self.id
+    }
+
+    fn name(&self) -> &str {
+        &self.name
+    }
+}
+
+impl WindowsKeyboardLayout {
+    pub(crate) fn new() -> Result<Self> {
+        let mut buffer = [0u16; KL_NAMELENGTH as usize];
+        unsafe { GetKeyboardLayoutNameW(&mut buffer)? };
+        let id = HSTRING::from_wide(&buffer).to_string();
+        let entry = windows_registry::LOCAL_MACHINE.open(format!(
+            "System\\CurrentControlSet\\Control\\Keyboard Layouts\\{}",
+            id
+        ))?;
+        let name = entry.get_hstring("Layout Text")?.to_string();
+        Ok(Self { id, name })
+    }
+
+    pub(crate) fn unknown() -> Self {
+        Self {
+            id: "unknown".to_string(),
+            name: "unknown".to_string(),
+        }
+    }
+}

crates/gpui/src/platform/windows/platform.rs 🔗

@@ -299,9 +299,9 @@ impl Platform for WindowsPlatform {
 
     fn keyboard_layout(&self) -> Box<dyn PlatformKeyboardLayout> {
         Box::new(
-            KeyboardLayout::new()
+            WindowsKeyboardLayout::new()
                 .log_err()
-                .unwrap_or(KeyboardLayout::unknown()),
+                .unwrap_or(WindowsKeyboardLayout::unknown()),
         )
     }
 
@@ -840,42 +840,6 @@ fn should_auto_hide_scrollbars() -> Result<bool> {
     Ok(ui_settings.AutoHideScrollBars()?)
 }
 
-struct KeyboardLayout {
-    id: String,
-    name: String,
-}
-
-impl PlatformKeyboardLayout for KeyboardLayout {
-    fn id(&self) -> &str {
-        &self.id
-    }
-
-    fn name(&self) -> &str {
-        &self.name
-    }
-}
-
-impl KeyboardLayout {
-    fn new() -> Result<Self> {
-        let mut buffer = [0u16; KL_NAMELENGTH as usize];
-        unsafe { GetKeyboardLayoutNameW(&mut buffer)? };
-        let id = HSTRING::from_wide(&buffer).to_string();
-        let entry = windows_registry::LOCAL_MACHINE.open(format!(
-            "System\\CurrentControlSet\\Control\\Keyboard Layouts\\{}",
-            id
-        ))?;
-        let name = entry.get_hstring("Layout Text")?.to_string();
-        Ok(Self { id, name })
-    }
-
-    fn unknown() -> Self {
-        Self {
-            id: "unknown".to_string(),
-            name: "unknown".to_string(),
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use crate::{ClipboardItem, read_from_clipboard, write_to_clipboard};