pinentry/kleopatra: NVDA reads text multiple times
Testing, NormalPublic

Assigned To
Authored By
ikloecker
Jul 24 2025, 4:49 PM

Description

Open notepad in Kleopatra and start encryption with symmetric passphase.
The pinentry window pops up and NVDA reads (according to speech log)

pinentry-qt5  dialog  Enter passphrase
Passphrase: edit protected blank
pinentry-qt5  dialog  Enter passphrase

where the second line isn't audible. Maybe it's canceled/skipped in favor of the third line.

INFO - __main__ (17:04:31.564) - MainThread (5092):
Starting NVDA version 2025.1.2 x86
[...]
DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:05:59.376) - MainThread (5092):
EvtTracker: object: <NVDAObjects.Dynamic_DialogUIAWindowNVDAObject object at 0x05DB3E10>
name: pinentry-qt5
role: DIALOG
event: foreground
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: 
class name: PinEntryDialog

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:05:59.376) - MainThread (5092):
EvtTracker: object: <NVDAObjects.Dynamic_DialogUIAWindowNVDAObject object at 0x0941AA90>
name: pinentry-qt5
role: DIALOG
event: focusEntered
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: 
class name: PinEntryDialog

IO - speech.speech.speak (17:05:59.444) - MainThread (5092):
Speaking [LangChangeCommand ('en_GB'), 'pinentry-qt5', 'dialog', 'Enter passphrase\n', CancellableSpeech (still valid)]

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:05:59.446) - MainThread (5092):
EvtTracker: object: <NVDAObjects.Dynamic_EditableTextWithAutoSelectDetectionUIA object at 0x013F81F0>
name: Passphrase:
role: EDITABLETEXT
event: gainFocus
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: 
class name: PinLineEdit

DEBUG - NVDAObjects.NVDAObject._get_placeholder (17:05:59.455) - MainThread (5092):
Potential unimplemented child class: <NVDAObjects.Dynamic_EditableTextWithAutoSelectDetectionUIA object at 0x013F81F0>

IO - speech.speech.speak (17:05:59.471) - MainThread (5092):
Speaking [LangChangeCommand ('en_GB'), 'Passphrase:', 'edit', 'protected', CancellableSpeech (still valid), 'blank']

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:05:59.476) - MainThread (5092):
EvtTracker: object: <NVDAObjects.IAccessible.Button object at 0x013F8E50>
name: pinentry.exe - 1 running window
role: BUTTON
event: stateChange
states: 16, 8192, 16777216
app module: AppModule(explorer, appName='explorer', processID=4632)
window class name: MSTaskListWClass
IAccessible accName: 'pinentry.exe - 1 running window'
IAccessibleChildID: 13

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:05:59.478) - MainThread (5092):
EvtTracker: object: <NVDAObjects.Dynamic_EditableTextWithAutoSelectDetectionUIA object at 0x013F81F0>
name: Passphrase:
role: EDITABLETEXT
event: loseFocus
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: 
class name: PinLineEdit

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:05:59.479) - MainThread (5092):
EvtTracker: object: <NVDAObjects.Dynamic_DialogUIAWindowNVDAObject object at 0x095E3E50>
name: pinentry-qt5
role: DIALOG
event: gainFocus
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: 
class name: PinEntryDialog

IO - speech.speech.speak (17:05:59.561) - MainThread (5092):
Speaking [LangChangeCommand ('en_GB'), 'pinentry-qt5', 'dialog', 'Enter passphrase\n', CancellableSpeech (still valid)]

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:05:59.564) - MainThread (5092):
EvtTracker: object: <NVDAObjects.Dynamic_DialogUIAWindowNVDAObject object at 0x013F8350>
name: pinentry-qt5
role: DIALOG
event: UIA_window_windowOpen
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: 
class name: PinEntryDialog

We see

  • focusEntered for pinentry-qt5 dialog -> NVDA speaks pinentry-qt5 dialog Enter passphrase
  • gainFocus for Passphrase input field -> NVDA speaks Passphrase: edit protected blank
  • loseFocus for Passphrase input field
  • gainFocus for pinentry-qt5 dialog -> NVDA speaks pinentry-qt5 dialog Enter passphrase

This could point to a bug in Qt with wrong order of events, e.g. focus event for dialog is sent after focus event for input field.

Update: This also happens with Qt 6 and with many secondary windows in kleopatra (e.g. Create New OpenPGP Certificate, Error windows, etc.).

Event Timeline

ikloecker created this task.

Other duplicate texts:

  • Enter some characters for Password and some other characters for Repeat and press Return.
  • Message box pops up to inform user that the two entered texts don't match. NVDA reads
does not match - try again  dialog
OK  button  Enter (not audible)
does not match - try again  dialog

