Skip to content

Commit

Permalink
ndk/input_queue: Replace InputQueueError with std::io::Error and …
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
MarijnS95 committed Jun 11, 2022
1 parent ac86821 commit e765038
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 27 deletions.
2 changes: 1 addition & 1 deletion ndk-examples/examples/looper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions ndk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
72 changes: 46 additions & 26 deletions ndk/src/input_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 *`]
Expand All @@ -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.
///
Expand All @@ -39,45 +38,65 @@ impl InputQueue {
self.ptr
}

pub fn get_event(&self) -> Option<InputEvent> {
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<Option<InputEvent>> {
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<bool, InputQueueError> {
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<bool> {
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<InputEvent> {
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(
Expand All @@ -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()) }
}
Expand Down

0 comments on commit e765038

Please sign in to comment.