ten1seven / what-input

A global utility for tracking the current input method (mouse/pointer, keyboard or touch).
https://ten1seven.github.io/what-input
MIT License
1.35k stars 89 forks source link

Using NVDA, input changing to mouse #117

Open mihkeleidast opened 3 years ago

mihkeleidast commented 3 years ago

This is really the same issue as #68 but decided to file a new one instead of pinging people on years-old issues :)

Use case

We have an implementation that opens Tooltips on hover, when input is mouse, and on click, when input is keyboard/touch etc. This is implemented by setting the correct event listeners on the element that triggers the opening. We listen to the input change from whatInput.registerOnChange and update the listeners accordingly. Additionally, we only show focus outlines on elements if the current input is keyboard.

When using NVDA with such an implementation and pressing Space/Enter keys in NVDA browse mode, NVDA triggers a mouse click. This causes what-input to trigger a change event, which results in our component deciding that it should not open on click anymore, since the current input is now mouse. This can be worked around by the user by pressing Space/Enter with Ctrl key also pressed, as suggested in nvaccess/nvda#7646, but I feel that this is not a very optimal solution user experience wise.

Possible solution

I hacked together the following logic:

whatInput.registerOnChange((nextInput) => {
    setInput((prevInput) => {
        if (
            prevInput === 'keyboard' && nextInput === 'mouse' &&
            (document.activeElement && isTabbable(document.activeElement))
        ) {
            return prevInput;
        }
        return nextInput;
    });
}, 'intent');

Essentially, if the prev input is keyboard and next input mouse, and the current active element is tabbable (like a <button>), do not update our internal input. This basically solves the issue, expect for styles - we use the global attributes on <html> element to determine that and it's not possible to prevent what-input from changing that.

I feel like this hacky workaround could be improved upon if the logic was inside what-input. For example, it could check the specific event type that was fired, so that a click in this case would not change the input, but a mousemove etc would. Additionally, we could keep a log of previous event types and check against that before changing input - in my experience, if most previous events are keyboard events and then there is that single mouse click that triggers input change, it's probably some sort of accident (or triggered by NVDA in my case).

Would it be possible to work around this issue inside what-input? Looks like the issues reported to NVDA regarding this have not gotten anywhere in years.