fix(core): handle AllModifiersRelease event on macOS to prevent modifier state getting out-of-sync with shortcuts. Fix #791

This commit is contained in:
Federico Terzi 2021-10-13 22:36:25 +02:00
parent 0b23a5cc30
commit 44dd54e2e1
6 changed files with 28 additions and 19 deletions

View File

@ -37,12 +37,12 @@ impl<'a> funnel::Source<'a> for DetectSource {
select.recv(&self.receiver) select.recv(&self.receiver)
} }
fn receive(&self, op: SelectedOperation) -> Event { fn receive(&self, op: SelectedOperation) -> Option<Event> {
let (input_event, source_id) = op let (input_event, source_id) = op
.recv(&self.receiver) .recv(&self.receiver)
.expect("unable to select data from DetectSource receiver"); .expect("unable to select data from DetectSource receiver");
match input_event { match input_event {
InputEvent::Keyboard(keyboard_event) => Event { InputEvent::Keyboard(keyboard_event) => Some(Event {
source_id, source_id,
etype: EventType::Keyboard(KeyboardEvent { etype: EventType::Keyboard(KeyboardEvent {
key: convert_to_engine_key(keyboard_event.key), key: convert_to_engine_key(keyboard_event.key),
@ -50,20 +50,21 @@ impl<'a> funnel::Source<'a> for DetectSource {
status: convert_to_engine_status(keyboard_event.status), status: convert_to_engine_status(keyboard_event.status),
variant: keyboard_event.variant.map(convert_to_engine_variant), variant: keyboard_event.variant.map(convert_to_engine_variant),
}), }),
}, }),
InputEvent::Mouse(mouse_event) => Event { InputEvent::Mouse(mouse_event) => Some(Event {
source_id, source_id,
etype: EventType::Mouse(MouseEvent { etype: EventType::Mouse(MouseEvent {
status: convert_to_engine_status(mouse_event.status), status: convert_to_engine_status(mouse_event.status),
button: convert_to_engine_mouse_button(mouse_event.button), button: convert_to_engine_mouse_button(mouse_event.button),
}), }),
}, }),
InputEvent::HotKey(hotkey_event) => Event { InputEvent::HotKey(hotkey_event) => Some(Event {
source_id, source_id,
etype: EventType::HotKey(HotKeyEvent { etype: EventType::HotKey(HotKeyEvent {
hotkey_id: hotkey_event.hotkey_id, hotkey_id: hotkey_event.hotkey_id,
}), }),
}, }),
InputEvent::AllModifiersReleased => None,
} }
} }
} }

View File

@ -45,13 +45,13 @@ impl<'a> funnel::Source<'a> for ExitSource<'a> {
select.recv(&self.exit_signal) select.recv(&self.exit_signal)
} }
fn receive(&self, op: SelectedOperation) -> Event { fn receive(&self, op: SelectedOperation) -> Option<Event> {
let mode = op let mode = op
.recv(&self.exit_signal) .recv(&self.exit_signal)
.expect("unable to select data from ExitSource receiver"); .expect("unable to select data from ExitSource receiver");
Event { Some(Event {
source_id: self.sequencer.next_id(), source_id: self.sequencer.next_id(),
etype: EventType::ExitRequested(mode), etype: EventType::ExitRequested(mode),
} })
} }
} }

View File

@ -81,6 +81,8 @@ pub fn init_and_spawn(
// Update the modifiers state // Update the modifiers state
if let Some((modifier, is_pressed)) = get_modifier_status(&event) { if let Some((modifier, is_pressed)) = get_modifier_status(&event) {
modifier_state_store_clone.update_state(modifier, is_pressed); modifier_state_store_clone.update_state(modifier, is_pressed);
} else if let InputEvent::AllModifiersReleased = &event {
modifier_state_store_clone.clear_state();
} }
// Update the key state (if needed) // Update the key state (if needed)

View File

@ -91,6 +91,13 @@ impl ModifierStateStore {
} }
} }
} }
pub fn clear_state(&self) {
let mut state = self.state.lock().expect("unable to obtain modifier state");
for (_, status) in &mut state.modifiers {
status.release();
}
}
} }
struct ModifiersState { struct ModifiersState {

View File

@ -50,13 +50,13 @@ impl<'a> funnel::Source<'a> for SecureInputSource<'a> {
} }
} }
fn receive(&self, op: SelectedOperation) -> Event { fn receive(&self, op: SelectedOperation) -> Option<Event> {
if cfg!(target_os = "macos") { if cfg!(target_os = "macos") {
let si_event = op let si_event = op
.recv(&self.receiver) .recv(&self.receiver)
.expect("unable to select data from SecureInputSource receiver"); .expect("unable to select data from SecureInputSource receiver");
Event { Some(Event {
source_id: self.sequencer.next_id(), source_id: self.sequencer.next_id(),
etype: match si_event { etype: match si_event {
SecureInputEvent::Disabled => EventType::SecureInputDisabled, SecureInputEvent::Disabled => EventType::SecureInputDisabled,
@ -64,13 +64,12 @@ impl<'a> funnel::Source<'a> for SecureInputSource<'a> {
EventType::SecureInputEnabled(SecureInputEnabledEvent { app_name, app_path }) EventType::SecureInputEnabled(SecureInputEnabledEvent { app_name, app_path })
} }
}, },
} })
} else { } else {
println!("noop"); Some(Event {
Event {
source_id: self.sequencer.next_id(), source_id: self.sequencer.next_id(),
etype: EventType::NOOP, etype: EventType::NOOP,
} })
} }
} }
} }

View File

@ -46,12 +46,12 @@ impl<'a> funnel::Source<'a> for UISource<'a> {
select.recv(&self.ui_receiver) select.recv(&self.ui_receiver)
} }
fn receive(&self, op: SelectedOperation) -> Event { fn receive(&self, op: SelectedOperation) -> Option<Event> {
let ui_event = op let ui_event = op
.recv(&self.ui_receiver) .recv(&self.ui_receiver)
.expect("unable to select data from UISource receiver"); .expect("unable to select data from UISource receiver");
Event { Some(Event {
source_id: self.sequencer.next_id(), source_id: self.sequencer.next_id(),
etype: match ui_event { etype: match ui_event {
UIEvent::TrayIconClick => EventType::TrayIconClicked, UIEvent::TrayIconClick => EventType::TrayIconClicked,
@ -60,6 +60,6 @@ impl<'a> funnel::Source<'a> for UISource<'a> {
} }
UIEvent::Heartbeat => EventType::Heartbeat, UIEvent::Heartbeat => EventType::Heartbeat,
}, },
} })
} }
} }