Repository: nvaccess/nvda

Issue:
in tabbed notepad when switching between tabs nvda should announce some way to differentiate between tabs

### Steps to reproduce:
download the new tabbed notepad.
now using the menu create a new tab
now switch between tabs with ctrl+tabe
### Actual behavior:
nvda announces blank edition text editor
### Expected behavior:
Before writing what I want, I would like to talk about my discoveries, sorry if it doesn't make sense.
I typed a different word into the first line of text on each tab.
guide example 1
Fernando
guide 2
silva
using object navigation I found the list of tabs and within this list there was each tab named with what was written in the first line of text.
Now I left the first line of text empty in tab 1
in the list of tabs tab 1 appears with the name of untitled
from what i understand if the first line of text is characters this text will be the title of the tab.
If the first line of text is empty, the tab will have an untitled title.
so my suggestion is:
when switching between tabs in notepad in this example by pressing ctrl+tab nvda should announce the title of the tab which will be what is typed in the first line.
But this doesn't work if the first line of the tabs is empty, so I suggest that nvda also announce the position of the tab within the list.
example
guide 1
first line
Fernando
guide 2
first line
empty
guide 3
first line
silva
when switching between tabs nvda would announce:
guide 1 of 3 fernando
guide 2 of 3 untitled
guide 3 of 3 silva
Tab name and tab count could also be announced by command nvda + t to read window name.
### NVDA logs, crash dumps and other attachments:

### System configuration
#### NVDA installed/portable/running from source:
instaled
#### NVDA version:
nvda.exe, NVDA alpha-27590,180c9f2b
#### Windows version:
11 22.623.1095
#### Name and version of other software in use when reproducing the issue:
Notepad.exe, Microsoft.WindowsNotepad 11.2212.33.0

#### Other information about your system:

### 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.
no
#### 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


Discussion:
Hi,

Technical: UIA element selected event must be handled. Note that this event is fired three times: once when the tab loses focus and twice more when the new tab receives focus.

This change will be part of Windows App Essentials January 26th dev build and will be included in 23.02 stable.

Thanks.

Resolving patch:
diff --git a/source/appModules/notepad.py b/source/appModules/notepad.py
--- a/source/appModules/notepad.py
+++ b/source/appModules/notepad.py
@@ -10,13 +10,38 @@
 from comtypes import COMError
 import appModuleHandler
 import api
+import braille
+import controlTypes
+import eventHandler
+import speech
 import UIAHandler
 from NVDAObjects.UIA import UIA
 from NVDAObjects import NVDAObject
+from typing import Callable
 
 
 class AppModule(appModuleHandler.AppModule):
 
+	def event_UIA_elementSelected(self, obj: NVDAObject, nextHandler: Callable[[], None]):
+		# Announce currently selected tab when it changes.
+		if (
+			obj.role == controlTypes.Role.TAB
+			# this is done because 2 selection events are sent for the same object, so to prevent double speaking.
+			and not eventHandler.isPendingEvents("UIA_elementSelected")
+			and controlTypes.State.SELECTED in obj.states
+		):
+			speech.cancelSpeech()
+			speech.speakObject(obj, reason=controlTypes.OutputReason.FOCUS)
+			braille.handler.message(
+				braille.getPropertiesBraille(
+					name=obj.name,
+					role=obj.role,
+					states=obj.states,
+					positionInfo=obj.positionInfo
+				)
+			)
+		nextHandler()
+
 	def _get_statusBar(self) -> NVDAObject:
 		"""Retrieves Windows 11 Notepad status bar.
 		In Windows 10 and earlier, status bar can be obtained by looking at the bottom of the screen.


Test patch: