Skip to content

Commit 1fb1180

Browse files
madsmtmkchibisov
authored andcommitted
macOS: Fix crash when pressing Caps Lock (#4024)
Events emitted by `flagsChanged:` cannot access `charactersIgnoringModifiers`. We were previously doing this because we were trying to re-use the `create_key_event` function, but that is unsuited for this purpose, so I have separated the `flagsChanged:` logic out from it.
1 parent d6ab3dc commit 1fb1180

File tree

3 files changed

+37
-32
lines changed

3 files changed

+37
-32
lines changed

src/changelog/unreleased.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,4 @@ changelog entry.
6060
- On X11, creating windows on screen that is not the first one (e.g. `DISPLAY=:0.1`) works again.
6161
- On X11, creating windows while passing `with_x11_screen(non_default_screen)` works again.
6262
- On X11, fix XInput handling that prevented a new window from getting the focus in some cases.
63+
- On macOS, fix crash when pressing Caps Lock in certain configurations.

src/platform_impl/macos/event.rs

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,12 @@ fn get_logical_key_char(ns_event: &NSEvent, modifierless_chars: &str) -> Key {
9292
/// Create `KeyEvent` for the given `NSEvent`.
9393
///
9494
/// This function shouldn't be called when the IME input is in process.
95-
pub(crate) fn create_key_event(
96-
ns_event: &NSEvent,
97-
is_press: bool,
98-
is_repeat: bool,
99-
key_override: Option<PhysicalKey>,
100-
) -> KeyEvent {
95+
pub(crate) fn create_key_event(ns_event: &NSEvent, is_press: bool, is_repeat: bool) -> KeyEvent {
10196
use ElementState::{Pressed, Released};
10297
let state = if is_press { Pressed } else { Released };
10398

10499
let scancode = unsafe { ns_event.keyCode() };
105-
let mut physical_key = key_override.unwrap_or_else(|| scancode_to_physicalkey(scancode as u32));
100+
let mut physical_key = scancode_to_physicalkey(scancode as u32);
106101

107102
// NOTE: The logical key should heed both SHIFT and ALT if possible.
108103
// For instance:
@@ -111,20 +106,15 @@ pub(crate) fn create_key_event(
111106
// * Pressing CTRL SHIFT A: logical key should also be "A"
112107
// This is not easy to tease out of `NSEvent`, but we do our best.
113108

114-
let text_with_all_modifiers: Option<SmolStr> = if key_override.is_some() {
109+
let characters = unsafe { ns_event.characters() }.map(|s| s.to_string()).unwrap_or_default();
110+
let text_with_all_modifiers = if characters.is_empty() {
115111
None
116112
} else {
117-
let characters =
118-
unsafe { ns_event.characters() }.map(|s| s.to_string()).unwrap_or_default();
119-
if characters.is_empty() {
120-
None
121-
} else {
122-
if matches!(physical_key, PhysicalKey::Unidentified(_)) {
123-
// The key may be one of the funky function keys
124-
physical_key = extra_function_key_to_code(scancode, &characters);
125-
}
126-
Some(SmolStr::new(characters))
113+
if matches!(physical_key, PhysicalKey::Unidentified(_)) {
114+
// The key may be one of the funky function keys
115+
physical_key = extra_function_key_to_code(scancode, &characters);
127116
}
117+
Some(SmolStr::new(characters))
128118
};
129119

130120
let key_from_code = code_to_key(physical_key, scancode);

src/platform_impl/macos/view.rs

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ use super::app_state::ApplicationDelegate;
2020
use super::cursor::{default_cursor, invisible_cursor};
2121
use super::event::{
2222
code_to_key, code_to_location, create_key_event, event_mods, lalt_pressed, ralt_pressed,
23-
scancode_to_physicalkey,
23+
scancode_to_physicalkey, KeyEventExtra,
2424
};
2525
use super::window::WinitWindow;
2626
use super::DEVICE_ID;
2727
use crate::dpi::{LogicalPosition, LogicalSize};
2828
use crate::event::{
29-
DeviceEvent, ElementState, Ime, Modifiers, MouseButton, MouseScrollDelta, TouchPhase,
29+
DeviceEvent, ElementState, Ime, KeyEvent, Modifiers, MouseButton, MouseScrollDelta, TouchPhase,
3030
WindowEvent,
3131
};
3232
use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState, NamedKey};
@@ -482,7 +482,7 @@ declare_class!(
482482
};
483483

484484
if !had_ime_input || self.ivars().forward_key_to_app.get() {
485-
let key_event = create_key_event(&event, true, unsafe { event.isARepeat() }, None);
485+
let key_event = create_key_event(&event, true, unsafe { event.isARepeat() });
486486
self.queue_event(WindowEvent::KeyboardInput {
487487
device_id: DEVICE_ID,
488488
event: key_event,
@@ -505,7 +505,7 @@ declare_class!(
505505
) {
506506
self.queue_event(WindowEvent::KeyboardInput {
507507
device_id: DEVICE_ID,
508-
event: create_key_event(&event, false, false, None),
508+
event: create_key_event(&event, false, false),
509509
is_synthetic: false,
510510
});
511511
}
@@ -552,7 +552,7 @@ declare_class!(
552552
.expect("could not find current event");
553553

554554
self.update_modifiers(&event, false);
555-
let event = create_key_event(&event, true, unsafe { event.isARepeat() }, None);
555+
let event = create_key_event(&event, true, unsafe { event.isARepeat() });
556556

557557
self.queue_event(WindowEvent::KeyboardInput {
558558
device_id: DEVICE_ID,
@@ -933,22 +933,36 @@ impl WinitView {
933933
let scancode = unsafe { ns_event.keyCode() };
934934
let physical_key = scancode_to_physicalkey(scancode as u32);
935935

936-
// We'll correct the `is_press` later.
937-
let mut event = create_key_event(ns_event, false, false, Some(physical_key));
938-
939-
let key = code_to_key(physical_key, scancode);
936+
let logical_key = code_to_key(physical_key, scancode);
940937
// Ignore processing of unknown modifiers because we can't determine whether
941938
// it was pressed or release reliably.
942-
let Some(event_modifier) = key_to_modifier(&key) else {
939+
//
940+
// Furthermore, sometimes normal keys are reported inside flagsChanged:, such as
941+
// when holding Caps Lock while pressing another key, see:
942+
// https://github.com/alacritty/alacritty/issues/8268
943+
let Some(event_modifier) = key_to_modifier(&logical_key) else {
943944
break 'send_event;
944945
};
945-
event.physical_key = physical_key;
946-
event.logical_key = key.clone();
947-
event.location = code_to_location(physical_key);
946+
947+
let mut event = KeyEvent {
948+
location: code_to_location(physical_key),
949+
logical_key: logical_key.clone(),
950+
physical_key,
951+
repeat: false,
952+
// We'll correct this later.
953+
state: Pressed,
954+
text: None,
955+
platform_specific: KeyEventExtra {
956+
text_with_all_modifiers: None,
957+
key_without_modifiers: logical_key.clone(),
958+
},
959+
};
960+
948961
let location_mask = ModLocationMask::from_location(event.location);
949962

950963
let mut phys_mod_state = self.ivars().phys_modifiers.borrow_mut();
951-
let phys_mod = phys_mod_state.entry(key).or_insert(ModLocationMask::empty());
964+
let phys_mod =
965+
phys_mod_state.entry(logical_key).or_insert(ModLocationMask::empty());
952966

953967
let is_active = current_modifiers.state().contains(event_modifier);
954968
let mut events = VecDeque::with_capacity(2);

0 commit comments

Comments
 (0)