-
Notifications
You must be signed in to change notification settings - Fork 64
Open
Description
Even though I have the relevant axis inputs turned on, when I connect the mouse to my phone via otg and input it, I can't receive any mouse events in rust
use android_activity::{
input::{Axis, Button, InputEvent, KeyAction, KeyEvent, KeyMapChar, MotionAction},
AndroidApp, InputStatus, MainEvent, PollEvent,
};
use log::info;
#[no_mangle]
fn android_main(app: AndroidApp) {
android_logger::init_once(android_logger::Config::default().with_min_level(log::Level::Info));
app.enable_motion_axis(Axis::X);
app.enable_motion_axis(Axis::Y);
app.enable_motion_axis(Axis::Vscroll);
app.enable_motion_axis(Axis::Hscroll);
app.enable_motion_axis(Axis::RelativeX);
app.enable_motion_axis(Axis::RelativeY);
app.enable_motion_axis(Axis::X);
app.enable_motion_axis(Axis::Y);
app.enable_motion_axis(Axis::Pressure);
app.enable_motion_axis(Axis::Size);
app.enable_motion_axis(Axis::TouchMajor);
app.enable_motion_axis(Axis::TouchMinor);
app.enable_motion_axis(Axis::Orientation);
let mut quit = false;
let mut redraw_pending = true;
let mut native_window: Option<ndk::native_window::NativeWindow> = None;
let mut combining_accent = None;
while !quit {
app.poll_events(
Some(std::time::Duration::from_secs(1)), /* timeout */
|event| {
match event {
PollEvent::Wake => {}
PollEvent::Timeout => {
// Real app would probably rely on vblank sync via graphics API...
redraw_pending = true;
}
PollEvent::Main(main_event) => {
match main_event {
MainEvent::SaveState { saver, .. } => {
saver.store("foo://bar".as_bytes());
}
MainEvent::Pause => {}
MainEvent::Resume { loader, .. } => {
if let Some(state) = loader.load() {
if let Ok(uri) = String::from_utf8(state) {}
}
}
MainEvent::InitWindow { .. } => {
native_window = app.native_window();
redraw_pending = true;
}
MainEvent::TerminateWindow { .. } => {
native_window = None;
}
MainEvent::WindowResized { .. } => {
redraw_pending = true;
}
MainEvent::RedrawNeeded { .. } => {
redraw_pending = true;
}
MainEvent::InputAvailable { .. } => {
redraw_pending = true;
}
MainEvent::ConfigChanged { .. } => {}
MainEvent::LowMemory => {}
MainEvent::Destroy => quit = true,
_ => { /* ... */ }
}
}
_ => {}
}
if redraw_pending {
if let Some(native_window) = &native_window {
redraw_pending = false;
// Handle input, via a lending iterator
match app.input_events_iter() {
Ok(mut iter) => loop {
if !iter.next(|event| {
match event {
InputEvent::KeyEvent(key_event) => {
let combined_key_char = character_map_and_combine_key(
&app,
key_event,
&mut combining_accent,
);
}
InputEvent::MotionEvent(motion_event) => {
let action = match motion_event.action() {
MotionAction::Down => "Down",
MotionAction::Up => "Up",
MotionAction::Move => "Move",
MotionAction::Cancel => "Cancel",
MotionAction::Outside => "Outside",
MotionAction::PointerDown => "PointerDown",
MotionAction::PointerUp => "PointerUp",
MotionAction::HoverMove => "HoverMove",
MotionAction::Scroll => "Scroll",
MotionAction::HoverEnter => "HoverEnter",
MotionAction::HoverExit => "HoverExit",
MotionAction::ButtonPress => "ButtonPress",
MotionAction::ButtonRelease => "ButtonRelease",
_ => "Unknow Action",
};
let button = match motion_event.action_button() {
Button::Back => "Back",
Button::Forward => "Forward",
Button::Primary => "Primary",
Button::Secondary => "Secondary",
Button::StylusPrimary => "StylusPrimary",
Button::StylusSecondary => "StylusSecondary",
Button::Tertiary => "Tertiary",
_ => "Unknow Action",
};
println!(
"MotionEvent, Button: {:?}, Action: {:?}",
button, action
);
}
InputEvent::TextEvent(state) => {}
_ => {}
}
InputStatus::Unhandled
}) {
break;
}
},
Err(err) => {
log::error!("Failed to get input events iterator: {err:?}");
}
}
dummy_render(native_window);
}
}
},
);
}
}
/// Tries to map the `key_event` to a `KeyMapChar` containing a unicode character or dead key accent
///
/// This shows how to take a `KeyEvent` and look up its corresponding `KeyCharacterMap` and
/// use that to try and map the `key_code` + `meta_state` to a unicode character or a
/// dead key that be combined with the next key press.
fn character_map_and_combine_key(
app: &AndroidApp,
key_event: &KeyEvent,
combining_accent: &mut Option<char>,
) -> Option<KeyMapChar> {
let device_id = key_event.device_id();
let key_map = match app.device_key_character_map(device_id) {
Ok(key_map) => key_map,
Err(err) => {
log::error!("Failed to look up `KeyCharacterMap` for device {device_id}: {err:?}");
return None;
}
};
match key_map.get(key_event.key_code(), key_event.meta_state()) {
Ok(KeyMapChar::Unicode(unicode)) => {
// Only do dead key combining on key down
if key_event.action() == KeyAction::Down {
let combined_unicode = if let Some(accent) = combining_accent {
match key_map.get_dead_char(*accent, unicode) {
Ok(Some(key)) => {
info!("KeyEvent: Combined '{unicode}' with accent '{accent}' to give '{key}'");
Some(key)
}
Ok(None) => None,
Err(err) => {
log::error!("KeyEvent: Failed to combine 'dead key' accent '{accent}' with '{unicode}': {err:?}");
None
}
}
} else {
info!("KeyEvent: Pressed '{unicode}'");
Some(unicode)
};
*combining_accent = None;
combined_unicode.map(|unicode| KeyMapChar::Unicode(unicode))
} else {
Some(KeyMapChar::Unicode(unicode))
}
}
Ok(KeyMapChar::CombiningAccent(accent)) => {
if key_event.action() == KeyAction::Down {
info!("KeyEvent: Pressed 'dead key' combining accent '{accent}'");
*combining_accent = Some(accent);
}
Some(KeyMapChar::CombiningAccent(accent))
}
Ok(KeyMapChar::None) => {
// Leave any combining_accent state in tact (seems to match how other
// Android apps work)
info!("KeyEvent: Pressed non-unicode key");
None
}
Err(err) => {
log::error!("KeyEvent: Failed to get key map character: {err:?}");
*combining_accent = None;
None
}
}
}
/// Post a NOP frame to the window
///
/// Since this is a bare minimum test app we don't depend
/// on any GPU graphics APIs but we do need to at least
/// convince Android that we're drawing something and are
/// responsive, otherwise it will stop delivering input
/// events to us.
fn dummy_render(native_window: &ndk::native_window::NativeWindow) {
unsafe {
let mut buf: ndk_sys::ANativeWindow_Buffer = std::mem::zeroed();
let mut rect: ndk_sys::ARect = std::mem::zeroed();
ndk_sys::ANativeWindow_lock(
native_window.ptr().as_ptr() as _,
&mut buf as _,
&mut rect as _,
);
// Note: we don't try and touch the buffer since that
// also requires us to handle various buffer formats
ndk_sys::ANativeWindow_unlockAndPost(native_window.ptr().as_ptr() as _);
}
}
Metadata
Metadata
Assignees
Labels
No labels