Skip to content

Commit a3779fe

Browse files
Update framework to 2026.502.1; add disable pen click option; fix DeX cursor on SurfaceView
Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/9e4704cb-dc9c-48d9-a063-a068bd1cb558 Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
1 parent 4f05f73 commit a3779fe

8 files changed

Lines changed: 51 additions & 9 deletions

File tree

osu.Android.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
</PropertyGroup>
100100

101101
<ItemGroup>
102-
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.501.2" />
102+
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.502.1" />
103103
<!-- `ppy.osu.Framework.NativeLibs` is a transitive dependency of `ppy.osu.Framework`
104104
that ships desktop-only natives (Linux/macOS/Windows) under `runtimes/<rid>/native/`
105105
— including a bare Linux `libbass.so`/`libbass_fx.so`/`libbassmix.so` for linux-arm64.

osu.Android/Input/AndroidStylusHandler.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,15 @@ public class AndroidStylusHandler : InputHandler, ITabletHandler
7676
/// </summary>
7777
public volatile bool TreatAsTouch;
7878

79+
/// <summary>
80+
/// Mirrored from <see cref="osu.Game.Configuration.OsuSetting.AndroidStylusDisableClick"/>.
81+
/// When true, no left-button click is ever synthesised from pen tip pressure, so the
82+
/// S Pen can be used purely for cursor positioning without accidentally registering taps.
83+
/// Held as a volatile field so the OS dispatch thread can read it without
84+
/// crossing the managed-config bindable lock on every motion event.
85+
/// </summary>
86+
public volatile bool DisableClick;
87+
7988
// Cached area values for hot path (avoids bindable access per event).
8089
private float areaLeft, areaTop, areaWidth, areaHeight;
8190
private float outLeft, outTop, outWidth, outHeight;
@@ -532,10 +541,10 @@ private void handlePointer(MotionEvent e, int historyIndex, MotionEventActions a
532541
// are intentionally NOT mapped to right/middle (see comment block below), so a single
533542
// read is unavoidable but bounded.
534543
var buttonState = e.ButtonState;
535-
bool isLeftDown = pressure >= cachedPressureThreshold;
536-
if (actionMasked == MotionEventActions.Down || actionMasked == MotionEventActions.ButtonPress) isLeftDown = true;
544+
bool isLeftDown = !DisableClick && pressure >= cachedPressureThreshold;
545+
if (!DisableClick && (actionMasked == MotionEventActions.Down || actionMasked == MotionEventActions.ButtonPress)) isLeftDown = true;
537546
else if (actionMasked == MotionEventActions.Up || actionMasked == MotionEventActions.ButtonRelease || actionMasked == MotionEventActions.Cancel) isLeftDown = false;
538-
else if (actionMasked == MotionEventActions.Move && (buttonState & MotionEventButtonState.Primary) != 0) isLeftDown = true;
547+
else if (!DisableClick && actionMasked == MotionEventActions.Move && (buttonState & MotionEventButtonState.Primary) != 0) isLeftDown = true;
539548

540549
if (TreatAsTouch)
541550
{

osu.Android/Input/AndroidStylusSettings.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,14 @@ public AndroidStylusSettings(AndroidStylusHandler handler)
2929
private void load(OsuConfigManager osuConfig)
3030
{
3131
// Appended after the base TabletSettings.AddRange (the area-selection UI),
32-
// so the toggle appears at the bottom of the section. Settings search
33-
// (FilterTerms below) still surfaces it under "s pen" / "stylus" / "touch".
32+
// so the toggles appear at the bottom of the section. Settings search
33+
// (FilterTerms below) still surfaces them under "s pen" / "stylus" / "touch".
34+
Add(new SettingsItemV2(new FormCheckBox
35+
{
36+
Caption = "Disable pen click",
37+
HintText = "When enabled, pressing the S Pen tip does not register as a left click. Useful if you want to use the pen purely for cursor positioning (e.g. when using a keyboard or gamepad for input).",
38+
Current = osuConfig.GetBindable<bool>(OsuSetting.AndroidStylusDisableClick),
39+
}));
3440
Add(new SettingsItemV2(new FormCheckBox
3541
{
3642
Caption = "Treat S Pen as touch",
@@ -41,7 +47,7 @@ private void load(OsuConfigManager osuConfig)
4147

4248
public override IEnumerable<LocalisableString> FilterTerms => base.FilterTerms.Concat(new LocalisableString[]
4349
{
44-
@"s pen", @"spen", @"stylus", @"pen", @"touch", @"samsung",
50+
@"s pen", @"spen", @"stylus", @"pen", @"touch", @"samsung", @"click", @"disable",
4551
});
4652
}
4753
}

osu.Android/OsuGameActivity.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,22 @@ protected override void OnCreate(Bundle? savedInstanceState)
289289

290290
holder.AddCallback(this);
291291
}
292+
293+
// Also hide the pointer icon on the SurfaceView itself.
294+
// Setting it only on DecorView is not enough in DeX mode: Android
295+
// uses the innermost view's pointer icon when the cursor is over
296+
// that view, so the SurfaceView's default arrow would still show.
297+
try
298+
{
299+
var surface = GetSurface();
300+
301+
if (surface != null)
302+
surface.PointerIcon = PointerIcon.GetSystemIcon(this, PointerIconType.Null);
303+
}
304+
catch (Exception e)
305+
{
306+
Logger.Log($"[osu!] Failed to hide SurfaceView pointer icon: {e.Message}", LoggingTarget.Input);
307+
}
292308
}
293309
catch (Exception e)
294310
{

osu.Android/OsuGameAndroid.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ public partial class OsuGameAndroid : OsuGame
9494
private readonly Bindable<bool> startupFrameSyncMigrationEnabled = new Bindable<bool>();
9595
private readonly Bindable<bool> verboseLogging = new Bindable<bool>();
9696
private readonly Bindable<bool> stylusAsTouch = new Bindable<bool>();
97+
private readonly Bindable<bool> stylusDisableClick = new Bindable<bool>();
9798

9899
[Cached(typeof(IHighPerformanceSessionManager))]
99100
private readonly IHighPerformanceSessionManager highPerformanceSessionManager = new AndroidHighPerformanceSessionManager();
@@ -281,6 +282,7 @@ private void load(FrameworkConfigManager frameworkConfig)
281282
LocalConfig.BindWith(OsuSetting.AndroidStartupFrameSyncMigrationEnabled, startupFrameSyncMigrationEnabled);
282283
LocalConfig.BindWith(OsuSetting.AndroidVerboseLogging, verboseLogging);
283284
LocalConfig.BindWith(OsuSetting.AndroidStylusAsTouch, stylusAsTouch);
285+
LocalConfig.BindWith(OsuSetting.AndroidStylusDisableClick, stylusDisableClick);
284286

285287
// Mirror the stylus-as-touch toggle into the volatile flag the OS-thread
286288
// dispatch hot path reads on AndroidStylusHandler. Subscribed (not just
@@ -294,6 +296,12 @@ private void load(FrameworkConfigManager frameworkConfig)
294296
stylusHandler.TreatAsTouch = e.NewValue;
295297
}, true);
296298

299+
stylusDisableClick.BindValueChanged(e =>
300+
{
301+
if (stylusHandler != null)
302+
stylusHandler.DisableClick = e.NewValue;
303+
}, true);
304+
297305
// sentinelOnDisable=true → presence ⇒ "feature disabled". The
298306
// safety nets default to ON, so the sentinel is created only
299307
// when the user explicitly disables them.
@@ -1995,6 +2003,7 @@ private void registerAndroidInputHandlers(GameHost host)
19952003
// in load() may have fired before this point (when stylusHandler was
19962004
// still null) — re-applying the current value here closes that race.
19972005
stylusHandler.TreatAsTouch = stylusAsTouch.Value;
2006+
stylusHandler.DisableClick = stylusDisableClick.Value;
19982007

19992008
gameActivity.StylusHandler = stylusHandler;
20002009
gameActivity.MouseHandler = mouseHandler;

osu.Game/Configuration/OsuConfigManager.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ protected override void InitialiseDefaults()
303303
SetDefault(OsuSetting.AndroidStartupFrameSyncMigrationEnabled, false);
304304
SetDefault(OsuSetting.AndroidVerboseLogging, false);
305305
SetDefault(OsuSetting.AndroidStylusAsTouch, false);
306+
SetDefault(OsuSetting.AndroidStylusDisableClick, false);
306307
SetDefault(OsuSetting.ShowFpsAdditionalInfo, false);
307308
}
308309

@@ -579,6 +580,7 @@ public enum OsuSetting
579580
AndroidStartupFrameSyncMigrationEnabled,
580581
AndroidVerboseLogging,
581582
AndroidStylusAsTouch,
583+
AndroidStylusDisableClick,
582584
ShowFpsAdditionalInfo,
583585
RefreshRateFullscreen,
584586
}

osu.Game/osu.Game.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
3939
</PackageReference>
4040
<PackageReference Include="Realm" Version="20.1.0" />
41-
<PackageReference Include="ppy.osu.Framework" Version="2026.501.2" />
41+
<PackageReference Include="ppy.osu.Framework" Version="2026.502.1" />
4242
<!--
4343
Explicitly pin `ppy.Veldrid.SPIRV` to the winnerspiros fork build that
4444
`ppy.osu.Framework 2026.501.1` was compiled against. This version is the only

osu.iOS.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@
3333
<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
3434
</PropertyGroup>
3535
<ItemGroup>
36-
<PackageReference Include="ppy.osu.Framework.iOS" Version="2026.501.2" />
36+
<PackageReference Include="ppy.osu.Framework.iOS" Version="2026.502.1" />
3737
</ItemGroup>
3838
</Project>

0 commit comments

Comments
 (0)