Skip to content

Restrict most event processing to objects of interest to the user #11077

@jcsteh

Description

@jcsteh

problem

Some web apps, such as Twitter and Slack, fire a lot of events, most of which aren't things we need to report to the user. For example, when you focus the message list in Slack, it changes the name for every item in the list and adds the Message actions grouping to every item in the list. This results in noticeable performance problems. On my system with Firefox Nightly, focusing the Slack message list with 32 items in the list takes > 700 ms to respond. This is quite a bit faster in Chrome, so clearly there's some work to do in Firefox (and I'm looking into that as well). However, processing less of these events makes things significantly faster (~500 ms or less with my prototype).

We've had similar problems with UIA. For example, 1Password fires many property change events when you switch items in the list (#10508).

High Level Solution

NVDA already drops events for background windows, etc. However, there can be a lot of events even in the foreground window that aren't important to the user. For example, a nameChange on an object that isn't focused and isn't in the focus ancestry isn't reported in any way. Previously, these events were processed, NVDAObjects were instantiated for them and the events were queued, but they simply did nothing when they were finally handled by the NVDAObject.

To address this, I propose that NVDA only process most IAccessible events for the focus, focus ancestry, navigator object and desktop object. For UIA, we could do the same, but it probably makes sense to only listen for events on specific objects; see below.

Issues

I've prototyped two versions of this for IAccessible.

  1. Do all of this in IAccessibleHandler. Problems:
    • This doesn't integrate well with eventHandler.requestEvent. If a plugin requests an event, it will get dropped before shouldAcceptEvent is called. And we can't do this stuff after shouldAcceptEvent because it will return True for cases we want to block.
    • We'd need a completely separate implementation for UIA; we can't use any common code.
  2. Integrate it into shouldAcceptEvent. Pass raw API event params to shouldAcceptEvent and let it ask the relevant NVDAObjects whether the event is for them.
    • The problem is that for UIA, it makes more sense to just only listen for events on relevant objects, rather than listening for all events and dropping the ones we don't care about. In contrast, we can't specify specific objects for IAccessible.

It's really hard to come up with a framework that works well for both. On the other hand, as can be seen from the complexity of shouldAcceptEvent, duplicating all of the logic between IAccessible and UIA wouldn't be sustainable.

I think addressing this for both APIs is probably going to involve a hybrid approach. We'll need some common logic in eventHandler, but this will need to be split up so we can call different pieces in different places. For example, we need to be able to separately ask "did a plugin request this?" and "is this event for the foreground window?", rather than this all being handled in one call. We'll also need to be able to ask "what objects are of interest to the user?", since IAccessible and UIA will handle that differently (filtering vs selective registration).

@michaelDCurran, @feerrenrut, thoughts appreciated. I can push both of my prototype patches somewhere if you're interested (draft pull requests perhaps?), but I didn't want to spam with in-progress work without asking/discussing first.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions