From e76503836b772bf42caa8698df6afe6a5cd2ed8d Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sat, 11 Jun 2022 12:54:29 +0200 Subject: [PATCH] ndk/input_queue: Replace `InputQueueError` with `std::io::Error` and add missing docs These `AInputQueue` functions all return [standard `errno.h` error codes] which can and should be communicated back to the user instead of appearing as some opaque magic struct. In addition import the NDK documentation for all these functions and make the scope of `unsafe` blocks smaller. [standard `errno.h` error codes]: https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/jni/android_view_InputQueue.cpp;l=112;drc=7b3193e1e86ab5c0fcb784cb8616864045dd2515 --- ndk-examples/examples/looper.rs | 2 +- ndk/CHANGELOG.md | 1 + ndk/src/input_queue.rs | 72 +++++++++++++++++++++------------ 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/ndk-examples/examples/looper.rs b/ndk-examples/examples/looper.rs index eb07e89b..bf320245 100644 --- a/ndk-examples/examples/looper.rs +++ b/ndk-examples/examples/looper.rs @@ -118,7 +118,7 @@ fn main() { let input_queue = input_queue.as_ref().expect("Input queue not attached"); assert!(input_queue.has_events().unwrap()); // Consume as many events as possible - while let Some(event) = input_queue.get_event() { + while let Some(event) = input_queue.get_event().unwrap() { // Pass the event by a possible IME (Input Method Editor, ie. an open keyboard) first if let Some(event) = input_queue.pre_dispatch(event) { info!("Input event {:?}", event); diff --git a/ndk/CHANGELOG.md b/ndk/CHANGELOG.md index 92c66af4..bbcd2a31 100644 --- a/ndk/CHANGELOG.md +++ b/ndk/CHANGELOG.md @@ -13,6 +13,7 @@ - native_activity: Add `set_window_flags()` to change window behavior. (#278) - Add `SurfaceTexture` bindings. (#267) - Improve library and structure documentation, linking back to the NDK docs more rigorously. (#290) +- **Breaking:** input_queue: `InputQueue::{get_event,has_events}()` now return a `Result` with `std::io::Error`; `InputQueueError` has been removed. (#292) # 0.6.0 (2022-01-05) diff --git a/ndk/src/input_queue.rs b/ndk/src/input_queue.rs index e7cf73d1..ef925a60 100644 --- a/ndk/src/input_queue.rs +++ b/ndk/src/input_queue.rs @@ -2,11 +2,13 @@ //! //! [`AInputQueue`]: https://developer.android.com/ndk/reference/group/input#ainputqueue +use std::io::{Error, Result}; use std::os::raw::c_int; -use std::ptr; -use std::ptr::NonNull; +use std::ptr::{self, NonNull}; use crate::event::InputEvent; +#[cfg(doc)] +use crate::event::KeyEvent; use crate::looper::ForeignLooper; /// A native [`AInputQueue *`] @@ -23,9 +25,6 @@ pub struct InputQueue { unsafe impl Send for InputQueue {} unsafe impl Sync for InputQueue {} -#[derive(Debug)] -pub struct InputQueueError; - impl InputQueue { /// Construct an [`InputQueue`] from the native pointer. /// @@ -39,45 +38,65 @@ impl InputQueue { self.ptr } - pub fn get_event(&self) -> Option { - unsafe { - let mut out_event = ptr::null_mut(); - if ffi::AInputQueue_getEvent(self.ptr.as_ptr(), &mut out_event) < 0 { - None - } else { + /// Returns the next available [`InputEvent`] from the queue. + /// + /// Returns [`None`] if no event is available. + pub fn get_event(&self) -> Result> { + let mut out_event = ptr::null_mut(); + match unsafe { ffi::AInputQueue_getEvent(self.ptr.as_ptr(), &mut out_event) } { + 0 => { debug_assert!(!out_event.is_null()); - Some(InputEvent::from_ptr(NonNull::new_unchecked(out_event))) + Ok(Some(unsafe { + InputEvent::from_ptr(NonNull::new_unchecked(out_event)) + })) } + r if r < 0 => match Error::from_raw_os_error(-r) { + e if e.kind() == std::io::ErrorKind::WouldBlock => Ok(None), + e => Err(e), + }, + r => unreachable!("AInputQueue_getEvent returned positive integer {}", r), } } - pub fn has_events(&self) -> Result { - unsafe { - match ffi::AInputQueue_hasEvents(self.ptr.as_ptr()) { - 0 => Ok(false), - 1 => Ok(true), - x if x < 0 => Err(InputQueueError), - x => unreachable!("AInputQueue_hasEvents returned {}", x), - } + /// Returns [`true`] if there are one or more events available in the input queue. + pub fn has_events(&self) -> Result { + match unsafe { ffi::AInputQueue_hasEvents(self.ptr.as_ptr()) } { + 0 => Ok(false), + 1 => Ok(true), + r if r < 0 => Err(Error::from_raw_os_error(-r)), + r => unreachable!("AInputQueue_hasEvents returned non-boolean {}", r), } } + /// Sends the key for standard pre-dispatching that is, possibly deliver it to the current IME + /// to be consumed before the app. + /// + /// Returns [`Some`] if it was not pre-dispatched, meaning you can process it right now. If + /// [`None`] is returned, you must abandon the current event processing and allow the event to + /// appear again in the event queue (if it does not get consumed during pre-dispatching). + /// + /// Also returns [`None`] if `event` is not a [`KeyEvent`]. pub fn pre_dispatch(&self, event: InputEvent) -> Option { - unsafe { - if ffi::AInputQueue_preDispatchEvent(self.ptr.as_ptr(), event.ptr().as_ptr()) == 0 { - Some(event) - } else { - None - } + match unsafe { ffi::AInputQueue_preDispatchEvent(self.ptr.as_ptr(), event.ptr().as_ptr()) } + { + 0 => Some(event), + 1 => None, + r => unreachable!("AInputQueue_preDispatchEvent returned non-boolean {}", r), } } + /// Report that dispatching has finished with the given [`InputEvent`]. + /// + /// This must be called after receiving an event with [`InputQueue::get_event()`]. pub fn finish_event(&self, event: InputEvent, handled: bool) { unsafe { ffi::AInputQueue_finishEvent(self.ptr.as_ptr(), event.ptr().as_ptr(), handled as c_int) } } + /// Add this input queue to a [`ForeignLooper`] for processing. + /// + /// See [`ForeignLooper::add_fd()`] for information on the `ident`, `callback`, and `data` params. pub fn attach_looper(&self, looper: &ForeignLooper, id: i32) { unsafe { ffi::AInputQueue_attachLooper( @@ -90,6 +109,7 @@ impl InputQueue { } } + /// Remove this input queue from the [`ForeignLooper`] it is currently attached to. pub fn detach_looper(&self) { unsafe { ffi::AInputQueue_detachLooper(self.ptr.as_ptr()) } }