feat(android): pen input, soft keyboard and exports to Downloads (Issues #42, #44)

- Pen vs. finger (#44): the patched winit hands Android pointers with
  tool type stylus/eraser to the app separately (take_pen_samples, with
  hover and button state) instead of as touch events. src/pen.rs turns
  them, like octotablet's events on the desktop, into one PenInput
  stream, so pen buttons, the eraser end and palm rejection work the
  same everywhere. Hover exit right before touch-down does not count as
  leaving; a pen without hover leaves 150 ms after lifting.
- Soft keyboard: shown via AndroidApp::show_soft_input when a text field
  gets focus, hidden when it loses it. The patched winit now fills
  KeyEvent::text, so typed characters reach egui.
- Exports (PDF, PNG, SVG) are written to the app folder and copied to
  Download/ink-notes through the MediaStore (Android 10+, via JNI).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
haraldandClaude Opus 5.5 committed 2026-10-27 20:54:48 +01:00
1 parent 4ca21483e5
commit a8aef30db7
13 files changed
+1187 -559

No files matched your search

+35
View File
@@ -77,6 +77,41 @@ impl<T> EventLoopBuilderExtAndroid for EventLoopBuilder<T> {
/// depending on the `android_activity` crate, and instead consume the API that
/// is re-exported by Winit.
///
/// ink-notes patch: what a pen sample reports (Issue #44).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PenAction {
/// Pen comes near the screen, moves above it or leaves it
HoverEnter,
HoverMove,
HoverExit,
/// Pen touches the screen, moves on it, is lifted or the gesture is cancelled
Down,
Move,
Up,
Cancel,
}
/// ink-notes patch: one sample of a pen (tool type stylus or eraser). Such pointers are not
/// reported as `WindowEvent::Touch`; the app collects them with [`take_pen_samples`].
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PenSample {
pub action: PenAction,
/// Position in physical pixels
pub x: f32,
pub y: f32,
/// Usually 0..=1
pub pressure: f32,
/// Eraser end of the pen (tool type eraser)
pub eraser: bool,
/// `MotionEvent.getButtonState()`; the pen buttons are 0x20 (primary) and 0x40 (secondary)
pub buttons: u32,
}
/// ink-notes patch: the pen samples received since the last call, oldest first.
pub fn take_pen_samples() -> Vec<PenSample> {
crate::platform_impl::take_pen_samples()
}
/// For compatibility applications should then import the `AndroidApp` type for
/// their `android_main(app: AndroidApp)` function like:
/// ```rust