Logs:

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:06:28.847) - MainThread (5092):
EvtTracker: object: <NVDAObjects.UIA.UIA object at 0x013F4E10>
name: does not match - try again
role: STATICTEXT
event: nameChange
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: qt_msgbox_label
class name: QLabel

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:06:28.862) - MainThread (5092):
EvtTracker: object: <NVDAObjects.UIA.UIA object at 0x013F49B0>
name: OK
role: BUTTON
event: nameChange
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: 
class name: QPushButton

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:06:28.862) - MainThread (5092):
EvtTracker: object: <NVDAObjects.Dynamic_EditableTextWithAutoSelectDetectionUIA object at 0x0943E890>
name: Repeat:
role: EDITABLETEXT
event: loseFocus
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: 
class name: PinLineEdit

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:06:28.901) - MainThread (5092):
EvtTracker: object: <NVDAObjects.Dynamic_DialogUIAWindowNVDAObject object at 0x05D81810>
name: does not match - try again
role: DIALOG
event: focusEntered
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: 
class name: QMessageBox

IO - speech.speech.speak (17:06:28.948) - MainThread (5092):
Speaking [LangChangeCommand ('en_GB'), 'does not match - try again', 'dialog', CancellableSpeech (still valid)]

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:06:28.951) - MainThread (5092):
EvtTracker: object: <NVDAObjects.UIA.UIA object at 0x0800F170>
name: 
role: GROUPING
event: focusEntered
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: qt_msgbox_buttonbox
class name: QDialogButtonBox

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:06:28.955) - MainThread (5092):
EvtTracker: object: <NVDAObjects.UIA.UIA object at 0x09D03C50>
name: OK
role: BUTTON
event: gainFocus
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: 
class name: QPushButton

IO - speech.speech.speak (17:06:28.970) - MainThread (5092):
Speaking [LangChangeCommand ('en_GB'), 'OK', 'button', 'Enter', CancellableSpeech (still valid)]

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:06:28.971) - MainThread (5092):
EvtTracker: object: <NVDAObjects.UIA.UIA object at 0x09D03C50>
name: OK
role: BUTTON
event: loseFocus
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: 
class name: QPushButton

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:06:28.972) - MainThread (5092):
EvtTracker: object: <NVDAObjects.Dynamic_DialogUIAWindowNVDAObject object at 0x0946C2D0>
name: does not match - try again
role: DIALOG
event: gainFocus
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: 
class name: QMessageBox

IO - speech.speech.speak (17:06:29.004) - MainThread (5092):
Speaking [LangChangeCommand ('en_GB'), 'does not match - try again', 'dialog', CancellableSpeech (still valid)]

DEBUG - external:globalPlugins.evtTracker.GlobalPlugin.evtDebugLogging (17:06:29.007) - MainThread (5092):
EvtTracker: object: <NVDAObjects.Dynamic_DialogUIAWindowNVDAObject object at 0x013F4BF0>
name: does not match - try again
role: DIALOG
event: UIA_window_windowOpen
app module: AppModule(appModuleHandler, appName='pinentry', processID=7840)
window class name: Qt5159QWindowIcon
UIA Automation Id: 
class name: QMessageBox

We see a similar pattern as above

  • focusEntered for "does not match - try again" dialog -> NVDA speaks does not match - try again dialog
  • gainFocus for OK button -> NVDA speaks OK button Enter
  • loseFocus for OK button
  • gainFocus for "does not match - try again" dialog -> NVDA speaks does not match - try again dialog
ebo mentioned this in Unknown Object (Maniphest Task).Jul 25 2025, 11:52 AM
ebo added a subscriber: ebo.
ikloecker mentioned this in Unknown Object (Maniphest Task).Jul 28 2025, 9:59 AM
ikloecker mentioned this in Unknown Object (Maniphest Task).Jul 28 2025, 3:14 PM
ikloecker added a parent task: Unknown Object (Maniphest Task).

Ideally, this will be solved for VSD 3.4.

ikloecker mentioned this in Unknown Object (Maniphest Task).Aug 4 2025, 9:37 AM
ikloecker mentioned this in Unknown Object (Maniphest Task).Aug 11 2025, 9:22 AM
ikloecker renamed this task from pinentry-qt5: NVDA reads text multiple times to pinentry/kleopatra: NVDA reads text multiple times.Aug 11 2025, 9:50 AM
ikloecker updated the task description. (Show Details)
ikloecker changed the task status from Open to Testing.Aug 13 2025, 12:21 PM
ikloecker moved this task from Backlog to WIP on the vsd34 board.

Fixed by adding a patch for Qt 6 (and a patch for Qt 5 in gpg4win-4-branch for VSD 3.4).

NVDA shouldn't read texts multiple times anymore when a new dialog/window is shown, e.g. error messages or the pinentry window.

ikloecker mentioned this in Unknown Object (Maniphest Task).Aug 25 2025, 9:59 AM
timegrid added a subscriber: timegrid.

Looks good to me on gpg4win-5.0.0-beta369 @ win10 (no lines omitted or duplicate readings):

pinentry-qt  dialog  Enter passphrase
Passphrase:  edit  protected  blank
[...]
does not match - try again  dialog
OK  button  Enter
ikloecker mentioned this in Unknown Object (Maniphest Task).Sep 22 2025, 9:55 AM
ikloecker mentioned this in Unknown Object (Maniphest Task).Nov 24 2025, 9:00 AM