1+ using osu . Android . Input ;
12// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
23// See the LICENCE file in the repository root for full licence text.
34
1819using osu . Framework . Android ;
1920using osu . Game . Database ;
2021using osu . Android . Native ;
22+ using osu . Framework . Logging ;
2123
2224namespace osu . Android
2325{
2426 [ Activity ( ConfigurationChanges = DEFAULT_CONFIG_CHANGES , Exported = true , LaunchMode = DEFAULT_LAUNCH_MODE , MainLauncher = true ) ]
2527 [ IntentFilter ( new [ ] { Intent . ActionView } , Categories = new [ ] { Intent . CategoryDefault } , DataScheme = "content" , DataPathPattern = ".*\\ .osz" , DataHost = "*" , DataMimeType = "*/*" ) ]
2628 [ IntentFilter ( new [ ] { Intent . ActionView } , Categories = new [ ] { Intent . CategoryDefault } , DataScheme = "content" , DataPathPattern = ".*\\ .osk" , DataHost = "*" , DataMimeType = "*/*" ) ]
2729 [ IntentFilter ( new [ ] { Intent . ActionView } , Categories = new [ ] { Intent . CategoryDefault } , DataScheme = "content" , DataPathPattern = ".*\\ .osr" , DataHost = "*" , DataMimeType = "*/*" ) ]
30+ [ IntentFilter ( new [ ] { Intent . ActionView } , Categories = new [ ] { Intent . CategoryDefault } , DataScheme = "content" , DataPathPattern = ".*\\ .osr" , DataHost = "*" , DataMimeType = "application/x-osu-replay" ) ]
2831 [ IntentFilter ( new [ ] { Intent . ActionView } , Categories = new [ ] { Intent . CategoryDefault } , DataScheme = "content" , DataMimeType = "application/x-osu-beatmap-archive" ) ]
2932 [ IntentFilter ( new [ ] { Intent . ActionView } , Categories = new [ ] { Intent . CategoryDefault } , DataScheme = "content" , DataMimeType = "application/x-osu-skin-archive" ) ]
3033 [ IntentFilter ( new [ ] { Intent . ActionView } , Categories = new [ ] { Intent . CategoryDefault } , DataScheme = "content" , DataMimeType = "application/x-osu-replay" ) ]
@@ -48,6 +51,7 @@ public class OsuGameActivity : AndroidGameActivity, ISurfaceHolderCallback
4851 public ScreenOrientation DefaultOrientation = ScreenOrientation . Unspecified ;
4952
5053 public new bool IsTablet { get ; private set ; }
54+ internal AndroidStylusHandler ? StylusHandler ;
5155
5256 private OsuGameAndroid ? game ;
5357
@@ -83,6 +87,19 @@ protected override void OnCreate(Bundle? savedInstanceState)
8387 {
8488 Window . AddFlags ( WindowManagerFlags . Fullscreen ) ;
8589 Window . AddFlags ( WindowManagerFlags . KeepScreenOn ) ;
90+
91+ // Hide the system pointer icon to prevent double cursors in DeX or with mouse.
92+ if ( OperatingSystem . IsAndroidVersionAtLeast ( 24 ) )
93+ {
94+ try
95+ {
96+ Window . DecorView . PointerIcon = PointerIcon . GetSystemIcon ( this , PointerIconType . Null ) ;
97+ }
98+ catch ( Exception e )
99+ {
100+ Logger . Log ( $ "[osu!] Failed to hide system pointer icon: { e . Message } ", LoggingTarget . Input ) ;
101+ }
102+ }
86103 }
87104
88105 if ( WindowManager ? . DefaultDisplay != null && Resources ? . DisplayMetrics != null )
@@ -106,6 +123,42 @@ protected override void OnCreate(Bundle? savedInstanceState)
106123
107124 protected override void OnNewIntent ( Intent ? intent ) => handleIntent ( intent ) ;
108125
126+ public override bool OnTouchEvent ( MotionEvent ? e )
127+ {
128+ if ( e != null && isStylusEvent ( e ) )
129+ {
130+ StylusHandler ? . HandleMotionEvent ( e ) ;
131+ return true ;
132+ }
133+ return base . OnTouchEvent ( e ) ;
134+ }
135+
136+ public override bool OnGenericMotionEvent ( MotionEvent ? e )
137+ {
138+ if ( e != null && isStylusEvent ( e ) )
139+ {
140+ StylusHandler ? . HandleMotionEvent ( e ) ;
141+ return true ;
142+ }
143+ return base . OnGenericMotionEvent ( e ) ;
144+ }
145+
146+ private bool isStylusEvent ( MotionEvent e )
147+ {
148+ // Check source first, as it's the most reliable indicator on some devices.
149+ if ( ( e . Source & InputSourceType . Stylus ) == InputSourceType . Stylus )
150+ return true ;
151+
152+ // Check tool type for each pointer.
153+ for ( int i = 0 ; i < e . PointerCount ; i ++ )
154+ {
155+ var toolType = e . GetToolType ( i ) ;
156+ if ( toolType == MotionEventToolType . Stylus || toolType == MotionEventToolType . Eraser )
157+ return true ;
158+ }
159+ return false ;
160+ }
161+
109162 public override void OnRequestPermissionsResult ( int requestCode , string [ ] permissions , Permission [ ] grantResults )
110163 {
111164 Microsoft . Maui . ApplicationModel . Platform . OnRequestPermissionsResult ( requestCode , permissions , grantResults ) ;
0 commit comments