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.
This commit is contained in:
Mads Marquart 2024-12-03 18:48:23 +01:00 committed by GitHub
parent 3657506f6e
commit f314cd2b9a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 38 additions and 33 deletions

View file

@ -21,13 +21,13 @@ use super::app_state::AppState;
use super::cursor::{default_cursor, invisible_cursor};
use super::event::{
code_to_key, code_to_location, create_key_event, event_mods, lalt_pressed, ralt_pressed,
scancode_to_physicalkey,
scancode_to_physicalkey, KeyEventExtra,
};
use super::window::WinitWindow;
use crate::dpi::{LogicalPosition, LogicalSize};
use crate::event::{
DeviceEvent, ElementState, Ime, Modifiers, MouseButton, MouseScrollDelta, PointerKind,
PointerSource, TouchPhase, WindowEvent,
DeviceEvent, ElementState, Ime, KeyEvent, Modifiers, MouseButton, MouseScrollDelta,
PointerKind, PointerSource, TouchPhase, WindowEvent,
};
use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState, NamedKey};
use crate::platform::macos::OptionAsAlt;
@ -490,7 +490,7 @@ declare_class!(
};
if !had_ime_input || self.ivars().forward_key_to_app.get() {
let key_event = create_key_event(&event, true, unsafe { event.isARepeat() }, None);
let key_event = create_key_event(&event, true, unsafe { event.isARepeat() });
self.queue_event(WindowEvent::KeyboardInput {
device_id: None,
event: key_event,
@ -513,7 +513,7 @@ declare_class!(
) {
self.queue_event(WindowEvent::KeyboardInput {
device_id: None,
event: create_key_event(&event, false, false, None),
event: create_key_event(&event, false, false),
is_synthetic: false,
});
}
@ -560,7 +560,7 @@ declare_class!(
.expect("could not find current event");
self.update_modifiers(&event, false);
let event = create_key_event(&event, true, unsafe { event.isARepeat() }, None);
let event = create_key_event(&event, true, unsafe { event.isARepeat() });
self.queue_event(WindowEvent::KeyboardInput {
device_id: None,
@ -946,22 +946,36 @@ impl WinitView {
let scancode = unsafe { ns_event.keyCode() };
let physical_key = scancode_to_physicalkey(scancode as u32);
// We'll correct the `is_press` later.
let mut event = create_key_event(ns_event, false, false, Some(physical_key));
let key = code_to_key(physical_key, scancode);
let logical_key = code_to_key(physical_key, scancode);
// Ignore processing of unknown modifiers because we can't determine whether
// it was pressed or release reliably.
let Some(event_modifier) = key_to_modifier(&key) else {
//
// Furthermore, sometimes normal keys are reported inside flagsChanged:, such as
// when holding Caps Lock while pressing another key, see:
// https://github.com/alacritty/alacritty/issues/8268
let Some(event_modifier) = key_to_modifier(&logical_key) else {
break 'send_event;
};
event.physical_key = physical_key;
event.logical_key = key.clone();
event.location = code_to_location(physical_key);
let mut event = KeyEvent {
location: code_to_location(physical_key),
logical_key: logical_key.clone(),
physical_key,
repeat: false,
// We'll correct this later.
state: Pressed,
text: None,
platform_specific: KeyEventExtra {
text_with_all_modifiers: None,
key_without_modifiers: logical_key.clone(),
},
};
let location_mask = ModLocationMask::from_location(event.location);
let mut phys_mod_state = self.ivars().phys_modifiers.borrow_mut();
let phys_mod = phys_mod_state.entry(key).or_insert(ModLocationMask::empty());
let phys_mod =
phys_mod_state.entry(logical_key).or_insert(ModLocationMask::empty());
let is_active = current_modifiers.state().contains(event_modifier);
let mut events = VecDeque::with_capacity(2);