nvaccess / nvda

NVDA, the free and open source Screen Reader for Microsoft Windows
https://www.nvaccess.org/
Other
2.11k stars 636 forks source link

NVDA does not report the spacebar key on WPF textboxes #16952

Open jmdaweb opened 3 months ago

jmdaweb commented 3 months ago

Steps to reproduce:

  1. Open a WPF application which has a textbox control, such as the one provided in the binary attachment.
  2. Configure NVDA to speak words while typing, and type some words in the textbox.
  3. Configure NVDA to speak characters while typing, and type some words on the textbox.

    Actual behavior:

    • NVDA doesn't speak the typed word when pressing spacebar.
    • NVDA doesn't speak "space" when spacebar is pressed and speak characters while typing is on.
    • NVDA reads all previously entered text as a single word, without spaces, when the period key is pressed.
    • If NVDA is restarted with the application on the foreground, the edit field behaves as expected and characters and words are spoken properly until focus changes to another window.

Expected behavior:

NVDA should behave exactly as in other standard edit fields.

NVDA logs, crash dumps and other attachments:

System configuration

NVDA installed/portable/running from source:

Installed.

NVDA version:

2024.2 and 2024.3beta5

Windows version:

Windows 11 23H2 build 22631.3958

Name and version of other software in use when reproducing the issue:

.net runtime 6.0.

Other information about your system:

N/A

Other questions

Does the issue still occur after restarting your computer?

Yes.

Have you tried any other versions of NVDA? If so, please report their behaviors.

Yes. Same behavior on 2024.2 and 2024.3beta5

If NVDA add-ons are disabled, is your problem still occurring?

Yes.

Does the issue still occur after you run the COM Registration Fixing Tool in NVDA's tools menu?

Yes.

jmdaweb commented 3 months ago

CC: @cnbonet @jmortizsilva @rperez030 @kastwey

jmdaweb commented 2 months ago

Hi, I have written this small global plugin:

import globalPluginHandler
import controlTypes

class GlobalPlugin(globalPluginHandler.GlobalPlugin):
    def event_gainFocus(self, obj, nextHandler):
        if obj.role == controlTypes.Role.EDITABLETEXT and hasattr(obj, 'UIAFrameworkId') and obj.UIAFrameworkId == 'WPF' and obj.UIAElement.CurrentClassName == 'TextBox':
            obj.appModule.helperLocalBindingHandle = None
        nextHandler()

It may help discovering where the issue comes from. While running, the behavior is as follows:

This might be related to a NVDA event which is triggered when a character is pressed or something similar. @nvdaes @seanbudd any idea on how to continue?

nvdaes commented 2 months ago

I'll investigate this in a few hours, playing with even_caret like done in the Perky add-on, or event_typedCharacters, like done in reportSymbols.

nvdaes commented 2 months ago

Hi @jmdaweb and all: My investigation is at a very initial stage. My results are as follows:

event_typedCharacter may not be fired when space bar is pressed. So my approach for now has been the following:

helperLocalBindingHandle = None


- Use `def chooseNVDAObjectOverlayClasses(self, obj, clsList):`to associate the edit box with the EnhancedDocument class
- In the EnhancedDocument class, create a script bound to the space gesture with this code:

``
    @script(
        gesture="kb:space"
    )
    def script_showsUnicodeBraille(self, gesture):
        gesture.send()
        speech.speakSpelling("")

Of course, this is rudimentary, just for an initial approach,and you can check the config.conf and the prior word to be reported when space is pressed when appropriate. Hope this helps.

nvdaes commented 2 months ago

@jmdaweb , I think that it would be easier to create a script for the space bar just invoking the event_typedCharacter event like that:

super().event_typedCharacter(" ") Of course with a cleaner code, but my idea for now is this, and words seem to be reported as well without checking config.conf.

jmdaweb commented 2 months ago

Thanks @nvdaes, it works! Putting all ideas together, this is a global plugin for all WPF textbox controls. I have learned a lot, I never worked with controls before on my developments:

import globalPluginHandler
import controlTypes
from NVDAObjects.behaviors import EditableTextWithAutoSelectDetection
from scriptHandler import script

class GlobalPlugin(globalPluginHandler.GlobalPlugin):

    def chooseNVDAObjectOverlayClasses(self, obj, clsList):
        if obj.role == controlTypes.Role.EDITABLETEXT and hasattr(obj, 'UIAFrameworkId') and obj.UIAFrameworkId == 'WPF' and obj.UIAElement.CurrentClassName == 'TextBox':
            clsList.append(WPFEditableTextWithAutoSelectDetection)
            clsList.remove(EditableTextWithAutoSelectDetection)

class WPFEditableTextWithAutoSelectDetection(EditableTextWithAutoSelectDetection):

    @script(
        gesture="kb:space"
    )
    def script_typeSpace(self, gesture):
        gesture.send()
        super().event_typedCharacter(" ")
nvdaes commented 2 months ago

When @seanbudd marks this as ready, you can create a PR.