On macOS, fix assertion when pressing Fn key
This commit is contained in:
parent
14140607d1
commit
7bed5eecfd
3 changed files with 95 additions and 91 deletions
|
|
@ -16,6 +16,7 @@ Unreleased` header.
|
||||||
- On Windows, fix `set_control_flow` in `AboutToWait` not being taken in account.
|
- On Windows, fix `set_control_flow` in `AboutToWait` not being taken in account.
|
||||||
- On macOS, send a `Resized` event after each `ScaleFactorChanged` event.
|
- On macOS, send a `Resized` event after each `ScaleFactorChanged` event.
|
||||||
- On Wayland, fix `wl_surface` being destroyed before associated objects.
|
- On Wayland, fix `wl_surface` being destroyed before associated objects.
|
||||||
|
- On macOS, fix assertion when pressing `Fn` key.
|
||||||
|
|
||||||
# 0.29.3
|
# 0.29.3
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -156,13 +156,11 @@ pub(crate) fn create_key_event(
|
||||||
// Also not checking if this is a release event because then this issue would
|
// Also not checking if this is a release event because then this issue would
|
||||||
// still affect the key release.
|
// still affect the key release.
|
||||||
Some(text) if !has_ctrl => Key::Character(text.clone()),
|
Some(text) if !has_ctrl => Key::Character(text.clone()),
|
||||||
_ => {
|
_ => match key_without_modifiers.as_ref() {
|
||||||
let modifierless_chars = match key_without_modifiers.as_ref() {
|
Key::Character(ch) => get_logical_key_char(ns_event, ch),
|
||||||
Key::Character(ch) => ch,
|
// Don't try to get text for events which likely don't have it.
|
||||||
_ => "",
|
_ => key_without_modifiers.clone(),
|
||||||
};
|
},
|
||||||
get_logical_key_char(ns_event, modifierless_chars)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
(logical_key, key_without_modifiers)
|
(logical_key, key_without_modifiers)
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,8 @@ enum ImeState {
|
||||||
bitflags! {
|
bitflags! {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
struct ModLocationMask: u8 {
|
struct ModLocationMask: u8 {
|
||||||
const LEFT = 1;
|
const LEFT = 0b0001;
|
||||||
const RIGHT = 2;
|
const RIGHT = 0b0010;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ModLocationMask {
|
impl ModLocationMask {
|
||||||
|
|
@ -88,13 +88,13 @@ impl ModLocationMask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key_to_modifier(key: &Key) -> ModifiersState {
|
fn key_to_modifier(key: &Key) -> Option<ModifiersState> {
|
||||||
match key {
|
match key {
|
||||||
Key::Named(NamedKey::Alt) => ModifiersState::ALT,
|
Key::Named(NamedKey::Alt) => Some(ModifiersState::ALT),
|
||||||
Key::Named(NamedKey::Control) => ModifiersState::CONTROL,
|
Key::Named(NamedKey::Control) => Some(ModifiersState::CONTROL),
|
||||||
Key::Named(NamedKey::Super) => ModifiersState::SUPER,
|
Key::Named(NamedKey::Super) => Some(ModifiersState::SUPER),
|
||||||
Key::Named(NamedKey::Shift) => ModifiersState::SHIFT,
|
Key::Named(NamedKey::Shift) => Some(ModifiersState::SHIFT),
|
||||||
_ => unreachable!(),
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -924,91 +924,96 @@ impl WinitView {
|
||||||
// event, thus we can't generate regular presses based on that. The `ModifiersChanged`
|
// event, thus we can't generate regular presses based on that. The `ModifiersChanged`
|
||||||
// later will work though, since the flags are attached to the event and contain valid
|
// later will work though, since the flags are attached to the event and contain valid
|
||||||
// information.
|
// information.
|
||||||
if is_flags_changed_event && ns_event.key_code() != 0 {
|
'send_event: {
|
||||||
let scancode = ns_event.key_code();
|
if is_flags_changed_event && ns_event.key_code() != 0 {
|
||||||
let physical_key = PhysicalKey::from_scancode(scancode as u32);
|
let scancode = ns_event.key_code();
|
||||||
|
let physical_key = PhysicalKey::from_scancode(scancode as u32);
|
||||||
|
|
||||||
// We'll correct the `is_press` later.
|
// We'll correct the `is_press` later.
|
||||||
let mut event = create_key_event(ns_event, false, false, Some(physical_key));
|
let mut event = create_key_event(ns_event, false, false, Some(physical_key));
|
||||||
|
|
||||||
let key = code_to_key(physical_key, scancode);
|
let key = code_to_key(physical_key, scancode);
|
||||||
let event_modifier = key_to_modifier(&key);
|
// Ignore processing of unkown modifiers because we can't determine whether
|
||||||
event.physical_key = physical_key;
|
// it was pressed or release reliably.
|
||||||
event.logical_key = key.clone();
|
let Some(event_modifier) = key_to_modifier(&key) else {
|
||||||
event.location = code_to_location(physical_key);
|
break 'send_event;
|
||||||
let location_mask = ModLocationMask::from_location(event.location);
|
};
|
||||||
|
event.physical_key = physical_key;
|
||||||
|
event.logical_key = key.clone();
|
||||||
|
event.location = code_to_location(physical_key);
|
||||||
|
let location_mask = ModLocationMask::from_location(event.location);
|
||||||
|
|
||||||
let mut phys_mod_state = self.state.phys_modifiers.borrow_mut();
|
let mut phys_mod_state = self.state.phys_modifiers.borrow_mut();
|
||||||
let phys_mod = phys_mod_state
|
let phys_mod = phys_mod_state
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert(ModLocationMask::empty());
|
.or_insert(ModLocationMask::empty());
|
||||||
|
|
||||||
let is_active = current_modifiers.state().contains(event_modifier);
|
let is_active = current_modifiers.state().contains(event_modifier);
|
||||||
let mut events = VecDeque::with_capacity(2);
|
let mut events = VecDeque::with_capacity(2);
|
||||||
|
|
||||||
// There is no API for getting whether the button was pressed or released
|
// There is no API for getting whether the button was pressed or released
|
||||||
// during this event. For this reason we have to do a bit of magic below
|
// during this event. For this reason we have to do a bit of magic below
|
||||||
// to come up with a good guess whether this key was pressed or released.
|
// to come up with a good guess whether this key was pressed or released.
|
||||||
// (This is not trivial because there are multiple buttons that may affect
|
// (This is not trivial because there are multiple buttons that may affect
|
||||||
// the same modifier)
|
// the same modifier)
|
||||||
if !is_active {
|
if !is_active {
|
||||||
event.state = Released;
|
event.state = Released;
|
||||||
if phys_mod.contains(ModLocationMask::LEFT) {
|
if phys_mod.contains(ModLocationMask::LEFT) {
|
||||||
let mut event = event.clone();
|
let mut event = event.clone();
|
||||||
event.location = KeyLocation::Left;
|
event.location = KeyLocation::Left;
|
||||||
event.physical_key = get_left_modifier_code(&event.logical_key).into();
|
event.physical_key = get_left_modifier_code(&event.logical_key).into();
|
||||||
events.push_back(WindowEvent::KeyboardInput {
|
events.push_back(WindowEvent::KeyboardInput {
|
||||||
device_id: DEVICE_ID,
|
device_id: DEVICE_ID,
|
||||||
event,
|
event,
|
||||||
is_synthetic: false,
|
is_synthetic: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if phys_mod.contains(ModLocationMask::RIGHT) {
|
if phys_mod.contains(ModLocationMask::RIGHT) {
|
||||||
event.location = KeyLocation::Right;
|
event.location = KeyLocation::Right;
|
||||||
event.physical_key = get_right_modifier_code(&event.logical_key).into();
|
event.physical_key = get_right_modifier_code(&event.logical_key).into();
|
||||||
events.push_back(WindowEvent::KeyboardInput {
|
events.push_back(WindowEvent::KeyboardInput {
|
||||||
device_id: DEVICE_ID,
|
device_id: DEVICE_ID,
|
||||||
event,
|
event,
|
||||||
is_synthetic: false,
|
is_synthetic: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
*phys_mod = ModLocationMask::empty();
|
*phys_mod = ModLocationMask::empty();
|
||||||
} else {
|
|
||||||
// is_active
|
|
||||||
if *phys_mod == location_mask {
|
|
||||||
// Here we hit a contradiction:
|
|
||||||
// The modifier state was "changed" to active,
|
|
||||||
// yet the only pressed modifier key was the one that we
|
|
||||||
// just got a change event for.
|
|
||||||
// This seemingly means that the only pressed modifier is now released,
|
|
||||||
// but at the same time the modifier became active.
|
|
||||||
//
|
|
||||||
// But this scenario is possible if we released modifiers
|
|
||||||
// while the application was not in focus. (Because we don't
|
|
||||||
// get informed of modifier key events while the application
|
|
||||||
// is not focused)
|
|
||||||
|
|
||||||
// In this case we prioritize the information
|
|
||||||
// about the current modifier state which means
|
|
||||||
// that the button was pressed.
|
|
||||||
event.state = Pressed;
|
|
||||||
} else {
|
} else {
|
||||||
phys_mod.toggle(location_mask);
|
if *phys_mod == location_mask {
|
||||||
let is_pressed = phys_mod.contains(location_mask);
|
// Here we hit a contradiction:
|
||||||
event.state = if is_pressed { Pressed } else { Released };
|
// The modifier state was "changed" to active,
|
||||||
|
// yet the only pressed modifier key was the one that we
|
||||||
|
// just got a change event for.
|
||||||
|
// This seemingly means that the only pressed modifier is now released,
|
||||||
|
// but at the same time the modifier became active.
|
||||||
|
//
|
||||||
|
// But this scenario is possible if we released modifiers
|
||||||
|
// while the application was not in focus. (Because we don't
|
||||||
|
// get informed of modifier key events while the application
|
||||||
|
// is not focused)
|
||||||
|
|
||||||
|
// In this case we prioritize the information
|
||||||
|
// about the current modifier state which means
|
||||||
|
// that the button was pressed.
|
||||||
|
event.state = Pressed;
|
||||||
|
} else {
|
||||||
|
phys_mod.toggle(location_mask);
|
||||||
|
let is_pressed = phys_mod.contains(location_mask);
|
||||||
|
event.state = if is_pressed { Pressed } else { Released };
|
||||||
|
}
|
||||||
|
|
||||||
|
events.push_back(WindowEvent::KeyboardInput {
|
||||||
|
device_id: DEVICE_ID,
|
||||||
|
event,
|
||||||
|
is_synthetic: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
events.push_back(WindowEvent::KeyboardInput {
|
drop(phys_mod_state);
|
||||||
device_id: DEVICE_ID,
|
|
||||||
event,
|
|
||||||
is_synthetic: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
drop(phys_mod_state);
|
for event in events {
|
||||||
|
self.queue_event(event);
|
||||||
for event in events {
|
}
|
||||||
self.queue_event(event);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue