KEMBAR78
[Android] Improve Keyboard Accessibility: Support Spacebar for Android Gesture recognisers by kubaflo · Pull Request #29649 · dotnet/maui · GitHub
Skip to content

Conversation

kubaflo
Copy link
Contributor

@kubaflo kubaflo commented May 24, 2025

…Recognizers

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description of Change

Currently, .NET MAUI does not support spacebar key events for gesture recognizers on Android. This lack of support presents a significant accessibility issue, as it prevents keyboard users from activating gesture-based UI elements using the spacebar—something expected under WCAG

This discrepancy also results in inconsistent behavior between platforms, as iOS correctly responds to the spacebar key for gesture recognition.

Issues Fixed

Fixes #29648
Fixes #30685

@Copilot Copilot AI review requested due to automatic review settings May 24, 2025 16:15
@kubaflo kubaflo requested a review from a team as a code owner May 24, 2025 16:15
@kubaflo kubaflo self-assigned this May 24, 2025
@dotnet-policy-service dotnet-policy-service bot added the community ✨ Community Contribution label May 24, 2025
@dotnet-policy-service
Copy link
Contributor

Hey there @@kubaflo! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR improves keyboard accessibility on Android by enabling the spacebar key to trigger gesture recognizers, aligning Android’s behavior with iOS and meeting WCAG standards.

  • Introduces a new KeyPress handler to detect and handle spacebar key events.
  • Adjusts focusable properties and event subscriptions to support key events alongside touch events.
Comments suppressed due to low confidence (1)

src/Controls/src/Core/Platform/GestureManager/GesturePlatformManager.Android.cs:218

  • [nitpick] Consider clarifying the intention behind resetting the Focusable property to _focusableDefaultValue before conditionally setting it to true when adding touch and key event handlers to avoid potential confusion.
platformView.KeyPress -= OnKeyPress; platformView.Focusable = _focusableDefaultValue;

@kubaflo kubaflo added platform/android area-gestures Gesture types t/a11y Relates to accessibility and removed community ✨ Community Contribution labels May 24, 2025
@kubaflo
Copy link
Contributor Author

kubaflo commented May 24, 2025

I use the following code for testing:

<VerticalStackLayout>
    <Label Text="Tap gesture recognizer with event">
        <Label.GestureRecognizers>
            <TapGestureRecognizer
                Tapped="TapGestureRecognizer_Tapped"/>
        </Label.GestureRecognizers>
    </Label>
    <Label Text="Tap gesture recognizer with command">
        <Label.GestureRecognizers>
            <TapGestureRecognizer
                Command="{Binding TapCommand}"/>
        </Label.GestureRecognizers>
    </Label>
    <Label Text="No tap gesture recognizer"/>
    <Switch>
        <Switch.GestureRecognizers>
            <TapGestureRecognizer
                Tapped="TapGestureRecognizer_Tapped"/>
        </Switch.GestureRecognizers>
    </Switch>
</VerticalStackLayout>
public partial class MainPage : ContentPage
{
	public Command TapCommand { get; set; }
	public MainPage()
	{
		InitializeComponent();

		TapCommand = new Command(() => DisplayAlert("Success", "Command", "OK"));
		BindingContext = this;
	}

	private void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e)
	{
		DisplayAlert("Success", "You tapped", "OK");
	}
}

@kubaflo kubaflo force-pushed the fix-29648 branch 2 times, most recently from 3a166be to 225ceed Compare May 24, 2025 17:56
@jsuarezruiz
Copy link
Contributor

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

Copy link
Member

@PureWeen PureWeen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @bhavanesh2001 on this one
https://github.com/dotnet/maui/pull/29649/files#r2106941403

What I wonder for this one is if there's a way to wire this in through the gesture detectors or somehow by overrides on the view

Here's the source code from android which would be ideal to mimic

    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) {
            if ((mViewFlags & ENABLED_MASK) == DISABLED) {
                return true;
            }
            if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) {
                setPressed(false);

                if (!mHasPerformedLongPress) {
                    // This is a tap, so remove the longpress check
                    removeLongPressCallback();
                    if (!event.isCanceled()) {
                        return performClickInternal();
                    }
                }
            }
        }
        return false;
    }

@PureWeen PureWeen added this to the .NET 9 SR11 milestone Jul 28, 2025
@kubaflo kubaflo force-pushed the fix-29648 branch 2 times, most recently from 27ddec1 to 91c8421 Compare July 29, 2025 15:28
@PureWeen
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

{
_innerKeyListener = new InnerKeyListener(tapRecognizers, View);
}
platformView.SetOnKeyListener(_innerKeyListener);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of keylistener here I think we just want to subscribe to the Key events we want

If we set the listener that's going to break anyone that's trying to subscribe to these events

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

@PureWeen
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

{
platformView.KeyPress += OnKeyPress;
}
platformView.Focusable = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this up into the if block for now so we're not changing too much behavior, we only really want focusable to get set for now if they've indicated a single tap

we can review other scenarios later

@PureWeen
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@PureWeen
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@PureWeen PureWeen moved this from Todo to Ready To Review in MAUI SDK Ongoing Aug 4, 2025
@sum0999
Copy link

sum0999 commented Aug 5, 2025

