diff --git a/osu.Framework.Android/Input/AndroidInputExtensions.cs b/osu.Framework.Android/Input/AndroidInputExtensions.cs index c0c8c796ec..0cb1e4a63a 100644 --- a/osu.Framework.Android/Input/AndroidInputExtensions.cs +++ b/osu.Framework.Android/Input/AndroidInputExtensions.cs @@ -172,6 +172,12 @@ public static bool TryGetMouseButton(this Keycode keycode, out MouseButton butto return false; } + public static bool IsKeyboard(this InputSourceType source) + { + // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags + return source is InputSourceType.Keyboard or (InputSourceType.Keyboard | InputSourceType.Dpad); + } + public static bool TryGetJoystickButton(this KeyEvent e, out JoystickButton button) { var keycode = e.KeyCode; @@ -192,7 +198,7 @@ public static bool TryGetJoystickButton(this KeyEvent e, out JoystickButton butt case Keycode.DpadDown: case Keycode.DpadLeft: case Keycode.DpadRight: - case Keycode.Back when e.Source == InputSourceType.Keyboard: + case Keycode.Back when e.Source.IsKeyboard(): default: button = JoystickButton.FirstButton; return false; diff --git a/osu.Framework.Android/Input/AndroidInputHandler.cs b/osu.Framework.Android/Input/AndroidInputHandler.cs index 6e3507f7ed..3c6fa554ca 100644 --- a/osu.Framework.Android/Input/AndroidInputHandler.cs +++ b/osu.Framework.Android/Input/AndroidInputHandler.cs @@ -100,7 +100,7 @@ protected virtual bool OnHover(MotionEvent hoverEvent) /// Subscribe to . to receive events here. /// Whether the event was handled. Unhandled events are logged. /// - protected virtual bool OnKeyDown(Keycode keycode, KeyEvent e) + protected virtual ReturnCode OnKeyDown(Keycode keycode, KeyEvent e) { throw new NotSupportedException($"{nameof(HandleKeyDown)} subscribed to {nameof(View.KeyDown)} but the relevant method was not overriden."); } @@ -112,7 +112,7 @@ protected virtual bool OnKeyDown(Keycode keycode, KeyEvent e) /// Subscribe to . to receive events here. /// Whether the event was handled. Unhandled events are logged. /// - protected virtual bool OnKeyUp(Keycode keycode, KeyEvent e) + protected virtual ReturnCode OnKeyUp(Keycode keycode, KeyEvent e) { throw new NotSupportedException($"{nameof(HandleKeyUp)} subscribed to {nameof(View.KeyUp)} but the relevant method was not overriden."); } @@ -191,7 +191,7 @@ protected void HandleKeyDown(Keycode keycode, KeyEvent e) { if (ShouldHandleEvent(e)) { - if (!OnKeyDown(keycode, e)) + if (OnKeyDown(keycode, e) == ReturnCode.Unhandled) logUnhandledEvent(nameof(OnKeyDown), e); } } @@ -203,7 +203,7 @@ protected void HandleKeyUp(Keycode keycode, KeyEvent e) { if (ShouldHandleEvent(e)) { - if (!OnKeyUp(keycode, e)) + if (OnKeyUp(keycode, e) == ReturnCode.Unhandled) logUnhandledEvent(nameof(OnKeyUp), e); } } @@ -228,5 +228,29 @@ private void logUnhandledEvent(string methodName, InputEvent inputEvent) { Log($"Unknown {GetType().ReadableName()}.{methodName} event: {inputEvent}"); } + + protected enum ReturnCode + { + /// + /// Denotes an event that was handled by this handler. + /// + Handled, + + /// + /// Denotes an event that this handler did not handle. + /// + /// + /// Since all events are first put through the filter, an unhandled event is considered a bug and is logged. + /// + Unhandled, + + /// + /// Same as , but will not be logged. + /// + /// + /// Used when an event might also be handled by another handler, but that cannot be determined purely on . + /// + UnhandledSuppressLogging, + } } } diff --git a/osu.Framework.Android/Input/AndroidJoystickHandler.cs b/osu.Framework.Android/Input/AndroidJoystickHandler.cs index a6d68d1d20..a9942cbce4 100644 --- a/osu.Framework.Android/Input/AndroidJoystickHandler.cs +++ b/osu.Framework.Android/Input/AndroidJoystickHandler.cs @@ -64,28 +64,34 @@ public override bool Initialize(GameHost host) return true; } - protected override bool OnKeyDown(Keycode keycode, KeyEvent e) + private ReturnCode returnCodeForSource(InputSourceType source) + { + // keyboard only events are handled in AndroidKeyboardHandler + return source.IsKeyboard() + ? ReturnCode.UnhandledSuppressLogging + : ReturnCode.Unhandled; + } + + protected override ReturnCode OnKeyDown(Keycode keycode, KeyEvent e) { if (e.TryGetJoystickButton(out var button)) { enqueueButtonDown(button); - return true; + return ReturnCode.Handled; } - // keyboard only events are handled in AndroidKeyboardHandler - return e.Source == InputSourceType.Keyboard; + return returnCodeForSource(e.Source); } - protected override bool OnKeyUp(Keycode keycode, KeyEvent e) + protected override ReturnCode OnKeyUp(Keycode keycode, KeyEvent e) { if (e.TryGetJoystickButton(out var button)) { enqueueButtonUp(button); - return true; + return ReturnCode.Handled; } - // keyboard only events are handled in AndroidKeyboardHandler - return e.Source == InputSourceType.Keyboard; + return returnCodeForSource(e.Source); } /// diff --git a/osu.Framework.Android/Input/AndroidKeyboardHandler.cs b/osu.Framework.Android/Input/AndroidKeyboardHandler.cs index 8aa5f4372c..163bbe8cd9 100644 --- a/osu.Framework.Android/Input/AndroidKeyboardHandler.cs +++ b/osu.Framework.Android/Input/AndroidKeyboardHandler.cs @@ -13,7 +13,12 @@ namespace osu.Framework.Android.Input { public class AndroidKeyboardHandler : AndroidInputHandler { - protected override IEnumerable HandledEventSources => new[] { InputSourceType.Keyboard }; + protected override IEnumerable HandledEventSources => new[] + { + InputSourceType.Keyboard, + // Some physical keyboards report as (Keyboard | Dpad) + InputSourceType.Dpad, + }; public AndroidKeyboardHandler(AndroidGameView view) : base(view) @@ -44,30 +49,38 @@ public override bool Initialize(GameHost host) public override bool IsActive => true; - protected override bool OnKeyDown(Keycode keycode, KeyEvent e) + private ReturnCode returnCodeForKeycode(Keycode keycode) + { + // gamepad buttons are handled in AndroidJoystickHandler + return KeyEvent.IsGamepadButton(keycode) + ? ReturnCode.UnhandledSuppressLogging + : ReturnCode.Unhandled; + } + + protected override ReturnCode OnKeyDown(Keycode keycode, KeyEvent e) { var key = GetKeyCodeAsKey(keycode); if (key != Key.Unknown) { enqueueInput(new KeyboardKeyInput(key, true)); - return true; + return ReturnCode.Handled; } - return false; + return returnCodeForKeycode(keycode); } - protected override bool OnKeyUp(Keycode keycode, KeyEvent e) + protected override ReturnCode OnKeyUp(Keycode keycode, KeyEvent e) { var key = GetKeyCodeAsKey(keycode); if (key != Key.Unknown) { enqueueInput(new KeyboardKeyInput(key, false)); - return true; + return ReturnCode.Handled; } - return false; + return returnCodeForKeycode(keycode); } /// diff --git a/osu.Framework.Android/Input/AndroidMouseHandler.cs b/osu.Framework.Android/Input/AndroidMouseHandler.cs index 625f2f82ec..21cb95acb0 100644 --- a/osu.Framework.Android/Input/AndroidMouseHandler.cs +++ b/osu.Framework.Android/Input/AndroidMouseHandler.cs @@ -136,27 +136,27 @@ private void updatePointerCapture() View.PointerCapture = shouldCapture; } - protected override bool OnKeyDown(Keycode keycode, KeyEvent e) + protected override ReturnCode OnKeyDown(Keycode keycode, KeyEvent e) { // some implementations might send Mouse1 and Mouse2 as keyboard keycodes, so we handle those here. if (keycode.TryGetMouseButton(out var button)) { handleMouseButton(button, true); - return true; + return ReturnCode.Handled; } - return false; + return ReturnCode.Unhandled; } - protected override bool OnKeyUp(Keycode keycode, KeyEvent e) + protected override ReturnCode OnKeyUp(Keycode keycode, KeyEvent e) { if (keycode.TryGetMouseButton(out var button)) { handleMouseButton(button, false); - return true; + return ReturnCode.Handled; } - return false; + return ReturnCode.Unhandled; } protected override bool OnHover(MotionEvent hoverEvent)