mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-11 05:21:31 +11:00
On Android, change default implementation to ignore volume keys and let operating system handle them (#2748)
This commit is contained in:
parent
ab46aa5b79
commit
4a36741f9c
|
@ -8,6 +8,8 @@ And please only add new entries to the top of this list, right below the `# Unre
|
||||||
|
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- On Android, changed default behavior of Android to ignore volume keys letting the operating system handle them.
|
||||||
|
- On Android, added `EventLoopBuilderExtAndroid::handle_volume_keys` to indicate that the application will handle the volume keys manually.
|
||||||
- **Breaking:** Rename `DeviceEventFilter` to `DeviceEvents` reversing the behavior of variants.
|
- **Breaking:** Rename `DeviceEventFilter` to `DeviceEvents` reversing the behavior of variants.
|
||||||
- **Breaking:** Rename `EventLoopWindowTarget::set_device_event_filter` to `listen_device_events`.
|
- **Breaking:** Rename `EventLoopWindowTarget::set_device_event_filter` to `listen_device_events`.
|
||||||
- On X11, fix `EventLoopWindowTarget::listen_device_events` effect being reversed.
|
- On X11, fix `EventLoopWindowTarget::listen_device_events` effect being reversed.
|
||||||
|
|
|
@ -42,6 +42,11 @@ pub trait EventLoopBuilderExtAndroid {
|
||||||
///
|
///
|
||||||
/// This must be called on Android since the `AndroidApp` is not global state.
|
/// This must be called on Android since the `AndroidApp` is not global state.
|
||||||
fn with_android_app(&mut self, app: AndroidApp) -> &mut Self;
|
fn with_android_app(&mut self, app: AndroidApp) -> &mut Self;
|
||||||
|
|
||||||
|
/// Calling this will mark the volume keys to be manually handled by the application
|
||||||
|
///
|
||||||
|
/// Default is to let the operating system handle the volume keys
|
||||||
|
fn handle_volume_keys(&mut self) -> &mut Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopBuilderExtAndroid for EventLoopBuilder<T> {
|
impl<T> EventLoopBuilderExtAndroid for EventLoopBuilder<T> {
|
||||||
|
@ -49,6 +54,11 @@ impl<T> EventLoopBuilderExtAndroid for EventLoopBuilder<T> {
|
||||||
self.platform_specific.android_app = Some(app);
|
self.platform_specific.android_app = Some(app);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_volume_keys(&mut self) -> &mut Self {
|
||||||
|
self.platform_specific.ignore_volume_keys = false;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Re-export of the `android_activity` API
|
/// Re-export of the `android_activity` API
|
||||||
|
|
|
@ -138,11 +138,22 @@ pub struct EventLoop<T: 'static> {
|
||||||
user_events_sender: mpsc::Sender<T>,
|
user_events_sender: mpsc::Sender<T>,
|
||||||
user_events_receiver: PeekableReceiver<T>, //must wake looper whenever something gets sent
|
user_events_receiver: PeekableReceiver<T>, //must wake looper whenever something gets sent
|
||||||
running: bool,
|
running: bool,
|
||||||
|
ignore_volume_keys: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub(crate) struct PlatformSpecificEventLoopAttributes {
|
pub(crate) struct PlatformSpecificEventLoopAttributes {
|
||||||
pub(crate) android_app: Option<AndroidApp>,
|
pub(crate) android_app: Option<AndroidApp>,
|
||||||
|
pub(crate) ignore_volume_keys: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PlatformSpecificEventLoopAttributes {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
android_app: Default::default(),
|
||||||
|
ignore_volume_keys: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sticky_exit_callback<T, F>(
|
fn sticky_exit_callback<T, F>(
|
||||||
|
@ -192,6 +203,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
user_events_sender,
|
user_events_sender,
|
||||||
user_events_receiver: PeekableReceiver::from_recv(user_events_receiver),
|
user_events_receiver: PeekableReceiver::from_recv(user_events_receiver),
|
||||||
running: false,
|
running: false,
|
||||||
|
ignore_volume_keys: attributes.ignore_volume_keys,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,8 +339,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process input events
|
// Process input events
|
||||||
|
|
||||||
self.android_app.input_events(|event| {
|
self.android_app.input_events(|event| {
|
||||||
|
let mut input_status = InputStatus::Handled;
|
||||||
match event {
|
match event {
|
||||||
InputEvent::MotionEvent(motion_event) => {
|
InputEvent::MotionEvent(motion_event) => {
|
||||||
let window_id = window::WindowId(WindowId);
|
let window_id = window::WindowId(WindowId);
|
||||||
|
@ -395,67 +407,78 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::KeyEvent(key) => {
|
InputEvent::KeyEvent(key) => {
|
||||||
let state = match key.action() {
|
match key.key_code() {
|
||||||
KeyAction::Down => event::ElementState::Pressed,
|
// Flagg keys related to volume as unhandled. While winit does not have a way for applications
|
||||||
KeyAction::Up => event::ElementState::Released,
|
// to configure what keys to flag as handled, this appears to be a good default until winit
|
||||||
_ => event::ElementState::Released,
|
// can be configured.
|
||||||
};
|
ndk::event::Keycode::VolumeUp |
|
||||||
|
ndk::event::Keycode::VolumeDown |
|
||||||
#[cfg(feature = "android-native-activity")]
|
ndk::event::Keycode::VolumeMute => {
|
||||||
let (keycode_u32, scancode_u32) = unsafe {
|
if self.ignore_volume_keys {
|
||||||
// We abuse the fact that `android_activity`'s `KeyEvent` is `repr(transparent)`
|
input_status = InputStatus::Unhandled
|
||||||
let event = (key as *const android_activity::input::KeyEvent<'_>).cast::<ndk::event::KeyEvent>();
|
}
|
||||||
// We use the unsafe function directly because we want to forward the
|
|
||||||
// keycode value even if it doesn't have a variant defined in the ndk
|
|
||||||
// crate.
|
|
||||||
(
|
|
||||||
AKeyEvent_getKeyCode((*event).ptr().as_ptr()) as u32,
|
|
||||||
(*event).scan_code() as u32
|
|
||||||
)
|
|
||||||
};
|
|
||||||
#[cfg(feature = "android-game-activity")]
|
|
||||||
let (keycode_u32, scancode_u32) = (key.keyCode as u32, key.scanCode as u32);
|
|
||||||
let keycode = keycode_u32
|
|
||||||
.try_into()
|
|
||||||
.unwrap_or(ndk::event::Keycode::Unknown);
|
|
||||||
let physical_key = KeyCode::Unidentified(
|
|
||||||
NativeKeyCode::Android(scancode_u32),
|
|
||||||
);
|
|
||||||
let native = NativeKey::Android(keycode_u32);
|
|
||||||
let logical_key = keycode_to_logical(keycode, native);
|
|
||||||
// TODO: maybe use getUnicodeChar to get the logical key
|
|
||||||
|
|
||||||
let event = event::Event::WindowEvent {
|
|
||||||
window_id: window::WindowId(WindowId),
|
|
||||||
event: event::WindowEvent::KeyboardInput {
|
|
||||||
device_id: event::DeviceId(DeviceId),
|
|
||||||
event: event::KeyEvent {
|
|
||||||
state,
|
|
||||||
physical_key,
|
|
||||||
logical_key,
|
|
||||||
location: keycode_to_location(keycode),
|
|
||||||
repeat: key.repeat_count() > 0,
|
|
||||||
text: None,
|
|
||||||
platform_specific: KeyEventExtra {},
|
|
||||||
},
|
|
||||||
is_synthetic: false,
|
|
||||||
},
|
},
|
||||||
};
|
_ => {
|
||||||
sticky_exit_callback(
|
let state = match key.action() {
|
||||||
event,
|
KeyAction::Down => event::ElementState::Pressed,
|
||||||
self.window_target(),
|
KeyAction::Up => event::ElementState::Released,
|
||||||
control_flow,
|
_ => event::ElementState::Released,
|
||||||
callback,
|
};
|
||||||
);
|
|
||||||
|
#[cfg(feature = "android-native-activity")]
|
||||||
|
let (keycode_u32, scancode_u32) = unsafe {
|
||||||
|
// We abuse the fact that `android_activity`'s `KeyEvent` is `repr(transparent)`
|
||||||
|
let event = (key as *const android_activity::input::KeyEvent<'_>).cast::<ndk::event::KeyEvent>();
|
||||||
|
// We use the unsafe function directly because we want to forward the
|
||||||
|
// keycode value even if it doesn't have a variant defined in the ndk
|
||||||
|
// crate.
|
||||||
|
(
|
||||||
|
AKeyEvent_getKeyCode((*event).ptr().as_ptr()) as u32,
|
||||||
|
(*event).scan_code() as u32
|
||||||
|
)
|
||||||
|
};
|
||||||
|
#[cfg(feature = "android-game-activity")]
|
||||||
|
let (keycode_u32, scancode_u32) = (key.keyCode as u32, key.scanCode as u32);
|
||||||
|
let keycode = keycode_u32
|
||||||
|
.try_into()
|
||||||
|
.unwrap_or(ndk::event::Keycode::Unknown);
|
||||||
|
let physical_key = KeyCode::Unidentified(
|
||||||
|
NativeKeyCode::Android(scancode_u32),
|
||||||
|
);
|
||||||
|
let native = NativeKey::Android(keycode_u32);
|
||||||
|
let logical_key = keycode_to_logical(keycode, native);
|
||||||
|
// TODO: maybe use getUnicodeChar to get the logical key
|
||||||
|
|
||||||
|
let event = event::Event::WindowEvent {
|
||||||
|
window_id: window::WindowId(WindowId),
|
||||||
|
event: event::WindowEvent::KeyboardInput {
|
||||||
|
device_id: event::DeviceId(DeviceId),
|
||||||
|
event: event::KeyEvent {
|
||||||
|
state,
|
||||||
|
physical_key,
|
||||||
|
logical_key,
|
||||||
|
location: keycode_to_location(keycode),
|
||||||
|
repeat: key.repeat_count() > 0,
|
||||||
|
text: None,
|
||||||
|
platform_specific: KeyEventExtra {},
|
||||||
|
},
|
||||||
|
is_synthetic: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
sticky_exit_callback(
|
||||||
|
event,
|
||||||
|
self.window_target(),
|
||||||
|
control_flow,
|
||||||
|
callback,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
warn!("Unknown android_activity input event {event:?}")
|
warn!("Unknown android_activity input event {event:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
input_status
|
||||||
// Assume all events are handled, while Winit doesn't currently give a way for
|
|
||||||
// applications to report whether they handled an input event.
|
|
||||||
InputStatus::Handled
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Empty the user event buffer
|
// Empty the user event buffer
|
||||||
|
|
Loading…
Reference in a new issue