From bd48946b02268cb5a7ae932e388abfa75fe9e375 Mon Sep 17 00:00:00 2001 From: BradySimon Date: Fri, 8 Mar 2024 09:35:43 -0500 Subject: [PATCH 1/3] Add Command + ArrowLeft/Right input behavior for macos --- widget/src/text_editor.rs | 37 +++++++++++++++--- widget/src/text_input.rs | 81 +++++++++++++++++++++++++++++---------- 2 files changed, 92 insertions(+), 26 deletions(-) diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index 7c0b98ea6d..3b6647e444 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -767,7 +767,7 @@ impl Update { } if let keyboard::Key::Named(named_key) = key.as_ref() { - if let Some(motion) = motion(named_key) { + if let Some(motion) = motion(named_key, modifiers) { let motion = if platform::is_jump_modifier_pressed( modifiers, ) { @@ -793,14 +793,26 @@ impl Update { } } -fn motion(key: key::Named) -> Option { +fn motion(key: key::Named, modifiers: keyboard::Modifiers) -> Option { match key { - key::Named::ArrowLeft => Some(Motion::Left), - key::Named::ArrowRight => Some(Motion::Right), - key::Named::ArrowUp => Some(Motion::Up), - key::Named::ArrowDown => Some(Motion::Down), key::Named::Home => Some(Motion::Home), key::Named::End => Some(Motion::End), + key::Named::ArrowLeft => { + if platform::is_macos_command_pressed(modifiers) { + Some(Motion::Home) + } else { + Some(Motion::Left) + } + } + key::Named::ArrowRight => { + if platform::is_macos_command_pressed(modifiers) { + Some(Motion::End) + } else { + Some(Motion::Right) + } + } + key::Named::ArrowUp => Some(Motion::Up), + key::Named::ArrowDown => Some(Motion::Down), key::Named::PageUp => Some(Motion::PageUp), key::Named::PageDown => Some(Motion::PageDown), _ => None, @@ -817,6 +829,19 @@ mod platform { modifiers.control() } } + + /// Whether the command key is pressed on a macOS device. + /// + /// This is relevant for actions like ⌘ + ArrowLeft to move to the beginning of the + /// line where the equivalent behavior for `modifiers.command()` is instead a jump on + /// other platforms. + pub fn is_macos_command_pressed(modifiers: keyboard::Modifiers) -> bool { + if cfg!(target_os = "macos") { + modifiers.logo() + } else { + false + } + } } /// The possible status of a [`TextEditor`]. diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs index e9f0783876..2c951c12a0 100644 --- a/widget/src/text_input.rs +++ b/widget/src/text_input.rs @@ -876,6 +876,54 @@ where update_cache(state, &self.value); } + keyboard::Key::Named(key::Named::Home) => { + if modifiers.shift() { + state.cursor.select_range( + state.cursor.start(&self.value), + 0, + ); + } else { + state.cursor.move_to(0); + } + } + keyboard::Key::Named(key::Named::End) => { + if modifiers.shift() { + state.cursor.select_range( + state.cursor.start(&self.value), + self.value.len(), + ); + } else { + state.cursor.move_to(self.value.len()); + } + } + keyboard::Key::Named(key::Named::ArrowLeft) + if platform::is_macos_command_pressed( + modifiers, + ) => + { + if modifiers.shift() { + state.cursor.select_range( + state.cursor.start(&self.value), + 0, + ); + } else { + state.cursor.move_to(0); + } + } + keyboard::Key::Named(key::Named::ArrowRight) + if platform::is_macos_command_pressed( + modifiers, + ) => + { + if modifiers.shift() { + state.cursor.select_range( + state.cursor.start(&self.value), + self.value.len(), + ); + } else { + state.cursor.move_to(self.value.len()); + } + } keyboard::Key::Named(key::Named::ArrowLeft) => { if platform::is_jump_modifier_pressed(modifiers) && !self.is_secure @@ -914,26 +962,6 @@ where state.cursor.move_right(&self.value); } } - keyboard::Key::Named(key::Named::Home) => { - if modifiers.shift() { - state.cursor.select_range( - state.cursor.start(&self.value), - 0, - ); - } else { - state.cursor.move_to(0); - } - } - keyboard::Key::Named(key::Named::End) => { - if modifiers.shift() { - state.cursor.select_range( - state.cursor.start(&self.value), - self.value.len(), - ); - } else { - state.cursor.move_to(self.value.len()); - } - } keyboard::Key::Named(key::Named::Escape) => { state.is_focused = None; state.is_dragging = false; @@ -1291,6 +1319,19 @@ mod platform { modifiers.control() } } + + /// Whether the command key is pressed on a macOS device. + /// + /// This is relevant for actions like ⌘ + ArrowLeft to move to the beginning of the + /// line where the equivalent behavior for `modifiers.command()` is instead a jump on + /// other platforms. + pub fn is_macos_command_pressed(modifiers: keyboard::Modifiers) -> bool { + if cfg!(target_os = "macos") { + modifiers.logo() + } else { + false + } + } } fn offset( From 8cfa8149f56a0e58eb0257ebb181c69bec5c095f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 31 May 2024 16:10:59 +0200 Subject: [PATCH 2/3] Keep unary `motion` function in `text_editor` --- widget/src/text_editor.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index 3b6647e444..9e4943942c 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -767,7 +767,19 @@ impl Update { } if let keyboard::Key::Named(named_key) = key.as_ref() { - if let Some(motion) = motion(named_key, modifiers) { + if let Some(motion) = motion(named_key) { + let motion = if platform::is_macos_command_pressed( + modifiers, + ) { + match motion { + Motion::Left => Motion::Home, + Motion::Right => Motion::End, + _ => motion, + } + } else { + motion + }; + let motion = if platform::is_jump_modifier_pressed( modifiers, ) { @@ -793,26 +805,14 @@ impl Update { } } -fn motion(key: key::Named, modifiers: keyboard::Modifiers) -> Option { +fn motion(key: key::Named) -> Option { match key { - key::Named::Home => Some(Motion::Home), - key::Named::End => Some(Motion::End), - key::Named::ArrowLeft => { - if platform::is_macos_command_pressed(modifiers) { - Some(Motion::Home) - } else { - Some(Motion::Left) - } - } - key::Named::ArrowRight => { - if platform::is_macos_command_pressed(modifiers) { - Some(Motion::End) - } else { - Some(Motion::Right) - } - } + key::Named::ArrowLeft => Some(Motion::Left), + key::Named::ArrowRight => Some(Motion::Right), key::Named::ArrowUp => Some(Motion::Up), key::Named::ArrowDown => Some(Motion::Down), + key::Named::Home => Some(Motion::Home), + key::Named::End => Some(Motion::End), key::Named::PageUp => Some(Motion::PageUp), key::Named::PageDown => Some(Motion::PageDown), _ => None, From 3312dc808012e2c049fb2f178d51bfe0b4e30399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 31 May 2024 16:23:09 +0200 Subject: [PATCH 3/3] Create `jump` and `macos_command` methods in `keyboard::Modifiers` --- core/src/keyboard/modifiers.rs | 24 ++++++++++++++++++ widget/src/text_editor.rs | 33 ++----------------------- widget/src/text_input.rs | 45 +++++----------------------------- 3 files changed, 32 insertions(+), 70 deletions(-) diff --git a/core/src/keyboard/modifiers.rs b/core/src/keyboard/modifiers.rs index e531510f79..edbf6d3825 100644 --- a/core/src/keyboard/modifiers.rs +++ b/core/src/keyboard/modifiers.rs @@ -84,4 +84,28 @@ impl Modifiers { is_pressed } + + /// Returns true if the "jump key" is pressed in the [`Modifiers`]. + /// + /// The "jump key" is the modifier key used to widen text motions. It is the `Alt` + /// key in macOS and the `Ctrl` key in other platforms. + pub fn jump(self) -> bool { + if cfg!(target_os = "macos") { + self.alt() + } else { + self.control() + } + } + + /// Returns true if the "command key" is pressed on a macOS device. + /// + /// This is relevant for macOS-specific actions (e.g. `⌘ + ArrowLeft` moves the cursor + /// to the beginning of the line). + pub fn macos_command(self) -> bool { + if cfg!(target_os = "macos") { + self.logo() + } else { + false + } + } } diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index 9e4943942c..41b058afc0 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -768,9 +768,7 @@ impl Update { if let keyboard::Key::Named(named_key) = key.as_ref() { if let Some(motion) = motion(named_key) { - let motion = if platform::is_macos_command_pressed( - modifiers, - ) { + let motion = if modifiers.macos_command() { match motion { Motion::Left => Motion::Home, Motion::Right => Motion::End, @@ -780,9 +778,7 @@ impl Update { motion }; - let motion = if platform::is_jump_modifier_pressed( - modifiers, - ) { + let motion = if modifiers.jump() { motion.widen() } else { motion @@ -819,31 +815,6 @@ fn motion(key: key::Named) -> Option { } } -mod platform { - use crate::core::keyboard; - - pub fn is_jump_modifier_pressed(modifiers: keyboard::Modifiers) -> bool { - if cfg!(target_os = "macos") { - modifiers.alt() - } else { - modifiers.control() - } - } - - /// Whether the command key is pressed on a macOS device. - /// - /// This is relevant for actions like ⌘ + ArrowLeft to move to the beginning of the - /// line where the equivalent behavior for `modifiers.command()` is instead a jump on - /// other platforms. - pub fn is_macos_command_pressed(modifiers: keyboard::Modifiers) -> bool { - if cfg!(target_os = "macos") { - modifiers.logo() - } else { - false - } - } -} - /// The possible status of a [`TextEditor`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Status { diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs index 2c951c12a0..941e9bdea4 100644 --- a/widget/src/text_input.rs +++ b/widget/src/text_input.rs @@ -826,7 +826,7 @@ where } } keyboard::Key::Named(key::Named::Backspace) => { - if platform::is_jump_modifier_pressed(modifiers) + if modifiers.jump() && state.cursor.selection(&self.value).is_none() { if self.is_secure { @@ -850,7 +850,7 @@ where update_cache(state, &self.value); } keyboard::Key::Named(key::Named::Delete) => { - if platform::is_jump_modifier_pressed(modifiers) + if modifiers.jump() && state.cursor.selection(&self.value).is_none() { if self.is_secure { @@ -897,9 +897,7 @@ where } } keyboard::Key::Named(key::Named::ArrowLeft) - if platform::is_macos_command_pressed( - modifiers, - ) => + if modifiers.macos_command() => { if modifiers.shift() { state.cursor.select_range( @@ -911,9 +909,7 @@ where } } keyboard::Key::Named(key::Named::ArrowRight) - if platform::is_macos_command_pressed( - modifiers, - ) => + if modifiers.macos_command() => { if modifiers.shift() { state.cursor.select_range( @@ -925,9 +921,7 @@ where } } keyboard::Key::Named(key::Named::ArrowLeft) => { - if platform::is_jump_modifier_pressed(modifiers) - && !self.is_secure - { + if modifiers.jump() && !self.is_secure { if modifiers.shift() { state .cursor @@ -944,9 +938,7 @@ where } } keyboard::Key::Named(key::Named::ArrowRight) => { - if platform::is_jump_modifier_pressed(modifiers) - && !self.is_secure - { + if modifiers.jump() && !self.is_secure { if modifiers.shift() { state .cursor @@ -1309,31 +1301,6 @@ impl operation::TextInput for State

{ } } -mod platform { - use crate::core::keyboard; - - pub fn is_jump_modifier_pressed(modifiers: keyboard::Modifiers) -> bool { - if cfg!(target_os = "macos") { - modifiers.alt() - } else { - modifiers.control() - } - } - - /// Whether the command key is pressed on a macOS device. - /// - /// This is relevant for actions like ⌘ + ArrowLeft to move to the beginning of the - /// line where the equivalent behavior for `modifiers.command()` is instead a jump on - /// other platforms. - pub fn is_macos_command_pressed(modifiers: keyboard::Modifiers) -> bool { - if cfg!(target_os = "macos") { - modifiers.logo() - } else { - false - } - } -} - fn offset( text_bounds: Rectangle, value: &Value,