Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support the AccessKit focus and blur actions #596

Merged
merged 5 commits into from
Sep 19, 2024

Conversation

mwcampbell
Copy link
Contributor

I believe this is necessary to activate and deactivate input focus with TalkBack on Android. Assistive technologies on other platforms can also request the focus action, though none of the AccessKit backends support the blur action yet.

Copy link
Member

@DJMcNab DJMcNab left a comment

Choose a reason for hiding this comment

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

Should all of this behaviour be implicit for an item being in the focus chain?

masonry/src/widget/textbox.rs Outdated Show resolved Hide resolved
@mwcampbell
Copy link
Contributor Author

It certainly would be better for the framework to support this automatically for any focusable widget. I'll see if there's an easy way to do that in the current architecture.

@mwcampbell
Copy link
Contributor Author

To let the framework automatically handle the AccessKit focus and blur actions, it seems to me that we should add a flag to WidgetState to indicate whether the widget is in the focus chain, so build_access_node can check that flag. Does anyone have a different idea?

@DJMcNab
Copy link
Member

DJMcNab commented Sep 18, 2024

Yeah, I think that makes sense. Don't forget to reset that flag in the update_focus pass.

I know that our logic for focus has not been fully reasoned about, so a short-term change to unlock this functionality should be fine. (In particular, I don't think we know how setting a custom 'tab-index' will work)

@mwcampbell mwcampbell changed the title Support the AccessKit focus and blur actions in textboxes Support the AccessKit focus and blur actions Sep 18, 2024
@mwcampbell
Copy link
Contributor Author

OK, now the framework generically supports this for any widget in the focus chain.

Copy link
Member

@DJMcNab DJMcNab left a comment

Choose a reason for hiding this comment

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

Thanks, this is looking good.

I've not tested this myself

if ctx.is_in_focus_chain() && !ctx.is_disabled() && !ctx.is_focused() {
ctx.request_focus();
}
return;
Copy link
Member

Choose a reason for hiding this comment

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

There's an argument to be made that this return should be conditional only on ctx.is_in_focus_chain(), because that's when the corresponding implicit focus action was added.

However, I think that's probably YAGNI

match event.action {
accesskit::Action::Focus => {
if ctx.is_in_focus_chain() && !ctx.is_disabled() && !ctx.is_focused() {
ctx.request_focus();
Copy link
Member

Choose a reason for hiding this comment

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

I think we should probably also call ctx.set_handled() here. See #masonry>Missing event set_handled calls

@@ -111,6 +111,10 @@ fn build_access_node(widget: &dyn Widget, state: &WidgetState, scale_factor: f64
if state.clip.is_some() {
node.set_clips_children();
}
if state.in_focus_chain {
node.add_action(accesskit::Action::Focus);
node.add_action(accesskit::Action::Blur);
Copy link
Member

Choose a reason for hiding this comment

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

I presume it's meaningful to have the blur action available on an already unfocused widget?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, it's not. But can I check whether the widget is focused without passing global state into this function?

Copy link
Member

Choose a reason for hiding this comment

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

As far as I can see, the global state is available in the calling context, so passing it in is fine.
I'd probably shift this code around so that the functionality to set all of these properties is passed the AccessCtx.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, I think I just did what you suggested.

@mwcampbell
Copy link
Contributor Author

OK, I think my last push addresses all remaining review comments.

@mwcampbell
Copy link
Contributor Author

@DJMcNab @PoignardAzur Can you please give this one more look before I merge?

@PoignardAzur
Copy link
Contributor

Will do tomorrow.

Copy link
Contributor

@PoignardAzur PoignardAzur left a comment

Choose a reason for hiding this comment

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

Looks good to me.

Comment on lines +106 to 124
fn set_common_properties(ctx: &mut AccessCtx) {
if ctx.is_hot() {
ctx.current_node().set_hovered();
}
if state.is_disabled {
node.set_disabled();
if ctx.is_disabled() {
ctx.current_node().set_disabled();
}
if state.is_stashed {
node.set_hidden();
if ctx.is_stashed() {
ctx.current_node().set_hidden();
}
if state.clip.is_some() {
node.set_clips_children();
if ctx.widget_state.clip.is_some() {
ctx.current_node().set_clips_children();
}
if ctx.is_in_focus_chain() && !ctx.is_disabled() {
ctx.current_node().add_action(accesskit::Action::Focus);
}
if ctx.is_focused() {
ctx.current_node().add_action(accesskit::Action::Blur);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason this is split out from build_access_node?

Copy link
Member

Choose a reason for hiding this comment

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

... #596 (comment)

Essentially, build_access_node doesn't have the AccessCtx, which means it would either need to duplicate the logic of the context methods or not have this functionality implemented properly.

masonry/src/passes/event.rs Show resolved Hide resolved
Copy link
Contributor

@PoignardAzur PoignardAzur left a comment

Choose a reason for hiding this comment

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

LGTM.

@mwcampbell mwcampbell added this pull request to the merge queue Sep 19, 2024
Merged via the queue into main with commit 12ddfa3 Sep 19, 2024
17 checks passed
@mwcampbell mwcampbell deleted the textbox-accesskit-focus branch September 19, 2024 11:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants