Skip to content

Commit 2c7d4ca

Browse files
committed
Fix macOS Option character input
1 parent b9b82fb commit 2c7d4ca

5 files changed

Lines changed: 61 additions & 10 deletions

File tree

‎crates/icy_draw/src/window_manager.rs‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -996,9 +996,14 @@ impl WindowManager {
996996
Event::Mouse(icy_ui::mouse::Event::ButtonPressed { .. }) => Some(WindowManagerMessage::Event(window_id, event)),
997997
Event::Mouse(_) => None,
998998
// Keyboard events are handled below
999-
Event::Keyboard(keyboard::Event::KeyPressed { key, modifiers, .. }) => {
999+
Event::Keyboard(keyboard::Event::KeyPressed {
1000+
key,
1001+
modified_key,
1002+
modifiers,
1003+
..
1004+
}) => {
10001005
// Handle window manager keyboard shortcuts (Tab, Alt+Number, etc.)
1001-
if let Some(action) = icy_engine_gui::handle_window_manager_keyboard_press(key, modifiers) {
1006+
if let Some(action) = icy_engine_gui::handle_window_manager_keyboard_press(key, modified_key, modifiers) {
10021007
use icy_engine_gui::KeyboardAction;
10031008
return match action {
10041009
KeyboardAction::FocusWindow(target_id) => Some(WindowManagerMessage::FocusWindow(target_id)),

‎crates/icy_engine_gui/src/ui/window_manager.rs‎

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,14 @@ pub enum KeyboardAction {
265265
/// Window IDs: 1-9 map to windows 1-9, 0 maps to window 10.
266266
///
267267
/// Note: Uses Alt on all platforms. On macOS, Cmd is also accepted (without Ctrl).
268-
pub fn handle_window_manager_keyboard_press(key: &icy_ui::keyboard::Key, modifiers: &icy_ui::keyboard::Modifiers) -> Option<KeyboardAction> {
268+
/// `modified_key` must include the current keyboard layout and modifiers. This
269+
/// prevents Option+number combinations that produce punctuation on macOS from
270+
/// being mistaken for window shortcuts.
271+
pub fn handle_window_manager_keyboard_press(
272+
key: &icy_ui::keyboard::Key,
273+
modified_key: &icy_ui::keyboard::Key,
274+
modifiers: &icy_ui::keyboard::Modifiers,
275+
) -> Option<KeyboardAction> {
269276
use icy_ui::keyboard::key::Named;
270277

271278
// Handle Tab / Shift+Tab for focus navigation
@@ -283,7 +290,7 @@ pub fn handle_window_manager_keyboard_press(key: &icy_ui::keyboard::Key, modifie
283290
let is_alt_or_cmd = modifiers.alt() || (modifiers.command() && !modifiers.control());
284291

285292
if is_alt_or_cmd && !modifiers.shift() {
286-
if let icy_ui::keyboard::Key::Character(s) = key {
293+
if let icy_ui::keyboard::Key::Character(s) = modified_key {
287294
if let Some(digit) = s.chars().next() {
288295
if digit.is_ascii_digit() {
289296
let target_id = digit.to_digit(10).unwrap() as usize;
@@ -296,3 +303,34 @@ pub fn handle_window_manager_keyboard_press(key: &icy_ui::keyboard::Key, modifie
296303
}
297304
None
298305
}
306+
307+
#[cfg(test)]
308+
mod tests {
309+
use super::{handle_window_manager_keyboard_press, KeyboardAction};
310+
use icy_ui::keyboard::{Key, Modifiers};
311+
312+
#[test]
313+
fn alt_digit_focuses_window() {
314+
let key = Key::Character("5".into());
315+
assert_eq!(
316+
handle_window_manager_keyboard_press(&key, &key, &Modifiers::ALT),
317+
Some(KeyboardAction::FocusWindow(5))
318+
);
319+
}
320+
321+
#[test]
322+
fn option_generated_characters_are_not_window_shortcuts() {
323+
for (unmodified, modified, modifiers) in [
324+
("5", "[", Modifiers::ALT),
325+
("6", "]", Modifiers::ALT),
326+
("7", "|", Modifiers::ALT),
327+
("8", "{", Modifiers::ALT),
328+
("9", "}", Modifiers::ALT),
329+
("7", "\\", Modifiers::ALT | Modifiers::SHIFT),
330+
] {
331+
let unmodified_key = Key::Character(unmodified.into());
332+
let modified_key = Key::Character(modified.into());
333+
assert_eq!(handle_window_manager_keyboard_press(&unmodified_key, &modified_key, &modifiers), None);
334+
}
335+
}
336+
}

‎crates/icy_mail/src/ui/window_manager.rs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,13 +167,16 @@ impl WindowManager {
167167
window::close_events().map(WindowManagerMessage::WindowClosed),
168168
icy_ui::event::listen_with(|event, status, window_id| {
169169
let captured = matches!(status, icy_ui::event::Status::Captured);
170-
if let Event::Keyboard(keyboard::Event::KeyPressed { key, modifiers, .. }) = &event {
170+
if let Event::Keyboard(keyboard::Event::KeyPressed {
171+
key, modified_key, modifiers, ..
172+
}) = &event
173+
{
171174
// Tab cycles our own panes unless a text widget has focus and used it.
172175
let tab_owned_by_window = matches!(key, keyboard::Key::Named(keyboard::key::Named::Tab)) && !captured;
173176

174177
// Handle window manager keyboard shortcuts (Tab, Alt+Number, etc.)
175178
if !tab_owned_by_window {
176-
if let Some(action) = handle_window_manager_keyboard_press(key, modifiers) {
179+
if let Some(action) = handle_window_manager_keyboard_press(key, modified_key, modifiers) {
177180
return match action {
178181
KeyboardAction::FocusWindow(target_id) => Some(WindowManagerMessage::FocusWindow(target_id)),
179182
KeyboardAction::FocusNext => Some(WindowManagerMessage::FocusNext),

‎crates/icy_term/src/ui/window_manager.rs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,12 @@ impl WindowManager {
259259

260260
if !is_tab_in_terminal {
261261
// Handle Alt+Number window switching
262-
if let Event::Keyboard(keyboard::Event::KeyPressed { key, modifiers, .. }) = &event {
262+
if let Event::Keyboard(keyboard::Event::KeyPressed {
263+
key, modified_key, modifiers, ..
264+
}) = &event
265+
{
263266
if let Some(icy_engine_gui::KeyboardAction::FocusWindow(target_id)) =
264-
icy_engine_gui::handle_window_manager_keyboard_press(key, modifiers)
267+
icy_engine_gui::handle_window_manager_keyboard_press(key, modified_key, modifiers)
265268
{
266269
return Task::done(WindowManagerMessage::FocusWindow(target_id));
267270
}

‎crates/icy_view/src/window_manager.rs‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,11 @@ impl WindowManager {
246246
// Skip other mouse events.
247247
Event::Mouse(_) => None,
248248

249-
Event::Keyboard(keyboard::Event::KeyPressed { key, modifiers, .. }) => {
249+
Event::Keyboard(keyboard::Event::KeyPressed {
250+
key, modified_key, modifiers, ..
251+
}) => {
250252
// Handle window manager keyboard shortcuts (Tab, Alt+Number, etc.)
251-
if let Some(action) = icy_engine_gui::handle_window_manager_keyboard_press(key, modifiers) {
253+
if let Some(action) = icy_engine_gui::handle_window_manager_keyboard_press(key, modified_key, modifiers) {
252254
use icy_engine_gui::KeyboardAction;
253255
return match action {
254256
KeyboardAction::FocusWindow(target_id) => Some(WindowManagerMessage::FocusWindow(target_id)),

0 commit comments

Comments
 (0)