@kubaflo I tried this build on Android.

What works well:

  • Navigating to labels with gesture recognizers and triggering the gesture recognizers using the keyboard works well.
  • Navigating to elements inside of a static grid and triggering the gesture recognizers with the keyboard.

However, I had the following observations as well:

  1. Labels and grid items are not highlighted when focused. Edit: The label's Focused event is triggered.
  2. Grid tap gesture recognizer is still not triggered if the grid is generated from a data template in a collection view.

For (1), I also found that making labels focusable or clickable (or both) doesn't help. but adding a click listener (Even if it doesn't do anything) to the TextView does enable highlighting. For example:

Microsoft.Maui.Handlers.LabelHandler.Mapper.AppendToMapping("KeyboardFocusable", (handler, view) =>
{
if (handler.PlatformView is TextView nativeTextView && view is Label label && label.GestureRecognizers.Count > 0)
{
nativeTextView.Focusable = true;
nativeTextView.FocusableInTouchMode = true;
nativeTextView.Clickable = true;
nativeTextView.SetOnClickListener(new LabelClickListener(label)); //class LabelClickListener : Java.Lang.Object, global::Android.Views.View.IOnClickListener
}
});

For (2), I created a sample demonstrating the kind of layout I'm referring to and the observed behavior: https://github.com/sum0999/MAUIWithKeyboardSample

@PureWeen
Copy link
Member

PureWeen commented Aug 6, 2025

@kubaflo I tried this build on Android.

What works well:

  • Navigating to labels with gesture recognizers and triggering the gesture recognizers using the keyboard works well.
  • Navigating to elements inside of a static grid and triggering the gesture recognizers with the keyboard.

However, I had the following observations as well:

  1. Labels and grid items are not highlighted when focused. Edit: The label's Focused event is triggered.
  2. Grid tap gesture recognizer is still not triggered if the grid is generated from a data template in a collection view.

For (1), I also found that making labels focusable or clickable (or both) doesn't help. but adding a click listener (Even if it doesn't do anything) to the TextView does enable highlighting. For example:

Microsoft.Maui.Handlers.LabelHandler.Mapper.AppendToMapping("KeyboardFocusable", (handler, view) => { if (handler.PlatformView is TextView nativeTextView && view is Label label && label.GestureRecognizers.Count > 0) { nativeTextView.Focusable = true; nativeTextView.FocusableInTouchMode = true; nativeTextView.Clickable = true; nativeTextView.SetOnClickListener(new LabelClickListener(label)); //class LabelClickListener : Java.Lang.Object, global::Android.Views.View.IOnClickListener } });

For (2), I created a sample demonstrating the kind of layout I'm referring to and the observed behavior: https://github.com/sum0999/MAUIWithKeyboardSample

@sum0999 can you include a screen shot what you mean by "not highlighted"? I'm testing on an API 28 and API 36 device and they both seem to highlight with the tap gestures

image

@sum0999
Copy link

sum0999 commented Aug 8, 2025

@PureWeen Added a couple of videos in addition to the screenshots to make it more clear. When hovering over a label, I can interact with it using Space/Enter, which brings up the alert, but the label is not actually highlighted at all.

image

If I instead use a ClickHandler like below, then I am able to get the label highlighted, and also the navigation now reaches inside of each grid's text field.

image
RecordingWithoutTextViewClickHandler.mp4
RecordingWithTextViewClickHandler.mp4

@kubaflo
Copy link
Contributor Author

kubaflo commented Aug 9, 2025

@sum0999 Everything seems to be working as expected. Here’s a video showing the changes from this PR: the focus correctly switches to the grid and then to the label when TapGestureRecognizer is attached to these controls. After removing TapGestureRecognizer from the label, it no longer receives focus, as expected.

Screen.Recording.2025-08-09.at.12.49.34.mov

@PureWeen
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@PureWeen PureWeen merged commit 2faddc2 into dotnet:main Aug 11, 2025
129 checks passed
@github-project-automation github-project-automation bot moved this from Ready To Review to Done in MAUI SDK Ongoing Aug 11, 2025
SuthiYuvaraj pushed a commit to SuthiYuvaraj/maui that referenced this pull request Aug 12, 2025
…d Gesture recognizers (dotnet#29649)

* Improve Keyboard Accessibility: Support Spacebar for Android Gesture Recognizers

* Update GesturePlatformManager.Android.cs

* - update code a bit

* Update ViewExtensions.cs

---------

Co-authored-by: Shane Neuville <shneuvil@microsoft.com>
rmarinho pushed a commit that referenced this pull request Aug 13, 2025
…d Gesture recognizers (#29649)

* Improve Keyboard Accessibility: Support Spacebar for Android Gesture Recognizers

* Update GesturePlatformManager.Android.cs

* - update code a bit

* Update ViewExtensions.cs

---------

Co-authored-by: Shane Neuville <shneuvil@microsoft.com>
@github-actions github-actions bot locked and limited conversation to collaborators Sep 11, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-gestures Gesture types platform/android t/a11y Relates to accessibility

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

TapGestureRecognizer Controls Not Selectable with Physical Keyboard [Android] Spacebar Key Does Not Trigger Gesture Recognizers

6 participants