2022-12-25 09:57:27 +02:00
#![ cfg(android_platform) ]
2015-04-24 09:51:23 +02:00
2022-06-08 11:50:26 -07:00
use std ::{
collections ::VecDeque ,
2023-05-28 20:02:59 +02:00
convert ::TryInto ,
2022-11-10 16:55:19 +00:00
hash ::Hash ,
sync ::{
atomic ::{ AtomicBool , Ordering } ,
2023-01-17 03:30:14 +02:00
mpsc , Arc , RwLock ,
2022-11-10 16:55:19 +00:00
} ,
2022-06-08 11:50:26 -07:00
time ::{ Duration , Instant } ,
2020-05-06 15:27:49 +02:00
} ;
2022-06-08 11:50:26 -07:00
2023-05-28 20:02:59 +02:00
use android_activity ::input ::{ InputEvent , KeyAction , MotionAction } ;
2022-11-10 16:55:19 +00:00
use android_activity ::{
AndroidApp , AndroidAppWaker , ConfigurationRef , InputStatus , MainEvent , Rect ,
2020-05-06 15:27:49 +02:00
} ;
2023-01-17 03:30:14 +02:00
use once_cell ::sync ::Lazy ;
2022-07-21 22:22:36 +03:00
use raw_window_handle ::{
AndroidDisplayHandle , HasRawWindowHandle , RawDisplayHandle , RawWindowHandle ,
} ;
2022-06-08 11:50:26 -07:00
2023-05-28 20:02:59 +02:00
#[ cfg(feature = " android-native-activity " ) ]
use ndk_sys ::AKeyEvent_getKeyCode ;
2022-09-21 10:04:28 +02:00
use crate ::platform_impl ::Fullscreen ;
2022-06-08 11:50:26 -07:00
use crate ::{
dpi ::{ PhysicalPosition , PhysicalSize , Position , Size } ,
error ,
2023-05-28 20:02:59 +02:00
event ::{ self , StartCause } ,
2022-11-10 16:55:19 +00:00
event_loop ::{ self , ControlFlow , EventLoopWindowTarget as RootELW } ,
2023-05-28 20:02:59 +02:00
keyboard ::{ Key , KeyCode , KeyLocation , NativeKey , NativeKeyCode } ,
2023-01-29 16:46:46 +01:00
window ::{
self , CursorGrabMode , ImePurpose , ResizeDirection , Theme , WindowButtons , WindowLevel ,
} ,
2019-06-21 11:33:15 -04:00
} ;
2023-01-17 03:30:14 +02:00
static HAS_FOCUS : Lazy < RwLock < bool > > = Lazy ::new ( | | RwLock ::new ( true ) ) ;
2022-11-10 16:55:19 +00:00
struct PeekableReceiver < T > {
recv : mpsc ::Receiver < T > ,
first : Option < T > ,
}
impl < T > PeekableReceiver < T > {
pub fn from_recv ( recv : mpsc ::Receiver < T > ) -> Self {
Self { recv , first : None }
}
pub fn has_incoming ( & mut self ) -> bool {
if self . first . is_some ( ) {
return true ;
}
match self . recv . try_recv ( ) {
Ok ( v ) = > {
self . first = Some ( v ) ;
true
}
Err ( mpsc ::TryRecvError ::Empty ) = > false ,
Err ( mpsc ::TryRecvError ::Disconnected ) = > {
warn! ( " Channel was disconnected when checking incoming " ) ;
false
}
}
}
pub fn try_recv ( & mut self ) -> Result < T , mpsc ::TryRecvError > {
if let Some ( first ) = self . first . take ( ) {
return Ok ( first ) ;
}
self . recv . try_recv ( )
}
}
#[ derive(Clone) ]
struct SharedFlagSetter {
flag : Arc < AtomicBool > ,
}
impl SharedFlagSetter {
pub fn set ( & self ) -> bool {
self . flag
. compare_exchange ( false , true , Ordering ::AcqRel , Ordering ::Relaxed )
. is_ok ( )
}
}
struct SharedFlag {
flag : Arc < AtomicBool > ,
}
// Used for queuing redraws from arbitrary threads. We don't care how many
// times a redraw is requested (so don't actually need to queue any data,
// we just need to know at the start of a main loop iteration if a redraw
// was queued and be able to read and clear the state atomically)
impl SharedFlag {
pub fn new ( ) -> Self {
Self {
flag : Arc ::new ( AtomicBool ::new ( false ) ) ,
}
}
pub fn setter ( & self ) -> SharedFlagSetter {
SharedFlagSetter {
flag : self . flag . clone ( ) ,
}
}
pub fn get_and_reset ( & self ) -> bool {
self . flag . swap ( false , std ::sync ::atomic ::Ordering ::AcqRel )
}
}
#[ derive(Clone) ]
pub struct RedrawRequester {
flag : SharedFlagSetter ,
waker : AndroidAppWaker ,
}
impl RedrawRequester {
fn new ( flag : & SharedFlag , waker : AndroidAppWaker ) -> Self {
RedrawRequester {
flag : flag . setter ( ) ,
waker ,
}
}
pub fn request_redraw ( & self ) {
if self . flag . set ( ) {
// Only explicitly try to wake up the main loop when the flag
// value changes
self . waker . wake ( ) ;
}
2017-09-04 12:41:02 +02:00
}
2020-05-06 15:27:49 +02:00
}
2016-10-31 17:08:55 +01:00
2023-05-28 20:02:59 +02:00
#[ derive(Debug, Clone, Eq, PartialEq, Hash) ]
pub struct KeyEventExtra { }
2020-05-06 15:27:49 +02:00
pub struct EventLoop < T : 'static > {
2022-11-10 16:55:19 +00:00
android_app : AndroidApp ,
2020-05-06 15:27:49 +02:00
window_target : event_loop ::EventLoopWindowTarget < T > ,
2022-11-10 16:55:19 +00:00
redraw_flag : SharedFlag ,
2022-07-20 14:52:36 -03:00
user_events_sender : mpsc ::Sender < T > ,
2022-11-10 16:55:19 +00:00
user_events_receiver : PeekableReceiver < T > , //must wake looper whenever something gets sent
2020-06-17 15:55:52 +02:00
running : bool ,
}
2022-11-10 16:55:19 +00:00
#[ derive(Default, Debug, Clone, PartialEq) ]
pub ( crate ) struct PlatformSpecificEventLoopAttributes {
pub ( crate ) android_app : Option < AndroidApp > ,
}
2022-02-16 22:09:03 +01:00
2022-11-10 16:55:19 +00:00
fn sticky_exit_callback < T , F > (
evt : event ::Event < '_ , T > ,
target : & RootELW < T > ,
control_flow : & mut ControlFlow ,
callback : & mut F ,
) where
F : FnMut ( event ::Event < '_ , T > , & RootELW < T > , & mut ControlFlow ) ,
{
// make ControlFlow::ExitWithCode sticky by providing a dummy
// control flow reference if it is already ExitWithCode.
if let ControlFlow ::ExitWithCode ( code ) = * control_flow {
callback ( evt , target , & mut ControlFlow ::ExitWithCode ( code ) )
} else {
callback ( evt , target , control_flow )
}
}
struct IterationResult {
deadline : Option < Instant > ,
timeout : Option < Duration > ,
wait_start : Instant ,
2020-05-06 15:27:49 +02:00
}
2016-10-31 17:08:55 +01:00
2020-05-06 15:27:49 +02:00
impl < T : 'static > EventLoop < T > {
2022-11-10 16:55:19 +00:00
pub ( crate ) fn new ( attributes : & PlatformSpecificEventLoopAttributes ) -> Self {
2022-07-20 14:52:36 -03:00
let ( user_events_sender , user_events_receiver ) = mpsc ::channel ( ) ;
2022-11-10 16:55:19 +00:00
let android_app = attributes . android_app . as_ref ( ) . expect ( " An `AndroidApp` as passed to android_main() is required to create an `EventLoop` on Android " ) ;
let redraw_flag = SharedFlag ::new ( ) ;
2020-05-06 15:27:49 +02:00
Self {
2022-11-10 16:55:19 +00:00
android_app : android_app . clone ( ) ,
2020-05-06 15:27:49 +02:00
window_target : event_loop ::EventLoopWindowTarget {
p : EventLoopWindowTarget {
2022-11-10 16:55:19 +00:00
app : android_app . clone ( ) ,
redraw_requester : RedrawRequester ::new (
& redraw_flag ,
android_app . create_waker ( ) ,
) ,
2020-05-06 15:27:49 +02:00
_marker : std ::marker ::PhantomData ,
} ,
_marker : std ::marker ::PhantomData ,
} ,
2022-11-10 16:55:19 +00:00
redraw_flag ,
2022-07-20 14:52:36 -03:00
user_events_sender ,
2022-11-10 16:55:19 +00:00
user_events_receiver : PeekableReceiver ::from_recv ( user_events_receiver ) ,
2020-06-17 15:55:52 +02:00
running : false ,
2020-05-06 15:27:49 +02:00
}
2016-10-31 17:08:55 +01:00
}
2023-01-27 07:18:58 +03:00
fn single_iteration < F > (
2022-11-10 16:55:19 +00:00
& mut self ,
control_flow : & mut ControlFlow ,
2023-01-27 07:18:58 +03:00
main_event : Option < MainEvent < '_ > > ,
2022-11-10 16:55:19 +00:00
pending_redraw : & mut bool ,
cause : & mut StartCause ,
callback : & mut F ,
) -> IterationResult
2019-06-21 11:33:15 -04:00
where
2022-11-10 16:55:19 +00:00
F : FnMut ( event ::Event < '_ , T > , & RootELW < T > , & mut ControlFlow ) ,
2017-09-04 12:41:02 +02:00
{
2022-11-10 16:55:19 +00:00
trace! ( " Mainloop iteration " ) ;
sticky_exit_callback (
event ::Event ::NewEvents ( * cause ) ,
self . window_target ( ) ,
control_flow ,
callback ,
) ;
let mut resized = false ;
if let Some ( event ) = main_event {
trace! ( " Handling main event {:?} " , event ) ;
match event {
MainEvent ::InitWindow { .. } = > {
sticky_exit_callback (
event ::Event ::Resumed ,
self . window_target ( ) ,
control_flow ,
callback ,
) ;
}
MainEvent ::TerminateWindow { .. } = > {
sticky_exit_callback (
event ::Event ::Suspended ,
self . window_target ( ) ,
control_flow ,
callback ,
) ;
}
MainEvent ::WindowResized { .. } = > resized = true ,
MainEvent ::RedrawNeeded { .. } = > * pending_redraw = true ,
MainEvent ::ContentRectChanged { .. } = > {
warn! ( " TODO: find a way to notify application of content rect change " ) ;
}
MainEvent ::GainedFocus = > {
2023-01-17 03:30:14 +02:00
* HAS_FOCUS . write ( ) . unwrap ( ) = true ;
2022-11-10 16:55:19 +00:00
sticky_exit_callback (
event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::Focused ( true ) ,
} ,
self . window_target ( ) ,
control_flow ,
callback ,
) ;
}
MainEvent ::LostFocus = > {
2023-01-17 03:30:14 +02:00
* HAS_FOCUS . write ( ) . unwrap ( ) = false ;
2022-11-10 16:55:19 +00:00
sticky_exit_callback (
event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::Focused ( false ) ,
} ,
self . window_target ( ) ,
control_flow ,
callback ,
) ;
}
MainEvent ::ConfigChanged { .. } = > {
let monitor = MonitorHandle ::new ( self . android_app . clone ( ) ) ;
let old_scale_factor = monitor . scale_factor ( ) ;
let scale_factor = monitor . scale_factor ( ) ;
if ( scale_factor - old_scale_factor ) . abs ( ) < f64 ::EPSILON {
let mut size = MonitorHandle ::new ( self . android_app . clone ( ) ) . size ( ) ;
let event = event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::ScaleFactorChanged {
new_inner_size : & mut size ,
scale_factor ,
} ,
} ;
sticky_exit_callback ( event , self . window_target ( ) , control_flow , callback ) ;
}
}
MainEvent ::LowMemory = > {
// XXX: how to forward this state to applications?
// It seems like ideally winit should support lifecycle and
// low-memory events, especially for mobile platforms.
warn! ( " TODO: handle Android LowMemory notification " ) ;
}
MainEvent ::Start = > {
// XXX: how to forward this state to applications?
warn! ( " TODO: forward onStart notification to application " ) ;
}
MainEvent ::Resume { .. } = > {
debug! ( " App Resumed - is running " ) ;
self . running = true ;
}
MainEvent ::SaveState { .. } = > {
// XXX: how to forward this state to applications?
// XXX: also how do we expose state restoration to apps?
warn! ( " TODO: forward saveState notification to application " ) ;
}
MainEvent ::Pause = > {
debug! ( " App Paused - stopped running " ) ;
self . running = false ;
}
MainEvent ::Stop = > {
// XXX: how to forward this state to applications?
warn! ( " TODO: forward onStop notification to application " ) ;
}
MainEvent ::Destroy = > {
// XXX: maybe exit mainloop to drop things before being
// killed by the OS?
warn! ( " TODO: forward onDestroy notification to application " ) ;
}
MainEvent ::InsetsChanged { .. } = > {
// XXX: how to forward this state to applications?
warn! ( " TODO: handle Android InsetsChanged notification " ) ;
}
unknown = > {
trace! ( " Unknown MainEvent {unknown:?} (ignored) " ) ;
}
}
} else {
trace! ( " No main event to handle " ) ;
}
2020-06-17 15:55:52 +02:00
2022-11-10 16:55:19 +00:00
// Process input events
2020-06-17 15:55:52 +02:00
2022-11-10 16:55:19 +00:00
self . android_app . input_events ( | event | {
match event {
InputEvent ::MotionEvent ( motion_event ) = > {
let window_id = window ::WindowId ( WindowId ) ;
let device_id = event ::DeviceId ( DeviceId ) ;
let phase = match motion_event . action ( ) {
MotionAction ::Down | MotionAction ::PointerDown = > {
Some ( event ::TouchPhase ::Started )
2022-07-14 12:35:49 +02:00
}
2022-11-10 16:55:19 +00:00
MotionAction ::Up | MotionAction ::PointerUp = > {
Some ( event ::TouchPhase ::Ended )
2022-07-14 12:35:49 +02:00
}
2022-11-10 16:55:19 +00:00
MotionAction ::Move = > Some ( event ::TouchPhase ::Moved ) ,
MotionAction ::Cancel = > {
Some ( event ::TouchPhase ::Cancelled )
}
_ = > {
None // TODO mouse events
}
} ;
if let Some ( phase ) = phase {
let pointers : Box <
dyn Iterator < Item = android_activity ::input ::Pointer < '_ > > ,
> = match phase {
event ::TouchPhase ::Started
| event ::TouchPhase ::Ended = > {
Box ::new (
std ::iter ::once ( motion_event . pointer_at_index (
motion_event . pointer_index ( ) ,
) )
)
} ,
event ::TouchPhase ::Moved
| event ::TouchPhase ::Cancelled = > {
Box ::new ( motion_event . pointers ( ) )
}
} ;
for pointer in pointers {
let location = PhysicalPosition {
x : pointer . x ( ) as _ ,
y : pointer . y ( ) as _ ,
} ;
trace! ( " Input event {device_id:?}, {phase:?}, loc={location:?}, pointer={pointer:?} " ) ;
2020-05-06 15:27:49 +02:00
let event = event ::Event ::WindowEvent {
2022-11-10 16:55:19 +00:00
window_id ,
event : event ::WindowEvent ::Touch (
event ::Touch {
device_id ,
phase ,
location ,
id : pointer . pointer_id ( ) as u64 ,
force : None ,
} ,
) ,
2020-05-06 15:27:49 +02:00
} ;
2022-11-10 16:55:19 +00:00
sticky_exit_callback (
event ,
2020-06-17 15:55:52 +02:00
self . window_target ( ) ,
control_flow ,
2022-11-10 16:55:19 +00:00
callback
2020-06-17 15:55:52 +02:00
) ;
2020-05-06 15:27:49 +02:00
}
}
2019-06-24 12:14:55 -04:00
}
2022-11-10 16:55:19 +00:00
InputEvent ::KeyEvent ( key ) = > {
let state = match key . action ( ) {
KeyAction ::Down = > event ::ElementState ::Pressed ,
KeyAction ::Up = > event ::ElementState ::Released ,
_ = > event ::ElementState ::Released ,
} ;
2023-05-28 20:02:59 +02:00
#[ 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
2022-11-10 16:55:19 +00:00
let event = event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::KeyboardInput {
2023-05-28 20:02:59 +02:00
device_id : event ::DeviceId ( DeviceId ) ,
event : event ::KeyEvent {
2022-11-10 16:55:19 +00:00
state ,
2023-05-28 20:02:59 +02:00
physical_key ,
logical_key ,
location : keycode_to_location ( keycode ) ,
repeat : key . repeat_count ( ) > 0 ,
text : None ,
platform_specific : KeyEventExtra { } ,
2022-11-10 16:55:19 +00:00
} ,
is_synthetic : false ,
} ,
} ;
sticky_exit_callback (
event ,
self . window_target ( ) ,
control_flow ,
2023-05-28 20:02:59 +02:00
callback ,
2022-11-10 16:55:19 +00:00
) ;
}
_ = > {
warn! ( " Unknown android_activity input event {event:?} " )
2019-06-24 12:14:55 -04:00
}
2020-05-06 15:27:49 +02:00
}
2022-11-10 16:55:19 +00:00
// 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
{
while let Ok ( event ) = self . user_events_receiver . try_recv ( ) {
sticky_exit_callback (
crate ::event ::Event ::UserEvent ( event ) ,
self . window_target ( ) ,
control_flow ,
callback ,
) ;
}
}
2020-05-06 15:27:49 +02:00
2022-11-10 16:55:19 +00:00
sticky_exit_callback (
event ::Event ::MainEventsCleared ,
self . window_target ( ) ,
control_flow ,
callback ,
) ;
if self . running {
if resized {
let size = if let Some ( native_window ) = self . android_app . native_window ( ) . as_ref ( ) {
let width = native_window . width ( ) as _ ;
let height = native_window . height ( ) as _ ;
PhysicalSize ::new ( width , height )
} else {
PhysicalSize ::new ( 0 , 0 )
} ;
2020-05-06 15:27:49 +02:00
let event = event ::Event ::WindowEvent {
window_id : window ::WindowId ( WindowId ) ,
event : event ::WindowEvent ::Resized ( size ) ,
} ;
2022-11-10 16:55:19 +00:00
sticky_exit_callback ( event , self . window_target ( ) , control_flow , callback ) ;
2020-05-06 15:27:49 +02:00
}
2022-11-10 16:55:19 +00:00
* pending_redraw | = self . redraw_flag . get_and_reset ( ) ;
if * pending_redraw {
* pending_redraw = false ;
2020-05-06 15:27:49 +02:00
let event = event ::Event ::RedrawRequested ( window ::WindowId ( WindowId ) ) ;
2022-11-10 16:55:19 +00:00
sticky_exit_callback ( event , self . window_target ( ) , control_flow , callback ) ;
2020-05-06 15:27:49 +02:00
}
2022-11-10 16:55:19 +00:00
}
2020-05-06 15:27:49 +02:00
2022-11-10 16:55:19 +00:00
sticky_exit_callback (
event ::Event ::RedrawEventsCleared ,
self . window_target ( ) ,
control_flow ,
callback ,
) ;
let start = Instant ::now ( ) ;
let ( deadline , timeout ) ;
match control_flow {
ControlFlow ::ExitWithCode ( _ ) = > {
deadline = None ;
timeout = None ;
}
ControlFlow ::Poll = > {
* cause = StartCause ::Poll ;
deadline = None ;
timeout = Some ( Duration ::from_millis ( 0 ) ) ;
}
ControlFlow ::Wait = > {
* cause = StartCause ::WaitCancelled {
start ,
requested_resume : None ,
} ;
deadline = None ;
timeout = None ;
}
ControlFlow ::WaitUntil ( wait_deadline ) = > {
* cause = StartCause ::ResumeTimeReached {
start ,
requested_resume : * wait_deadline ,
} ;
timeout = if * wait_deadline > start {
Some ( * wait_deadline - start )
} else {
Some ( Duration ::from_millis ( 0 ) )
} ;
deadline = Some ( * wait_deadline ) ;
}
}
IterationResult {
wait_start : start ,
deadline ,
timeout ,
}
}
pub fn run < F > ( mut self , event_handler : F ) -> !
where
F : 'static
+ FnMut ( event ::Event < '_ , T > , & event_loop ::EventLoopWindowTarget < T > , & mut ControlFlow ) ,
{
let exit_code = self . run_return ( event_handler ) ;
::std ::process ::exit ( exit_code ) ;
}
pub fn run_return < F > ( & mut self , mut callback : F ) -> i32
where
F : FnMut ( event ::Event < '_ , T > , & RootELW < T > , & mut ControlFlow ) ,
{
let mut control_flow = ControlFlow ::default ( ) ;
let mut cause = StartCause ::Init ;
let mut pending_redraw = false ;
// run the initial loop iteration
let mut iter_result = self . single_iteration (
& mut control_flow ,
None ,
& mut pending_redraw ,
& mut cause ,
& mut callback ,
) ;
let exit_code = loop {
if let ControlFlow ::ExitWithCode ( code ) = control_flow {
break code ;
}
let mut timeout = iter_result . timeout ;
// If we already have work to do then we don't want to block on the next poll...
pending_redraw | = self . redraw_flag . get_and_reset ( ) ;
if self . running & & ( pending_redraw | | self . user_events_receiver . has_incoming ( ) ) {
timeout = Some ( Duration ::from_millis ( 0 ) )
}
let app = self . android_app . clone ( ) ; // Don't borrow self as part of poll expression
app . poll_events ( timeout , | poll_event | {
let mut main_event = None ;
match poll_event {
android_activity ::PollEvent ::Wake = > {
// In the X11 backend it's noted that too many false-positive wake ups
// would cause the event loop to run continuously. They handle this by re-checking
// for pending events (assuming they cover all valid reasons for a wake up).
//
// For now, user_events and redraw_requests are the only reasons to expect
// a wake up here so we can ignore the wake up if there are no events/requests.
// We also ignore wake ups while suspended.
pending_redraw | = self . redraw_flag . get_and_reset ( ) ;
if ! self . running
| | ( ! pending_redraw & & ! self . user_events_receiver . has_incoming ( ) )
{
return ;
}
}
android_activity ::PollEvent ::Timeout = > { }
android_activity ::PollEvent ::Main ( event ) = > {
main_event = Some ( event ) ;
}
unknown_event = > {
warn! ( " Unknown poll event {unknown_event:?} (ignored) " ) ;
2018-02-15 14:09:14 +01:00
}
2019-06-24 12:14:55 -04:00
}
2022-11-10 16:55:19 +00:00
let wait_cancelled = iter_result
. deadline
. map_or ( false , | deadline | Instant ::now ( ) < deadline ) ;
if wait_cancelled {
cause = StartCause ::WaitCancelled {
start : iter_result . wait_start ,
requested_resume : iter_result . deadline ,
2020-05-06 15:27:49 +02:00
} ;
2019-06-24 12:14:55 -04:00
}
2022-11-10 16:55:19 +00:00
iter_result = self . single_iteration (
& mut control_flow ,
main_event ,
& mut pending_redraw ,
& mut cause ,
& mut callback ,
) ;
} ) ;
} ;
sticky_exit_callback (
event ::Event ::LoopDestroyed ,
self . window_target ( ) ,
& mut control_flow ,
& mut callback ,
) ;
exit_code
2017-09-04 12:41:02 +02:00
}
2020-05-06 15:27:49 +02:00
pub fn window_target ( & self ) -> & event_loop ::EventLoopWindowTarget < T > {
& self . window_target
2018-02-15 14:09:14 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn create_proxy ( & self ) -> EventLoopProxy < T > {
EventLoopProxy {
2022-07-20 14:52:36 -03:00
user_events_sender : self . user_events_sender . clone ( ) ,
2022-11-10 16:55:19 +00:00
waker : self . android_app . create_waker ( ) ,
2020-05-06 15:27:49 +02:00
}
}
}
pub struct EventLoopProxy < T : 'static > {
2022-07-20 14:52:36 -03:00
user_events_sender : mpsc ::Sender < T > ,
2022-11-10 16:55:19 +00:00
waker : AndroidAppWaker ,
}
impl < T : 'static > Clone for EventLoopProxy < T > {
fn clone ( & self ) -> Self {
EventLoopProxy {
user_events_sender : self . user_events_sender . clone ( ) ,
waker : self . waker . clone ( ) ,
}
}
2017-09-04 12:41:02 +02:00
}
2020-05-06 15:27:49 +02:00
impl < T > EventLoopProxy < T > {
pub fn send_event ( & self , event : T ) -> Result < ( ) , event_loop ::EventLoopClosed < T > > {
2022-07-20 14:52:36 -03:00
self . user_events_sender
. send ( event )
2022-11-10 16:55:19 +00:00
. map_err ( | err | event_loop ::EventLoopClosed ( err . 0 ) ) ? ;
self . waker . wake ( ) ;
2017-09-04 12:41:02 +02:00
Ok ( ( ) )
}
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub struct EventLoopWindowTarget < T : 'static > {
2022-11-10 16:55:19 +00:00
app : AndroidApp ,
redraw_requester : RedrawRequester ,
2020-05-06 15:27:49 +02:00
_marker : std ::marker ::PhantomData < T > ,
}
2020-07-04 15:46:41 -04:00
impl < T : 'static > EventLoopWindowTarget < T > {
2022-09-21 10:04:28 +02:00
pub fn primary_monitor ( & self ) -> Option < MonitorHandle > {
2022-11-10 16:55:19 +00:00
Some ( MonitorHandle ::new ( self . app . clone ( ) ) )
2020-07-04 15:46:41 -04:00
}
pub fn available_monitors ( & self ) -> VecDeque < MonitorHandle > {
let mut v = VecDeque ::with_capacity ( 1 ) ;
2022-11-10 16:55:19 +00:00
v . push_back ( MonitorHandle ::new ( self . app . clone ( ) ) ) ;
2020-07-04 15:46:41 -04:00
v
}
2022-07-21 22:22:36 +03:00
pub fn raw_display_handle ( & self ) -> RawDisplayHandle {
RawDisplayHandle ::Android ( AndroidDisplayHandle ::empty ( ) )
}
2020-07-04 15:46:41 -04:00
}
2020-05-06 15:27:49 +02:00
#[ derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd) ]
2022-11-10 16:55:19 +00:00
pub ( crate ) struct WindowId ;
2017-09-04 12:41:02 +02:00
2018-12-21 09:51:48 -07:00
impl WindowId {
2021-08-30 19:40:02 +02:00
pub const fn dummy ( ) -> Self {
2018-12-21 09:51:48 -07:00
WindowId
}
}
2022-07-02 14:27:19 +03:00
impl From < WindowId > for u64 {
fn from ( _ : WindowId ) -> Self {
0
}
}
impl From < u64 > for WindowId {
fn from ( _ : u64 ) -> Self {
Self
}
}
2020-05-06 15:27:49 +02:00
#[ derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd) ]
2017-09-04 12:41:02 +02:00
pub struct DeviceId ;
2018-12-21 09:51:48 -07:00
impl DeviceId {
2021-08-30 19:40:02 +02:00
pub const fn dummy ( ) -> Self {
2018-12-21 09:51:48 -07:00
DeviceId
}
}
2020-05-06 15:27:49 +02:00
#[ derive(Clone, Copy, Debug, Default, Eq, PartialEq) ]
pub struct PlatformSpecificWindowBuilderAttributes ;
2017-09-04 12:41:02 +02:00
2022-11-10 16:55:19 +00:00
pub ( crate ) struct Window {
app : AndroidApp ,
redraw_requester : RedrawRequester ,
}
2018-06-14 19:42:18 -04:00
2020-05-06 15:27:49 +02:00
impl Window {
2022-06-10 19:05:28 +02:00
pub ( crate ) fn new < T : 'static > (
2022-11-10 16:55:19 +00:00
el : & EventLoopWindowTarget < T > ,
2020-05-06 15:27:49 +02:00
_window_attrs : window ::WindowAttributes ,
_ : PlatformSpecificWindowBuilderAttributes ,
) -> Result < Self , error ::OsError > {
// FIXME this ignores requested window attributes
2022-11-10 16:55:19 +00:00
Ok ( Self {
app : el . app . clone ( ) ,
redraw_requester : el . redraw_requester . clone ( ) ,
} )
2020-05-06 15:27:49 +02:00
}
2018-06-14 19:42:18 -04:00
2020-05-06 15:27:49 +02:00
pub fn id ( & self ) -> WindowId {
WindowId
2018-06-14 19:42:18 -04:00
}
2016-10-31 17:08:55 +01:00
2022-09-21 10:04:28 +02:00
pub fn primary_monitor ( & self ) -> Option < MonitorHandle > {
2022-11-10 16:55:19 +00:00
Some ( MonitorHandle ::new ( self . app . clone ( ) ) )
2017-09-04 12:41:02 +02:00
}
2016-10-31 17:08:55 +01:00
2020-05-06 15:27:49 +02:00
pub fn available_monitors ( & self ) -> VecDeque < MonitorHandle > {
let mut v = VecDeque ::with_capacity ( 1 ) ;
2022-11-10 16:55:19 +00:00
v . push_back ( MonitorHandle ::new ( self . app . clone ( ) ) ) ;
2020-05-06 15:27:49 +02:00
v
2016-10-31 17:08:55 +01:00
}
2017-09-07 09:33:46 +01:00
2022-09-21 10:04:28 +02:00
pub fn current_monitor ( & self ) -> Option < MonitorHandle > {
2022-11-10 16:55:19 +00:00
Some ( MonitorHandle ::new ( self . app . clone ( ) ) )
2017-09-07 09:33:46 +01:00
}
2017-10-17 14:56:38 +03:00
2020-01-03 14:52:27 -05:00
pub fn scale_factor ( & self ) -> f64 {
2022-11-10 16:55:19 +00:00
MonitorHandle ::new ( self . app . clone ( ) ) . scale_factor ( )
2017-10-17 14:56:38 +03:00
}
2016-10-31 17:08:55 +01:00
2020-05-06 15:27:49 +02:00
pub fn request_redraw ( & self ) {
2022-11-10 16:55:19 +00:00
self . redraw_requester . request_redraw ( )
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn inner_position ( & self ) -> Result < PhysicalPosition < i32 > , error ::NotSupportedError > {
Err ( error ::NotSupportedError ::new ( ) )
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn outer_position ( & self ) -> Result < PhysicalPosition < i32 > , error ::NotSupportedError > {
Err ( error ::NotSupportedError ::new ( ) )
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn set_outer_position ( & self , _position : Position ) {
// no effect
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn inner_size ( & self ) -> PhysicalSize < u32 > {
self . outer_size ( )
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn set_inner_size ( & self , _size : Size ) {
2020-07-26 21:13:17 +00:00
warn! ( " Cannot set window size on Android " ) ;
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn outer_size ( & self ) -> PhysicalSize < u32 > {
2022-11-10 16:55:19 +00:00
MonitorHandle ::new ( self . app . clone ( ) ) . size ( )
2018-04-16 21:40:30 -04:00
}
2020-05-06 15:27:49 +02:00
pub fn set_min_inner_size ( & self , _ : Option < Size > ) { }
2016-10-31 17:08:55 +01:00
2020-05-06 15:27:49 +02:00
pub fn set_max_inner_size ( & self , _ : Option < Size > ) { }
2018-03-23 05:35:35 -04:00
2022-09-03 21:50:22 +03:00
pub fn resize_increments ( & self ) -> Option < PhysicalSize < u32 > > {
None
}
pub fn set_resize_increments ( & self , _increments : Option < Size > ) { }
2020-05-06 15:27:49 +02:00
pub fn set_title ( & self , _title : & str ) { }
2018-03-23 05:35:35 -04:00
2023-01-15 23:39:36 +03:00
pub fn set_transparent ( & self , _transparent : bool ) { }
2020-05-06 15:27:49 +02:00
pub fn set_visible ( & self , _visibility : bool ) { }
2018-06-14 19:42:18 -04:00
2022-02-17 20:44:14 +02:00
pub fn is_visible ( & self ) -> Option < bool > {
None
}
2020-05-06 15:27:49 +02:00
pub fn set_resizable ( & self , _resizeable : bool ) { }
2016-10-31 17:08:55 +01:00
2022-02-17 17:03:17 +02:00
pub fn is_resizable ( & self ) -> bool {
false
}
2022-11-29 12:03:51 +02:00
pub fn set_enabled_buttons ( & self , _buttons : WindowButtons ) { }
pub fn enabled_buttons ( & self ) -> WindowButtons {
WindowButtons ::all ( )
}
2020-05-06 15:27:49 +02:00
pub fn set_minimized ( & self , _minimized : bool ) { }
2016-10-31 17:08:55 +01:00
2023-01-19 23:39:04 +02:00
pub fn is_minimized ( & self ) -> Option < bool > {
None
}
2020-05-06 15:27:49 +02:00
pub fn set_maximized ( & self , _maximized : bool ) { }
2016-10-31 17:08:55 +01:00
2021-01-27 20:01:17 +02:00
pub fn is_maximized ( & self ) -> bool {
false
}
2022-09-21 10:04:28 +02:00
pub fn set_fullscreen ( & self , _monitor : Option < Fullscreen > ) {
2020-07-26 21:13:17 +00:00
warn! ( " Cannot set fullscreen on Android " ) ;
2016-10-31 17:08:55 +01:00
}
2022-09-21 10:04:28 +02:00
pub fn fullscreen ( & self ) -> Option < Fullscreen > {
2020-05-06 15:27:49 +02:00
None
2016-10-31 17:08:55 +01:00
}
2020-05-06 15:27:49 +02:00
pub fn set_decorations ( & self , _decorations : bool ) { }
2018-06-18 12:32:18 -04:00
2022-02-17 15:31:13 +02:00
pub fn is_decorated ( & self ) -> bool {
true
}
2022-11-26 03:50:58 +02:00
pub fn set_window_level ( & self , _level : WindowLevel ) { }
2016-10-31 17:08:55 +01:00
2020-05-06 15:27:49 +02:00
pub fn set_window_icon ( & self , _window_icon : Option < crate ::icon ::Icon > ) { }
2017-08-28 00:22:26 +01:00
2020-05-06 15:27:49 +02:00
pub fn set_ime_position ( & self , _position : Position ) { }
2022-05-07 05:29:25 +03:00
pub fn set_ime_allowed ( & self , _allowed : bool ) { }
2023-01-29 16:46:46 +01:00
pub fn set_ime_purpose ( & self , _purpose : ImePurpose ) { }
2021-05-19 18:39:53 +02:00
pub fn focus_window ( & self ) { }
2020-11-27 03:03:08 +01:00
pub fn request_user_attention ( & self , _request_type : Option < window ::UserAttentionType > ) { }
2020-05-06 15:27:49 +02:00
pub fn set_cursor_icon ( & self , _ : window ::CursorIcon ) { }
2019-12-22 01:04:11 -05:00
2020-05-06 15:27:49 +02:00
pub fn set_cursor_position ( & self , _ : Position ) -> Result < ( ) , error ::ExternalError > {
Err ( error ::ExternalError ::NotSupported (
error ::NotSupportedError ::new ( ) ,
) )
2017-09-07 09:33:46 +01:00
}
2022-06-13 09:43:14 +03:00
pub fn set_cursor_grab ( & self , _ : CursorGrabMode ) -> Result < ( ) , error ::ExternalError > {
2020-05-06 15:27:49 +02:00
Err ( error ::ExternalError ::NotSupported (
error ::NotSupportedError ::new ( ) ,
) )
2019-04-26 03:09:32 +10:00
}
2020-05-06 15:27:49 +02:00
pub fn set_cursor_visible ( & self , _ : bool ) { }
2021-03-07 10:43:23 +01:00
pub fn drag_window ( & self ) -> Result < ( ) , error ::ExternalError > {
Err ( error ::ExternalError ::NotSupported (
error ::NotSupportedError ::new ( ) ,
) )
}
2023-01-11 18:07:09 +01:00
pub fn drag_resize_window (
& self ,
_direction : ResizeDirection ,
) -> Result < ( ) , error ::ExternalError > {
Err ( error ::ExternalError ::NotSupported (
error ::NotSupportedError ::new ( ) ,
) )
}
2022-04-12 19:10:46 +02:00
pub fn set_cursor_hittest ( & self , _hittest : bool ) -> Result < ( ) , error ::ExternalError > {
Err ( error ::ExternalError ::NotSupported (
error ::NotSupportedError ::new ( ) ,
) )
}
2021-11-30 17:50:23 +01:00
pub fn raw_window_handle ( & self ) -> RawWindowHandle {
2022-11-10 16:55:19 +00:00
if let Some ( native_window ) = self . app . native_window ( ) . as_ref ( ) {
2022-06-10 11:37:06 +02:00
native_window . raw_window_handle ( )
2020-05-06 15:27:49 +02:00
} else {
2020-10-29 16:23:46 -05:00
panic! ( " Cannot get the native window, it's null and will always be null before Event::Resumed and after Event::Suspended. Make sure you only call this function between those events. " ) ;
2022-06-10 11:37:06 +02:00
}
2017-08-28 01:43:34 +01:00
}
2022-07-21 22:22:36 +03:00
pub fn raw_display_handle ( & self ) -> RawDisplayHandle {
RawDisplayHandle ::Android ( AndroidDisplayHandle ::empty ( ) )
}
2022-11-10 16:55:19 +00:00
pub fn config ( & self ) -> ConfigurationRef {
self . app . config ( )
2017-12-22 07:50:46 -05:00
}
2020-05-06 15:27:49 +02:00
pub fn content_rect ( & self ) -> Rect {
2022-11-10 16:55:19 +00:00
self . app . content_rect ( )
2018-05-20 10:24:05 -04:00
}
2022-10-19 03:34:36 +09:00
2022-11-29 11:05:51 +02:00
pub fn set_theme ( & self , _theme : Option < Theme > ) { }
2022-10-19 03:34:36 +09:00
pub fn theme ( & self ) -> Option < Theme > {
None
}
2022-11-03 10:11:37 -07:00
2023-01-17 03:30:14 +02:00
pub fn has_focus ( & self ) -> bool {
* HAS_FOCUS . read ( ) . unwrap ( )
}
2022-11-03 10:11:37 -07:00
pub fn title ( & self ) -> String {
String ::new ( )
}
2023-05-28 20:02:59 +02:00
pub fn reset_dead_keys ( & self ) { }
2020-05-06 15:27:49 +02:00
}
2018-05-20 10:24:05 -04:00
2020-05-06 15:27:49 +02:00
#[ derive(Default, Clone, Debug) ]
pub struct OsError ;
use std ::fmt ::{ self , Display , Formatter } ;
impl Display for OsError {
fn fmt ( & self , fmt : & mut Formatter < '_ > ) -> Result < ( ) , fmt ::Error > {
write! ( fmt , " Android OS Error " )
2018-05-07 17:36:21 -04:00
}
2020-05-06 15:27:49 +02:00
}
2018-05-07 17:36:21 -04:00
2020-05-06 15:27:49 +02:00
pub ( crate ) use crate ::icon ::NoIcon as PlatformIcon ;
2022-11-10 16:55:19 +00:00
#[ derive(Clone, Debug, PartialEq, Eq, Hash) ]
pub struct MonitorHandle {
app : AndroidApp ,
}
impl PartialOrd for MonitorHandle {
fn partial_cmp ( & self , _other : & Self ) -> Option < std ::cmp ::Ordering > {
Some ( std ::cmp ::Ordering ::Equal )
}
}
impl Ord for MonitorHandle {
fn cmp ( & self , _other : & Self ) -> std ::cmp ::Ordering {
std ::cmp ::Ordering ::Equal
}
}
2020-05-06 15:27:49 +02:00
impl MonitorHandle {
2022-11-10 16:55:19 +00:00
pub ( crate ) fn new ( app : AndroidApp ) -> Self {
Self { app }
}
2020-05-06 15:27:49 +02:00
pub fn name ( & self ) -> Option < String > {
Some ( " Android Device " . to_owned ( ) )
2018-05-17 21:28:30 -04:00
}
2020-05-06 15:27:49 +02:00
pub fn size ( & self ) -> PhysicalSize < u32 > {
2022-11-10 16:55:19 +00:00
if let Some ( native_window ) = self . app . native_window ( ) {
PhysicalSize ::new ( native_window . width ( ) as _ , native_window . height ( ) as _ )
2020-05-06 15:27:49 +02:00
} else {
PhysicalSize ::new ( 0 , 0 )
2019-06-21 11:33:15 -04:00
}
2017-08-28 00:22:26 +01:00
}
2016-10-31 17:08:55 +01:00
2020-05-06 15:27:49 +02:00
pub fn position ( & self ) -> PhysicalPosition < i32 > {
( 0 , 0 ) . into ( )
2018-06-16 10:14:12 -04:00
}
2020-05-06 15:27:49 +02:00
pub fn scale_factor ( & self ) -> f64 {
2022-11-10 16:55:19 +00:00
self . app
. config ( )
2020-05-06 15:27:49 +02:00
. density ( )
. map ( | dpi | dpi as f64 / 160.0 )
. unwrap_or ( 1.0 )
}
2022-07-08 13:25:56 +03:00
pub fn refresh_rate_millihertz ( & self ) -> Option < u32 > {
2022-07-15 14:02:12 -02:30
// FIXME no way to get real refresh rate for now.
2022-07-08 13:25:56 +03:00
None
}
2022-09-21 10:04:28 +02:00
pub fn video_modes ( & self ) -> impl Iterator < Item = VideoMode > {
2020-05-06 15:27:49 +02:00
let size = self . size ( ) . into ( ) ;
// FIXME this is not the real refresh rate
2022-06-10 13:43:33 +03:00
// (it is guaranteed to support 32 bit color though)
2022-09-21 10:04:28 +02:00
std ::iter ::once ( VideoMode {
size ,
bit_depth : 32 ,
refresh_rate_millihertz : 60000 ,
monitor : self . clone ( ) ,
2022-06-10 13:43:33 +03:00
} )
2018-06-16 10:14:12 -04:00
}
2020-05-06 15:27:49 +02:00
}
2018-06-16 10:14:12 -04:00
2020-05-06 15:27:49 +02:00
#[ derive(Clone, Debug, Eq, Hash, PartialEq) ]
pub struct VideoMode {
size : ( u32 , u32 ) ,
bit_depth : u16 ,
2022-07-08 13:25:56 +03:00
refresh_rate_millihertz : u32 ,
2020-05-06 15:27:49 +02:00
monitor : MonitorHandle ,
}
impl VideoMode {
pub fn size ( & self ) -> PhysicalSize < u32 > {
self . size . into ( )
2016-10-31 17:08:55 +01:00
}
2019-09-30 17:17:01 +02:00
2020-05-06 15:27:49 +02:00
pub fn bit_depth ( & self ) -> u16 {
self . bit_depth
2019-09-30 17:17:01 +02:00
}
2017-07-06 23:33:42 +02:00
2022-07-08 13:25:56 +03:00
pub fn refresh_rate_millihertz ( & self ) -> u32 {
self . refresh_rate_millihertz
2020-05-06 15:27:49 +02:00
}
2017-09-04 12:41:02 +02:00
2022-09-21 10:04:28 +02:00
pub fn monitor ( & self ) -> MonitorHandle {
self . monitor . clone ( )
2020-05-06 15:27:49 +02:00
}
}
2023-05-28 20:02:59 +02:00
fn keycode_to_logical ( keycode : ndk ::event ::Keycode , native : NativeKey ) -> Key {
use ndk ::event ::Keycode ::* ;
// The android `Keycode` is sort-of layout dependent. More specifically
// if I press the Z key using a US layout, then I get KEYCODE_Z,
// but if I press the same key after switching to a HUN layout, I get
// KEYCODE_Y.
//
// To prevents us from using this value to determine the `physical_key`
// (also know as winit's `KeyCode`)
//
// Unfortunately the documentation says that the scancode values
// "are not reliable and vary from device to device". Which seems to mean
// that there's no way to reliably get the physical_key on android.
match keycode {
Unknown = > Key ::Unidentified ( native ) ,
// Can be added on demand
SoftLeft = > Key ::Unidentified ( native ) ,
SoftRight = > Key ::Unidentified ( native ) ,
// Using `BrowserHome` instead of `GoHome` according to
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
Home = > Key ::BrowserHome ,
Back = > Key ::BrowserBack ,
Call = > Key ::Call ,
Endcall = > Key ::EndCall ,
//-------------------------------------------------------------------------------
// Reporting unidentified, because the specific character is layout dependent.
// (I'm not sure though)
Keycode0 = > Key ::Unidentified ( native ) ,
Keycode1 = > Key ::Unidentified ( native ) ,
Keycode2 = > Key ::Unidentified ( native ) ,
Keycode3 = > Key ::Unidentified ( native ) ,
Keycode4 = > Key ::Unidentified ( native ) ,
Keycode5 = > Key ::Unidentified ( native ) ,
Keycode6 = > Key ::Unidentified ( native ) ,
Keycode7 = > Key ::Unidentified ( native ) ,
Keycode8 = > Key ::Unidentified ( native ) ,
Keycode9 = > Key ::Unidentified ( native ) ,
Star = > Key ::Unidentified ( native ) ,
Pound = > Key ::Unidentified ( native ) ,
A = > Key ::Unidentified ( native ) ,
B = > Key ::Unidentified ( native ) ,
C = > Key ::Unidentified ( native ) ,
D = > Key ::Unidentified ( native ) ,
E = > Key ::Unidentified ( native ) ,
F = > Key ::Unidentified ( native ) ,
G = > Key ::Unidentified ( native ) ,
H = > Key ::Unidentified ( native ) ,
I = > Key ::Unidentified ( native ) ,
J = > Key ::Unidentified ( native ) ,
K = > Key ::Unidentified ( native ) ,
L = > Key ::Unidentified ( native ) ,
M = > Key ::Unidentified ( native ) ,
N = > Key ::Unidentified ( native ) ,
O = > Key ::Unidentified ( native ) ,
P = > Key ::Unidentified ( native ) ,
Q = > Key ::Unidentified ( native ) ,
R = > Key ::Unidentified ( native ) ,
S = > Key ::Unidentified ( native ) ,
T = > Key ::Unidentified ( native ) ,
U = > Key ::Unidentified ( native ) ,
V = > Key ::Unidentified ( native ) ,
W = > Key ::Unidentified ( native ) ,
X = > Key ::Unidentified ( native ) ,
Y = > Key ::Unidentified ( native ) ,
Z = > Key ::Unidentified ( native ) ,
Comma = > Key ::Unidentified ( native ) ,
Period = > Key ::Unidentified ( native ) ,
Grave = > Key ::Unidentified ( native ) ,
Minus = > Key ::Unidentified ( native ) ,
Equals = > Key ::Unidentified ( native ) ,
LeftBracket = > Key ::Unidentified ( native ) ,
RightBracket = > Key ::Unidentified ( native ) ,
Backslash = > Key ::Unidentified ( native ) ,
Semicolon = > Key ::Unidentified ( native ) ,
Apostrophe = > Key ::Unidentified ( native ) ,
Slash = > Key ::Unidentified ( native ) ,
At = > Key ::Unidentified ( native ) ,
Plus = > Key ::Unidentified ( native ) ,
//-------------------------------------------------------------------------------
DpadUp = > Key ::ArrowUp ,
DpadDown = > Key ::ArrowDown ,
DpadLeft = > Key ::ArrowLeft ,
DpadRight = > Key ::ArrowRight ,
DpadCenter = > Key ::Enter ,
VolumeUp = > Key ::AudioVolumeUp ,
VolumeDown = > Key ::AudioVolumeDown ,
Power = > Key ::Power ,
Camera = > Key ::Camera ,
Clear = > Key ::Clear ,
AltLeft = > Key ::Alt ,
AltRight = > Key ::Alt ,
ShiftLeft = > Key ::Shift ,
ShiftRight = > Key ::Shift ,
Tab = > Key ::Tab ,
Space = > Key ::Space ,
Sym = > Key ::Symbol ,
Explorer = > Key ::LaunchWebBrowser ,
Envelope = > Key ::LaunchMail ,
Enter = > Key ::Enter ,
Del = > Key ::Backspace ,
// According to https://developer.android.com/reference/android/view/KeyEvent#KEYCODE_NUM
Num = > Key ::Alt ,
Headsethook = > Key ::HeadsetHook ,
Focus = > Key ::CameraFocus ,
Menu = > Key ::Unidentified ( native ) ,
Notification = > Key ::Notification ,
Search = > Key ::BrowserSearch ,
MediaPlayPause = > Key ::MediaPlayPause ,
MediaStop = > Key ::MediaStop ,
MediaNext = > Key ::MediaTrackNext ,
MediaPrevious = > Key ::MediaTrackPrevious ,
MediaRewind = > Key ::MediaRewind ,
MediaFastForward = > Key ::MediaFastForward ,
Mute = > Key ::MicrophoneVolumeMute ,
PageUp = > Key ::PageUp ,
PageDown = > Key ::PageDown ,
Pictsymbols = > Key ::Unidentified ( native ) ,
SwitchCharset = > Key ::Unidentified ( native ) ,
// -----------------------------------------------------------------
// Gamepad events should be exposed through a separate API, not
// keyboard events
ButtonA = > Key ::Unidentified ( native ) ,
ButtonB = > Key ::Unidentified ( native ) ,
ButtonC = > Key ::Unidentified ( native ) ,
ButtonX = > Key ::Unidentified ( native ) ,
ButtonY = > Key ::Unidentified ( native ) ,
ButtonZ = > Key ::Unidentified ( native ) ,
ButtonL1 = > Key ::Unidentified ( native ) ,
ButtonR1 = > Key ::Unidentified ( native ) ,
ButtonL2 = > Key ::Unidentified ( native ) ,
ButtonR2 = > Key ::Unidentified ( native ) ,
ButtonThumbl = > Key ::Unidentified ( native ) ,
ButtonThumbr = > Key ::Unidentified ( native ) ,
ButtonStart = > Key ::Unidentified ( native ) ,
ButtonSelect = > Key ::Unidentified ( native ) ,
ButtonMode = > Key ::Unidentified ( native ) ,
// -----------------------------------------------------------------
Escape = > Key ::Escape ,
ForwardDel = > Key ::Delete ,
CtrlLeft = > Key ::Control ,
CtrlRight = > Key ::Control ,
CapsLock = > Key ::CapsLock ,
ScrollLock = > Key ::ScrollLock ,
MetaLeft = > Key ::Super ,
MetaRight = > Key ::Super ,
Function = > Key ::Fn ,
Sysrq = > Key ::PrintScreen ,
Break = > Key ::Pause ,
MoveHome = > Key ::Home ,
MoveEnd = > Key ::End ,
Insert = > Key ::Insert ,
Forward = > Key ::BrowserForward ,
MediaPlay = > Key ::MediaPlay ,
MediaPause = > Key ::MediaPause ,
MediaClose = > Key ::MediaClose ,
MediaEject = > Key ::Eject ,
MediaRecord = > Key ::MediaRecord ,
F1 = > Key ::F1 ,
F2 = > Key ::F2 ,
F3 = > Key ::F3 ,
F4 = > Key ::F4 ,
F5 = > Key ::F5 ,
F6 = > Key ::F6 ,
F7 = > Key ::F7 ,
F8 = > Key ::F8 ,
F9 = > Key ::F9 ,
F10 = > Key ::F10 ,
F11 = > Key ::F11 ,
F12 = > Key ::F12 ,
NumLock = > Key ::NumLock ,
Numpad0 = > Key ::Unidentified ( native ) ,
Numpad1 = > Key ::Unidentified ( native ) ,
Numpad2 = > Key ::Unidentified ( native ) ,
Numpad3 = > Key ::Unidentified ( native ) ,
Numpad4 = > Key ::Unidentified ( native ) ,
Numpad5 = > Key ::Unidentified ( native ) ,
Numpad6 = > Key ::Unidentified ( native ) ,
Numpad7 = > Key ::Unidentified ( native ) ,
Numpad8 = > Key ::Unidentified ( native ) ,
Numpad9 = > Key ::Unidentified ( native ) ,
NumpadDivide = > Key ::Unidentified ( native ) ,
NumpadMultiply = > Key ::Unidentified ( native ) ,
NumpadSubtract = > Key ::Unidentified ( native ) ,
NumpadAdd = > Key ::Unidentified ( native ) ,
NumpadDot = > Key ::Unidentified ( native ) ,
NumpadComma = > Key ::Unidentified ( native ) ,
NumpadEnter = > Key ::Unidentified ( native ) ,
NumpadEquals = > Key ::Unidentified ( native ) ,
NumpadLeftParen = > Key ::Unidentified ( native ) ,
NumpadRightParen = > Key ::Unidentified ( native ) ,
VolumeMute = > Key ::AudioVolumeMute ,
Info = > Key ::Info ,
ChannelUp = > Key ::ChannelUp ,
ChannelDown = > Key ::ChannelDown ,
ZoomIn = > Key ::ZoomIn ,
ZoomOut = > Key ::ZoomOut ,
Tv = > Key ::TV ,
Window = > Key ::Unidentified ( native ) ,
Guide = > Key ::Guide ,
Dvr = > Key ::DVR ,
Bookmark = > Key ::BrowserFavorites ,
Captions = > Key ::ClosedCaptionToggle ,
Settings = > Key ::Settings ,
TvPower = > Key ::TVPower ,
TvInput = > Key ::TVInput ,
StbPower = > Key ::STBPower ,
StbInput = > Key ::STBInput ,
AvrPower = > Key ::AVRPower ,
AvrInput = > Key ::AVRInput ,
ProgRed = > Key ::ColorF0Red ,
ProgGreen = > Key ::ColorF1Green ,
ProgYellow = > Key ::ColorF2Yellow ,
ProgBlue = > Key ::ColorF3Blue ,
AppSwitch = > Key ::AppSwitch ,
Button1 = > Key ::Unidentified ( native ) ,
Button2 = > Key ::Unidentified ( native ) ,
Button3 = > Key ::Unidentified ( native ) ,
Button4 = > Key ::Unidentified ( native ) ,
Button5 = > Key ::Unidentified ( native ) ,
Button6 = > Key ::Unidentified ( native ) ,
Button7 = > Key ::Unidentified ( native ) ,
Button8 = > Key ::Unidentified ( native ) ,
Button9 = > Key ::Unidentified ( native ) ,
Button10 = > Key ::Unidentified ( native ) ,
Button11 = > Key ::Unidentified ( native ) ,
Button12 = > Key ::Unidentified ( native ) ,
Button13 = > Key ::Unidentified ( native ) ,
Button14 = > Key ::Unidentified ( native ) ,
Button15 = > Key ::Unidentified ( native ) ,
Button16 = > Key ::Unidentified ( native ) ,
LanguageSwitch = > Key ::GroupNext ,
MannerMode = > Key ::MannerMode ,
Keycode3dMode = > Key ::TV3DMode ,
Contacts = > Key ::LaunchContacts ,
Calendar = > Key ::LaunchCalendar ,
Music = > Key ::LaunchMusicPlayer ,
Calculator = > Key ::LaunchApplication2 ,
ZenkakuHankaku = > Key ::ZenkakuHankaku ,
Eisu = > Key ::Eisu ,
Muhenkan = > Key ::NonConvert ,
Henkan = > Key ::Convert ,
KatakanaHiragana = > Key ::HiraganaKatakana ,
Yen = > Key ::Unidentified ( native ) ,
Ro = > Key ::Unidentified ( native ) ,
Kana = > Key ::KanjiMode ,
Assist = > Key ::Unidentified ( native ) ,
BrightnessDown = > Key ::BrightnessDown ,
BrightnessUp = > Key ::BrightnessUp ,
MediaAudioTrack = > Key ::MediaAudioTrack ,
Sleep = > Key ::Standby ,
Wakeup = > Key ::WakeUp ,
Pairing = > Key ::Pairing ,
MediaTopMenu = > Key ::MediaTopMenu ,
Keycode11 = > Key ::Unidentified ( native ) ,
Keycode12 = > Key ::Unidentified ( native ) ,
LastChannel = > Key ::MediaLast ,
TvDataService = > Key ::TVDataService ,
VoiceAssist = > Key ::VoiceDial ,
TvRadioService = > Key ::TVRadioService ,
TvTeletext = > Key ::Teletext ,
TvNumberEntry = > Key ::TVNumberEntry ,
TvTerrestrialAnalog = > Key ::TVTerrestrialAnalog ,
TvTerrestrialDigital = > Key ::TVTerrestrialDigital ,
TvSatellite = > Key ::TVSatellite ,
TvSatelliteBs = > Key ::TVSatelliteBS ,
TvSatelliteCs = > Key ::TVSatelliteCS ,
TvSatelliteService = > Key ::TVSatelliteToggle ,
TvNetwork = > Key ::TVNetwork ,
TvAntennaCable = > Key ::TVAntennaCable ,
TvInputHdmi1 = > Key ::TVInputHDMI1 ,
TvInputHdmi2 = > Key ::TVInputHDMI2 ,
TvInputHdmi3 = > Key ::TVInputHDMI3 ,
TvInputHdmi4 = > Key ::TVInputHDMI4 ,
TvInputComposite1 = > Key ::TVInputComposite1 ,
TvInputComposite2 = > Key ::TVInputComposite2 ,
TvInputComponent1 = > Key ::TVInputComponent1 ,
TvInputComponent2 = > Key ::TVInputComponent2 ,
TvInputVga1 = > Key ::TVInputVGA1 ,
TvAudioDescription = > Key ::TVAudioDescription ,
TvAudioDescriptionMixUp = > Key ::TVAudioDescriptionMixUp ,
TvAudioDescriptionMixDown = > Key ::TVAudioDescriptionMixDown ,
TvZoomMode = > Key ::ZoomToggle ,
TvContentsMenu = > Key ::TVContentsMenu ,
TvMediaContextMenu = > Key ::TVMediaContext ,
TvTimerProgramming = > Key ::TVTimer ,
Help = > Key ::Help ,
NavigatePrevious = > Key ::NavigatePrevious ,
NavigateNext = > Key ::NavigateNext ,
NavigateIn = > Key ::NavigateIn ,
NavigateOut = > Key ::NavigateOut ,
StemPrimary = > Key ::Unidentified ( native ) ,
Stem1 = > Key ::Unidentified ( native ) ,
Stem2 = > Key ::Unidentified ( native ) ,
Stem3 = > Key ::Unidentified ( native ) ,
DpadUpLeft = > Key ::Unidentified ( native ) ,
DpadDownLeft = > Key ::Unidentified ( native ) ,
DpadUpRight = > Key ::Unidentified ( native ) ,
DpadDownRight = > Key ::Unidentified ( native ) ,
MediaSkipForward = > Key ::MediaSkipForward ,
MediaSkipBackward = > Key ::MediaSkipBackward ,
MediaStepForward = > Key ::MediaStepForward ,
MediaStepBackward = > Key ::MediaStepBackward ,
SoftSleep = > Key ::Unidentified ( native ) ,
Cut = > Key ::Cut ,
Copy = > Key ::Copy ,
Paste = > Key ::Paste ,
SystemNavigationUp = > Key ::Unidentified ( native ) ,
SystemNavigationDown = > Key ::Unidentified ( native ) ,
SystemNavigationLeft = > Key ::Unidentified ( native ) ,
SystemNavigationRight = > Key ::Unidentified ( native ) ,
AllApps = > Key ::Unidentified ( native ) ,
Refresh = > Key ::BrowserRefresh ,
ThumbsUp = > Key ::Unidentified ( native ) ,
ThumbsDown = > Key ::Unidentified ( native ) ,
ProfileSwitch = > Key ::Unidentified ( native ) ,
}
}
fn keycode_to_location ( keycode : ndk ::event ::Keycode ) -> KeyLocation {
use ndk ::event ::Keycode ::* ;
match keycode {
AltLeft = > KeyLocation ::Left ,
AltRight = > KeyLocation ::Right ,
ShiftLeft = > KeyLocation ::Left ,
ShiftRight = > KeyLocation ::Right ,
// According to https://developer.android.com/reference/android/view/KeyEvent#KEYCODE_NUM
Num = > KeyLocation ::Left ,
CtrlLeft = > KeyLocation ::Left ,
CtrlRight = > KeyLocation ::Right ,
MetaLeft = > KeyLocation ::Left ,
MetaRight = > KeyLocation ::Right ,
NumLock = > KeyLocation ::Numpad ,
Numpad0 = > KeyLocation ::Numpad ,
Numpad1 = > KeyLocation ::Numpad ,
Numpad2 = > KeyLocation ::Numpad ,
Numpad3 = > KeyLocation ::Numpad ,
Numpad4 = > KeyLocation ::Numpad ,
Numpad5 = > KeyLocation ::Numpad ,
Numpad6 = > KeyLocation ::Numpad ,
Numpad7 = > KeyLocation ::Numpad ,
Numpad8 = > KeyLocation ::Numpad ,
Numpad9 = > KeyLocation ::Numpad ,
NumpadDivide = > KeyLocation ::Numpad ,
NumpadMultiply = > KeyLocation ::Numpad ,
NumpadSubtract = > KeyLocation ::Numpad ,
NumpadAdd = > KeyLocation ::Numpad ,
NumpadDot = > KeyLocation ::Numpad ,
NumpadComma = > KeyLocation ::Numpad ,
NumpadEnter = > KeyLocation ::Numpad ,
NumpadEquals = > KeyLocation ::Numpad ,
NumpadLeftParen = > KeyLocation ::Numpad ,
NumpadRightParen = > KeyLocation ::Numpad ,
_ = > KeyLocation ::Standard ,
}
}