Skip to content

Commit f26459f

Browse files
committed
Add support for the Back key on Android
Successfully tested with this code forward-focus: my-key-handler; my-key-handler := FocusScope { key-pressed(event) => { if (event.text == Key.Back) { root.close(); } accept } } but also without (that was the hard part: letting Android terminate the activity on Back if it's not accepted by slint, which no longer happened after returning Some(...) in key_codes.rs)
1 parent 35fa421 commit f26459f

File tree

4 files changed

+50
-14
lines changed

4 files changed

+50
-14
lines changed

internal/backends/android-activity/androidwindowadapter.rs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,32 @@ impl AndroidWindowAdapter {
264264
Ok(ControlFlow::Continue(()))
265265
}
266266

267+
fn try_dispatch_key_event(&self, ev: WindowEvent) -> i_slint_core::input::KeyEventResult {
268+
match ev {
269+
WindowEvent::KeyPressed { text } => WindowInner::from_pub(&self.window)
270+
.process_key_input(i_slint_core::input::KeyEvent {
271+
text,
272+
repeat: false,
273+
event_type: i_slint_core::input::KeyEventType::KeyPressed,
274+
..Default::default()
275+
}),
276+
WindowEvent::KeyPressRepeated { text } => WindowInner::from_pub(&self.window)
277+
.process_key_input(i_slint_core::input::KeyEvent {
278+
text,
279+
repeat: true,
280+
event_type: i_slint_core::input::KeyEventType::KeyPressed,
281+
..Default::default()
282+
}),
283+
WindowEvent::KeyReleased { text } => WindowInner::from_pub(&self.window)
284+
.process_key_input(i_slint_core::input::KeyEvent {
285+
text,
286+
event_type: i_slint_core::input::KeyEventType::KeyReleased,
287+
..Default::default()
288+
}),
289+
_ => i_slint_core::input::KeyEventResult::EventIgnored,
290+
}
291+
}
292+
267293
fn process_inputs(&self) -> Result<(), PlatformError> {
268294
let mut iter =
269295
self.app.input_events_iter().map_err(|e| PlatformError::Other(e.to_string()))?;
@@ -272,8 +298,13 @@ impl AndroidWindowAdapter {
272298
let read_input = iter.next(|event| match event {
273299
InputEvent::KeyEvent(key_event) => match map_key_event(key_event) {
274300
Some(ev) => {
275-
result = self.window.try_dispatch_event(ev);
276-
InputStatus::Handled
301+
if self.try_dispatch_key_event(ev)
302+
== i_slint_core::input::KeyEventResult::EventAccepted
303+
{
304+
InputStatus::Handled
305+
} else {
306+
InputStatus::Unhandled
307+
}
277308
}
278309
None => InputStatus::Unhandled,
279310
},
@@ -322,7 +353,7 @@ impl AndroidWindowAdapter {
322353
.to_logical(self.window.scale_factor()),
323354
button: PointerEventButton::Left,
324355
})
325-
.and_then(|()| {
356+
.and_then(|_| {
326357
// Also send exit to avoid remaining hover state
327358
self.window.try_dispatch_event(WindowEvent::PointerExited)
328359
});
@@ -538,7 +569,7 @@ fn map_key_code(code: android_activity::input::Keycode) -> Option<SharedString>
538569
Keycode::SoftLeft => None,
539570
Keycode::SoftRight => None,
540571
Keycode::Home => None,
541-
Keycode::Back => None,
572+
Keycode::Back => Some(Key::Back.into()),
542573
Keycode::Call => None,
543574
Keycode::Endcall => None,
544575
Keycode::Keycode0 => Some("0".into()),

internal/common/key_codes.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright © SixtyFPS GmbH <[email protected]>
22
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
33

4-
//! This module is meant to be included by different crate and each crate must define the macro for_each_keys
4+
//! This module is meant to be included by different crates and each crate must define the macro for_each_special_keys
55
//!
66
//! The key code comes from <https://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CORPCHAR.TXT>
77
//! the names comes should match with <https://www.w3.org/TR/uievents-key/#named-key-attribute-values>,
@@ -121,6 +121,7 @@ macro_rules! for_each_special_keys {
121121
//'\u{F745}' # Find # Qt_Key_Key_Find # ;
122122
//'\u{F746}' # Help # Qt_Key_Key_Help # ;
123123
//'\u{F747}' # ModeSwitch # Qt_Key_Key_Mode_switch # ;
124+
'\u{F748}' # Back # Qt_Key_Key_Back # # ;
124125
];
125126
};
126127
}

internal/core/api.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -632,22 +632,22 @@ impl Window {
632632
repeat: false,
633633
event_type: KeyEventType::KeyPressed,
634634
..Default::default()
635-
})
635+
});
636636
}
637637
crate::platform::WindowEvent::KeyPressRepeated { text } => {
638638
self.0.process_key_input(crate::input::KeyEvent {
639639
text,
640640
repeat: true,
641641
event_type: KeyEventType::KeyPressed,
642642
..Default::default()
643-
})
643+
});
644644
}
645645
crate::platform::WindowEvent::KeyReleased { text } => {
646646
self.0.process_key_input(crate::input::KeyEvent {
647647
text,
648648
event_type: KeyEventType::KeyReleased,
649649
..Default::default()
650-
})
650+
});
651651
}
652652
crate::platform::WindowEvent::ScaleFactorChanged { scale_factor } => {
653653
self.0.set_scale_factor(scale_factor);

internal/core/window.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,10 @@ impl WindowInner {
766766
///
767767
/// Arguments:
768768
/// * `event`: The key event received by the windowing system.
769-
pub fn process_key_input(&self, mut event: KeyEvent) {
769+
pub fn process_key_input(&self, mut event: KeyEvent) -> crate::input::KeyEventResult {
770+
scopeguard::defer! {
771+
crate::properties::ChangeTracker::run_change_handlers();
772+
}
770773
if let Some(updated_modifier) = self
771774
.modifiers
772775
.get()
@@ -803,8 +806,7 @@ impl WindowInner {
803806
if i.borrow().as_ref().capture_key_event(&event, &self.window_adapter(), &i)
804807
== crate::input::KeyEventResult::EventAccepted
805808
{
806-
crate::properties::ChangeTracker::run_change_handlers();
807-
return;
809+
return crate::input::KeyEventResult::EventAccepted;
808810
}
809811
}
810812

@@ -815,8 +817,7 @@ impl WindowInner {
815817
if focus_item.borrow().as_ref().key_event(&event, &self.window_adapter(), &focus_item)
816818
== crate::input::KeyEventResult::EventAccepted
817819
{
818-
crate::properties::ChangeTracker::run_change_handlers();
819-
return;
820+
return crate::input::KeyEventResult::EventAccepted;
820821
}
821822
item = focus_item.parent_item(ParentItemTraversalMode::StopAtPopups);
822823
}
@@ -829,12 +830,14 @@ impl WindowInner {
829830
&& event.event_type == KeyEventType::KeyPressed
830831
{
831832
self.focus_next_item();
833+
return crate::input::KeyEventResult::EventAccepted;
832834
} else if (event.text.starts_with(key_codes::Backtab)
833835
|| (event.text.starts_with(key_codes::Tab) && event.modifiers.shift))
834836
&& event.event_type == KeyEventType::KeyPressed
835837
&& !extra_mod
836838
{
837839
self.focus_previous_item();
840+
return crate::input::KeyEventResult::EventAccepted;
838841
} else if event.event_type == KeyEventType::KeyPressed
839842
&& event.text.starts_with(key_codes::Escape)
840843
{
@@ -860,8 +863,9 @@ impl WindowInner {
860863
if close_on_escape {
861864
window.close_top_popup();
862865
}
866+
return crate::input::KeyEventResult::EventAccepted;
863867
}
864-
crate::properties::ChangeTracker::run_change_handlers();
868+
crate::input::KeyEventResult::EventIgnored
865869
}
866870

867871
/// Installs a binding on the specified property that's toggled whenever the text cursor is supposed to be visible or not.

0 commit comments

Comments
 (0)