word.jss

; Copyright 1995-2024 Freedom Scientific, Inc.
; Script file For Microsoft Word versions 2016 and O365.

Include "HJConst.jsh"
Include "MSAAConst.jsh"
Include "winstyles.jsh"
Include "HJGlobal.jsh"
Include "UIA.jsh"
Include "hjHelp.jsh"
Include "Common.jsm"
Include "office.jsh"
Include "msOffice.jsm"
Include "Word.jsh"
Include "word.jsm"

Import "wordsettings.jsd"
Import "say.jsd" ; For FormatOutputMessage, ensure Script Manager will compile.
Import "UIA.jsd"
Import "touch.jsd"

Use "office.jsb"
Use "WordQuickNav.jsb"
Use "wordFunc.jsb"
Use "WordSettings.jsb"
Use "wordBrl.jsb"

;Shared Globals:
Globals
    Int LastUIATextChangeTime, ;shared with Office.jss -> WindowCreatedEvent.
    String globalAutocorrectSound ;from Default For Autocorrect sound
;Objects:
Globals
; For spellcheck with split buttons,
; store the default or first suggestion so enter key can quickly press it:
    Object oSuggestionSplitButton

;Collections:
Globals
Collection c_WordFocus,
    ; c_WordFocus caches things commonly tested For the focus window.
    ; It cannot be used For tests applicable To document content,
    ; since that can change without any focus change.
    ;
    ; Members are:
    ; String WindowClass -- Result of getWindowClass For focus.
    ; String RealWindowName -- Result of GetWindowName For real window of focus.
    ; String RealWindowClass -- Result of GetWindowClass For real window of focus.
    ; String HeaderForNewAddressListField -- Result of GetHeaderForNewAddressListField Function call.
    ; Int ObjectSubType -- Result of getObjectSubtypeCode at level 0.
    ; Int WindowSubtype -- Result of GetWindowSubtypeCode of focus.
    ; Int windowCategory -- Result of getWindowCategory Function call.
    ; Int IsWordDocumentActive -- Result of IsWordDocumentActiveTest Function call.
    ; Int OutlookIsActive = Result of OutlookIsActiveTest Function call.
    ; Int InMicrosoftEditorProofingPaneIssueChecker -- Result of InMicrosoftEditorProofingPaneIssueChecker Function call.
    ; Int InProofingPaneSpellCheckWithSplitButtons -- Result of InProofingPaneSpellCheckWithSplitButtons Function call.
    ; Int InProofingPaneSpellCheck -- Result of InProofingPaneSpellCheck Function call.
    ; Int IsReadOnlyMessage -- Result of IsReadOnlyMessage Function call.
    ; Int IsReadOnlyVirtualMessage -- Result of calculating IsVirtualPCCursor and IsReadOnlyMessage Function calls.
    ; Int IsStatusBarToolBar -- Result of IsStatusBarToolBarTest Function call.
    Collection c_WordTester
    ; For variables which are set or cleared under certain conditions and tested elsewhere when something happens.
    ;
    ; Members are:
    ; Int FocusChangedOnSelectATable
    ; Int WasOfficeSplashScreen
    ; Int WasTaskPaneDialog
    ; Int NextIsAccentedChar
    ; Int PrevFocusWasLevelZeroChangeListBoxItem
    ; Int PressEnterCausedNewListItem -- For reading list items as user presses enter To navigate.
    ; Int PressTabOrShiftTabCausedNewListItem ; same as enter but For tab and shift tab.
    ; Int SupportsMAGicOptions
    ; Int WindowStateToggledByScript
    ; String globalTaskOrProofingPaneGroupName -- For speaking when the parent of focus is a group, and it changes.
    ; Int SelectionRectChangedEventID -- The schedule ID For RunSelectionContextEvents.
    ; Int ProcessMainDocumentWindowTimerID -- The schedule ID For ProcessMainDocumentWindowWrapper.
    ; Int AnnounceNoOpenDocumentTimerID -- The schedule ID For AnnounceNoOpenDocument.
    ; Handle c_WordTester.hWndPrevFocus --
    ;       Because global focus and global prev focus variables are Not reliably updated when focus change moves To a menu,
    ;       relying On these Globals To suppress double announcement of the document edit
    ;       causes the focus change from the menus To the document Not To speak sometimes.
    ;       This is an added variable that is set in FocusChangedEventEx To allow For testing of the actual prev focus window.
    ; Int WordContextMenuActive

Void Function WordInit()
WordQuickNavInit()
WordFuncInit()
WordSettingsInit()
WordBrlInit()
EndFunction

Void Function AutoStartEvent()
InitNewWordCollections()
;Call init functions For dependent Word-specific modules:
WordInit()
; turn On options dialog support:
c_WordTester.SupportsMAGicOptions = True
initializeSettings()
EndFunction

Void Function AutoFinishEvent()
c_WordTester.SupportsMAGicOptions = False ; prevent unnecessary running of adjustMAGicOptions
ClearAllCollectionsAndTimers()
c_WordTester.TaskOrProofingPaneGroupName = cscNull
SetTypingEchoLanguage() ; reset in case it was changed For language detection
EndFunction

Void Function InitNewWordCollections()
If !c_WordFocus c_WordFocus = New Collection EndIf
If !c_WordTester c_WordTester = New Collection EndIf
EndFunction

Void Function ClearAllCollectionsAndTimers()
collectionRemoveAll(c_WordFocus)
CollectionRemoveAll(c_WordTester)
ClearProcessMainDocumentWindowTimer()
ClearAnnounceNoOpenDocumentTimer()
EndFunction

Void Function ClearProcessMainDocumentWindowTimer()
If c_WordTester.ProcessMainDocumentWindowTimerID
    unscheduleFunction(c_WordTester.ProcessMainDocumentWindowTimerID)
    c_WordTester.ProcessMainDocumentWindowTimerID = 0
EndIf
EndFunction

Void Function ClearAnnounceNoOpenDocumentTimer()
If c_WordTester.AnnounceNoOpenDocumentTimerID
    unscheduleFunction(c_WordTester.AnnounceNoOpenDocumentTimerID)
    c_WordTester.AnnounceNoOpenDocumentTimerID = 0
EndIf
EndFunction

Void Function NullSuggestionSplitButton()
oSuggestionSplitButton = null()
EndFunction

Void Function UpdateWordFocus(Handle hWnd)
Var Handle realWindow = GetRealWindow(hWnd)
c_WordFocus.WindowClass = getWindowClass(hWnd)
c_WordFocus.RealWindowName = GetWindowName(RealWindow)
c_WordFocus.RealWindowClass = GetWindowClass(RealWindow)
c_WordFocus.WindowSubtype = getWindowSubtypeCode(hWnd)
c_WordFocus.ObjectSubType = getObjectSubtypeCode()
c_WordFocus.windowCategory = getWindowCategory(hWnd)
c_WordFocus.IsWordDocumentActive = IsWordDocumentActiveTest()
c_WordFocus.OutlookIsActive = OutlookIsActiveTest()
c_WordFocus.IsStatusBarToolBar = IsStatusBarToolBarTest(hWnd)
;Must test the proofing pane in this order, since InProofingPaneSpellCheck depends On InProofingPaneSpellCheckWithSplitButtons:
c_WordFocus.InMicrosoftEditorProofingPaneIssueChecker = InMicrosoftEditorProofingPaneIssueChecker()
c_WordFocus.InProofingPaneSpellCheckWithSplitButtons = InProofingPaneSpellCheckWithSplitButtons()
c_WordFocus.InProofingPaneSpellCheck = InProofingPaneSpellCheck()
c_WordFocus.IsReadOnlyMessage = IsReadOnlyMessage()
If c_WordFocus.IsReadOnlyMessage
    c_WordFocus.IsReadOnlyVirtualMessage = IsVirtualPCCursor()
else
    c_WordFocus.IsReadOnlyVirtualMessage = False
EndIf
If c_WordFocus.RealWindowName == wn_NewAddressList
&& c_WordFocus.WindowSubType == wt_edit
    c_WordFocus.HeaderForNewAddressListField = GetHeaderForNewAddressListField ()
else
    c_WordFocus.HeaderForNewAddressListField = cscNull
EndIf
EndFunction

Int Function FindWindowCategoryType(Handle hwnd)
If IsStandardUnknownWindowCategoryType(hwnd)
    giWndCategoryType = WCAT_UNKNOWN
    Return giWndCategoryType
EndIf
Var
    String sRealName,
    String sClass
sClass = GetWindowclass(hWnd)
If stringCompare(sClass, cwc_Word_Document2) == 0
|| stringCompare(sClass, cwc_Word_Document) == 0
    If stringContains(GetWindowClass(GetParent(hWnd)), "bosa_sdm_")
        sRealName = getWindowName(getRealWindow(hWnd))
        If stringContains(sRealName, wn_spellingAndGrammar)
        || stringContains(sRealName, wn_spelling)
            giWndCategoryType = WCAT_SPELL_CHECKER
            Return giWndCategoryType
        else
            giWndCategoryType = wCat_Unknown
            Return giWndCategoryType
        EndIf
    EndIf
    giWndCategoryType = WCAT_DOCUMENT
    Return giWndCategoryType
EndIf
If c_WordFocus.WindowClass == cwc_NetUIHwnd
    Return FindWindowCategoryType(hWnd)
EndIf
sRealName = getWindowName(getRealWindow(hWnd))
If stringContains(sRealName, wn_spellingAndGrammar)
|| stringContains(sRealName, wn_spelling)
    giWndCategoryType = WCAT_SPELL_CHECKER
    Return giWndCategoryType
EndIf
If sClass == cwc_RichEdit20W
&& getWindowSubtypeCode(getParent(hWnd)) == WT_LISTVIEW
    ;Mailing dialogs need To respond To activeItemChangedEvent:
    giWndCategoryType = WCAT_UNKNOWN
    Return giWndCategoryType
EndIf
Return FindWindowCategoryType(hwnd)
EndFunction

Int Function OnEditFieldWithSuggestion()
If c_WordFocus.WindowClass != cwc_NetUIHwnd
    Return False
EndIf
If !oSuggestionSplitButton
|| oSuggestionSplitButton.isOffScreen
|| !oSuggestionSplitButton.GetInvokePattern()
    ;The suggestion split button is Not available:
    Return False
EndIf
If getObjectTypeCode(True) != WT_EDIT
    ;Not On any kind of edit field--read-only, multiline or single-line:
    Return False
EndIf
Return True
EndFunction

Void Function ReturnToDocumentFromEmbeddedSpreadsheet()
WordInit()
initializeSettings()
SayFocusedWindow()
EndFunction

Void Function Unknown (String TheName, Int IsScript, optional Int IsDueToRecursion)
If IsDueToRecursion
    ;recursive calls may happen If a Function is running,
    ;and the Word event fires and calls the Function that is already running.
    ;Note, however, that any test of a Function which fails To run will evaluate as False.
    Return
EndIf
TheName = StringLower (TheName)
; CaretMovedEvent throws when in comment pane and deleting first character.
If stringContains (TheName, "caretmovedevent") Return EndIf
Unknown (TheName, IsScript, IsDueToRecursion)
EndFunction

Void Function UIANotificationEvent(Int notificationKind, Int notificationProcessing, String displayString, String activityId, String appName)
If ActivityID == "AccSN2" || activityID == "AccSN3"
    ; ControlDelete and ControlBackspace are sending fake notifications
    ;which clutter when we're reading the actual words that got deleted.
    Var String scriptName = GetScriptAssignedTo(GetCurrentScriptKeyName())
    If scriptName == "DeleteWord" || scriptName == "ControlBackspace"
        Return
    EndIf
EndIf
Return UIANotificationEvent(notificationKind, notificationProcessing, displayString, activityId, appName)
EndFunction

Void Function UIATextEditTextChangedEvent(Int changeType, String text)
If changeType!=TextEditChangeType_AutoCorrect
    Return
EndIf
LastUIATextChangeTime = getTickCount()
Var String line = GetLine()
If line==cscNull || line==cscSpace
    sayMessage(OT_SCREEN_MESSAGE, text)
ElIf getJCFOption(OPT_INDICATE_MISTYPED_WORD)
&& !stringIsBlank(text)
    ; autocorrection While typing.
    If GetCharacterValue(stringLeft(text, 1)) <= 8
        ; keep ugly nonprintable character from showing up On Braille display.
        ; sometimes, the leading character is one of the lower control characters like ^d.
        text = stringChopLeft(text, 1)
    EndIf
    If stringLength(text) == 1
    && IsAutoCorrectExceptionCharacter(getCharacterValue(text))
        ; the standard quotes and apostrophes are being turned into Unicode left and right quotes and single quotes.
        Return
    EndIf
    If (c_WordTester.PressEnterCausedNewListItem
    || c_WordTester.PressTabOrShiftTabCausedNewListItem)
    && InList()
        If ! c_WordTester.PressTabOrShiftTabCausedNewListItem Then
        ; Speak text from here after user pressed enter in a numbered list.
        ; however tab or shift tab would make it speak twice which we don't want.
            say(text, OT_LINE)
        EndIf
        c_WordTester.PressEnterCausedNewListItem = False
        c_WordTester.PressTabOrShiftTabCausedNewListItem = False
        Return
    EndIf
    text = stringTrimLeadingBlanks(text)
    Var String message = formatString(msgAutocorrect, text)
    PlaySound(GetSoundFileLocation(globalAutocorrectSound))
    sayMessage(OT_SCREEN_MESSAGE, message)
    ; don't spell strings that are artificially supplied such as "bullet", "list item", etc:
    If stringContains(line, text)
        spellString(text)
    EndIf
EndIf
EndFunction

String Function getPositionInGroupFromUIAElement(Object element)
If ! element Return EndIf
Var
    Int index,
    String size,
    String positionInfo
size = element.sizeOfSet
If !size Return EndIf
index = element.positionInSet
; account For out of bounds UIA where something's wrong:
If !index || index > size Return EndIf
positionInfo = formatString(cmsgPosInGroup1, index, size)
Return positionInfo
EndFunction

Void Function ItemNotFoundEvent(Int hwnd)
; event indicating that the requested item can't be found.
If WindowCategoryIsWordDocument()
    Return
else
    beep()
EndIf
EndFunction

Void Function SelectionRectChangedEvent(Int newLeft, Int newTop, Int newRight, Int newBottom, Int oldLeft, Int oldTop, Int oldRight, Int oldBottom, Int navUnit)
If c_WordTester.SelectionRectChangedEventID
    UnscheduleFunction(c_WordTester.SelectionRectChangedEventID)
    c_WordTester.SelectionRectChangedEventID = 0;
EndIf
SelectionRectChangedEvent(newLeft, newTop, newRight, newBottom, oldLeft, oldTop, oldRight, oldBottom, navUnit)
EndFunction

Int Function IsWordDocumentActiveTest()
If c_WordFocus.ObjectSubType == WT_DOCUMENT
|| GetObjectRole () == ROLE_SYSTEM_DOCUMENT
    Return True
EndIf
If !StringContainsCaseInsensitive (getWindowOwner(GetFocus()), WordAppDocumentArea)
    Return False
EndIf
Var
    Int iAncestorCount = GetAncestorCount (),
    Int i
For i = 0 To iAncestorCount
    If GetObjectAutomationId (i) == "Body"
        Return True
    ElIf GetObjectSubTypeCode (SOURCE_CACHED_DATA, i) == WT_DOCUMENT
        Return False
    EndIf
EndFor
Return False
EndFunction

Int Function IsWordDocumentActive()
Return c_WordFocus.IsWordDocumentActive == True
EndFunction

Int Function OutlookIsActive()
Return c_WordFocus.OutlookIsActive == True
EndFunction

Int Function WindowCategoryIsWordDocument()
Return c_WordFocus.windowCategory == wCat_document
EndFunction

Int Function IsStatusBarToolBar()
Return c_WordFocus.IsStatusBarToolBar == True
EndFunction

Int Function IsRibbonEditComboDroppedDown()
Var Handle hWnd = GetFirstWindow(GetTopLevelWindow(GetFocus()))
Return GetWindowClass(hwnd) == wc_NetUIToolWindow
    && GetParent(hWnd) == GetAppMainWindow(GetFocus())
    && (GetWindowStyleBits(hWnd) &(WS_POPUP | WS_VISIBLE) == WS_POPUP | WS_VISIBLE)
    && GetWindowClass(GetFirstChild(hWnd)) == cwc_NetUIHwnd
EndFunction

Int Function InTaskPaneDialog()
Return c_WordFocus.windowCategory == WCAT_TASK_PANE
EndFunction

Int Function InbosaSDMMso96Dialog()
Return c_WordFocus.RealWindowClass == wc_bosa_sdm_Mso96
EndFunction

Int Function IsNavPaneVisible(Handle hwnd)
;For 2010 Find and Replace when it is invoked by user and remains open
;even after returning To document,
;or when user checks Navigation pane from the View ribbon.
Return isWindowVisible(
    FindWindow(getAppMainWindow(hwnd), cwcMsoCmd, wn_2010WordNavigationPane))
EndFunction

Int Function IsTextReadingAppropriateForCurrentElement()
;For the touch cursor.
; Insure that document areas of versions of Word earlier than 2013 are detected:
Var Object element = TouchCursorObject()
Return (element.controlType == UIA_PaneControlTypeID && element.className == wc_wwg)
    || IsTextReadingAppropriateForCurrentElement()
EndFunction

Int Function InMicrosoftEditorProofingPaneIssueChecker()
;Note, this Function only returns True when actively reviewing issues.
;It returns False If in the Microsoft Editor pane but only in the overview.
If InbosaSDMMso96Dialog() Return False EndIf
If GetObjectName(False, 3) != wn_Editor
&& GetObjectName(False, 4) != wn_Editor
    ;Not in Microsoft Editor pane.
    Return False
EndIf
Var Object oPane = FSUIAGetParentOfElement (FSUIAGetFocusedElement ())
If oPane.controlType != UIA_PaneControlTypeID
    ;Some controls are children of the pane element.
    ;Others are grandchildren.
    ;Get the parent and check again.
    oPane = FSUIAGetParentOfElement (oPane)
EndIf
If oPane.controlType != UIA_PaneControlTypeID
    ;Not in Microsoft Editor pane.
    Return False
EndIf
Var Object oCondition = FSUIACreateStringPropertyCondition (UIA_AutomationIDPropertyID, "DrillInPane_Title")
If oPane.findFirst(TreeScope_Children, oCondition)
    ;In Microsoft Editor pane actively reviewing issues.
    Return True
EndIf
Return False;May be in Microsoft Editor pane, but Not reviewing issues
EndFunction

Int Function InProofingPaneSpellCheckWithSplitButtons()
If c_WordFocus.InMicrosoftEditorProofingPaneIssueChecker Return True EndIf
If InbosaSDMMso96Dialog() Return False EndIf
If GetObjectName(False, 2) != wn_Editor
    Return False
EndIf
Var String name = GetObjectName(False, 1)
If stringContains(name, wn_Proofing_Pane_Grammar)
|| stringContains(name, wn_Proofing_Pane_Spelling) Then
    Return True
EndIf
Var
    Object oUIA = CreateObjectEx("FreedomSci.UIA", 0, "UIAScriptAPI.x.manifest" ),
    Object treewalker = CreateUIARawViewTreeWalker(True),
    Object oGroupTypeCondition = oUIA.createIntPropertyCondition(UIA_ControlTypePropertyId, UIA_GroupControlTypeId),
    Object oGroupElements,
    Object oGroup
If !treewalker
|| !oGroupTypeCondition
    Return False
EndIf
treeWalker.currentElement = FSUIAGetFocusedElement()
While treewalker.currentElement.controlType != UIA_PaneControlTypeId
&& treewalker.currentElement.controlType != UIA_CustomControlTypeId
&& UIAGetParent (treewalker.currentElement)
    treewalker.gotoParent()
EndWhile
oGroupElements = treewalker.currentElement.findAll(TreeScope_Descendants, oGroupTypeCondition)
If GetGroupWithSpellingOrGrammarName(oGroupElements)
    Return True
EndIf
Return False
EndFunction

Int Function InProofingPaneSpellCheck()
If c_WordFocus.InProofingPaneSpellCheckWithSplitButtons Return True EndIf
Var String sName = GetObjectNameUnfiltered(1)
If StringIsBlank(sName)
|| sName == suggestionsListboxPrompt
    ; may be in a list of suggestions...
    sName = GetObjectNameUnfiltered(2)
EndIf
If StringIsBlank(sName) ; may be in a list of languages...
    sName = GetObjectNameUnfiltered(5)
EndIf
; the name can contain a lot more text, so we need To Use starts-with instead.
Return StringStartsWith(sName, wn_Proofing_Pane_Spelling)
    || StringStartsWith(sName, wn_Proofing_Pane_Grammar)
EndFunction

Int Function ReadProofingPaneWithSplitButtons()
Var
    Object UIA,
    Object element,
    Object currentSentenceTextField,
    Object spellingError,
    Object treewalker,
    String tmp,
    String Message;
UIA = CreateObjectEx("FreedomSci.UIA", 0, "UIAScriptAPI.x.manifest" )
If !UIA Return False EndIf
element = GetUIAFocusElement(UIA)
treewalker = UIA.CreateTreeWalker(UIA.CreateRawViewCondition())
If !element || !treewalker Return False EndIf
If element.controlType == UIA_SplitButtonControlTypeId
    oSuggestionSplitButton = element
EndIf
treewalker.currentElement = element
Var
    Object oGroupTypeCondition = UIA.createIntPropertyCondition(UIA_ControlTypePropertyId, UIA_GroupControlTypeId),
    Object oGroupElements
While (treewalker.currentElement.controlType != UIA_PaneControlTypeId
|| treewalker.currentElement.controlType != UIA_CustomControlTypeId)
&& UIAGetParent (treewalker.currentElement)
    treewalker.gotoParent()
EndWhile
oGroupElements = treewalker.currentElement.findAll(TreeScope_Descendants, oGroupTypeCondition)
treewalker.currentElement = GetGroupWithSpellingOrGrammarName(oGroupElements)
; If the control group contains a read-only text field,
; it's the New method using split buttons
Var
    Object controlTypeCondition,
    Object isValuePatternAvailable,
    Object isReadOnly,
    Object condition
controlTypeCondition = UIA.CreateIntPropertyCondition(UIA_ControlTypePropertyId, UIA_EditControlTypeId)
isValuePatternAvailable = UIA.CreateBoolPropertyCondition( UIA_IsValuePatternAvailablePropertyId, UIATrue)
isReadOnly = UIA.CreateBoolPropertyCondition( UIA_ValueIsReadOnlyPropertyId, UIATrue)
condition = UIA.CreateAndCondition(controlTypeCondition, isValuePatternAvailable)
condition = UIA.CreateAndCondition(condition, isReadOnly)
currentSentenceTextField = treewalker.currentElement.FindFirst(TREESCOPE_SUBTREE, condition)
If !currentSentenceTextField Return False EndIf
; group name contains prompt, text and spelling of text.
; Not necessarily in that order.
spellingError = treewalker.currentElement
condition = UIA.CreateIntPropertyCondition(UIA_ControlTypePropertyId, UIA_SplitButtonControlTypeId)
While treeWalker.GoToNextSibling()
    If treewalker.currentElement.controlType != UIA_GroupControlTypeId
    && treewalker.currentElement.controlType != UIA_ScrollBarControlTypeId
        Return False
    EndIf
    ; Split buttons are suggestions:
    If !oSuggestionSplitButton
        oSuggestionSplitButton = treewalker.currentElement.FindFirst(TREESCOPE_SUBTREE, condition)
    EndIf
EndWhile
treewalker.currentElement = element
Message = spellingError.name
; since we now keep track of active group name, speaking only when it changes:
c_WordTester.TaskOrProofingPaneGroupName = Message
sayMessage(OT_LINE, spellingError.name)
If oSuggestionSplitButton
    treewalker.currentElement = oSuggestionSplitButton
    treewalker.gotoParent
    tmp = treewalker.currentElement.name
    If !stringIsBlank(tmp)
        Message = Message+cscSpace+tmp
        sayMessage(OT_CONTROL_NAME, tmp)
    EndIf
    treewalker.currentElement = oSuggestionSplitButton
    tmp = oSuggestionSplitButton.name
    If !stringIsBlank(tmp)
        If stringSegmentCount(tmp, ", ")
            ; separate out the first segment, as the name contains more than just the suggestion:
            tmp = stringSegment(tmp, ", ", 1)
        EndIf
        Message = Message + cscSpace + tmp
        sayMessage(OT_LINE, tmp)
        spellString(tmp)
    EndIf
else
    ; no split buttons available, no suggestion
    Message = message + cscSpace + msgNoSpellingSuggestions1_L
    sayMessage(OT_ERROR, msgNoSpellingSuggestions1_L)
EndIf
BrailleMessage(Message)
Return True
EndFunction

Object Function GetGroupWithSpellingOrGrammarName (Object oGroupArray)
Var
    Object oGroup

ForEach oGroup in oGroupArray
    If stringContains(oGroup.name, wn_Proofing_Pane_Grammar)
    || stringContains(oGroup.name, wn_Proofing_Pane_Spelling) Then
        Return oGroup
    EndIf
EndForEach
Return Null()
EndFunction

Int Function IsWordContextMenuActive()
Return c_WordTester.WordContextMenuActive == True
EndFunction

Int Function CheckForUnsupportedDocumentView()
Var String sViewName
If !IsNormalOrDraftView()
    sViewName = GetActiveDocumentViewName()
    SayFormattedMessage(ot_screen_message,
        FormatString(msgDocumentView_l, sViewName),
        FormatString(msgDocumentView_s, sViewName))
    If IsReadingViewActive()
        SayFormattedMessage(ot_smart_help, msgReadingLayout)
        If BrailleInUse()
            BrailleRefresh()
        EndIf
        Return True
    EndIf
EndIf
Return False
EndFunction

Void Function SetNewLineIndicationMode()
Var
    Int iMode,
    Int iNewMode,
    Int bShow
iMode = NewLinesAndParagraphsIndication()
If GetActiveDocumentViewName() == msgWeb
    If iMode != wdVerbosityOff
        SetNewLinesAndParagraphsIndication(wdVerbosityOff)
    EndIf
    Return
EndIf
;Only manipulate the setting If it is possible that
;the user changed display options in Word:
If GlobalWasHjDialog
|| getAppMainWindow(GetFocus()) != globalPrevApp
    Return
EndIf
iNewMode = iMode
bShow = (isShowParagraphs() || isShowAll())
If bShow
    If iMode == wdVerbosityOff
        iNewMode=IndicateWhenReading
    EndIf
else
    iNewMode = wdVerbosityOff
EndIf
If iMode != iNewMode
    SetNewLinesAndParagraphsIndication(iNewMode)
EndIf
EndFunction

String Function GetWordCountDlgStaticText(Handle focusWindow)
If c_WordFocus.RealWindowName != wn_WordCountDialog
|| !StringStartsWith(c_WordFocus.WindowClass, "bosa_sdm_")
|| GetJCFOption(OPT_USE_SDM_API) == 0
    Return cscNull
EndIf
Var Object element = FSUIAGetElementFromHandle(focusWindow)
If !element Return cscNull EndIf
Var Object textElements = element.findAll(TREESCOPE_SUBTREE, FSUIACreateIntPropertyCondition(UIA_ControlTypePropertyId, UIA_TextControlTypeId))
If !textElements || !textElements.count Return cscNull EndIf
Var Int i, String text
For i=0 To textElements.count-1
    If !stringIsBlank(text) text=text+cscBufferNewLine EndIf
    text=formatString(text+"%1", textElements(i).name) ; since can't concatenate data members direct into a String literal
EndFor
Return text
EndFunction

Int Function PreProcessKeyPressedEvent(Int nKey, String strKeyName, Int nIsBrailleKey, Int nIsScriptKey)
Var Int bStopProcessing = PreProcessKeyPressedEvent(nKey, strKeyName, nIsBrailleKey, nIsScriptKey)
If !bStopProcessing
    If QuickNavKeyTrapping()
        If QuickNavTrappedKeyProcessed(nKey, strKeyName, nIsScriptKey)
            Return True
        EndIf
    EndIf
    If !UserBufferIsActive()
        ; process accented characters:
        If nKey == kiAltCtrlQuestion
        || nKey == kiAltCtrlExclaim
            SayAccentedCharacter()
            Return True
        ElIf c_WordTester.NextIsAccentedChar
            c_WordTester.NextIsAccentedChar = False
            ScheduleFunction("SayAccentedCharacter", 1)
            Return True
        else
            If nKey == kiCtrlApostrophe
            || nKey == kiCtrlGrave
            || nKey == kiCtrlTilde
            || nKey == kiCtrlCaret
            || nKey == kiCtrlColon
            || nKey == kiCtrlAt
            || nKey == kiCtrlAnd
            || nKey == kiCtrlComma
            || nKey == kiCtrlSlash
                c_WordTester.NextIsAccentedChar = True
                Return True
            EndIf
        EndIf
    EndIf
EndIf
Return bStopProcessing
EndFunction

Int Function NewTextEventShouldBeSilent(Handle hFocus, Handle hwnd, String buffer, Int nAttributes,
    Int nTextColor, Int nBackgroundColor, Int nEcho, String sFrameName)
If InRibbons()  ; suppress non-focused controls announcement.
    Return True
EndIf
Var String class = GetWindowClass(hWnd)
If class == wc_bosa_sdm_Mso96
&& c_WordFocus.windowCategory== WCAT_SPELL_CHECKER
    Return True
EndIf
If hWnd == hFocus
    If class == wc_ReComboBox20W
        Return False
    EndIf
else
    If class == wc_OOCWindow
    && GetParent(hWnd) == hFocus
        Return True
    EndIf
EndIf
Return NewTextEventShouldBeSilent(hFocus, hwnd, buffer, nAttributes, nTextColor, nBackgroundColor, nEcho, sFrameName)
EndFunction

Void Function ProcessSpeechOnNewTextEvent(Handle hFocus, Handle hwnd, String buffer, Int nAttributes,
    Int nTextColor, Int nBackgroundColor, Int nEcho, String sFrameName)
If hWnd == getFocus()
&& GetWindowClass(hwnd) == wc_ReComboBox20W
    Say(buffer, ot_line)
    Return
EndIf
ProcessSpeechOnNewTextEvent(hFocus, hwnd, buffer, nAttributes, nTextColor, nBackgroundColor, nEcho, sFrameName)
EndFunction

Void Function sayHighlightedText(Handle hwnd, String buffer)
If WindowCategoryIsWordDocument()
    Var Int screenEcho = GetScreenEcho()
    If screenEcho > 0
    && GetLastMouseMovementTime() >= GetLastKeyPressTime()
    && !IsVirtualPCCursor()
        ; This code block fixes bug 50538(Running both JAWS and MAGic together - click On a
        ; word To select it is Not saying the selected word in multiple apps).
        ; This code block gets called when text is selected using the mouse and focus is in the
        ; main document window in Microsoft Word. Note there are three common scenarios For
        ; selecting text with the mouse. The first is To double click the left mouse button On
        ; a word. This causes the word that was double clicked To become selected. In this
        ; case the last mouse movement time will be greater than the last key press time. The
        ; second method of selecting text with the mouse is To position the caret at one end of
        ; the region that you wish To select, hold down the shift key, and click the left mouse
        ; button once at the other end of the region that you wish To select. In this case the
        ; last mouse movement time will often be the same as the last key press time(unless you
        ; pause For a full millisecond after pressing the shift key before pressing the left
        ; mouse button). The third method of selecting text with the mouse is To click with the
        ; left mouse button at one end of the region that you wish To select, hold down the
        ; mouse button, drag the mouse To the other end of the region that you wish To select,
        ; and Then release the left mouse button.
        ; This code block causes JAWS To speak correctly in the first and second scenarios. Note
        ; that the second scenario in which the last mouse movement time may be the same as the
        ; last key press time is why the >=(greater than or equal) operator is used in this If
        ; statement instead of the >(greater than) operator.
        ; Also note that there is currently no good method of ensuring that JAWS or MAGic speaks
        ; correctly in the third scenario.
        say(buffer, ot_highlighted_screen_text, True)
        Return
    EndIf
    If screenEcho <= 1
    && hwnd != getFocus()
        ; Headings that redraw as you type into the document below them
        ; are stopped from speaking here.
        Return
    EndIf
EndIf
sayHighlightedText(hwnd, buffer)
EndFunction

Void Function ConfigurationChangedEvent(String newConfiguration)
;Sometimes, when leaving Quicksettings, the scripts receive the FocusChangedEventEx before the QuickSettings scripts unload.
;When this occurs, quick navigation gets out of sync.
;So we run WordQuickNavInit here To compensate.
If newConfiguration == "word"
    WordQuickNavInit()
EndIf
ConfigurationChangedEvent(newConfiguration)
EndFunction

Int Function IsContextMenu(Int type)
If type == wt_contextMenu
    Return True
ElIf type != wt_menu
    Return False
EndIf
;It's a menu, but is it a context menu:
Return GetWindowSubtypecode(GetFocus()) == wt_contextMenu
    || GetObjectSubtypecode(False, 1) == wt_contextMenu
EndFunction

Int Function MenuProcessedOnFocusChangedEventEx(
    Handle hwndFocus, Handle hwndPrevFocus,
    Int nType, optional Int nChangeDepth)
If IsVirtualRibbonActive() Return MenuProcessedOnFocusChangedEventEx(hwndFocus, hwndPrevFocus, nType, nChangeDepth) EndIf
c_WordTester.WordContextMenuActive = IsContextMenu(nType)
If !nType
    ;due To timing, when leaving a context menu in the document
    ;the GetMenuMode Function may Return menu_active.
    ;this causes the context menu To be announced as If it is appearing.
    ;So, we test For the type here, and If it is 0 Return False.
    GlobalMenuMode = GetMenuMode()
    Return GlobalMenuMode != menu_inactive
EndIf
Return MenuProcessedOnFocusChangedEventEx(hwndFocus, hwndPrevFocus, nType, nChangeDepth)
EndFunction

Int Function ContextMenuProcessed(Handle hwnd)
Var Int bRetVal = contextMenuProcessed(hwnd)
c_WordTester.WordContextMenuActive = (bRetVal || IsContextMenu(GetObjectSubtypeCode()))
Return bRetVal
EndFunction

Void Function MenuModeEvent(Handle WinHandle, Int mode)
TrackEvent(event_menuMode)
MenuModeEvent(WinHandle, mode)
EstablishQuickNavState()
EndFunction

Int Function FocusRedirectedOnFocusChangedEventEx(
    Handle hwndFocus, Int nObject, Int nChild,
    Handle hwndPrevFocus, Int nPrevObject, Int nPrevChild,
    Int nChangeDepth)
;We have quite a lot of trouble with double firing of the focus change.
;It appears that in some SDM dialogs, the undesired focus change can be detected by the objID, childID, prevObjID and prevChildID all being 0.
If !nObject && !nChild && !nPrevObject && !nPrevChild
&& hwndFocus == hwndPrevFocus
&& StringStartsWith(c_WordFocus.RealWindowClass, "bosa_sdm_")
    Return True
EndIf
Return FocusRedirectedOnFocusChangedEventEx(hwndFocus, nObject, nChild, hwndPrevFocus, nPrevObject, nPrevChild, nChangeDepth)
EndFunction

Int Function FocusChangedEventShouldProcessAncestors(Handle FocusWindow, optional Handle prevFocusWindow)
If c_WordFocus.windowCategory == wCat_document
|| c_WordFocus.windowCategory == WCAT_SPELL_CHECKER
|| c_WordFocus.InProofingPaneSpellCheck
    Return False
EndIf
If c_WordFocus.ObjectSubType == WT_MULTILINE_EDIT
&& c_WordFocus.WindowClass == cwc_NetUIHwnd
&& getObjectSubtypeCode(False, 2) == WT_DIALOG_PAGE
    Return False
EndIf
; Readability Statistics is now a pane / transparent dialog even though it's still SDM,
; and the relevant controls are UIA text children of the dialog / window.
If getObjectName(False, 1) == wn_ReadabilityStatistics Return True EndIf
Return FocusChangedEventShouldProcessAncestors(FocusWindow, prevFocusWindow)
EndFunction

Void Function FocusChangedEventProcessAncestors(Handle FocusWindow, Handle PrevWindow)
;Keep edit combos On proofing pane from announcing themselves twice:
If c_WordFocus.InProofingPaneSpellCheck
&& c_WordFocus.ObjectSubType == WT_LISTBOXITEM
    sayObjectTypeAndText()
    Return
EndIf
Var Handle hDialog = getRealWindow(focusWindow)
If FocusWindow != PrevWindow
&& c_WordFocus.WindowClass == cwc_NetUIHwnd
&& GetWindowClass(hDialog) == wc_NUIDialog
&& GetWindowSubtypeCode(hDialog) == WT_DIALOG
    SayObjectTypeAndText()  ; Reads control name and type.
    Return
EndIf
FocusChangedEventProcessAncestors(FocusWindow, PrevWindow)
EndFunction

Void Function PreProcessFocusChangedEventEx(
    Handle hwndFocus, Int nObject, Int nChild,
    Handle hwndPrevFocus, Int nPrevObject, Int nPrevChild,
    Int nChangeDepth)
If nChangeDepth >= 0
    UpdateWordFocus(hwndFocus)
EndIf
PreProcessFocusChangedEventEx(hwndFocus, nObject, nChild, hwndPrevFocus, nPrevObject, nPrevChild, nChangeDepth)
EndFunction

Void Function FocusChangedEventEx(
    Handle hwndFocus, Int nObject, Int nChild,
    Handle hwndPrevFocus, Int nPrevObject, Int nPrevChild,
    Int nChangeDepth)
; always kill suggestion split button because proofing pane code will reinitialize If appropriate.
oSuggestionSplitButton = null()
ClearProcessMainDocumentWindowTimer()
If FocusRedirectedOnFocusChangedEventEx(hwndFocus, nObject, nChild,
    hwndPrevFocus, nPrevObject, nPrevChild, nChangeDepth)
    Return
EndIf
c_WordTester.hWndPrevFocus = hwndPrevFocus
c_WordTester.WasOfficeSplashScreen = WasOfficeSplashScreen() ;See comment in Office.jss FocusChangedEventEx
CancelFocusItemMonitors()
FocusChangedEventEx(hwndFocus, nObject, nChild, hwndPrevFocus, nPrevObject, nPrevChild, nChangeDepth)
EstablishQuickNavState()
EndFunction

Void Function ProcessEventOnFocusChangedEventEx(
    Handle hwndFocus, Int nObject, Int nChild,
    Handle hwndPrevFocus, Int nPrevObject, Int nPrevChild,
    Int nChangeDepth, String sClass, Int nType)
ManageUIAEvents()
If inHjDialog()
&& hwndFocus == hwndPrevFocus
&& c_WordFocus.WindowClass == "SearchBox"
&& inQuickSettingsDialog()
    ;Dispel erroneous speech from items in QuickSettings Search Box:
    Return; prevent over-chatter:
EndIf
If nChangeDepth == 0
&& nType == wt_ListBoxItem
    ;Some listbox items can focus To each item in the list using tab,
    ;and their change depth is 0.
    ;here we attempt To avoid repetative speaking of the list name For each item in the list:
    ;Currently, we only know about the listbox items in the navigation pane:
    If IsSearchDocumentDialogType()
        If c_WordTester.PrevFocusWasLevelZeroChangeListBoxItem
            Return ActiveItemChangedEvent(hwndFocus, nObject, nChild,
                hwndPrevFocus, nPrevObject, nPrevChild)
        else
            c_WordTester.PrevFocusWasLevelZeroChangeListBoxItem = True
            Return ProcessEventOnFocusChangedEventEx(hwndFocus, nObject, nChild,
                hwndPrevFocus, nPrevObject, nPrevChild, nChangeDepth, sClass, nType)
        EndIf
    EndIf
ElIf c_WordTester.PrevFocusWasLevelZeroChangeListBoxItem
    c_WordTester.PrevFocusWasLevelZeroChangeListBoxItem = False
EndIf
ProcessEventOnFocusChangedEventEx(hwndFocus, nObject, nChild,
    hwndPrevFocus, nPrevObject, nPrevChild, nChangeDepth, sClass, nType)
EndFunction

Void Function FocusChangedEvent(Handle FocusWindow, Handle PrevWindow)
If !c_WordFocus.InProofingPaneSpellCheckWithSplitButtons
    c_WordTester.TaskOrProofingPaneGroupName = cscNull
EndIf
If c_WordFocus.WindowClass == "Excel7"
    SwitchToConfiguration("Excel")
    ;Schedule call For ExcelFunc Function:
    ScheduleFunction("InitializeObjectsForWordEmbeddedWorksheet", 3)
    Return
EndIf
; For document load from Office where Word doesn't automatically open To a document window:
If c_WordFocus.WindowClass == wc_wordMainDocumentWindow
    ; exclude returning To document from embedded combo box in form fields:
    If getWindowClass(PrevWindow) != cWcMenuClass
    && !IsFormField()
    && prevWindow != focusWindow
        WordInit()
        c_WordTester.SelectionRectChangedEventID = ScheduleFunction("RunSelectionContextEvents", 2)
    EndIf
EndIf
If ReturningFromResearchItDialog()
    Return default::FocusChangedEvent(FocusWindow, PrevWindow)
EndIf
If !c_WordTester.FocusChangedOnSelectATable
    TrackEvent(event_FocusChanged)
else
    ;See Script SelectATable For why this is used
    c_WordTester.FocusChangedOnSelectATable = False
EndIf
GlobalRealWindowName = c_WordFocus.RealWindowName
;A blank password contains the same characters as a non-breaking space symbol,
;so make sure that nonbreaking symbol detection is Off in passwords:
AllowNonbreakingSymbolsDetection(!(dialogActive() && c_WordFocus.ObjectSubType == wt_passwordEdit))
Var
    Int bSavedSDM,
    Int savedUseSDMOption
If GlobalRealWindowName != globalPrevRealName
&& GlobalRealWindowName == wn_WordCountDialog
    ; must turn On SDM dialog reading For this dialog, even though we read via UIA.
    ; In english, this is alt+R, W.
    bSavedSDM = True
    savedUseSDMOption = GetJCFOption(OPT_USE_SDM_API)
    SetJCFOption(OPT_USE_SDM_API, 1)
EndIf
FocusChangedEvent(FocusWindow, PrevWindow)
; If SDM option had been set To speak window properly, set it back:
If bSavedSDM
    SetJCFOption(OPT_USE_SDM_API, savedUseSDMOption)
EndIf
EndFunction

Int Function HandleCustomAppWindows(Handle AppWindow)
If !IsWindowVisible(AppWindow)
    ; The app window is either invalid or hidden.
    ; Either way, we don't want To do anything special here because we're likely To hang
    Return False
EndIf
If !IsUpdatingDocumentData()
    WDApp_DocumentChange()
EndIf
If HandleCustomSpellCheckRealWindows(AppWindow)
    ;This behaves as app window change:
    Return True
EndIf
;Dialogs may be real and app window both:
Return HandleCustomAppWindows(AppWindow)
EndFunction

Void Function ProcessSayAppWindowOnFocusChange(Handle AppWindow, Handle FocusWindow)
If GlobalPrevApp == AppWindow
&& WindowCategoryIsWordDocument()
    If !IsUpdatingDocumentData()
        WDApp_DocumentChange()
    EndIf
    Return
EndIf
ProcessSayAppWindowOnFocusChange(AppWindow, FocusWindow)
EndFunction

Int Function HandleCustomSpellCheckRealWindows(Handle hReal)
;Actually processed as app window change but behaves like a real or dialog window
Var
    Handle focusWindow = getFocus(),
    String sRealName
If c_WordFocus.WindowClass == cwc_NetUIHwnd
    Return False
EndIf
If c_WordFocus.windowCategory== WCAT_SPELL_CHECKER
&& c_WordFocus.WindowSubtype == WT_MULTILINE_EDIT
    sRealName = stringSegment(getWindowName(hReal), cScColon, 1)+cScColon
    indicateControlType(wt_dialog, sRealName)
    HandleCustomSpellCheckWindows(focusWindow)
    Return True
EndIf
Return False
EndFunction

Int Function HandleCustomRealWindows(Handle RealWindow)
Var
    Handle AppWindow = GetAppMainWindow(RealWindow),
    String RealWindowName = GetWindowName(RealWindow)
If StringContains(GetWindowName(AppWindow), RealWindowName)
    ;Don't repeat the document name If it has already been spoken by the app focus change
    If !dialogActive()
        Return True
    EndIf
EndIf
Return HandleCustomRealWindows(RealWindow)
EndFunction

Void Function ProcessSayRealWindowOnFocusChange(Handle AppWindow, Handle RealWindow, String RealWindowName, Handle FocusWindow)
If GlobalPrevRealName == RealWindowName
&& GlobalPrevReal == RealWindow
&& GlobalCommandBarWindow == globalPrevCommandBarWindow
    ;The real window did Not change, so just Return.
    Return
EndIf
If c_WordFocus.windowCategory== WCAT_TASK_PANE
    c_WordTester.WasTaskPaneDialog = True
    If c_WordFocus.InMicrosoftEditorProofingPaneIssueChecker
        ;In the Microsoft Editor pane, real window is same as the document real window.
        ;Speaking will be handled through downstream functions of processsayfocuswindowonfocuschange.
        Return
    EndIf
    If c_WordFocus.InProofingPaneSpellCheck
        ReadSpellCheckInfoUIA(True)
        Return
    EndIf
    Return
EndIf
If c_WordTester.WasTaskPaneDialog
    c_WordTester.WasTaskPaneDialog = False
    If WindowCategoryIsWordDocument()
        SayWindowTypeAndText(RealWindow)
        Return
    EndIf
EndIf
If RealWindowName == wn_WordCountDialog
&& GetJCFOption(OPT_USE_SDM_API) == 1
&& StringStartsWith(c_WordFocus.RealWindowClass, "bosa_sdm_")
    ; only Handle special case If we got the word count properly:
    Var String wordCountText = GetWordCountDlgStaticText(focusWindow)
    If !stringIsBlank(wordCountText)
        indicateControlType(WT_DIALOG, realWindowName)
        sayMessage(OT_DIALOG_TEXT, wordCountText)
        Return
    EndIf
EndIf
If InbosaSDMMso96Dialog()
&& c_WordFocus.InProofingPaneSpellCheck
    ReadSpellCheckInfo()
    Return
EndIf
ProcessSayRealWindowOnFocusChange(AppWindow, RealWindow, RealWindowName, FocusWindow)
EndFunction

Int Function HandleCustomSpellCheckWindows(Handle hwnd)
If c_WordFocus.windowCategory!= WCAT_SPELL_CHECKER
    Return False
EndIf
Var Int iSubtype = c_WordFocus.ObjectSubType
If c_WordFocus.WindowClass == wc_bosa_sdm_Mso96
    If iSubtype == wt_edit
        ;Occasionally, when an accellerator key is used While focus is in the edit field showing the word in context,
        ;Focus change will fire and the class will be the bosa sdm window While the Object is wt_edit.
        ;This is a transitional focus change, and we want To ignore it.
        Return True
    EndIf
    If iSubtype == wt_button
        Return False
    EndIf
EndIf
If iSubtype == wt_Document
|| iSubtype == wt_multiline_edit
    ;The error will be shown in context in an element of type document.
    ReadSpellCheckInfo()
 Return True
ElIf iSubtype == wt_listboxItem
    IndicateControlType(wt_ListBox, GetObjectName(False, 1), GetObjectName())
    spellString(GetObjectName())
    SayMessage(OT_POSITION, PositionInGroup())
    Return True
EndIf
Return False
EndFunction

Int Function handleCustomWindows(Handle hwnd)
If HandleCustomSpellCheckWindows(hwnd)
    Return True
EndIf
Return handleCustomWindows(hwnd)
EndFunction

Void Function ProcessSayFocusWindowOnFocusChange(String RealWindowName, Handle FocusWindow)
If GlobalWasHJDialog
&& UserBufferIsActive()
    ;SayLine or SayAll will be performed,
    ;so don't say the user buffer as the focus item.
    Return
EndIf
If c_WordFocus.InProofingPaneSpellCheck
&& getRealWindow(GlobalFocusWindow) != GlobalPrevReal
    ; Real window is speaking spell check info in dialog first load.
    Return
EndIf
ProcessSayFocusWindowOnFocusChange(RealWindowName, FocusWindow)
EndFunction

Void Function ProcessSayWindowPromptAndTextTutorialHelp(Int iSubtype, Handle hwnd, Int bSpeak, Int nTrainingMode)
If dialogActive () Then
; open or Save As dialogs will read the toolbar describing location
    SayFolderLocationForDialog ()
EndIf
SayTutorialHelp(iSubType, bSpeak)
SayTutorialHelpHotKey(hWnd, bSpeak)
IndicateComputerBraille(hwnd)
SpeakProgressBarInfo(bSpeak)
smmToggleTrainingMode(nTrainingMode)
EndFunction

Script SayWindowPromptAndText()
Var
    Int sayIt = True,
    Int ignoreFonts = True,
    Handle hWnd,
    Handle hFocus,
    Int iSubType,
    Int iObjType,
    Int nMode,
    String sWindowName,
    String sClass
c_WordTester.TaskOrProofingPaneGroupName = cscNull ; so SayObjectTypeAndText will read it properly.
DescribeTextAnnotationOrAttributes(sayIt, ignoreFonts)
If handleNoCurrentWindow()
    Return
EndIf
If MenusActive()
|| InHJDialog()
    performscript SayWindowPromptAndText()
    Return
EndIf
hWnd = GetCurrentWindow()
hFocus=GetFocus()
iSubType = GetWindowSubTypeCode(hWnd)
If !iSubType
    iSubType = c_WordFocus.ObjectSubType
Else
    iObjType=c_WordFocus.ObjectSubType
EndIf
If inRibbons()
|| IsVirtualRibbonActive()
|| (!OutlookIsActive()
&& isStatusBarToolbar())
    If IsVirtualRibbonActive()
        sayVirtualRibbonItem()
    else
        If InMultilevelListPane()
        && UsingShortNameOfMultiLevelListObject()
            IndicateControlType(wt_grid, GetWord2003MultiLevelListObjectNameOfFocusObject(), cscNull)
            Say(PositionInGroup(), ot_position)
            SayUsingVoice(vctx_message, GetObjectName(), ot_help)
        else
            self::SayObjectTypeAndText()
        EndIf
    EndIf
    ProcessSayWindowPromptAndTextTutorialHelp(iSubtype, hFocus, True, nMode)
    Return
EndIf
sClass = c_WordFocus.WindowClass
nMode = smmTrainingModeActive()
smmToggleTrainingMode(True)
If sClass == wc_officeDropdown
&& !iSubtype
&& !iObjType
    iSubtype = wt_ComboBox
    Say(GetLine(), ot_line)
    ProcessSayWindowPromptAndTextTutorialHelp(iSubtype, hwnd, True, nMode)
    Return
ElIf StringContains(GetObjectName(), scBallon)
    self::GetCustomTutorMessage()
    self::SayFocusedWindow()
    ProcessSayWindowPromptAndTextTutorialHelp(iSubtype, hwnd, True, nMode)
    Return
EndIf
If InTaskPaneDialog()
    GetCustomTutorMessage()
    SayFocusedWindow()
    ProcessSayWindowPromptAndTextTutorialHelp(iSubtype, hwnd, True, nMode)
    Return
EndIf
If (menusActive() || dialogActive())
&& !IsWordDocumentActive()
    ;For New document dialog:
    ; need To force following calls as standard calls To SayFocusedObject, etc. do Not provide enough information.
    If StringContains(GetWindowName(GetRealWindow(hwnd)), wn_newDocumentDlg)
    && c_WordFocus.ObjectSubType == wt_listboxItem
        SayWindowTypeAndText(GetParent(hwnd))
        SayMessage(ot_control_name, GetObjectName(SOURCE_CACHED_DATA, 1))
        indicateControlType(wt_listboxItem, GetObjectName()) ; iObjType does Not get correct info here.
    Else
        If InTaskPaneDialog()
            GetCustomTutorMessage()
            SayFocusedObject()
        Else
            self::sayFocusedWindow()
        EndIf
    EndIf
    ProcessSayWindowPromptAndTextTutorialHelp(iSubtype, hwnd, True, nMode)
    Return
EndIf
If WindowCategoryIsWordDocument()
    If IsVirtualPcCursor()
        speakSmartNavLevelSetting()
    EndIf
    If IsFormField()
        self::SayObjectTypeAndText()
        SayF1Help()
        If inTable()
            sayCellCoordinatesInfo()
        EndIf
    ElIf inTable()
        sayCellPromptAndText()
    else ; Not in a table so If On a field, announce it
        ;may need further refactor.
        self::SayLine()
; the following uses globalInBorderedText, which is Not set anywhere:
;       ;only read text in a bordered region If the region is determined To be arbitrary rather
;       ;than a paragraph or number of paragraphs or sections.
;       ;For example If the author places a border around several words.
;       If globalInBorderedText
;           sayTextInBorderedRegion()
;       EndIf
    EndIf
    Return
else
    If StringContains(getWindowName(GetRealWindow(hwnd)), wn_options)
        If c_WordFocus.ObjectSubType == wt_listBoxItem
            self::sayFocusedWindow()
            SayUsingVoice(vctx_message, msgOptionsDlgCategoriesTutorHelp, ot_line)
        else
            self::sayObjectTypeAndText()
        EndIf
        ProcessSayWindowPromptAndTextTutorialHelp(iSubtype, hwnd, True, nMode)
        Return
    EndIf
EndIf
performscript SayWindowPromptAndText()
EndScript

Void Function SayControlGroupNameForTaskAndProofingPane()
; could apply To other groups in task panes in future, but applies To spellCheck with split buttons at the moment.
If !c_WordFocus.InProofingPaneSpellCheckWithSplitButtons
    c_WordTester.TaskOrProofingPaneGroupName = cscNull
    Return
EndIf
Var Object element = FSUIAGetFocusedElement() ; get current button or control
If !element
    c_WordTester.TaskOrProofingPaneGroupName = cscNull
    Return
EndIf
Var Int isReadOnlyEditElement =(element.controlType == UIA_EditControlTypeId
        && element.GetValuePattern().IsReadOnly)
element = CreateUIAParentOfElement(element)
If !element
|| element.ControlType != UIA_GroupControlTypeId
    c_WordTester.TaskOrProofingPaneGroupName = cscNull
    Return
EndIf
If isReadOnlyEditElement
|| c_WordFocus.ObjectSubType == WT_READONLYEDIT
    ; read mistake and first suggestion split button
    ReadProofingPaneWithSplitButtons()
ElIf element.name != c_WordTester.TaskOrProofingPaneGroupName
    sayMessage(OT_CONTROL_GROUP_NAME, element.name)
EndIf
c_WordTester.TaskOrProofingPaneGroupName = element.name
EndFunction

Void Function SayObjectTypeAndText(optional Int nLevel, Int includeContainerName)
If WasSayObjectTypeAndTextExceptionProcessed(nLevel, includeContainerName) Return EndIf
If UserBufferIsActive()
    If c_WordFocus.InProofingPaneSpellCheck
        Return ; so we don't get double repeated text from the first time the Reason Text viewer comes up.
    else
        SayObjectTypeAndText(nLevel, includeContainerName)
        Return
    EndIf
EndIf
Var
    Handle hWnd = getCurrentWindow(),
    Int iType,
    String sValue,
    String sObjectHelp = GetObjectHelp()
If nLevel == 0
    SayControlGroupNameForTaskAndProofingPane()
    iType = GetObjectSubtypeCode(SOURCE_CACHED_DATA)
    If iType == WT_STATIC
    && ReadMicrosoftEditorIssueCheckerInfo(True, False)
        Return
    ElIf iType == WT_SPLITBUTTON
    && ReadMicrosoftEditorSuggestion()
        Return
    ElIf iType == WT_LISTBOXITEM
    && c_WordFocus.InProofingPaneSpellCheck
        SayObjectTypeAndText(nLevel, includeContainerName)
        If GetObjectStateCode(True) & STATE_SYSTEM_DEFAULT
            ; avoid spelling the drop down item in the language combo box when it first opens To a list box:
            SpellString(GetObjectName(SOURCE_CACHED_DATA))
        EndIf
        Return
    ElIf iType == WT_LISTBOXITEM
    && c_WordFocus.WindowClass == "bosa_sdm_msword"
        indicateControlType(WT_LISTBOX, getObjectName(0, 1), getObjectName())
        say(PositionInGroup(), OT_POSITION)
        Return
    ElIf getObjectTypeCode() == WT_EDIT
    && c_WordFocus.InProofingPaneSpellCheckWithSplitButtons
        ; current sentence edit field does Not read whole sentence but only current line:
        Var Object pattern = FSUIAGetFocusedElement().GetValuePattern()
        If !stringIsBlank(pattern.value)
            Return indicateControlType(WT_READONLYEDIT, getObjectName(SOURCE_CACHED_DATA), pattern.value)
        EndIf
    EndIf
    If iType == wt_grid
        If InMultilevelListPane()
            IndicateControlType(wt_grid, GetWord2003MultiLevelListObjectNameOfFocusObject(), cscNull)
            Say(PositionInGroup(), ot_position)
            ;we notify the user of context help because
            ;we have substituted the actual name with a user-friendly shorter version,
            ;and the context help is the aqctual name of the Object.
            NotifyIfContextHelp()
            Return
        EndIf
    EndIf
EndIf
If c_WordFocus.HeaderForNewAddressListField != cscNull
    IndicateControlType (iType, c_WordFocus.HeaderForNewAddressListField, GetObjectValue ())
    Return
EndIf
If GetObjectName(SOURCE_CACHED_DATA, 1) == wn_SearchResultsList
    Say(sObjectHelp, OT_LINE)
EndIf
SayObjectTypeAndText(nLevel, includeContainerName)
If nLevel == 0
    SpeakSuggestionsAvailable()
    ; If the Object is the button type and has a path in the help message we should announce it...
    ; a good example is the recent files buttons in the open ribbon dialogue
    If iType == WT_BUTTON
    && !StringIsBlank(sObjectHelp)
    && GetObjectName(SOURCE_CACHED_DATA) != sObjectHelp
    && GetWindowClass(hWnd) == cwc_NetUIHwnd
    && isBackStageView(hWnd)
        Say(sObjectHelp, OT_SCREEN_MESSAGE)
    EndIf
EndIf
EndFunction

Void Function AnnounceNoOpenDocument()
c_WordTester.AnnounceNoOpenDocumentTimerID = 0
;make sure that focus is still On the empty client workspace,
;since focus can briefly land in an empty client workspace before firing again To land elsewhere,
;such as a newly opened document:
If c_WordFocus.windowCategory == WCAT_DOCUMENT_WORKSPACE
    BrailleRefresh()
    SayUsingVoice(vctx_message, msgNoOpenDocument, ot_help)
EndIf
EndFunction

Void Function SayFocusedWindow()
If c_WordFocus.windowCategory == wCat_document
    If GetObjectSubTypeCode(SOURCE_CACHED_DATA, 0)!=WT_DOCUMENT
        sayobjectTypeAndText()
        Return
    EndIf
    ; may need To re-initialize application pointer.
    If IsAppObjInvalid()
        InitializeAppObj()
    EndIf
    If (getRunningFSProducts() == PRODUCT_MAGic ||!BrailleInUse ())
    && (!globalPrevFocus || stringContains(getWindowClass(globalPrevFocus), cwc_NetUIHwnd)) Then ; returning from the ribbons
        RunSelectionContextEvents(); update all relevant data For tables.
        updateTableManually()
        cwdUpdateTitleColumnsAndRows()
    EndIf
    globalDocumentName = GetActiveDocumentName()
    ;Check that this is Not a double firing of focus change For a window,
    ;where the window was already announced.
    ;Testing here with c_WordTester.hWndPrevFocus instead of GlobalPrevFocus
    ;allows detection of focus change due To leaving menus:
    If c_WordTester.WasOfficeSplashScreen
    || !(c_WordTester.hWndPrevFocus == GlobalFocusWindow
    && globalPrevDocumentName == globalDocumentName)
        c_WordTester.ProcessMainDocumentWindowTimerID = scheduleFunction("ProcessMainDocumentWindowWrapper", 1)
    EndIf
    globalPrevDocumentName = globalDocumentName
    Return
ElIf c_WordFocus.windowCategory == WCAT_DOCUMENT_WORKSPACE
    globalDocumentName = cscNull
    globalPrevDocumentName = globalDocumentName
    c_WordTester.AnnounceNoOpenDocumentTimerID = ScheduleFunction("AnnounceNoOpenDocument", 10)
    Return
EndIf
SetTypingEchoLanguage() ; reset in case it was changed For language detection
If dialogActive()
&& c_WordFocus.windowCategory != WCAT_SPELL_CHECKER
|| c_WordFocus.windowCategory == WCAT_TASK_PANE
    Return SayFocusedWindow()
EndIf
If menusActive()
    Return; handled separately.
EndIf
SayFocusedWindow()
EndFunction

Void Function ProcessMainDocumentWindow(Handle hFocus)
If NotifyZoomManyPages()
    Return
EndIf
If OutlookIsActive()
    Return ProcessOutlookMessageWindow(hFocus)
EndIf
; Enhanced edit must be On in nav area of document.
If GetJcfOption(OPT_EDIT_USE_OSM)
    setJcfOption(OPT_EDIT_USE_OSM, 0)
EndIf
;Document name may have been announced On app change,
;but If the app did Not change but the document did,
;the New document name gets announced here instead:
If GlobalPrevApp == GetAppMainWindow(GetFocus())
&& globalPrevDocumentName != globalDocumentName
    Say(GlobalDocumentName, ot_dialog_name)
EndIf
Var Int bIsFormfield = IsFormfield()
If !inTable()
&& !bIsFormfield
&& !IsActiveDocumentProtected()
&& !GlobalWasHJDialog
;Testing here with GlobalPrevFocus instead of c_WordTester.hWndPrevFocus
;allows this announcement To be skipped when leaving menus:
&& globalPrevFocus != GlobalFocusWindow
    If CheckForUnsupportedDocumentView()
        Return
    EndIf
EndIf
DetectDocumentHeadersFooters()
If !bIsFormfield
    ;   ProcessMeasurementUnitSetting()
    SetNewLineIndicationMode()
    IndicateControlType(wt_edit, cscSpace, cscSpace)
    Return
EndIf
If bIsFormfield
&& !IsDocumentTableActive()
    self::sayObjectTypeAndText()
    SayF1Help()
EndIf
EndFunction

Void Function ProcessMainDocumentWindowWrapper()
ProcessMainDocumentWindow(globalFocusWindow)
EndFunction

Void Function ProcessOutlookMessageWindow(Optional Handle hWnd)
Var
    Int iQuickNavigationOption,
    String sFormat
If !hWnd
    hWnd = GetFocus()
EndIf
;ReadHeader(1)
If IsActiveWindowProtected()
    ReadOutlookMessage()
    If !sayAllInProgress()
    && ShouldMessageTypeSpeak()
        Say(GetWindowName(hWnd), OT_CONTROL_NAME)
        sFormat = StringSegment(GetWindowName(GetAppMainWindow(hWnd)), "()", -2)
        If !StringIsBlank(sFormat)
            Say(sFormat, OT_SCREEN_MESSAGE)
        EndIf
    EndIf
    If sayAllInProgress() && ShouldSetQuickNavModeTo2()
        iQuickNavigationOption = 2
    else
        iQuickNavigationOption = 1
    EndIf
Else
    IndicateControlType(WT_MULTILINE_EDIT)
    iQuickNavigationOption = 0
EndIf
SetJcfOption(OPT_QUICK_KEY_NAVIGATION_MODE, iQuickNavigationOption)
SetQuickKeyNavigationState(iQuickNavigationOption)
Return
EndFunction

Void Function ActiveItemChangedEvent(Handle curHwnd, Int curObjectId, Int curChildId,
    Handle prevHwnd, Int prevObjectId, Int prevChildId)
Var Int ObjectSubtypeCode = GetObjectSubtypeCode()
If c_WordFocus.InProofingPaneSpellCheck
&& (ObjectSubtypeCode == WT_LISTBOXITEM || ObjectSubtypeCode == WT_COMBOBOX)
; avoid spelling the items in the language combo when it drops down To list.
; This list contains items without a state code.
&& GetObjectStateCode(True) & STATE_SYSTEM_DEFAULT
    SayObjectActiveItem()
    SpellString(GetObjectName(SOURCE_CACHED_DATA))
    Return
EndIf
ActiveItemChangedEvent(curHwnd, curObjectId, curChildId, prevHwnd, prevObjectId, prevChildId)
EndFunction

Void Function ObjStateChangedEvent(Handle hObj, optional Int iObjType, Int nChangedState, Int nState, Int nOldState)
Var
    Handle hFocus = GetFocus()
If hObj == hFocus
&& iObjType == wt_TabControl
&& nChangedState & ctrl_selected
    ;just say the selected state, don't Include the pressed state:
    indicateControlState(wt_tabControl, ctrl_selected)
    Return
EndIf
If iObjType == wt_listBoxItem
&& !nState
    If !nOldState
        ;this occasionally happens when pressing Enter On a style in the taskpane
        ;and the Object gets this event before focus returns To the document
        Return
    ElIf nOldState == ctrl_selected
    && c_WordFocus.WindowClass == cwc_NetUIHwnd
        ;For Word 2007/2010,
        ;the Options dialog uses a listbox instead of tab controls For the multiple pages.
        ;When navigating this listbox,
        ;the deselection of a listbox item may happen before the focus moves To the New item.
        ;Do nothing For this state change.
        Return
    EndIf
EndIf
ObjStateChangedEvent(hObj, iObjType, nChangedState, nState, nOldState)
EndFunction

Void Function RunNavQuickKeysManager()
NavigationQuickKeysManager(1)
EndFunction

Int Function InTextWindow()
If c_WordFocus.windowCategory== wCat_document
    Return True
Else
    Return inTextWindow() ;default
EndIf
EndFunction

Int Function IsTextAnalysisValid()
;overwritten here so that the Function returns True For Word document windows and Outlook message windows.
If c_WordFocus.windowCategory== wCat_document
&& !UserBufferIsActive()
&& !quickNavKeyTrapping()
    Return True
EndIf
Return IsTextAnalysisValid()
EndFunction

Int Function ShouldForceComputerBraille(Handle hwndTrans)
;Overwritten here so that the user can type in contracted English Braille in the main document area.
If c_WordFocus.windowCategory== wCat_document
&& !UserBufferIsActive() Then
    Return False
EndIf
Return ShouldForceComputerBraille(hwndTrans)
EndFunction

Int Function ContractedBrailleInputAllowedNow()
;Overridden here For when quick keys mode is enabled.
If QuickNavKeyTrapping()
&& !UserBufferIsActive() Then
    Return False
EndIf
Return ContractedBrailleInputAllowedNow()
EndFunction

Int Function UsesUnderlyingDom()
If c_WordFocus.windowCategory== wCat_document
&& !globalMenuMode
&& !DialogActive()
&& QuickKeyNavigationModeActive()
    Return True
EndIf
Return UsesUnderlyingDom()
EndFunction

Int Function KeyHasJAWSModifier(String sKey)
Var String s = StringLower(sKey)
Return StringContains(s, "jawskey")
    || StringContains(s, "insert")
    || StringContains(s, "capslock")
EndFunction

Int Function IsDocumentAreaScriptException(optional Int bValidInOutlook)
If InHJDialog()
    SayFormattedMessage(OT_ERROR, cmsg337_L, cmsg337_S)
    Return True
EndIf
If c_WordFocus.windowCategory!= wCat_document
    If !KeyHasJAWSModifier(GetCurrentScriptKeyName())
        SayCurrentScriptKeyLabel()
        TypeCurrentScriptKey()
    else
        If bValidInOutlook
        && OutlookIsActive()
            sayMessage(ot_error, msgNotInOutlookMessage_l, msgNotInOutlookMessage_s)
        else
            SayFormattedMessage(OT_error, msgNotInDocumentWindow1_L)
        EndIf
    EndIf
    Return True
EndIf
Return False
EndFunction

Int Function SayCursorMovementException(Int UnitMovement, optional Int bMoved)
Return isVirtualPCCursor()
    || SayCursorMovementException(UnitMovement, bMoved)
EndFunction

Void Function SayPageUpDownUnit(Int UnitMovement)
If SayCursorMovementException(unitMovement)
    SayPageUpDownUnit(unitMovement)
    Return
EndIf
If c_WordFocus.windowCategory== wCat_document
    Return
EndIf
SayPageUpDownUnit(UnitMovement)
EndFunction

Void Function LineSpacingDescChangedEvent(String lineSpacingDescription)
; Outlook's old spell checker is now trying To report text inconsistencies, and it shouldn't be doing this.
If c_WordFocus.windowCategory== WCAT_SPELL_CHECKER Return False EndIf
Return LineSpacingDescChangedEvent(lineSpacingDescription)
EndFunction

Int Function IsSearchDocumentDialogType()
If c_WordFocus.windowCategory != wCat_Task_Pane
    Return False
EndIf
Var
    String sObjNameAtLevel1,
    String sObjNameAtLevel2
sObjNameAtLevel1 = GetObjectName(SOURCE_CACHED_DATA, 1)
sObjNameAtLevel2 = GetObjectName(SOURCE_CACHED_DATA, 2)
If StringCompare(sObjNameAtLevel1, on_Find_And_Replace) == 0
|| StringCompare(sObjNameAtLevel2, on_Find_And_Replace) == 0
|| StringCompare(sObjNameAtLevel1, on_Navigation_Pane) == 0
|| StringCompare(sObjNameAtLevel2, on_Navigation_Pane) == 0
    Return True
EndIf
If GetObjectName(SOURCE_CACHED_DATA) == wn_SearchDocument
    Return True
EndIf
Return False
EndFunction

Int Function ShouldNotifyIfContextHelp()
If UsingShortNameOfMultiLevelListObject()
    Return True
EndIf
Return ShouldNotifyIfContextHelp()
EndFunction

Void Function NotifyIfContextHelp()
If !ShouldNotifyIfContextHelp() Return EndIf
If UsingShortNameOfMultiLevelListObject()
    SayUsingVoice(vctx_message, cMsgContextHelp, OT_SMART_HELP)
    Return
EndIf
NotifyIfContextHelp()
EndFunction

Void Function ProcessBoundaryStrike(Handle hWnd, Int edge)
If IsReadOnlyVirtualMessage()
    ;Scoping To avoid calling the one in WordFunc:
    Return default::ProcessBoundaryStrike(hWnd, Edge)
EndIf
If c_WordFocus.windowCategory == wCat_document
||(OutlookIsActive() && c_WordFocus.WindowClass == wc_wwg)
    giScheduledDocumentTopAndBottomEdgeAlert =
    ScheduleFunction("DocumentTopAndBottomEdgeAlert", 3)
    Return
EndIf
If GetJCFOption(OPT_TOP_AND_BOTTOM_EDGE_ALERT)
    ProcessBoundaryStrike(hWnd, edge)
EndIf
EndFunction

Void Function DocumentTopAndBottomEdgeAlert()
giScheduledDocumentTopAndBottomEdgeAlert = 0
; If we're reading sentence or paragraph, must special case this:
Var String LastScript = GetScriptAssignedTo(GetCurrentScriptKeyName())
If StringContains(LastScript, "Arrow") ; paragraph reading
    SayParagraph()
    Return
ElIf StringContains(LastScript, "Listbox")
|| StringContains(LastScript, "Sentence") Then ; sentence reading
    SaySentence()
    Return
EndIf
Beep()
If !BrailleIsInputSource()
; If edit callbacks is Off, line navigation already reads this:
&& SupportsEditCallbacks()
    SayLine()
EndIf
EndFunction

Int Function NotifyZoomManyPages()
If getCurrentZoomLevel() == ZOOM_MANY_PAGES
    sayFormattedMessage(OT_ERROR, msgZoomManyPages_l, msgZoomManyPages_s)
    Return True
EndIf
Return False
EndFunction

Script ScriptFileName()
ScriptAndAppNames(msgWordForWindowsAppName)
EndScript

Void Function SayUIARegSetting ()
Var Int val
val=getRegistryEntryDWORD(1, "Software\Freedom Scientific\FSDomSrv", "MSWordNoUIA")
If val
    SayMessage(OT_status, "DOM")
else
    SayMessage(OT_status, "UIA")
EndIf
EndFunction

Script TestSayUIARegSetting()
SayUIARegSetting()
EndScript

Void Function SayActivePaneName()
If !IsWordDocumentActive()
    If c_WordFocus.RealWindowName == wn_applyStyles
        sayMessage(ot_dialog_name, wn_ApplyStyles)
    ElIf c_WordFocus.RealWindowName == wn_Styles
        sayMessage(ot_dialog_name, wn_Styles)
    EndIf
    Return
EndIf
SayActivePane()
EndFunction

Script switchPanes()
EnsureNoUserBufferActive()
sayCurrentScriptKeyLabel()
TypeKey(ksSwitchPanes)
delay(2, True)
SayActivePaneName()
EndScript

Script switchPanesReverse()
EnsureNoUserBufferActive()
sayCurrentScriptKeyLabel()
TypeKey(ksSwitchPanesReverse)
pause()
SayActivePaneName()
EndScript

Script SwitchDocumentView()
SayCurrentScriptKeyLabel()
TypeCurrentScriptKey()
If WindowCategoryIsWordDocument()
    Pause()
    Var String sViewName = GetActiveDocumentViewName()
    SayFormattedMessage(ot_status,
        FormatString(msgDocumentView_l, sViewName),
        FormatString(msgDocumentView_s, sViewName))
EndIf
EndScript

Script ReadWordInContext()
readWordInContext()
EndScript

Void Function WindowMinMaxEvent(Handle hWindow, Int nMinMaxRest, Int nShow)
If c_WordTester.WindowStateToggledByScript
    c_WordTester.WindowStateToggledByScript = False
    If nMinMaxRest==1
        Say(msgWindowStateToggleMaximize, ot_screen_message)
    ElIf nMinMaxRest==2
        Say(msgWindowStateToggleRestore, ot_screen_message)
    EndIf
EndIf
EndFunction

Script ToggleWindowState()
c_WordTester.WindowStateToggledByScript = True
TypeKey(ksToggleWindowState) ; AltF10 in English
EndScript

Script AltF4()
ReleaseEditInterfaces()
;debug add back: wordFunc::AutoFinishEvent()
TypeCurrentScriptKey()
SayCurrentScriptKeyLabel()
EndScript

Script CloseDocumentWindow()
If StringContains(c_WordFocus.WindowClass, wc_wwf)
&& !DialogActive()
&& !StringContains(GetWindowClass(GetParent(GlobalFocusWindow)), cwc_Dlg32770)
    IndicateControlType(wt_MDIClient)
EndIf
PerformScript CloseDocumentWindow()
EndScript

Int Function ChooseHeadingLevelInSelectAHeadingDialog()
;This Function should be called only in the scripts assigned To Alt+Number, For the exception of handling the heading list HJDialog.
If !InHJDialog()
|| c_WordFocus.RealWindowName != cWn16 ; Heading List
 Return False
EndIf
sayCurrentScriptKeyLabel()
TypeCurrentScriptKey()
SayLine()
Return True
EndFunction

Script Alt1()
If ChooseHeadingLevelInSelectAHeadingDialog() Return EndIf
EnsureNoUserBufferActive()
If c_WordFocus.windowCategory== WCAT_MESSAGE
    PerformScript ReadOutlookHeader(1)
    Return
EndIf
sayCurrentScriptKeyLabel()
TypeCurrentScriptKey()
EndScript

Script Alt2()
If ChooseHeadingLevelInSelectAHeadingDialog() Return EndIf
EnsureNoUserBufferActive()
If c_WordFocus.windowCategory== WCAT_MESSAGE
    PerformScript ReadOutlookHeader(2)
    Return
EndIf
sayCurrentScriptKeyLabel()
TypeCurrentScriptKey()
EndScript

Script Alt3()
If ChooseHeadingLevelInSelectAHeadingDialog() Return EndIf
EnsureNoUserBufferActive()
If c_WordFocus.windowCategory== WCAT_MESSAGE
    PerformScript ReadOutlookHeader(3)
    Return
EndIf
sayCurrentScriptKeyLabel()
TypeCurrentScriptKey()
EndScript

Script Alt4()
If ChooseHeadingLevelInSelectAHeadingDialog() Return EndIf
EnsureNoUserBufferActive()
If c_WordFocus.windowCategory== WCAT_MESSAGE
    PerformScript ReadOutlookHeader(4)
    Return
EndIf
sayCurrentScriptKeyLabel()
TypeCurrentScriptKey()
EndScript

Script Alt5()
If ChooseHeadingLevelInSelectAHeadingDialog() Return EndIf
EnsureNoUserBufferActive()
If c_WordFocus.windowCategory== WCAT_MESSAGE
    PerformScript ReadOutlookHeader(5)
    Return
EndIf
sayCurrentScriptKeyLabel()
TypeCurrentScriptKey()
EndScript

Script Alt6()
If ChooseHeadingLevelInSelectAHeadingDialog() Return EndIf
EnsureNoUserBufferActive()
If c_WordFocus.windowCategory== WCAT_MESSAGE
    PerformScript ReadOutlookHeader(6)
    Return
EndIf
sayCurrentScriptKeyLabel()
TypeCurrentScriptKey()
EndScript

Script Alt7()
If ChooseHeadingLevelInSelectAHeadingDialog() Return EndIf
EnsureNoUserBufferActive()
If c_WordFocus.windowCategory== WCAT_MESSAGE
    PerformScript ReadOutlookHeader(7)
    Return
EndIf
sayCurrentScriptKeyLabel()
TypeCurrentScriptKey()
EndScript

Script Alt8()
If ChooseHeadingLevelInSelectAHeadingDialog() Return EndIf
EnsureNoUserBufferActive()
If c_WordFocus.windowCategory== WCAT_MESSAGE
    PerformScript ReadOutlookHeader(8)
    Return
EndIf
sayCurrentScriptKeyLabel()
TypeCurrentScriptKey()
EndScript

Script Alt9()
If ChooseHeadingLevelInSelectAHeadingDialog() Return EndIf
EnsureNoUserBufferActive()
If c_WordFocus.windowCategory== WCAT_MESSAGE
    PerformScript ReadOutlookHeader(9)
    Return
EndIf
sayCurrentScriptKeyLabel()
TypeCurrentScriptKey()
EndScript

Script Alt0()
If ChooseHeadingLevelInSelectAHeadingDialog() Return EndIf
EnsureNoUserBufferActive()
If c_WordFocus.windowCategory== WCAT_MESSAGE
    PerformScript ReadOutlookHeader(10)
    Return
EndIf
sayCurrentScriptKeyLabel()
TypeCurrentScriptKey()
EndScript

Script SayCurrentSchemeName()
Var String sScheme = getCurrentSchemeName()
SayFormattedMessage(ot_user_requested_information,
    FormatString(msgSchemeName_l, sScheme),
    FormatString(msgSchemeName_s, sScheme))
EndScript

Script SelectAScheme()
Var String sPrevScheme = GetCurrentSchemeName()
PerformScript SelectAScheme() ; default
;update global scheme name in appropriate .jsi file.
Var String SchemeName = GetCurrentSchemeName()
If stringCompare(sPrevScheme, SchemeName) == 0
    Return
EndIf
If !SchemeIsDocSpecific() ; scheme same throughout app
    WriteSettingString(section_options, hKey_scheme, SchemeName, FT_CURRENT_JCF)
Else
    WriteSettingString("Doc", hKey_Scheme, SchemeName, FT_JSI, wdUser, getActiveDocumentJSIFileName())
EndIf
EndScript

Void Function ListLists()
Var
    String sList,
    Int index,
    Int nCurrentList
sList = GetListOfLists(LIST_ITEM_SEPARATOR)
If !sList
    SayFormattedMessage(ot_error, msgNoLists1_L)
    Return
EndIf
nCurrentList = GetListIndex()
index = DlgSelectItemInList(sList, msgSelectAListDialogName1_L, False, nCurrentList)
If index
    MoveToListByIndex(index)
EndIf
EndFunction

Script selectAList()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException(True) Then
    Return
EndIf
ListLists()
EndScript

Void Function ListTables()
Var
    String sList,
    Int index,
    Int nCurrentTable
sList = GetListOfTables(LIST_ITEM_SEPARATOR)
If !sList
    SayFormattedMessage(ot_error, msgNoTables1_L, msgNoTables1_l)
    Return
EndIf
nCurrentTable = GetTableIndex()
index = DlgSelectItemInList(sList, msgSelectATableDialogName1_L, False, nCurrentTable)
If index
    MoveToTableByIndex(index)
EndIf
If index != nCurrentTable
    ;The TableEnteredEvent will fire before the FocusChangedEvent,
    ;so set a variable used by FocusChangedEvent To test If this has happened.
    ;Normally, FocusChangedEvent happens before TableEnteredEvent,
    ;and TableEnteredEvent tests For this and does Not process all of the speech in the event.
    c_WordTester.FocusChangedOnSelectATable = True
EndIf
EndFunction

Script selectATable()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException(True) Then
    Return
EndIf
ListTables()
EndScript

Script routeJAWSCursorToPc()
If GetSelectionContext() & SelCtxFields
&& !IsObjectNavigationActive()
    routeJAWSCursorToField()
else
    performScript routeJAWSCursorToPc()
EndIf
EndScript

Script BrailleShowRevisionInfo()
Var
    Int nCell,
    String sRevisionText
;flash Braille message For revision information:
If c_WordFocus.windowCategory == wCat_document
&& isPCCursor()
    sRevisionText = GetSelectionContextRevisionText()
    If sRevisionText
        nCell = GetLastBrailleRoutingKey()
        If BrailleGetStatusCellCount()>0
        && nCell==-1
            BrailleRoutingButton(nCell)
            BrailleMessage(sRevisionText
                +cscSpace+GetRevisionTypeString(GetSelectionContextRevisionType())
                +cscSpace+formatString(msgRevAuthor_s, GetSelectionContextRevisionAuthor())
                +cscSpace+GetSelectionContextRevisionDate())
        else
            BrailleRoutingButton(nCell)
            BrailleRefresh()
        EndIf
        Return
    EndIf
EndIf
performScript BrailleRouting()
EndScript

Script NextCell()
If WindowCategoryIsWordDocument()
&& !IsReadOnlyVirtualMessage()
    If TableErrorEncountered(UnitMove_Next)
        Return
    EndIf
    If !NextCell()
        SayUsingVoice(VCTX_message, cMSGEndOfRow, OT_JAWS_message)
        Return
    EndIf
    SetDocumentTableNavType(TABLE_NAV_HORIZONTAL)
    Return
EndIf
PerformScript NextCell()
EndScript

Script PriorCell()
If WindowCategoryIsWordDocument()
&& !IsReadOnlyVirtualMessage()
    If TableErrorEncountered(UnitMove_Prior)
        Return
    EndIf
    If !PriorCell()
        SayUsingVoice(VCTX_message, cMSGBeginningOfRow, OT_JAWS_message)
        Return
    EndIf
    SetDocumentTableNavType(TABLE_NAV_HORIZONTAL)
    Return
EndIf
PerformScript PriorCell()
EndScript

Script UpCell()
If c_WordFocus.windowCategory == wCat_document
&& !IsReadOnlyVirtualMessage()
    If TableErrorEncountered(UnitMove_Up)
        Return
    EndIf
    If !UpCell()
        SayUsingVoice(VCTX_message, cMSGTopOfColumn, OT_JAWS_message)
        Return
    EndIf
    SetDocumentTableNavType(TABLE_NAV_VERTICAL)
    Return
EndIf
PerformScript UpCell()
EndScript

Script DownCell()
If c_WordFocus.windowCategory == wCat_document
&& !IsReadOnlyVirtualMessage()
    If TableErrorEncountered(UnitMove_Down)
        Return
    EndIf
    If !DownCell()
        SayUsingVoice(VCTX_message, cMSGBottomOfColumn, OT_JAWS_message)
        Return
    EndIf
    SetDocumentTableNavType(TABLE_NAV_VERTICAL)
    Return
EndIf
PerformScript DownCell()
EndScript

Script FirstCellInTable()
If WindowCategoryIsWordDocument()
&& !IsReadOnlyVirtualMessage()
    If !InTable()
    && GetCurrentScriptKeyName() == ks_Word_Browse_Objects
        ;Alt+Control+Home is the Word keystroke To Browse Object.
        ;Make sure that the Const exactly matches the name received by KeyPressedEvent.
        TypeCurrentScriptKey()
        Return
    EndIf
    If TableErrorEncountered(UnitMove_Start)
        Return
    EndIf
    SayUsingVoice(VCTX_message, cmsgBeginningOfTable, OT_JAWS_message)
    SetDocumentTableNavType(TABLE_NAV_TABLE_EXTENTS)
    FirstCell()
    Return
EndIf
PerformScript FirstCellInTable()
EndScript

Script LastCellInTable()
If WindowCategoryIsWordDocument()
&& !IsReadOnlyVirtualMessage()
    If TableErrorEncountered(UnitMove_End)
        Return
    EndIf
    SayUsingVoice(VCTX_message, cmsgEndOfTable, OT_JAWS_message)
    SetDocumentTableNavType(TABLE_NAV_TABLE_EXTENTS)
    LastCell()
    Return
EndIf
PerformScript LastCellInTable()
EndScript

Script MoveToStartOfRow()
If !InTable()
&& GetCurrentScriptKeyName() == ks_Word_MoveToStartOfRow
    ;Allowing Alt+Home To pass through means that
    ;Calendar can navigate To start and end of week when Not in tables
    SayCurrentScriptKeyLabel()
    TypeCurrentScriptKey()
    Return
EndIf
If WindowCategoryIsWordDocument()
&& !IsReadOnlyVirtualMessage()
    If TableErrorEncountered(UnitMove_First)
        Return
    EndIf
    SayUsingVoice(VCTX_message, cmsgStartOfRow, OT_JAWS_message)
    SetDocumentTableNavType(TABLE_NAV_ROW_EXTENTS)
    If !StartOfRow()
        SayUsingVoice(VCTX_message, cMsgStartOfRowFailed, OT_JAWS_message)
    EndIf
    Return
EndIf
PerformScript MoveToStartOfRow()
EndScript

Script MoveToEndOfRow()
If !InTable()
&& GetCurrentScriptKeyName() == ks_Word_MoveToEndOfRow
    ;Allowing Alt+Home To pass through means that
    ;Calendar can navigate To start and end of week when Not in tables
    SayCurrentScriptKeyLabel()
    TypeCurrentScriptKey()
    Return
EndIf
If WindowCategoryIsWordDocument()
&& !IsReadOnlyVirtualMessage()
    If TableErrorEncountered(UnitMove_Last)
        Return
    EndIf
    SayUsingVoice(VCTX_message, cmsgEndOfRow, OT_JAWS_message)
    SetDocumentTableNavType(TABLE_NAV_ROW_EXTENTS)
    If !EndOfRow()
        SayUsingVoice(VCTX_message, cMsgEndOfRowFailed, OT_JAWS_message)
    EndIf
    Return
EndIf
PerformScript MoveToEndOfRow()
EndScript

Script MoveToTopOfColumn()
Var String ScriptKeyName = GetCurrentScriptKeyName()
If (!InTable() || !GetFocus())
&& (ScriptKeyName == ks_Word_MoveToTopOfColumn || ScriptKeyName == ks_Word_MoveToTopOfColumn_Extended)
    ;Allowing Alt+PageUp To pass through means that
    ;Skype calls can be answered when Not in tables
    SayCurrentScriptKeyLabel()
    TypeCurrentScriptKey()
    Return
EndIf
If WindowCategoryIsWordDocument()
&& !IsReadOnlyVirtualMessage()
    If TableErrorEncountered(UnitMove_Top)
        Return
    EndIf
    SayUsingVoice(VCTX_message, cmsgTopOfColumn, OT_JAWS_message)
    SetDocumentTableNavType(TABLE_NAV_COLUMN_EXTENTS)
    If !TopOfColumn()
        SayFormattedMessage(OT_error, cMsgTopOfColumnFailed, cMSGNotInTable_S) ; Could Not move To Top of column
    EndIf
    Return
EndIf
PerformScript MoveToTopOfColumn()
EndScript

Script MoveToBottomOfColumn()
Var String ScriptKeyName = GetCurrentScriptKeyName()
If (!InTable() || !GetFocus())
&& (ScriptKeyName == ks_Word_MoveToBottomOfColumn || ScriptKeyName == ks_Word_MoveToBottomOfColumn_Extended)
    ;Allowing Alt+PageDown To pass through means that
    ;Skype calls can be terminated when Not in tables
    SayCurrentScriptKeyLabel()
    TypeCurrentScriptKey()
    Return
EndIf
If WindowCategoryIsWordDocument()
&& !IsReadOnlyVirtualMessage()
    If TableErrorEncountered(UnitMove_Bottom)
        Return
    EndIf
    SayUsingVoice(VCTX_message, cmsgBottomOfColumn, OT_JAWS_message)
    SetDocumentTableNavType(TABLE_NAV_COLUMN_EXTENTS)
    If !BottomOfColumn()
        SayFormattedMessage(OT_error, cMsgBottomOfColumnFailed, cMSGNotInTable_s) ; Could Not move To Bottom of column
    EndIf
    Return
EndIf
PerformScript MoveToBottomOfColumn()
EndScript

Script SayCell()
If IsVirtualPcCursor()
    PerformScript SayCell()
    Return
EndIf
If !InTable()
    SayMessage(ot_error, cMSGNotInTable_L)
    Return
EndIf
If TestForEndOfCellOrRowMarker(True)
    Return
EndIf
SayCellHeaders(OT_USER_REQUESTED_INFORMATION)
SayCell()
SayCellCoordinatesInfo()
EndScript

Script SayFirstCellInColumn()
EnsureNoUserBufferActive()
If WindowCategoryIsWordDocument()
    If InTable()
        Var String sText = GetColumnText(cscNull, cscNull, msgBlankCell1_l, 1, 1)
        If !IsTableUniform()
        && !sText
            sayMessage(ot_error, msgNonuniformTableFirstCellInColumnError)
        else
            Say(sText, ot_user_requested_information)
        EndIf
    Else
        sayMessage(ot_ERROR, cmsgNotInTable_l, cmsgNotInTable_s)
    EndIf
    Return
EndIf
EndScript

Script SayFirstCellInRow()
EnsureNoUserBufferActive()
If WindowCategoryIsWordDocument()
    If InTable()
        Say(GetRowText(cscNull, cscNull, msgBlankCell1_l, 1, 1), ot_user_requested_information)
    Else
        sayMessage(ot_ERROR, cmsgNotInTable_l, cmsgNotInTable_s)
    EndIf
    Return
EndIf
EndScript

Void Function readTableRow()
say(GetRowText(), ot_line, True)
EndFunction

Script readCurrentRow()
EnsureNoUserBufferActive()
If !inTable()
    SayMessage(ot_error, cMSGNotInTable_L)
    Return
EndIf
readTableRow()
EndScript

Script SayPriorRow()
If IsReadOnlyVirtualMessage()
    PerformScript SayPriorRow()
    Return
EndIf
EnsureNoUserBufferActive()
If !InTable()
    SayMessage(ot_error, cMSGNotInTable_L)
    Return
EndIf
SetDocumentTableNavType(TABLE_NAV_SAY_ROW)
If !UpCell()
    SayFormattedMessage(ot_error, msgFirstRow)
    Return
EndIf
EndScript

Script SayNextRow()
If IsReadOnlyVirtualMessage()
    PerformScript SayNextRow()
    Return
EndIf
EnsureNoUserBufferActive()
If !InTable()
    SayMessage(ot_error, cMSGNotInTable_L)
    Return
EndIf
SetDocumentTableNavType(TABLE_NAV_SAY_ROW)
If !DownCell()
    SayFormattedMessage(ot_error, msgLastRow)
    Return
EndIf
EndScript

Void Function readTableColumn()
say(GetColumnText(), ot_line, True)
EndFunction

Script ReadCurrentColumn()
EnsureNoUserBufferActive()
If !inTable()
    SayMessage(ot_error, cMSGNotInTable_L)
    Return
EndIf
If !IsTableUniform()
    sayMessage(ot_error, msgNonUniformTableColumnError_l, msgNonUniformTableColumnError_s)
    Return
EndIf
readTableColumn()
EndScript

Script SayPriorColumn()
EnsureNoUserBufferActive()
If !InTable()
    SayMessage(ot_error, cMSGNotInTable_L)
    Return
EndIf
SetDocumentTableNavType(TABLE_NAV_SAY_COLUMN)
If !PriorCell()
    SayFormattedMessage(ot_error, msgFirstColumn)
    Return
EndIf
If !IsTableUniform()
    sayMessage(ot_error, msgNonUniformTableColumnError_l, msgNonUniformTableColumnError_s)
    Return
EndIf
EndScript

Script SayNextColumn()
EnsureNoUserBufferActive()
If !InTable()
    SayMessage(ot_error, cMSGNotInTable_L)
    Return
EndIf
SetDocumentTableNavType(TABLE_NAV_SAY_COLUMN)
If !NextCell()
    SayFormattedMessage(ot_error, msgLastColumn)
    Return
EndIf
If !IsTableUniform()
    sayMessage(ot_error, msgNonUniformTableColumnError_l, msgNonUniformTableColumnError_s)
    Return
EndIf
EndScript

Void Function sayColumnHeader()
SayColumnTitle()
EndFunction

Script sayColumnTitle()
EnsureNoUserBufferActive()
If InTable()
    sayColumnTitle()
else
    SayFormattedMessage(ot_error, cMSGNotInTable_L, cMSGNotInTable_S)
EndIf
EndScript

Void Function sayRowHeader()
SayRowTitle()
EndFunction

Script sayRowTitle()
EnsureNoUserBufferActive()
If InTable()
    sayRowTitle()
else
    SayMessage(ot_error, cMSGNotInTable_L, cMSGNotInTable_S)
EndIf
EndScript

String Function GetHeadingSoundFile(Int iLevel)
Var
    String sHeadingKey,
    String sData1
sHeadingKey = IntToString(iLevel+WT_HTML_HEADING1-1)
smmGetBehavior(Section_smm_ControlType, sHeadingKey, sData1)
If StringContains(stringSegment(sData1, cScDoubleBackSlash , -1), FileNameExt_Wav)
    Return sData1
else
    Return cscNull
EndIf
EndFunction

Void Function SayCurrentHeading()
Var
    String sSoundFile,
    String sText,
    Int iLevel
If !inTable()
&& !isFormField()
    sText = GetCurrentHeading()
    If sText
        iLevel = getCurrentHeadingLevel()
        sSoundFile = GetHeadingSoundFile(iLevel)
        If sSoundFile
            PlaySound(sSoundFile)
        else
            sText = FormatString(MsgHeadingLevel, IntToString(iLevel))+cscSpace+sText
        EndIf
        sayMessage(ot_line, sText)
    EndIf
EndIf
EndFunction

Void Function ReportHeadingsNotAvailable(optional Int reason)
Var
    String message_L,
    String message_S
If OutlookIsActive()
    message_L = msgNoOutlookMessageHeadings_l
    message_S = msgNoOutlookMessageHeadings_s
Else
    message_L = msgNoHeadings_l
    message_S = msgNoHeadings_s
EndIf
If (product_MAGic == GetRunningFSProducts())
    ExMessageBox(msgMagNoHeadings_L, SelectAHeadingDialogName, MB_OK)
    Return
EndIf
SayMessage(OT_ERROR, message_L, message_S)
If shouldItemSpeak(OT_Error) == 1
    scheduleBrailleFlashMessageWithSpeechOutput(OT_ERROR, message_L, 8)
else
    scheduleBrailleFlashMessageWithSpeechOutput(OT_ERROR, message_S, 8)
EndIf
EndFunction

Int Function SelectAHeadingDialog()
If !dlgListOfHeadings()
    ReportHeadingsNotAvailable(NotAvailableReason_NotFound)
EndIf
Return True
EndFunction

Script ListHeadings()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException(True)
    Return
EndIf
SelectAHeadingDialog()
EndScript

Script SayField()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
If IsActiveDocumentProtectedForm()
    performScript SayWindowPromptAndText()
ElIf GetSelectionContext() & SelCtxFields
    SayField()
EndIf
EndScript

Script selectAField()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
ListFields()
EndScript

Script SelectNextOrPriorField()
SayCurrentScriptKeyLabel()
TypeCurrentScriptKey()
;The SelectionChangedEvent will speak the New field,
;so the code which previously handled that functionality has been removed.
EndScript

Script listSpellingErrors()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
If !IsCheckSpellingAsYouTypeEnabled()
    SayFormattedMessage(ot_smart_help, msgCheckSpellingDisabled1) ; option To check spelling as you type is disabled
    Return
EndIf
listSpellingErrors()
EndScript

Script listGrammaticalErrors()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
If !IsCheckGrammarAsYouTypeEnabled()
    SayFormattedMessage(ot_smart_help, msgCheckGrammarDisabled1)
    Return
EndIf
listGrammaticalErrors()
EndScript

Script ListBookmarks()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
ListBookmarks()
EndScript

String Function formatAnnotationOutput(String RefText, String text, String author, optional String dateTime)
Var String result = RefText+cscBufferNewLine
result = result + text+cscBufferNewLine
If !stringIsBlank(author)
    result = result + formatString(msgAnnotationAuthor, author) + cscBufferNewLine
EndIf
If !stringIsBlank(DateTime)
    result = result + formatString(msgAnnotationDateTime, DateTime) + cscBufferNewLine
EndIf
Return result
EndFunction

Void Function announceComment(Int iOutputType)
Var
    Int index,
    Int count = GetAnnotationCountAtCaret(),
    String output ,
    String MessageToFormat,
    String Text,
    String Author,
    String refText,
    String Desc,
    String DateTime
If !count && ! GetProofreadingElementInfo(peComment, Text, Author, refText, Desc, DateTime)
    ProcessMessage (msgNoComment1_L, cscNull, ot_error, cscNull, MB_OK|MB_ICONERROR)
    Return
EndIf
count = count-1
For index=0 To count
    GetAnnotationAtCaret(index, refText, Author, Text, DateTime, Desc)
    ;For the output For comments, we want the refText because it distinguishes between comments and replies wheras the type does Not.
    If NotesDetection() >= wdVerbosityHigh
        MessageToFormat = formatAnnotationOutput(refText, Text, Author, DateTime)
    else
        MessageToFormat = formatAnnotationOutput(refText, Text, Author)
    EndIf
    If ! stringIsBlank(MessageToFormat)
        output = output+cscBufferNewLine+MessageToFormat
    EndIf
EndFor
ProcessMessage(output, output, iOutputType, msgCommentMessageBoxTitle, MB_OK|MB_ICONASTERISK)
EndFunction

Script announceComment()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
If isSameScript()
    announceComment(ot_user_buffer)
    UserBufferAddText(cscBufferNewLine+FormatString(msgCommentDocumentText, GetSelectionCommentDocumentText(        )))
    UserBufferAddText(cscBufferNewLine+cmsgBuffExit)
else
    announceComment(ot_user_requested_information)
EndIf
EndScript

Script PostComment()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
Var
    String sText,
    String sAuthor,
    String sInitials,
    String sDesc,
    String sDate
If GetProofreadingElementInfo(peComment, sText, sAuthor, sInitials, sDesc, sDate)
    If NotesDetection() >= wdVerbosityHigh
        exMessageBox(FormatString(msgCommentWithDate_L, sText, sAuthor, sDate),
            msgCommentMessageBoxTitle, MB_OK|MB_ICONASTERISK)
    else
        exMessageBox(FormatString(msgComment1_L, sText, sAuthor),
            msgCommentMessageBoxTitle, MB_OK|MB_ICONASTERISK)
    EndIf
else
    exMessageBox(msgNoComment1_L, cscNull, MB_OK|MB_ICONERROR)
EndIf
EndScript

Script listComments()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
listComments()
EndScript

Void Function announceFootnoteOrEndNote(Int iOutputType)
Var
    String sText,
    String sAuthor,
    String sInitials,
    String sDesc,
    String sDate,
    String sMsg
If GetProofreadingElementInfo(peFootnote, sText, sAuthor, sInitials, sDesc, sDate)
    sMsg = formatString(msgFootnoteReference, sDesc, sText)
    ProcessMessage(sMsg, sMsg, iOutputType, msgFootnote, MB_OK|MB_ICONASTERISK)
ElIf GetProofreadingElementInfo(peEndNote, sText, sAuthor, sInitials, sDesc, sDate)
    sMsg = formatString(msgEndNoteReference, sDesc, SText)
    ProcessMessage(sMsg, sMsg, iOutputType, msgEndnote, MB_OK|MB_ICONASTERISK)
Else
    ProcessMessage(msgNoFootnoteOrEndNote1_L, msgNoFootnoteOrEndNote1_L, ot_error, msgError, MB_OK|MB_ICONERROR)
EndIf
EndFunction

Script announceFootnoteOrEndNote()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
If isSameScript()
    announceFootnoteOrEndNote(ot_user_buffer)
    UserBufferAddText(cscBufferNewLine+cmsgBuffExit)
else
    announceFootnoteOrEndNote(ot_user_requested_information)
EndIf
EndScript

Script ListFootnotes()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
ListFootnotes()
EndScript

Script ListEndnotes()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
ListEndnotes()
EndScript

Int Function GetRevisionInfo(Int iOutputType, String ByRef sRevInfo, String ByRef sRevText)
Var
    String sAuthor,
    String sInitials,
    String sDesc,
    String sDate
sRevInfo = cscNull
If !GetProofreadingElementInfo(peRevision, sRevText, sAuthor, sInitials, sDesc, sDate)
    Return False
EndIf
If sRevText == cscSpace
    sRevText = cmsgSpace1
EndIf
If sDesc != cscNull
    sRevInfo=sDesc
else
    sRevInfo = GetRevisionTypeString(GetSelectionContextRevisionType())
EndIf
sRevInfo = sRevInfo+cscSpace+FormatOutputMessage(iOutputType, False,
    msgRevAuthor_L, msgRevAuthor_s, sAuthor)
sRevInfo = sRevInfo+cscSpace+FormatOutputMessage(iOutputType, False,
    msgRevDate_L, msgRevDate_s, sDate)
Return True
EndFunction

Script AnnounceRevision()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
Var
    String sRevInfo,
    String sRevText,
    Int bJAWSOnly =(getRunningFSProducts() == product_JAWS),
    Int iOutputType
If !IsActiveDocumentTrackChangesEnabled()
    ProcessMessage(msgAnnounceRevisionError_l, msgAnnounceRevisionError_s, ot_error, msgError, MB_OK|MB_ICONERROR)
    Return
EndIf
EnsureNoUserBufferActive()
If bJAWSOnly && isSameScript()
    iOutputType = ot_user_buffer
Else
    iOutputType = ot_user_requested_information
EndIf
If !GetRevisionInfo(iOutputType, sRevInfo, sRevText)
    ProcessMessage(msgNoRevision, null(), ot_error, msgError, MB_OK|MB_ICONERROR)
    Return
EndIf
If iOutputType == ot_user_buffer
    SayFormattedMessage(iOutputType,
        sRevInfo+cscBufferNewLine+sRevText,
        sRevInfo+cscBufferNewLine+sRevText)
    UserBufferAddText(cscBufferNewLine+cmsgBuffExit)
else
    BeginFlashMessage()
    Say(sRevText, iOutputType, True)
    ProcessMessage(sRevInfo, sRevInfo, iOutputType, msgRevision, MB_OK|MB_ICONINFORMATION, vctx_message)
    EndFlashMessage()
EndIf
EndScript

Script postRevision()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
Var
    String sRevInfo,
    String sRevText,
    Int iOutputType
If !IsActiveDocumentTrackChangesEnabled()
    ProcessMessage(msgAnnounceRevisionError_l, msgAnnounceRevisionError_s, ot_error, msgError, MB_OK|MB_ICONERROR)
    Return
EndIf
iOutputType = ot_user_buffer ; so MAGic always gets the text:
If !GetRevisionInfo(iOutputType, sRevInfo, sRevText)
    ProcessMessage(msgNoRevision, null(), ot_error, msgError, MB_OK|MB_ICONERROR)
    Return
EndIf
ProcessMessage(sRevInfo+cscBufferNewLine+sRevText, sRevInfo+cscBufferNewLine+sRevText, ot_user_requested_information, msgRevision, MB_OK|MB_ICONINFORMATION, vctx_message)
EndScript

Script listRevisions()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
If !IsActiveDocumentTrackChangesEnabled()
    SayFormattedMessage(ot_error, msgTrackChangesNotEnabled1)
    Return
EndIf
listRevisions()
EndScript

Script RevisionDetectionToggle()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
Var Int iStatus = ShowRevisionsView()
If !iStatus
    If RevisionDetection() > 0
        setRevisionsManually(Off)
        sayMessage(ot_status, msgRevisionDetectionOff_l, msgRevisionDetectionOff_s)
    else
        sayMessage(ot_error, msgRevisionDetectionAlreadyOff)
    EndIf
else
    If !RevisionDetection() Then ; Return To default revision detection setting.
        setRevisionsManually(On)
        sayMessage(ot_status, msgRevisionDetectionDefault_l, msgRevisionDetectionDefault_s)
    else ;Revision detection is already On.
        sayMessage(ot_error, formatString(msgRevisionDetectionAlreadyOn, toggleRevisionDetection(True)))
    EndIf
EndIf
EndScript

Script ToggleTrackChanges()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
SayCurrentScriptKeyLabel()
TypeKey(ksToggleTrackChanges)
Pause()
If IsActiveDocumentTrackChangesEnabled()
    SayMessage(ot_help, msgTrackChangesOn_l, msgTrackChangesOn_S)
else
    SayMessage(ot_help, msgTrackChangesOff_l, msgTrackChangesOff_S)
EndIf
Refresh() ; Force FSDomNodeMSWord.dll To be reloaded so that the track changes state change is detected without a focus change.
EndScript

Script listObjects()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
listObjects()
EndScript

Void Function SayFontSize()
SayFormattedMessageWithVoice(vctx_message, ot_status, GetFontSizeString(), GetFontSizeString())
EndFunction

Script GrowFont1Point()
If QuickNavKeyTrapping()
    Return
EndIf
TypeKey(ksGrowFont1Point) ; ControlRightBracket in English
SayFontSize()
EndScript

Script ShrinkFont1Point()
If QuickNavKeyTrapping()
    Return
EndIf
TypeKey(ksShrinkFont1Point) ; ControlLeftBracket in English
SayFontSize()
EndScript

Script GrowFont()
If QuickNavKeyTrapping()
    Return
EndIf
TypeKey(ksGrowFont) ; ControlShiftPeriod in English
SayFontSize()
EndScript

Script ShrinkFont()
If QuickNavKeyTrapping()
    Return
EndIf
TypeKey(ksShrinkFont) ; ControlShiftComma in English
SayFontSize()
EndScript

Script sayFont()
sayFont()
EndScript

Script describeBorderOfTextUnit()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
describeBorderOfTextUnit()
EndScript

Script sayLineAndColumn()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
SayLineAndColumn()
EndScript

Script InsertComment()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
Var
    Int index,
    String sAuthor,
    String sInitials
TypeKey(GetScriptKeyName("InsertComment"))
GetCommentInfo(index, sAuthor, sInitials)
If sAuthor!=cscNull
    SayUsingVoice(vctx_message,
        FormatString(msgInsertingComment, IntToString(index), sAuthor, sInitials),
        ot_help)
EndIf
EndScript

Script toggleBetweenAllAndHeadingsOnly()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
If isOutlineViewActive()
    TypeKey(ksToggleBetweenAllAndHeadingsOnly) ; AltShiftA in English
    pause()
    Var String sLevel = GetVisibleHeadingLevelString()
    If sLevel
        SayUsingVoice(vctx_message,
            FormatString(msgHeadingsOnly1_L, sLevel),
            ot_status)
    EndIf
Else
    ; Not in outline view.
    SayFormattedMessageWithVoice(vctx_message, ot_error, msgNotINOutlineView, msgNotInOutlineView)
EndIf
EndScript

Script showHeading1()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
If isOutlineViewActive()
    TypeKey(ksShowHeading1) ; AltShift1 in English)
    pause()
    SayFormattedMessageWithVoice(vctx_message, ot_status,
        GetOutlineViewStatusMessage(ot_status))
Else
    SayFormattedMessageWithVoice(vctx_message, ot_error,
        msgNotINOutlineView, msgNotInOutlineView)
EndIf
EndScript

Script showHeading2()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
If isOutlineViewActive()
    TypeKey(ksShowHeading2) ; AltShift2 in English)
    pause()
    SayFormattedMessageWithVoice(vctx_message, ot_status,
        GetOutlineViewStatusMessage(ot_status))
Else
    SayFormattedMessageWithVoice(vctx_message, ot_error,
        msgNotINOutlineView, msgNotInOutlineView)
EndIf
EndScript

Script showHeading3()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException(True)
    Return
EndIf
If isOutlineViewActive()
    TypeKey(ksShowHeading3) ; AltShift3 in English)
    pause()
    SayFormattedMessageWithVoice(vctx_message, ot_status,
        GetOutlineViewStatusMessage(ot_status))
Else
    SayFormattedMessageWithVoice(vctx_message, ot_error,
        msgNotINOutlineView, msgNotInOutlineView)
EndIf
EndScript

Script showHeading4()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException(True)
    Return
EndIf
If isOutlineViewActive()
    TypeKey(ksShowHeading4) ; AltShift4 in English)
    pause()
    SayFormattedMessageWithVoice(vctx_message, ot_status,
        GetOutlineViewStatusMessage(ot_status))
Else
    SayFormattedMessageWithVoice(vctx_message, ot_error,
        msgNotINOutlineView, msgNotInOutlineView)
EndIf
EndScript

Script showHeading5()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
If isOutlineViewActive()
    TypeKey(ksShowHeading5) ; AltShift5 in English)
    pause()
    SayFormattedMessageWithVoice(vctx_message, ot_status,
        GetOutlineViewStatusMessage(ot_status))
Else
    SayFormattedMessageWithVoice(vctx_message, ot_error,
        msgNotINOutlineView, msgNotInOutlineView)
EndIf
EndScript

Script showHeading6()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
If isOutlineViewActive()
    TypeKey(ksShowHeading6) ; AltShift6 in English)
    pause()
    SayFormattedMessageWithVoice(vctx_message, ot_status,
        GetOutlineViewStatusMessage(ot_status))
Else
    SayFormattedMessageWithVoice(vctx_message, ot_error,
        msgNotINOutlineView, msgNotInOutlineView)
EndIf
EndScript

Script showHeading7()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
If isOutlineViewActive()
    TypeKey(ksShowHeading7) ; AltShift7 in English)
    pause()
    SayFormattedMessageWithVoice(vctx_message, ot_status,
        GetOutlineViewStatusMessage(ot_status))
Else
    SayFormattedMessageWithVoice(vctx_message, ot_error,
        msgNotINOutlineView, msgNotInOutlineView)
EndIf
EndScript

Script showHeading8()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
If isOutlineViewActive()
    TypeKey(ksShowHeading8) ; AltShift8 in English)
    pause()
    SayFormattedMessageWithVoice(vctx_message, ot_status,
        GetOutlineViewStatusMessage(ot_status))
Else
    SayFormattedMessageWithVoice(vctx_message, ot_error,
        msgNotINOutlineView, msgNotInOutlineView)
EndIf
EndScript

Script showHeading9()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
If isOutlineViewActive()
    TypeKey(ksShowHeading9) ; AltShift9 in English)
    pause()
    SayFormattedMessageWithVoice(vctx_message, ot_status,
        GetOutlineViewStatusMessage(ot_status))
Else
    SayFormattedMessageWithVoice(vctx_message, ot_error,
        msgNotINOutlineView, msgNotInOutlineView)
EndIf
EndScript

Script selectNextHeadingOrListLevelStyle()
If !isPcCursor()
    performScript mouseRight()
    Return
EndIf
If QuickNavKeyTrapping()
    Return
EndIf
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
TypeKey(ksSelectNextHeadingOrListLevelStyle) ; AltShiftRightArrow in English
pause()
sayStyleAtCursor()
EndScript

Script selectPriorHeadingOrListLevelStyle()
If !isPcCursor()
    performScript mouseLeft()
    Return
EndIf
If QuickNavKeyTrapping()
    Return
EndIf
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
TypeKey(ksSelectPriorHeadingOrListLevelStyle) ; AltShiftLeftArrow in English
pause()
sayStyleAtCursor()
EndScript

Script MoveItemDown()
If !isPcCursor()
    performScript mouseDown()
    Return
EndIf
If QuickNavKeyTrapping()
    Return
EndIf
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
TypeKey(ksMoveHeadingDown) ; AltShiftDownArrow in English
pause()
sayFormattedMessageWithVoice(VCTX_message, ot_status,
    msgMoveItemDown_L, msgMoveItemDown_S)
EndScript

Script MoveItemUp()
If !isPcCursor()
    performScript mouseUp()
    Return
EndIf
If QuickNavKeyTrapping()
    Return
EndIf
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
TypeKey(ksMoveHeadingUp) ; AltShiftUpArrow in English
pause()
sayFormattedMessageWithVoice(VCTX_message, ot_status,
    msgMoveItemUp_L, msgMoveItemUp_S)
EndScript

Void Function sayHorizontalPosition()
If WindowCategoryIsWordDocument()
&& isPcCursor()
    Var String sCursorHorizPos = GetCursorColString(GetActiveCursor(), getDesiredUnitsOfMeasure())
    SayFormattedMessageWithVoice(vctx_message, ot_status,
        formatString(msgFromLeft1_L, sCursorHorizPos),
        formatString(msgFromLeft1_S, sCursorHorizPos))
EndIf
EndFunction

Script indent()
If QuickNavKeyTrapping()
    Return
EndIf
TypeKey(ksIndent) ; CtrlM in English
If isPCCursor()
&& !UserBufferIsActive()
&& WindowCategoryIsWordDocument()
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgIndent1_L, msgIndent1_S)
    delay(1)
    sayHorizontalPosition()
EndIf
EndScript

Script outdent()
If !WindowCategoryIsWordDocument()
|| IsReadOnlyMessage()
    SayCurrentScriptKeyLabel()
    typeCurrentScriptKey()
    Return
ElIf QuickNavKeyTrapping()
    Return
EndIf
typeCurrentScriptKey()
If IsPCCursor()
&& !UserBufferIsActive()
&& WindowCategoryIsWordDocument()
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgOutDent1_L, msgOutdent1_S)
    delay(1)
    sayHorizontalPosition()
EndIf
EndScript

Void Function sayHangingIndent()
If WindowCategoryIsWordDocument()
&& isPcCursor()
    Var String sIndent = GetCursorPosString(GetActiveCursor(), smmGetDesiredUnitsOfMeasure())
    SayFormattedMessageWithVoice(vctx_message, ot_status, formatString(msgFromLeft1_L, sIndent), formatString(msgFromLeft1_S, sIndent))
EndIf
EndFunction

Script hangingIndent()
If QuickNavKeyTrapping()
    Return
EndIf
TypeKey(ksHangingIndent)
If isPCCursor()
&& !UserBufferIsActive()
&& WindowCategoryIsWordDocument()
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgHangingIndent1_L, msgHangingIndent1_S)
    delay(1)
    sayHorizontalPosition()
EndIf
EndScript

Script removeHangingIndent()
If QuickNavKeyTrapping()
    Return
EndIf
TypeKey(ksRemoveHangingIndent)
If isPCCursor()
&& !UserBufferIsActive()
&& WindowCategoryIsWordDocument()
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgRemoveHangingIndent1_L, msgRemoveHangingIndent1_S)
    delay(1)
    sayHorizontalPosition()
EndIf
EndScript

Int Function isFormatForFindAndReplaceDlg(String sFormatOff, String sFormatOn, String sMsgOff, String sMsgOn)
If DialogActive()
&& globalRealWindowName==wn_FindAndReplace
    Var String sObjName
    SaveCursor()
    InvisibleCursor()
    If FindString(GetCurrentWindow(), sc_Format, s_top, s_unrestricted)
        NextChunk()
        sObjName=GetObjectName()
        If stringContains(sObjName, sFormatOff)
            SayFormattedMessageWithVoice(vctx_message, ot_status, sMsgOff, cMsgSilent)
        ElIf StringContains(sObjName, sFormatOn)
            SayFormattedMessageWithVoice(vctx_message, ot_status, sMsgOn, cMsgSilent)
        EndIf
        RestoreCursor()
        Return True
    EndIf
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgNotFormatted, cMsgSilent)
    RestoreCursor()
    Return True
EndIf
Return False
EndFunction

Int Function IsNotificationPossible()
Return IsWindows10()
    && GetJCFOption(OPT_ENABLE_ACCESSIBLE_NOTIFICATION_EVENTS)
EndFunction

Script BoldText()
If QuickNavKeyTrapping()
    Return
EndIf
If IsDocumentAreaScriptException()
    Return
EndIf
TypeKey(ksBold) ; Ctrl+b in English
If !getRunningFSProducts() & product_JAWS
    Return sayCurrentScriptKeyLabel()
EndIf
If IsNotificationPossible()
&& !OutlookIsActive()
    Return
EndIf
pause()
If IsFormatForFindAndReplaceDlg(sc_NotBold, sc_bold, msgBoldOff1_l, msgBoldOn1_l)
    Return
EndIf
If fontIsBold()
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgBoldOn1_L, cmsgOn)
else
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgBoldOff1_L, cmsgOff)
EndIf
If !isSelectionModeActive()
&& IsExtendedSelectionModeWatchActive()
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgSelectionModeOff1_L, msgSelectionModeOff1_L)
    StopExtendedSelectionModeWatch()
EndIf
EndScript

Script ItalicText()
If QuickNavKeyTrapping()
    Return
EndIf
If IsDocumentAreaScriptException()
    Return
EndIf
TypeKey(ksItalic) ; Ctrl+i in English
If ! getRunningFSProducts() & product_JAWS
    Return sayCurrentScriptKeyLabel()
EndIf
If IsNotificationPossible()
&& !OutlookIsActive()
    Return
EndIf
pause()
If IsFormatForFindAndReplaceDlg(sc_NotItalic, sc_italic, msgItalicOff1_l, msgItalicOn1_l)
    Return
EndIf
If fontIsItalic()
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgItalicOn1_L, cmsgOn)
else
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgItalicOff1_L, cmsgOff)
EndIf
If !isSelectionModeActive()
&& IsExtendedSelectionModeWatchActive()
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgSelectionModeOff1_L, msgSelectionModeOff1_L)
    StopExtendedSelectionModeWatch()
EndIf
EndScript

Script UnderlineText()
If QuickNavKeyTrapping()
    Return
EndIf
If IsDocumentAreaScriptException()
    Return
EndIf
TypeKey(ksUnderline) ; Ctrl+u in English
If ! getRunningFSProducts() & product_JAWS
    Return sayCurrentScriptKeyLabel()
EndIf
If IsNotificationPossible()
&& !OutlookIsActive()
    Return
EndIf
pause()
If IsFormatForFindAndReplaceDlg(sc_NoUnderline, sc_underline, msgUnderlineOff1_l, msgUnderlineOn1_l)
    Return
EndIf
If fontIsUnderlined()
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgUnderlineOn1_L, cmsgOn)
else
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgUnderlineOff1_L, cmsgOff)
EndIf
If !isSelectionModeActive()
&& IsExtendedSelectionModeWatchActive()
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgSelectionModeOff1_L, msgSelectionModeOff1_L)
    StopExtendedSelectionModeWatch()
EndIf
EndScript

Script LeftJustify()
If QuickNavKeyTrapping()
    Return
EndIf
If IsDocumentAreaScriptException()
    Return
EndIf
TypeCurrentScriptKey() ; Ctrll in English
If ! getRunningFSProducts() & product_JAWS
    Return sayCurrentScriptKeyLabel()
EndIf
Pause()
BrailleRefresh()
SayParagraphAlignment(vctx_message, ot_status)
EndScript

Script CenterText()
If QuickNavKeyTrapping()
    Return
EndIf
If IsDocumentAreaScriptException()
    Return
EndIf
TypeCurrentScriptKey() ; CtrlE in English.
If ! getRunningFSProducts() & product_JAWS
    Return sayCurrentScriptKeyLabel()
EndIf
Pause()
BrailleRefresh()
SayParagraphAlignment(vctx_message, ot_status)
EndScript

Script RightJustify()
If IsReadOnlyVirtualMessage()
    ;This block should theoretically never be executed, since Script ReplyOrRightJustify in Outlook should have pre-empted it.
    If ksRightJustify == ksReply
        TypeKey(ksReply) ; CtrlR in English
    EndIf
    Return
ElIf QuickNavKeyTrapping()
|| UserBufferIsActive()
    Return
EndIf
If IsDocumentAreaScriptException()
    Return
EndIf
TypeCurrentScriptKey() ; CtrlR in English
If ! getRunningFSProducts() & product_JAWS
    Return sayCurrentScriptKeyLabel()
EndIf
Pause()
BrailleRefresh()
SayParagraphAlignment(vctx_message, ot_status)
EndScript

Script JustifyText()
If QuickNavKeyTrapping()
    Return
EndIf
If IsDocumentAreaScriptException()
    Return
EndIf
TypeCurrentScriptKey() ; CtrlJ in English
If ! getRunningFSProducts() & product_JAWS
    Return sayCurrentScriptKeyLabel()
EndIf
Pause()
BrailleRefresh()
SayParagraphAlignment(vctx_message, ot_status)
EndScript

Script convertShapesToInline()
If QuickNavKeyTrapping()
    Return
EndIf
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
convertShapesToInline()
EndScript

Script GoBack()
If c_WordFocus.windowCategory == wCat_document
&& HasNavigatedForwardInCurrentDocument()
    TrackLinkNavigation(MOVE_BACK)
    TypeKey(ksGoBack)
    SayFormattedMessageWithVoice(vctx_message, ot_help, msgReturnToTOC_l, msgReturnToTOC_s)
    If BrailleInUse()
        BrailleClearMessage()
    EndIf
    SayLine()
    Return
EndIf
SayCurrentScriptKeyLabel()
TypeKey(ksGoBack)
EndScript

Script GoForward()
If c_WordFocus.windowCategory == wCat_document
&& HasNavigatedForwardInCurrentDocument()
&& IsHyperlinkField()
    ;Enter must have been used at least once in a document
    ;To navigate forward before the Alt+Right is allowed To move forward:
    TrackLinkNavigation(MOVE_FORWARD)
    TypeKey(ksGoForward)
    SayFormattedMessageWithVoice(vctx_message, ot_help, msgForwardFromTOC_l, msgForwardFromTOC_s)
    If BrailleInUse()
        BrailleClearMessage()
    EndIf
    SayLine()
    Return
EndIf
SayCurrentScriptKeyLabel()
TypeKey(ksGoForward)
EndScript

Void Function ReportLinksNotAvailable(optional Int reason)
If product_MAGic == GetRunningFSProducts()
    ExMessageBox(cmsgMagNoLinks_L, SelectALinkDialogName, MB_OK)
    Return
EndIf
sayFormattedMessage(ot_error, cmsgNoLinks + cscSpace + msgCheckForLinkFields)
scheduleBrailleFlashMessageWithSpeechOutput(ot_error, cmsgNoLinks + cscSpace + msgCheckForLinkFields, 8, True)
EndFunction

Int Function SelectALinkDialog()
If UserBufferIsActive()
    default::SelectALinkDialog() ; default behaviors in userBuffer.
    Return True
EndIf
If InHJDialog()
    SayFormattedMessage(OT_error, cMSG337_L, cMSG337_S)
    Return True
EndIf
If !(DialogActive() || GetMenuMode())
&& c_WordFocus.WindowClass == wc_WordMainDocumentWindow
    If !dlgListOfLinks()
        ReportLinksNotAvailable(NotAvailableReason_NotFound)
    EndIf
    Return True
EndIf
Return False
EndFunction

Void Function ReadSpellCheckInfo(optional Int bAcknowledgeSuggestions)
Var
    Object oWindow,
    Object oItem,
    String sItemPrompt,
    String sItemText,
    String sListName,
    String sListValue,
    Int bSpellText,
    Handle hFocus = getFocus(),
    Handle hReal = getRealWindow(hFocus),
    String sBrlMSG,
    Int savedUseSDMOption
;obtained using iAccessible methods:
oWindow = GetUIAObjectTree(hReal)
If !oWindow Return EndIf
oItem = oWindow.FindByRole(ROLE_SYSTEM_TEXT)
sItemPrompt = oItem.name
sItemText = oItem.Value
bSpellText = True
sayMessage(OT_CONTROL_NAME, sItemPrompt)
sayMessage(OT_DIALOG_TEXT, sItemText)
If bSpellText
    spellString(sItemText)
EndIf
sBrlMSG = sItemPrompt + cscSpace + sItemText
;now For the suggestions list:
;Neither UIA nor iAccessible interface reliably gets grammatical error suggestions,
;so we will Use SDM To get the suggestion:
savedUseSDMOption = GetJCFOption(OPT_USE_SDM_API)
SetJCFOption(OPT_USE_SDM_API, 1)
sListName = SDMGetControlName(hReal, cID_O365_SuggestionListPrompt )
sListValue = SDMGetControlActiveItem(hReal, cID_O365_SpellingSuggestionsList)
If !sListValue
    sListValue = SDMGetControlActiveItem(getRealWindow(GetFocus()), cID_O365_GrammarSuggestionsList)
EndIf
SetJCFOption(OPT_USE_SDM_API, savedUseSDMOption)
If stringIsBlank(sListValue)
|| sListValue == noSelectedItem
    ;SDM failed To get suggestions, try UIA
    Var
        Object oUIA = CreateObjectEx("FreedomSci.UIA", 0, "UIAScriptAPI.x.manifest" ),
        Object treewalker = CreateUIARawViewTreeWalker(True),
        Object oListTypeCondition = oUIA.createIntPropertyCondition(UIA_ControlTypePropertyId, UIA_ListControlTypeId),
        Object oSuggestionList,
        Object oValuePattern
    If !treewalker
    || !oListTypeCondition
        Return
    EndIf
    treeWalker.currentElement = FSUIAGetFocusedElement()
    While treewalker.currentElement.controlType != UIA_WindowControlTypeId
    && UIAGetParent (treewalker.currentElement)
        treewalker.gotoParent()
    EndWhile
    oSuggestionList = treewalker.currentElement.findFirst(TreeScope_Descendants, oListTypeCondition)
    oValuePattern = oSuggestionList.getValuePattern()
    sListValue = oValuePattern.value
EndIf
If stringIsBlank(sListValue)
    ;UIA also failed To get suggestions
 If bAcknowledgeSuggestions
        SayMessage(ot_error, msgSuggestionsListNotAvailable_L, msgSuggestionsListNotAvailable_S)
    else
        SayMessage(ot_error, msgNoSpellingSuggestions1_L, msgNoSuggestions1_L)
    EndIf
    sBrlMSG = sBrlMSG + msgNoSuggestions1_L
    BrailleMessage(sBrlMSG)
    Return
EndIf
If stringContains(sListValue, scNoSelectedItem)
    sListValue = msgNoSpellingSuggestions1_L
    bSpellText = Off
EndIf
indicateControlType(wt_ListBox, sListName, sListValue)
If bSpellText
    spellString(sListValue)
EndIf
sBrlMSG = sBrlMSG + cscSpace + sListName + cscSpace + sListValue
BrailleMessage(sBrlMSG)
EndFunction

Void Function ReadSpellCheckInfoUIA(optional Int bAcknowledgeSuggestions)
; uses older AccessibleTreeBuilder To manage Word 2013 and versions of Word 2016 without suggestions as split buttons.
Var
    Int bGrammarError,
    Int bContainsSuggestion,
    Int bFocusInSuggestionList, ; For user tabs To suggestion list and press insert+f7
    Object oFocus = GetUIAObjectFocusItem(),
    Object oParent = oFocus.parent,
    Object oSuggestionList = oParent.FindByRole(ROLE_SYSTEM_LIST),
    Object oGrammarSuggestion,
    Int bSpellText,
    String sText,
    String sPrompt,
    String sSuggestion,
    String sExtraGrammarInfo,
    String sBrlMSG,
    String sTmp
If ReadProofingPaneWithSplitButtons() Return EndIf
If oFocus.Role == ROLE_SYSTEM_LISTITEM
    oSuggestionList = oFocus.parent
    oParent = oSuggestionList.parent
    bFocusInSuggestionList = True
EndIf
If !bFocusInSuggestionList&& ! oSuggestionList.FindByState(STATE_SYSTEM_SELECTED)
    bGrammarError = True
else
    If bFocusInSuggestionList
        sSuggestion = oFocus.name
    else
        sSuggestion = oSuggestionList.FindByState(STATE_SYSTEM_SELECTED).name
    EndIf
EndIf
oGrammarSuggestion = oSuggestionList.NextSibling
While oGrammarSuggestion && oGrammarSuggestion.role != ROLE_SYSTEM_STATICTEXT
    ; For those cases where buttons appear before the grammar label
    oGrammarSuggestion = oGrammarSuggestion.NextSibling
EndWhile
sTmp = oGrammarSuggestion.name
;Pick up the extra grammar text,
;e.g. explanation of grammar rules:
oGrammarSuggestion = oGrammarSuggestion.NextSibling
While oGrammarSuggestion && oGrammarSuggestion.role == ROLE_SYSTEM_STATICTEXT
    sTmp = oGrammarSuggestion.name
    If !stringIsBlank(sExtraGrammarInfo)
    && !stringIsBlank(sTmp)
        sExtraGrammarInfo = sExtraGrammarInfo + cscSpace
    EndIf
    sExtraGrammarInfo = sExtraGrammarInfo + sTmp
    oGrammarSuggestion = oGrammarSuggestion.NextSibling
EndWhile
sPrompt = oParent.name
sText = oParent.FirstChild.Name
sBrlMSG = sBrlMSG + sPrompt
bContainsSuggestion = ! stringIsBlank(sSuggestion)
If bGrammarError
    If bContainsSuggestion
        sPrompt = msgSuggestion
        sayMessage(OT_CONTROL_NAME, sPrompt)
        sBrlMSG = sBrlMSG + cscSpace + sPrompt
    else
        sayMessage(OT_CONTROL_NAME, sSuggestion)
        sayMessage(OT_LINE, sText)
        spellString(sText)
        sBrlMSG = sBrlMSG + cscSpace + sText
    EndIf
    If !bContainsSuggestion
        If bAcknowledgeSuggestions
            sayMessage(OT_ERROR, msgNoSpellingSuggestions1_L)
        EndIf
        sBrlMSG = sBrlMSG + cscSpace + msgNoSpellingSuggestions1_L
    else
        sayMessage(OT_CONTROL_NAME, sSuggestion)
        sayMessage(OT_LINE, sText)
        spellString(sText)
        sBrlMSG = sBrlMSG + cscSpace + sText
    EndIf
else
    sayMessage(OT_CONTROL_NAME, sPrompt)
    sBrlMSG = sPrompt
    sayMessage(OT_LINE, sText)
    spellString(sText)
    sBrlMSG = sBrlMSG + cscSpace + sText
    sPrompt = msgSuggestion
    If stringIsBlank(sSuggestion)
        If bAcknowledgeSuggestions
            sayMessage(OT_ERROR, msgNoSpellingSuggestions1_L)
        EndIf
        sBrlMSG = sBrlMSG + cscSpace + msgNoSpellingSuggestions1_L
    else
        sayMessage(OT_CONTROL_NAME, sPrompt)
        sBrlMSG = sBrlMSG + cscSpace + sPrompt
        sayMessage(OT_LINE, sSuggestion)
        spellString(sSuggestion)
        sBrlMSG = sBrlMSG + cscSpace + sSuggestion
    EndIf
EndIf
If !stringIsBlank(sExtraGrammarInfo)
    If getRunningFSProducts() & PRODUCT_MAGic
        ; do Not virtualize, causes crashes:
        sayMessage(OT_HELP, sExtraGrammarInfo)
        sBrlMSG = sBrlMSG + cscSpace + sExtraGrammarInfo
    else
        sayMessage(OT_HELP, msgReasonTextAvailable)
        sBrlMSG = sBrlMSG + cscSpace + msgReasonTextAvailable
        UserBufferClear()
        UserBufferDeactivate()
        UserBufferAddText(sExtraGrammarInfo+cscBufferNewLine+cMsgBuffExit)
        UserBufferActivate()
        If UserBufferIsActive()
            JAWSTopOfFile()
            SayLine()
        EndIf
    EndIf
EndIf
If !stringIsBlank(sBrlMSG)
    BrailleMessage(sBrlMSG)
EndIf
EndFunction

Int Function ReadMicrosoftEditorSuggestion(optional Object oElement)
If !c_WordFocus.InMicrosoftEditorProofingPaneIssueChecker Return False EndIf
Var
    Int iIndicateTypeAndPosition = False,
    Int iIndicateSuggestion = True
If !oElement
    oElement = FSUIAGetFocusedElement ()
    iIndicateTypeAndPosition = True
    iIndicateSuggestion = False
EndIf
If oElement.controlType != UIA_SplitButtonControlTypeId
|| !StringStartsWith (oElement.AutomationID, "SplitButton_", True)
    Return False
EndIf
Var
    Object oPane = FSUIAGetAncestorOfControlType (oElement, UIA_PaneControlTypeID),
    Object oIssueTypeCondition = FSUIACreateStringPropertyCondition (UIA_AutomationIDPropertyID, "DrillInPane_Title"),
    String sIssueType = oPane.findFirst(TreeScope_Children, oIssueTypeCondition).name,
    String sText
If StringIsBlank (sIssueType) Return False EndIf
If iIndicateSuggestion
    Say(msgSuggestion, OT_LINE)
EndIf
If sIssueType == wn_Proofing_Pane_Spelling
    Var String sSuggestion = StringSegment (oElement.name, ", ", 1)
    sText = StringSegmentRemove(oElement.name, ", ", 1)
    sText = StringSegmentRemove(sText, ", ", 1)
    Say (sSuggestion, OT_LINE)
    SpellString (sSuggestion)
else
    sText = oElement.name
EndIf
If iIndicateTypeAndPosition
    IndicateControlType (WT_SPLITBUTTON, sText)
    Say(PositionInGroup (), OT_POSITION)
else
    Say(sText, OT_LINE)
EndIf
Return True
EndFunction

Int Function ReadMicrosoftEditorIssueCheckerInfo(optional Int bAcknowledgeSuggestions, Int includeContainerName)
If !c_WordFocus.InMicrosoftEditorProofingPaneIssueChecker Return False EndIf
Var Object oPane = FSUIAGetParentOfElement (FSUIAGetFocusedElement ())
If oPane.controlType != UIA_PaneControlTypeId
    ;Some focusable elements in the issue checker are children of a pane.
    ;Others are grandchildren.
    ;Move up one more time and Then check again.
    oPane = FSUIAGetParentOfElement (oPane)
EndIf
If oPane.controlType != UIA_PaneControlTypeId
    ;Not in O365 spell check
    Return False
EndIf
Var
    Object oGroupCondition = FSUIACreateIntPropertyCondition (UIA_ControlTypePropertyID, UIA_GroupControlTypeID),
    Object oIssueTypeCondition = FSUIACreateStringPropertyCondition (UIA_AutomationIDPropertyID, "DrillInPane_Title"),
    Object oGroup = oPane.findFirst(TreeScope_Children, oGroupCondition),
    Object oElement = FSUIAGetFirstChildOfElement (oGroup),
    String sIssueType = oPane.findFirst(TreeScope_Children, oIssueTypeCondition).name
If StringIsBlank(sIssueType) Return False EndIf
If includeContainerName
    Say (oGroup.name, OT_LINE)
EndIf
If sIssueType == wn_Proofing_Pane_Spelling
    Var String sMisspelled = StringTrimLeadingBlanks (StringSegment (oElement.name, ", ", 2))
    Say (sMisspelled, OT_LINE)
    SpellString (sMisspelled)
    oElement = FSUIAGetFirstChildOfElement (oElement)
    Say (oElement.name, OT_LINE);word in context
else
    ;Grammatical error or other refinement
    Say (oElement.name, OT_LINE)
EndIf
If bAcknowledgeSuggestions
    Delay (5, False)
    Var Object oSuggestionsCondition = FSUIACreateStringPropertyCondition (UIA_AutomationIDPropertyID, "SplitButton_", PropertyConditionFlags_MatchSubstring)
    oSuggestionSplitButton = oPane.findFirst(TreeScope_Descendants, oSuggestionsCondition)
    If GetObjectTypeCode() == WT_STATIC
        ;Focus is On the text element containing the misspelled word.
        ;Read the first suggestion, as enter has been scripted To invoke it.
        If !ReadMicrosoftEditorSuggestion(oSuggestionSplitButton)
            Say(msgNoSuggestions1_L, OT_ERROR)
        EndIf
    else
        ;Focus is Not On the text element containing the misspelled word.
        ;Just announce the number of suggestions.
        If oSuggestionSplitButton.sizeOfSet
            SayFormattedMessage (OT_LINE, msgSuggestions, msgSuggestions, oSuggestionSplitButton.sizeOfSet)
        else
            Say(msgNoSuggestions1_L, OT_ERROR)
        EndIf
        EndIf
EndIf
Return True
EndFunction

Script ReadMistakeAndSuggestion()
If SelectALinkDialog()
    Return
EndIf
If ReadMicrosoftEditorIssueCheckerInfo(True, True)
    Return
EndIf
If c_WordFocus.windowCategory== WCAT_TASK_PANE
    If c_WordFocus.InProofingPaneSpellCheck
    || c_WordFocus.OutlookIsActive
        ReadSpellCheckInfoUIA(True)
        Return
    EndIf
    sayMessage(ot_error, msgTaskPaneLinkError_l, msgTaskpaneLinkError_s)
    Return
ElIf c_WordFocus.InProofingPaneSpellCheck
    ReadSpellCheckInfo(True)
    Return
EndIf
sayMessage(ot_error, msgNotInSpellChecker)
EndScript

Script SelectALink()
; We want insert f7 To repeat the Spellcheck functionality in case the Reason text is being read.
If UserBufferIsActive() && !(getRunningFSProducts() & PRODUCT_MAGic)
    If c_WordFocus.InProofingPaneSpellCheck
        ReadProofingPaneWithSplitButtons()
        Return
    EndIf
EndIf
performScript SelectALink()
EndScript

Script sayLanguageInUse()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
sayLanguageInUse()
EndScript

Script FocusToFirstFormField()
EnsureNoUserBufferActive()
If IsDocumentAreaScriptException()
    Return
EndIf
focusToFirstFormField()
EndScript

Script ShowItemsInVirtualViewer()
EnsureNoUserBufferActive(False)
If IsDocumentAreaScriptException()
    Return
EndIf
Var
    String sList,
    String sItem,
    Int iCount,
    Int iType,
    Int iChoice
sList = stringChopLeft(ListItemsToDisplay, 1)
iChoice = DlgSelectItemInList(sList, msgListOfItemsToDisplayInVV, False)
sItem = stringSegment(sList, cscListSeparator , iChoice)
If sItem == scComments
    iType = peComment
ElIf sItem == scFootnotes
    iType = peFootnote
ElIf sItem == scEndnotes
    iType = peEndnote
ElIf sItem == scRevisions
    iType = peRevision
else
    Return
EndIf
SayFormattedMessage(ot_smart_help, formatString(msgListItemsPleaseWait, sItem))
;a table in the revisions may cause revised text To Include list_item_separator,
;so temporarily Use some other character as the revision delimiter and Then clean up the list:
; This may help but will Not hurt For values of iType other than peRevision.
sList = GetListOfProofreadingElements(iType, "\001")
sList = StringReplaceSubstrings(sList, list_item_separator, cscSpace)
sList = StringReplaceSubstrings(sList, "\001", list_item_separator)
;now it's cleaned up, list_item_separator is safe To Use as the revision delimiter.
iCount = StringSegmentCount(sList, list_item_separator)
If iCount == 0
    SayMessage(ot_error, msgNoItemsToDisplay)
    Return
ElIf iCount == 1
    sItem = stringSegment(stringChopLeft(
        ListItemsToDisplay_singular, 1), cscListSeparator , iChoice)
EndIf
ShowListInVirtualViewer(iType, sItem, sList, iCount)
EndScript

Script ToggleWritingMode()
EnsureNoUserBufferActive()
toggleOverTypeMode()
EndScript

Script ToggleCase()
If QuickNavKeyTrapping()
    Return
EndIf
Var
    String sSelectedText,
    Int iLength,
    String sFirstSelectedWord,
    String sLastSelectedWord
SayCurrentScriptKeyLabel()
TypeKey(ksToggleCase)
If WindowCategoryIsWordDocument()
&& isPcCursor()
    sSelectedText = stringStripAllBlanks(GetSelectedText())
    iLength = StringLength(sSelectedText)
    If iLength> 1
    && iLength <= 255 Then ;about one line of standard 12-point text.
        Say(sSelectedText, OT_SPELL)
    ElIf iLength > 255
        sFirstSelectedWord = stringSegment(GetSelectedText(), cscSpace, 1)
        sLastSelectedWord = stringSegment(GetSelectedText(), cscSpace, -2)
        SayMessage(ot_selected_item, msgChangedCaseFrom)
        Say(sFirstSelectedWord, ot_spell)
        SayMessage(ot_selected_item, msgChangedCaseTo)
        Say(sLastSelectedWord, ot_spell)
    else
        SpellWord()
    EndIf
    If BrailleInUse()
        BrailleRefresh()
    EndIf
EndIf
EndScript

Script ToggleShowHideNonprintingCharacters()
TypeCurrentScriptKey()
SayCurrentScriptKeyLabel()
;With windows 8 and later,
;we do Not get a NewTextEvent To Let us know that something changed:
Delay(5)
Refresh()
EndScript

Script JAWSDelete()
If QuickNavKeyTrapping()
    Return
EndIf
PerformScript JAWSDelete()
EndScript

Script Delete()
performScript JAWSDelete()
EndScript

Script JAWSBackspace()
If QuickNavKeyTrapping()
    Return
EndIf
PerformScript JAWSBackSpace()
EndScript

Script Backspace()
performScript JAWSBackspace()
EndScript

Script ControlBackSpace()
If QuickNavKeyTrapping()
    Return
EndIf
Var String sText = getPriorWord()
If sText
    SayMessage(ot_line, sText)
else
    Say(cmsgBlank1, ot_screen_message)
EndIf
TypeCurrentScriptKey()
EndScript

Script DeleteWord()
If QuickNavKeyTrapping()
    Return
EndIf
Var
    Int iSelectionCtxFlags,
    Int iStyleCtxFlag
TypeKey(ksDeleteWord) ; CtrlDel in English
pause()
PCCursor()
iSelectionCtxFlags = GetSelectionContextFlags()
iStyleCtxFlag = iSelectionCtxFlags & selCtxStyle
If iStyleCtxFlag
    ToggleSelCtxFlag(iSelectionCtxFlags, selCtxStyle) ; turn it Off temporarily.
EndIf
SayWord()
If iStyleCtxFlag
    ToggleSelCtxFlag(iSelectionCtxFlags, selCtxStyle) ; turn it back On.
EndIf
If!isSelectionModeActive()
&& IsExtendedSelectionModeWatchActive()
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgSelectionModeOff1_L, cMsgSilent)
    StopExtendedSelectionModeWatch()
EndIf
EndScript

Script PasteFromClipboard()
If !(GetRunningFSProducts() & product_JAWS)
    SayCurrentScriptKeyLabel()
    Return
EndIf
If QuickNavKeyTrapping()
    Return
EndIf
PerformScript PasteFromClipboard()
EndScript

Int Function ShouldUseLegacyCopyAndPasteFormat()
Var
    Int major,
    Int update,
    Int build
GetFixedProductVersion (GetAppFilePath (), major, 0, update, 0)
If major < 16
    Return True
EndIf
If major == 16
    If update < 17928
        Return True
    ElIf update == 17928
        build = StringToInt(StringSegment (GetVersionInfoString (GetAppFilePath (), cmsg283_L), ".", -1))
        If build < 20216
            Return True
        EndIf
    EndIf
EndIf
Return False
EndFunction

Script LegacyPasteFormat()
If ShouldUseLegacyCopyAndPasteFormat()
    PerformScript PasteFormat()
    Return
EndIf
SayCurrentScriptKeyLabel ()
TypeCurrentScriptKey ()
EndScript

Script LegacyCopyFormat()
If ShouldUseLegacyCopyAndPasteFormat()
    PerformScript CopyFormat()
    Return
EndIf
SayCurrentScriptKeyLabel ()
TypeCurrentScriptKey ()
EndScript

Script PasteFormat()
If IsDocumentAreaScriptException()
    Return
EndIf
If QuickNavKeyTrapping()
    ;read-only Messages have quick nav key trapping enabled,
    ;but we still want users To be able To move the Messages via the keystroke.
    If OutlookIsActive()
        SayCurrentScriptKeyLabel()
        TypeCurrentScriptKey ()
    EndIf
    Return
EndIf
TypeCurrentScriptKey ()
If WindowCategoryIsWordDocument()
    Pause()
    SayFormattedMessageWithVoice(vctx_message, ot_help, msgPasteFormat_l, msgPasteFormat_s)
EndIf
EndScript

Script CopyFormat()
If !(GetRunningFSProducts() & product_JAWS)
    SayCurrentScriptKeyLabel()
    TypeCurrentScriptKey()
    Return
EndIf
If IsDocumentAreaScriptException()
    Return
EndIf
If QuickNavKeyTrapping()
    Return
EndIf
TypeCurrentScriptKey ()
If WindowCategoryIsWordDocument()
    pause()
    SayFormattedMessageWithVoice(vctx_message, ot_help, msgCopyFormat_l, msgCopyFormat_s)
EndIf
EndScript

Script CutToClipboard()
If !(GetRunningFSProducts() & product_JAWS)
    PerformScript CutToClipboard()
    Return
EndIf
If QuickNavKeyTrapping()
    Return
EndIf
Var
    String sTheClass,
    Int iSubtype
sTheClass = c_WordFocus.WindowClass
iSubtype = GetWindowSubtypeCode(GlobalFocusWindow)
If (!GetSelectedText()
&& !(GetCharacterAttributes() & ATTRIB_HIGHLIGHT))
&& (iSubtype == wt_edit
|| iSubtype == wt_MultiLine_Edit
|| iSubtype == wt_ReadOnlyEdit
|| iSubtype == wt_PasswordEdit
|| iSubtype == wt_Upload_Edit
|| iSubtype == wt_EditCombo
|| iSubtype == wt_ListView
|| iSubtype == wt_ListViewItem
|| iSubtype == wt_TreeView
|| iSubtype == wt_TreeViewItem
|| iSubtype == wt_Static
|| sTheClass == wc_wordMainDocumentWindow)
    SayMessage(OT_ERROR, cmsgNothingSelected)
Else
    If !WillOverwriteClipboard()
        Return
    EndIf
    ClipboardTextChanged = Clipboard_Cut
    TypeKey(cksCut)
EndIf
EndScript

Script CopySelectedTextToClipboard()
If !(GetRunningFSProducts() & product_JAWS)
|| isVirtualPCCursor()
    PerformScript CopySelectedTextToClipboard()
    Return
EndIf
Var
    Handle hwnd,
    Int iSubType,
    String sTheClass
If IsSameScript()
    ; Double-clicking Control+C will open the Office Clipboard in the task pane
    TypeKey(ksCopySelectedTextToClipboard)
    If IsTextSelected()
        SayMessage(ot_help, msgCopiedToOfficeClipboard_l, msgCopiedToOfficeClipboard_s)
    else
        SayMessage(ot_help, msgOfficeClipboard_l, msgOfficeClipboard_s)
    EndIf
    Return
EndIf
hwnd=GetFocus()
iSubtype = GetWindowSubtypeCode(hwnd)
sTheClass = c_WordFocus.WindowClass
If (!GetSelectedText()
&& !(GetCharacterAttributes() & ATTRIB_HIGHLIGHT))
&& (iSubtype == wt_edit
|| iSubtype == wt_MultiLine_Edit
|| iSubtype == wt_ReadOnlyEdit
|| iSubtype == wt_PasswordEdit
|| iSubtype == wt_Upload_Edit
|| iSubtype == wt_EditCombo
|| iSubtype == wt_ListView
|| iSubtype == wt_ListViewItem
|| iSubtype == wt_TreeView
|| iSubtype == wt_TreeViewItem
|| iSubtype == wt_Static
|| sTheClass == wc_wordMainDocumentWindow)
    TypeKey(ksCopySelectedTextToClipboard)
    SayMessage(OT_ERROR, cmsgNothingSelected)
Else
    If !WillOverwriteClipboard()
        Return
    EndIf
    ClipboardTextChanged = CLIPBOARD_COPIED
    CopySelectionToClipboard()
EndIf
EndScript

Script JAWSFind()
;Activates native Find and Replace dialog For Outlook when in the message window.
;otherwise, performs default JAWSFind Function.
If OutlookIsActive()
&& !WindowCategoryIsWordDocument()
&& !isVirtualPCCursor()
&& !UserBufferIsActive()
    TypeKey(ksF4)
    Return
EndIf
performScript JAWSFind()
EndScript

Script MAGicFind()
performScript JAWSFind()
EndScript

Script GraphicsList()
SayMessage(ot_error,
    formatString(msgGraphicsListNotAvailable_l, GetCurrentScriptKeyName()),
    formatString(msgGraphicsListNotAvailable_s,     GetCurrentScriptKeyName()))
EndScript

Script TabKey()
c_WordTester.PressTabOrShiftTabCausedNewListItem = False
If c_WordFocus.windowCategory == wCat_document
    sayCurrentScriptKeyLabel()
    If OutlookIsActive()
    && IsActiveWindowProtected()
        TabInReadOnlyMessage(MOVE_FORWARD)
        Return
    EndIf
    If QuickNavKeyTrapping()
        If IsDocumentTableActive()
        && !AtLastCellInDocumentTable()
            TabKey()
        EndIf
        Return
    EndIf
    TabKey()
    If isPcCursor()
        If InList()
            c_WordTester.PressTabOrShiftTabCausedNewListItem = True
            Refresh(1)
            Pause()
            If BrailleInUse()
                BrailleRefresh()
            EndIf
            SayLine()
        EndIf
    EndIf
    Return
EndIf
PerformScript Tab()
EndScript

Script shiftTabKey()
c_WordTester.PressTabOrShiftTabCausedNewListItem = False
If c_WordFocus.windowCategory == wCat_document
    sayCurrentScriptKeyLabel()
    If OutlookIsActive()
    && IsActiveWindowProtected()
        TabInReadOnlyMessage(MOVE_BACK)
        Return
    EndIf
    If QuickNavKeyTrapping()
        If IsDocumentTableActive()
        && !AtFirstCellInDocumentTable()
            ShiftTabKey()
        EndIf
        Return
    EndIf
    shiftTabKey()
    If isPcCursor()
        If InList()
            c_WordTester.PressTabOrShiftTabCausedNewListItem = True
            Refresh(1)
            Pause()
            If BrailleInUse()
                BrailleRefresh()
            EndIf
            SayLine()
        EndIf
    EndIf
    Return
EndIf
PerformScript shiftTab()
EndScript

Script Enter()
SayCurrentScriptKeyLabel()
c_WordTester.PressEnterCausedNewListItem = False
Var Int typeCode
If c_WordFocus.windowCategory == wCat_document
    If OutlookIsActive()
        If IsHyperlinkField()
            EnterKey()
            Return
        EndIf
    EndIf
    If QuickNavKeyTrapping()
        ; Enter key has a Function in ZoomText and Fusion that was being trapped.
        If getRunningFSProducts() &(product_ZoomText | product_Fusion)
        && OutlookIsActive()
            enterKey()
        EndIf
        Return
    EndIf
    typeCode = getObjectSubtypeCode()
    If isPcCursor()
    && IsFormfield()
    && (typeCode == WT_ComboBox || typeCode == WT_Menu)
        If typeCode == wt_comboBox
            clickFormField()
        else
            TypeKey(cksAltDownArrow) ;alt+DownArrow
        EndIf
    ElIf IsHyperlinkField()
        TrackLinkNavigation(MOVE_FORWARD)
        EnterKey()
        sayLine()
    Else
        EnterKey()
        If InList()
            c_WordTester.PressEnterCausedNewListItem = True
        EndIf
    EndIf
    Return
EndIf
If c_WordFocus.InMicrosoftEditorProofingPaneIssueChecker
&& oSuggestionSplitButton && !oSuggestionSplitButton.isOffScreen
    FSUIAGetFirstChildOfElement (oSuggestionSplitButton).GetInvokePattern().Invoke()
    oSuggestionSplitButton = null()
    Return
EndIf
typeCode = getObjecttypeCode(True)
If oSuggestionSplitButton && !oSuggestionSplitButton.isOffScreen ; reset every time focus changes
&& typecode == WT_EDIT ; can be read-only, multiline or single-line
&& c_WordFocus.WindowClass == cwc_NetUIHwnd
    Var Object pattern = oSuggestionSplitButton.GetInvokePattern()
    If pattern.Invoke()
        ; must reread the spellcheck info but only If still in the read-only and Not On a button:
        delay(1)
        oSuggestionSplitButton = null() ; ensure recaching of New element
        If getObjectTypeCode(True) == typeCode Then ; spellCheck still in progress.
            performScript readMistakeAndSuggestion()
        EndIf
        Return
    EndIf
EndIf
If IsSearchDocumentDialogType()
    If c_WordFocus.WindowClass == cwc_Richedit60W
        ;For Word 2010,
        ;Text becomes selected as you enter a search term,
        ;and pressing Enter places focus On the Next Search Result button,
        ;but the first enstance of the found item is Not read automatically.
        ;So, perform ReadWordInContext when Enter is pressed after the search term is entered.
        EnterKey()
        Delay(2, True)
        Var Int IgnoreNotFoundMessage = False ;
        ; but expose the correct message:
        Var Int UseSearchStringNotFoundMessageInstead = True
        ReadWordInContext(IgnoreNotFoundMessage, UseSearchStringNotFoundMessageInstead)
    else
        ;ProcessNewTextEvent reads the word in context,
        ;so that the context is Not read before the document is updated.
        EnterKey()
    EndIf
    Return
EndIf
EnterKey()
EndScript

Script VirtualEnter()
If UserBufferIsActive()
|| isVirtualPCCursor()
    sayCurrentScriptKeyLabel()
    builtin::EnterKey()
EndIf
EndScript

Script ControlEnter()
PerformScript ControlEnter()
If WindowCategoryIsWordDocument()
&& !IsWordDocumentActive()
    SayLine()
EndIf
EndScript

Script NextDocumentWindow()
If WindowCategoryIsWordDocument()
&& InTable()
    TypeKey(cksControlTab)
    SayHorizontalPosition()
    Return
EndIf
PerformScript NextDocumentWindow()
EndScript

Script PreviousDocumentWindow()
If WindowCategoryIsWordDocument()
&& InTable()
    TypeKey(cksControlShiftTab)
    SayHorizontalPosition()
    Return
EndIf
PerformScript PreviousDocumentWindow()
EndScript

String Function GetActiveCursorName()
;Overwritten here To Handle the case For where the document is in Web view.
If StringContains(GetActiveCursorName(), CURSOR_FSDOM_EDIT)
    If IsPCCursor()
        Return cmsgPCCursorActive
    EndIf
EndIf
Return GetActiveCursorName()
EndFunction

Script PCCursor()
; must overwrite here so that JAWS does Not announce virtual cursor is active when quick keys are turned On.
Var Int bTurnOffFormsMode =
    IsFormsModeActive()
    && !IsJAWSCursor()
    && !IsInvisibleCursor()
    && !IsTouchCursor()
If IsObjectNavigationActive()
    If IsSameScript()
        ExitTouchNavigation()
    else
        BeginFlashMessage()
        sayMessage(OT_Status, cmsgTouchCursor_L, cmsgTouchCursor_L)
        If ShouldItemSpeak(ot_tutor)
            ;tutor Messages are normally Off For braile,
            ;but we want To make sure this is shown in braille:
            Say(cmsgTouchCursorDeactivateTutorMessage, ot_status)
        EndIf
        EndFlashMessage()
        Return
    EndIf
EndIf
ResetSynth()
PCCursor()
If QuickNavKeyTrapping()
&& WindowCategoryIsWordDocument()
&& !IsEmailMessage()
    SayFormattedMessage(ot_status, cmsg9_L, cmsg9_S) ; "PC Cursor"
    If BrailleInUse()
        RouteBrailleToPC()
        BrailleRefresh()
    EndIf
    Return
EndIf
If bTurnOffFormsMode
|| IsVirtualPCCursor()
    TurnOffFormsMode()
EndIf
If BrailleInUse()
    RouteBrailleToPC()
    BrailleRefresh()
EndIf
If IsVirtualPCCursor()
    SayFormattedMessage(ot_status, cMSG288_L, cMSG288_S) ; virtual pc cursor
else
    SayFormattedMessage(ot_status, cmsg9_L, cmsg9_S) ; "PC Cursor"
EndIf
EndScript

Script SayActiveCursor()
If !isPCCursor()
|| IsVirtualPcCursor()
|| !WindowCategoryIsWordDocument()
|| IsObjectNavigationActive()
    PerformScript SayActiveCursor()
    Return
EndIf
If GetActiveDocumentViewName() == msgWeb
    performScript SayActiveCursor()
    Return
EndIf
Var
    String sCursorPos,
    String sMsg_L,
    String sMsg_S
sCursorPos = GetCursorPosString(GetActiveCursor(), getDesiredUnitsOfMeasure())
If IsWordDocumentActive()
    sCursorPos = StringReplaceSubStrings(sCursorPos, sc_minus, cscSpace)
EndIf
sMsg_L = GetActiveCursorName()+cscBufferNewLine
    +sCursorPos+cscBufferNewLine
sMsg_S = sMsg_L
If !IsPCCursor()
    sMsg_L = sMsg_L+cmsg317_l
    sMsg_S = sMsg_S+cmsg317_s
EndIf
If quickNavState()
&& QuickNavKeyTrapping()
    sMsg_L = sMsg_L+cscBufferNewLine+cmsgNavigationModeOn_l
    sMsg_S = sMsg_S+cscBufferNewLine+cmsgNavigationModeOn_l
EndIf
sayMessage(ot_user_requested_information, sMsg_L, sMsg_S)
EndScript

Script SayTopLineOfWindow()
If WindowCategoryIsWordDocument()
&& IsPCCursor()
    SaveCursor()
    InvisibleCursor()
    RouteInvisibleToPC()
    JAWSPageUp()
    Say(GetWindowName(GetRealWindow(GetCurrentWindow())), ot_user_requested_information)
    RestoreCursor()
    Return
EndIf
performScript SayTopLineOfWindow()
EndScript

Script ReadOutlookHeader(Int iField)
If InHJDialog()
&& globalRealWindowName==cWn16 Then ; Heading List
    SayCurrentScriptKeyLabel()
    TypeKey(GetCurrentScriptKeyName())
    Return
EndIf
TypeKey(GetCurrentScriptKeyName())
EndScript

Script EMailHeader3Control()
TypeKey(ksEmailHeader3) ; Alt3 in English
EndScript

Script EMailHeader4Control()
TypeKey(ksEmailHeader4) ; Alt4 in English
EndScript

Script selectionByUnitMode()
If WindowCategoryIsWordDocument()
    ExtendedSelectionByUnitScriptRunEvent() ;this must run before the key is pressed
    TypeKey(ksSelectionByUnitMode) ; F8 in English
    pause()
    If IsExtendedSelectionModeWatchActive()
        saySelectedUnit()
        UpdateExtendedSelectionModeWatch()
        If !IsEntireDocumentSelected()
            sayWindow(getFocus(), read_highlighted)
        EndIf
    else
        If isSelectionModeActive()
            SayFormattedMessageWithVoice(vctx_message, ot_status, msgSelectionModeOn1_L, cmsgSilent)
            InitExtendedSelectionModeWatch()
        EndIf
    EndIf
else
    TypeKey(ksSelectionByUnitMode) ; F8 in English
    SayCurrentScriptKeyLabel()
EndIf
EndScript

Script reduceSelectionUnit()
If WindowCategoryIsWordDocument()
    ExtendedSelectionByUnitScriptRunEvent() ;this must run before the key is pressed
    TypeKey(ksReduceSelectionUnit) ; ShiftF8 in english
    pause()
    If IsExtendedSelectionModeWatchActive()
        saySelectedUnit()
        UpdateExtendedSelectionModeWatch()
        say(getSelectedText(), OT_LINE)
    else
        If isSelectionModeActive()
            SayFormattedMessageWithVoice(vctx_message, ot_status, msgSelectionModeOn1_L, cmsgSilent)
            InitExtendedSelectionModeWatch()
        EndIf
    EndIf
else
    TypeKey(ksSelectionByUnitMode) ; F8 in English
    SayCurrentScriptKeyLabel()
EndIf
EndScript

Script selectionByMovementMode()
If WindowCategoryIsWordDocument()
&& !IsExtendedSelectionModeWatchActive()
    If isVirtualPcCursor() ; Outlook virtualized message:
        sayMessage(OT_ERROR, msgExtendedSelectionNotAvailableVirtualizedMessages)
        Return
    EndIf
    TypeKey(ksSelectionByMovementMode) ; CtrlShiftF8 in English
    pause()
    SayFormattedMessageWithVoice(vctx_message, ot_status, msgSelectionModeOn1_L, cmsgSilent)
    InitExtendedSelectionModeWatch()
    Return
EndIf
TypeCurrentScriptKey()
SayCurrentScriptKeyLabel()
EndScript

; When unselecting text in Microsoft Word, JAWS will only speak the
; unselected text If the unselection was caused by a builtin unselection
; Script Function. This is because when selected text is deleted, JAWS is
; informed of the deletion in the same way as of an unselection and
; there is no need To speak the text being deleted.
; Selection/unselection of all units other than paragraphs was already
; handled by internal functions, now paragraphs are as well.
; (There really is no need For SelectParagraph To be handled by an
; internal Function since text selection in Word is spoken
; unconditionally, but the symetry of having both functions is compelling.)

Script SaySelectedText()
Var
    Handle hFocus = GetFocus(),
    Int bSpell,
    Int i = 20,
    String sStartSelected,
    String sEndSelected,
    String sSelectedText = GetSelectedText(),
    Int iSelectedTextLength = StringLength(sSelectedText)
If c_WordFocus.windowCategory(hFocus) == WCAT_DOCUMENT
    bSpell =(IsSameScript() && GetRunningFSProducts() != product_MAGic)
    If iSelectedTextLength >= 1000
    && !bSpell
        While SubString(sSelectedText, i, 1) != cScSpace
            i = i + 1
        EndWhile
        sStartSelected = StringLeft(sSelectedText, i)
        i = 20
        While SubString(sSelectedText, iSelectedTextLength - i, 1) != cScSpace
            i = i + 1
        EndWhile
        sEndSelected = StringRight(sSelectedText, i)
        SayFormattedMessage(OT_USER_REQUESTED_INFORMATION, FormatString(msgSelectedHugeAmountOfText, IntToString(iSelectedTextLength), sStartSelected, sEndSelected))
        Return
    EndIf
EndIf
PerformScript SaySelectedText()
EndScript

Int Function ShouldSetQuickNavModeTo2()
If IsVirtualPCCursor() Return False EndIf
Return IsPCCursor()
    && !InHJDialog()
EndFunction

Script SayAll()
If ShouldSetQuickNavModeTo2()
    If !WindowCategoryIsWordDocument()
        If c_WordFocus.ObjectSubType == wt_multiLine_edit
        || c_WordFocus.WindowSubtype == wt_multiline_edit
            performScript SayAll() ; default
        else
            SayLine()
        EndIf
        Return
    EndIf
    If isMAGicRunning()
    && getJCFOption(OPT_HIGHLIGHT_STYLE )>0 Then
        If QuickNavKeyTrapping() Then
            SaveCurrentQuickKeyNavigationMode()
            setJCFOption(opt_quick_key_navigation_Mode, 2) ; On by default
            SetQuickKeyNavigationState(0)
        EndIf
        performScript SayAll() ; default
        Return
    EndIf
    If IsActiveDocumentProtectedForm()
        sayMessage(ot_error, msgErrorSayAllProtectedForm_l, msgErrorSayAllProtectedForm_s)
        Return
    EndIf
    setJCFOption(opt_quick_key_navigation_Mode, 2) ; On by default
EndIf
If ShouldSetQuickNavModeTo2()
    SaveCurrentQuickKeyNavigationMode()
    setJCFOption(opt_quick_key_navigation_Mode, 2) ; On by default
EndIf   ; end of user buffer and HJDialog
performscript SayAll()
SetQuickKeyNavigationState(1)
EndScript

Script SayAllFromLocation()
If !WindowCategoryIsWordDocument()
    If c_WordFocus.ObjectSubType == wt_multiLine_edit
    || c_WordFocus.WindowSubtype == wt_multiline_edit
        performScript SayAllFromLocation() ; default
    else
        SayLine(True)
    EndIf
    Return
EndIf
If isMAGicRunning()
&& getJCFOption(OPT_HIGHLIGHT_STYLE )>0 Then
    If QuickNavKeyTrapping() Then
        SaveCurrentQuickKeyNavigationMode()
        setJCFOption(opt_quick_key_navigation_Mode, 2) ; On by default
        SetQuickKeyNavigationState(0)
    EndIf
    performScript SayAllFromLocation() ; default
    Return
EndIf
If IsActiveDocumentProtectedForm()
    processMessage(msgErrorSayAllProtectedForm_l, msgErrorSayAllProtectedForm_s, ot_error, msgError, MB_OK|MB_ICONERROR)
    Return
EndIf
SaveCurrentQuickKeyNavigationMode()
setJCFOption(opt_quick_key_navigation_Mode, 2) ; On by default
performScript SayAllFromLocation()
SetQuickKeyNavigationState(1)
EndScript

Script MarkPlace()
If c_WordFocus.windowCategory != WCAT_DOCUMENT
|| !isPCCursor()
|| isVirtualPCCursor()
|| UserBufferIsActive()
|| OutlookIsActive()
    Return
EndIf
Var
    Int bIsTextSelected,
    Int iMarkedPlace,
    Int iCurCharPos
bIsTextSelected = IsTextSelected()
If !bIsTextSelected
&& atStartOfDocument()
    ProcessMessage(msgMarkedPlaceBeginningOfDocumentError_L, msgMarkedPlaceBeginningOfDocumentError_S, OT_ERROR, msgError, MB_OK|MB_ICONERROR)
    Return
EndIf
If !InDocumentMainText()
    ProcessMessage(msgMarkedPlaceSaveStoryError_l, msgMarkedPlaceSaveStoryError_l, OT_ERROR, msgError, MB_OK|MB_ICONERROR)
    Return
EndIf
If !WasDocumentEverSaved()
    ProcessMessage(msgMarkedPlaceSaveDocError_l, msgMarkedPlaceSaveDocError_s, OT_ERROR, msgError, MB_OK|MB_ICONERROR)
    Return
EndIf
If IsActiveDocumentProtectedForm()
|| IsActiveDocumentProtected()
    ProcessMessage(msgProtectedDocOrFormMarkingPlaceError_l, msgProtectedDocOrFormMarkingPlaceError_s, OT_ERROR, msgError, MB_OK|MB_ICONERROR)
    Return
EndIf
If bIsTextSelected
    ProcessMessage(msgSelectedTextMarkingPlaceError_l, msgSelectedTextMarkingPlaceError_l, OT_ERROR, msgError, MB_OK|MB_ICONERROR)
    Return
EndIf
iMarkedPlace = GetCurrentDocumentMarkedPlace()
iCurCharPos = GetCurCharPos()
If iMarkedPlace == iCurCharPos
    ProcessMessage(msgPlaceAlreadyMarked, null(), OT_ERROR, msgError, MB_OK|MB_ICONERROR)
    Return
EndIf
setCurrentDocumentMarkedPlace(iCurCharPos)
processMessage(msgMarkingPlace, null(), ot_help, cscNull, MB_OK|MB_ICONINFORMATION)
EndScript

Script ReturnToMarkedPlace()
If c_WordFocus.windowCategory != WCAT_DOCUMENT
|| !isPCCursor()
|| isVirtualPCCursor()
|| UserBufferIsActive()
|| OutlookIsActive()
    Return
EndIf
Var
    Int iMarkedPlace
;If place is already marked, Return To it.
;Otherwise, beep and say error message.
iMarkedPlace = GetCurrentDocumentMarkedPlace()
If iMarkedPlace
    If iMarkedPlace == GetCurCharPos()
        processMessage(msgAlreadyAtMarkedPlace_l, msgAlreadyAtMarkedPlace_s, OT_ERROR, msgError, MB_OK|MB_ICONERROR)
        Return
    EndIf
    If TotalDocumentCharCount() < iMarkedPlace
        processMessage(msgMarkedPlaceNotValidError_l, msgMarkedPlaceNotValidError_s, OT_ERROR, msgError, MB_OK|MB_ICONERROR)
        Return
    EndIf
    If ReturnToMarkedPlace(iMarkedPlace)
        sayUsingVoice(vctx_message, msgReturningToMarkedPlace, ot_help)
        scheduleBrailleFlashMessageWithSpeechOutput(OT_Help, msgReturningToMarkedPlace)
        If inTable()
            SayCell()
            Return
        EndIf
        SayWordAtMarkedPlace()
    EndIf
else
    beep()
    SayMessage(OT_ERROR, msgMarkedPlaceError_l, msgMarkedPlaceError_s)
EndIf
EndScript

Script SelectTextBetweenMarkedPlaceAndCurrentPosition()
If IsVirtualPCCursor()
|| OutlookIsActive()
    ;These should be handled by default:
    PerformScript SelectTextBetweenMarkedPlaceAndCurrentPosition()
    Return
EndIf
If c_WordFocus.windowCategory != WCAT_DOCUMENT
|| !isPCCursor()
|| UserBufferIsActive()
    Return
EndIf
;Now we are handling the Word document:
Var Int iMarkedPlace = GetCurrentDocumentMarkedPlace()
If !iMarkedPlace
    sayMessage(ot_error, FormatString(msgMarkedPlaceSelectingTextError_l), FormatString(msgMarkedPlaceSelectingTextError_s))
    Return
EndIf
If SelectTextBetweenMarkedPlaceAndPos(iMarkedPlace, GetCurCharPos())
    SayMessage(ot_status, msgMarkedPlaceSelectingText)
EndIf
EndScript

Script DefineATempPlaceMarker()
If IsVirtualPcCursor()
|| OutlookIsActive()
    performScript DefineATempPlaceMarker()
else
    PerformScript MarkPlace()
EndIf
EndScript

Script ShowMathViewer()
ShowMathViewerHelper(MathViewerRequestor_MSWord)
EndScript

Script ShowMathEditor()
Var String requestor = MathEditorRequestor_Default;
If (isOffice365())
    requestor = MathEditorRequestor_MSWord;
EndIf
ShowMathEditorHelper(requestor);
EndScript

Script DescribeTextAnnotationOrAttributes()
DescribeTextAnnotationOrAttributes(True)
EndScript

Int Function IsAutoCorrectExceptionCharacter(Int charValue)
Return charValue == AutocorrectApostrophe
    || charValue == AutocorrectLeftQuote
    || charValue == AutocorrectRightQuote
EndFunction

Script sayCharacter()
If handleNoCurrentWindow()
    Return
EndIf
If !isPCCursor()
|| UserBufferIsActive()
    performScript sayCharacter()
    Return
EndIf
If WindowCategoryIsWordDocument()
    If IsFormField()
    && c_WordFocus.ObjectSubType == wt_checkbox
        self::SayObjectTypeAndText()
        Return
    EndIf
ElIf InMultilevelListPane()
    IndicateControlType(wt_grid, GetWord2003MultiLevelListObjectNameOfFocusObject(), cscNull)
    Return
EndIf
performScript sayCharacter()
EndScript

Script sayNextCharacter()
If !IsPcCursor()
|| IsVirtualPCCursor()
|| UserBufferIsActive()
|| InHJDialog()
|| (DialogActive() && OutlookIsActive())
    PerformScript SayNextCharacter()
    Return
EndIf
If WindowCategoryIsWordDocument()
    If IsExtendedSelectionModeWatchActive()
        nSaySelectAfter = True
        SelectingText(True)
        SelectNextCharacter()
        SelectingText(False)
        nSaySelectAfter = False
        Return
    EndIf
    SetDocumentCaretMovementType(Unit_Char_Next)
    nextCharacter()
    If IsLeftButtonDown()
    || IsRightButtonDown()
        SelectingText(True)
        pause()
        SelectingText(False)
        Return
    EndIf
    If !SupportsEditCallbacks()
    && IsWordDocumentActive()
        ; Not all MSWord instances will support edit callbacks.
        ; When run as part of the Enterprise Express Editor, used by Lighthouse Houston, events are blocked by their addin.
        ; In this case we must force legacy behaviour and speak here.
        CaretMovedEvent(Unit_CHAR_Next)
    EndIf
    Return
EndIf
Var
    Int iType,
    String sClass,
    String sObjName,
    Handle hwnd
hwnd = GetFocus()
sClass = c_WordFocus.WindowClass
sObjName = GetObjectName()
iType = c_WordFocus.WindowSubtype
If !iType
    iType = c_WordFocus.ObjectSubType
EndIf
If InTaskPaneDialog()
&& (iType == wt_edit
|| iType == wt_EditCombo
|| sClass == cwc_RichEdit20W)
    NextCharacter()
    SayCharacter()
ElIf sObjName == scUnderlineStyle
&& sClass != wc_MsoCommandBar
    NextLine()
    SayMessage(ot_highlighted_screen_text, GetObjectName(SOURCE_CACHED_DATA))
ElIf sClass == wc_msoCommandBar
    NextCharacter()
ElIf iType == wt_tabControl
    NextCharacter()
;ensure that extended ASCII and Unicode characters are announced as they gain focus.
ElIf globalRealWindowName == wn_symbol
&& c_WordFocus.ObjectSubType == wt_bitmap
    nextCharacter()
    sayCharacter()
else
    performScript sayNextCharacter() ; default
EndIf
EndScript

Script sayPriorCharacter()
If !IsPcCursor()
|| IsVirtualPCCursor()
|| UserBufferIsActive()
|| InHJDialog()
|| (DialogActive() && OutlookIsActive())
    PerformScript SayPriorCharacter()
    Return
EndIf
If WindowCategoryIsWordDocument()
    If IsExtendedSelectionModeWatchActive()
        nSaySelectAfter = True
        SelectingText(True)
        SelectPriorCharacter()
        SelectingText(False)
        nSaySelectAfter = False
        Return
    EndIf
    SetDocumentCaretMovementType(Unit_Char_Prior)
    priorCharacter()
    If IsLeftButtonDown()
    || IsRightButtonDown()
     SelectingText(True)
     pause()
     SelectingText(False)
     Return
    EndIf
    If !SupportsEditCallbacks()
    && IsWordDocumentActive()
        ; Not all MSWord instances will support edit callbacks.
        ; When run as part of the Enterprise Express Editor, used by Lighthouse Houston, events are blocked by their addin.
        ; In this case we must force legacy behaviour and speak here.
        CaretMovedEvent(Unit_Char_Prior)
    EndIf
    Return
EndIf
Var
    Int iType,
    String sClass,
    String sObjName,
    Handle hwnd
hwnd = GetFocus()
sClass = c_WordFocus.WindowClass
sObjName = GetObjectName()
iType = c_WordFocus.WindowSubtype
If !iType
    iType = c_WordFocus.ObjectSubType
EndIf
If InTaskPaneDialog()
&&(iType == wt_edit
|| iType == wt_EditCombo
|| sClass == cwc_RichEdit20W)
    PriorCharacter()
    SayCharacter()
ElIf sObjName == scUnderlineStyle
&& sClass != wc_MsoCommandBar
    PriorLine()
    SayMessage(ot_highlighted_screen_text, GetObjectName(SOURCE_CACHED_DATA))
ElIf sClass == wc_msoCommandBar
    PriorCharacter()
ElIf iType == wt_tabControl
    PriorCharacter()
;ensure that extended ASCII and Unicode characters are announced as they gain focus.
ElIf globalRealWindowName == wn_symbol
&& c_WordFocus.ObjectSubType == wt_bitmap
    PriorCharacter()
    sayCharacter()
else
    performScript sayPriorCharacter() ;default
EndIf
EndScript

Void Function SayWordUnit(Int UnitMovement)
If SayCursorMovementException(unitMovement)
    SayWordUnit(UnitMovement)
    Return
EndIf
If InTaskPaneDialog()
&& GetObjectTypeCode() != wt_edit
    Return
EndIf
If c_WordFocus.WindowClass == cwc_RichEdit20W
    ;Using SayWord On this class will cause the dialog title and entire edit field To be spoken,
    ;So we Use GetWord instead:
    Say(GetWord(), ot_word, True)
    Return
EndIf
SayWordUnit(UnitMovement)
EndFunction

Script sayWord()
If handleNoCurrentWindow()
    Return
EndIf
If !IsPCCursor()
|| UserBufferIsActive()
    PerformScript sayWord()
    Return
EndIf
If WindowCategoryIsWordDocument()
    If IsFormField()
    && c_WordFocus.ObjectSubType == wt_checkbox
        self::SayObjectTypeAndText()
        Return
    EndIf
ElIf InMultilevelListPane()
    IndicateControlType(wt_grid, GetWord2003MultiLevelListObjectNameOfFocusObject(), cscNull)
    Return
EndIf
PerformScript sayWord()
EndScript

Script sayNextWord()
Var String sClass = c_WordFocus.WindowClass
If getMenuMode() == 2
&& !userBufferIsActive()
&& (sClass == wc_wwg || sClass == wc_wwn)
    ;escape from menus such as Smart Tag For paste:
    typeKey(cksEscape)
EndIf
If UserBufferIsActive()
|| IsVirtualPCCursor()
|| InHJDialog()
|| !IsPcCursor()
|| sClass==wc_wwn
|| sClass == wc_wwo
    PerformScript SayNextWord()
    Return
EndIf
If WindowCategoryIsWordDocument()
    If IsExtendedSelectionModeWatchActive()
        nSaySelectAfter = True
        SelectingText(True)
        SelectNextWord()
        SelectingText(False)
        nSaySelectAfter = False
        Return
    EndIf
    SetDocumentCaretMovementType(Unit_Word_Next)
    nextWord()
    If IsLeftButtonDown()
    || IsRightButtonDown()
     SelectingText(True)
     pause()
     SelectingText(False)
     Return
    EndIf
    If !SupportsEditCallbacks()
        ; Not all MSWord instances will support edit callbacks.
        ; When run as part of the Enterprise Express Editor, used by Lighthouse Houston, events are blocked by their addin.
        ; In this case we must force legacy behaviour and speak here.
        CaretMovedEvent(Unit_Word_Next)
    EndIf
    Return
EndIf
performScript sayNextWord()
EndScript

Script sayPriorWord()
Var String sClass = c_WordFocus.WindowClass
If getMenuMode() == 2
&& !userBufferIsActive()
&& (sClass == wc_wwg || sClass == wc_wwn)
    ;escape from menus such as Smart Tag For paste:
    typeKey(cksEscape)
EndIf
If UserBufferIsActive()
|| IsVirtualPCCursor()
|| !IsPcCursor()
|| InHJDialog()
|| sClass==wc_wwn
|| sClass == wc_wwo
    PerformScript SayPriorWord()
    Return
EndIf
If WindowCategoryIsWordDocument()
    If IsExtendedSelectionModeWatchActive()
        nSaySelectAfter = True
        SelectingText(True)
        SelectPriorWord()
        SelectingText(False)
        nSaySelectAfter = False
        Return
    EndIf
    SetDocumentCaretMovementType(Unit_Word_Prior)
    priorWord()
    If IsLeftButtonDown()
    || IsRightButtonDown()
     SelectingText(True)
     pause()
     SelectingText(False)
     Return
    EndIf
    If !SupportsEditCallbacks()
        ; Not all MSWord instances will support edit callbacks.
        ; When run as part of the Enterprise Express Editor, used by Lighthouse Houston, events are blocked by their addin.
        ; In this case we must force legacy behaviour and speak here.
        CaretMovedEvent(Unit_Word_Prior)
    EndIf
    Return
EndIf
performScript sayPriorWord()
EndScript

Script JAWSHome()
If InHJDialog()
    performScript JAWSHome() ; default
    Return
EndIf
If WindowCategoryIsWordDocument()
    SayCurrentScriptKeyLabel()
    If IsExtendedSelectionModeWatchActive()
        nSaySelectAfter     = True
        SelectingText(True)
        SelectFromStartOfLine()
        SelectingText(False)
        nSaySelectAfter     = False
        Return
    EndIf
    SetDocumentCaretMovementType(Unit_Line_Start)
    JAWSHome()
    If IsLeftButtonDown()
    || IsRightButtonDown()
     SelectingText(True)
     pause()
     SelectingText(False)
     Return
    EndIf
    If !SupportsEditCallbacks()
        ; Not all MSWord instances will support edit callbacks.
        ; When run as part of the Enterprise Express Editor, used by Lighthouse Houston, events are blocked by their addin.
        ; In this case we must force legacy behaviour and speak here.
        CaretMovedEvent(Unit_Line_Start)
    EndIf
    Return
EndIf
performScript JAWSHome() ; default
EndScript

Script Home()
performScript JAWSHome()
EndScript

Script JAWSEnd()
If InHJDialog()
    performScript JAWSEnd() ; default
    Return
EndIf
If WindowCategoryIsWordDocument()
    SayCurrentScriptKeyLabel()
    If IsExtendedSelectionModeWatchActive()
        nSaySelectAfter = True
        SelectingText(True)
        SelectToEndOfLine()
        SelectingText(False)
        nSaySelectAfter = False
        Return
    EndIf
    SetDocumentCaretMovementType(Unit_Line_End)
    JAWSEnd()
    If IsLeftButtonDown()
    || IsRightButtonDown()
     SelectingText(True)
     pause()
     SelectingText(False)
     Return
    EndIf
    If !SupportsEditCallbacks()
        ; Not all MSWord instances will support edit callbacks.
        ; When run as part of the Enterprise Express Editor, used by Lighthouse Houston, events are blocked by their addin.
        ; In this case we must force legacy behaviour and speak here.
        CaretMovedEvent(Unit_Line_End)
    EndIf
    Return
EndIf
performScript JAWSEnd() ;default
EndScript

Script end()
performScript JAWSEnd()
EndScript

Void Function SayLineUnit(Int UnitMovement, optional Int bMoved)
If InEmptyCopilotEditWithSuggestions()
    Return
EndIf

If c_WordFocus.ObjectSubType == WT_EDIT_SPINBOX
&& IsPCCursor()
&& RibbonsActive()
    ;ValueChangedEvent speaks the change:
    Return
EndIf
SayLineUnit(UnitMovement, bMoved)
EndFunction

Script SayLine()
If handleNoCurrentWindow()
    Return
EndIf
Var Int inMenus = menusActive()
If !isPcCursor()
|| UserBufferIsActive()
|| inMenus
    performScript sayLine()
    Return
EndIf
If !isVirtualPCCursor()
&& WindowCategoryIsWordDocument()
    If isSameScript()
        SpellLine()
    Else
        SetDocumentReadingStartLocation()
        indicateInconsistenciesInRange(CheckLine)
        ResetSpeechMarkupAttributes()
        self::SayLine()
    EndIf
    Return
EndIf
If InMultilevelListPane()
    IndicateControlType(wt_grid, GetWord2003MultiLevelListObjectNameOfFocusObject(), cscNull)
    Say(PositionInGroup(), ot_position)
    Return
EndIf
If GetObjectName(SOURCE_CACHED_DATA, 1) == wn_SearchResultsList
    Say(GetObjectDescription (), OT_LINE)
EndIf
Var Int iType = GetObjectSubTypeCode(SOURCE_CACHED_DATA)
If iType == WT_STATIC
&& ReadMicrosoftEditorIssueCheckerInfo(False, False)
    Return
ElIf iType == WT_SPLITBUTTON
&& ReadMicrosoftEditorSuggestion()
    Return
EndIf
PerformScript SayLine()
EndScript

Script sayNextLine()
If !IsPcCursor()
|| isVirtualPCCursor()
|| UserBufferIsActive()
|| InHJDialog()
    PerformScript SayNextLine()
    Return
EndIf
If c_WordFocus.ObjectSubType == WT_EDIT_SPINBOX
    NextLine()
    Return SayLineUnit(UnitMove_Next)
EndIf
If WindowCategoryIsWordDocument()
    If IsExtendedSelectionModeWatchActive()
        nSaySelectAfter = True
        SelectingText(True)
        SelectNextLine()
        SelectingText(False)
        nSaySelectAfter = False
        Return
    EndIf
    SetDocumentCaretMovementType(Unit_Line_Next)
    nextLine()
    If !SupportsEditCallbacks()
    && IsWordDocumentActive()
        ; Not all MSWord instances will support edit callbacks.
        ; When run as part of the Enterprise Express Editor, used by Lighthouse Houston, events are blocked by their addin.
        ; In this case we must force legacy behaviour and speak here in the WordClassic Scripts.
        ; However, Office365 we need To Use SayLine as CaretMovedEvent is intermittent.
        ; CaretMovedEvent needs To be silent in this case To avoid doubling On line navigation.
        ;CaretMovedEvent(Unit_Line_Next)
        ;Must be scheduled in order To prevent speaking the wrong line.
        ; The final parameter To scheduleFunction kills the timer On key press and On event.
        scheduleFunction("sayLine", 1, True)
    EndIf
    Return
EndIf
;ensure that extended ASCII and Unicode characters are announced as they gain focus.
If globalRealWindowName == wn_symbol
&& c_WordFocus.ObjectSubType == wt_bitmap
    NextLine()
    sayCharacter()
    Return
EndIf
performScript sayNextLine() ; default
EndScript

Script sayPriorLine()
If !IsPcCursor()
|| isVirtualPCCursor()
|| UserBufferIsActive()
|| InHJDialog()
    PerformScript SayPriorLine()
    Return
EndIf
If c_WordFocus.ObjectSubType == WT_EDIT_SPINBOX
    PriorLine()
    Return SayLineUnit(UnitMove_Prior)
EndIf
If WindowCategoryIsWordDocument()
    If IsExtendedSelectionModeWatchActive()
        nSaySelectAfter = True
        SelectingText(True)
        SelectPriorLine()
        SelectingText(False)
        nSaySelectAfter = False
        Return
    EndIf
    SetDocumentCaretMovementType(Unit_Line_Prior)
    PriorLine()
    If !SupportsEditCallbacks()
    && IsWordDocumentActive()
        ; Not all MSWord instances will support edit callbacks.
        ; When run as part of the Enterprise Express Editor, used by Lighthouse Houston, events are blocked by their addin.
        ; In this case we must force legacy behaviour and speak here in the WordClassic Scripts.
        ; However, Office365 we need To Use SayLine as CaretMovedEvent is intermittent.
        ; CaretMovedEvent needs To be silent in this case To avoid doubling On line navigation.
        ;CaretMovedEvent(Unit_Line_Next)
        ;Must be scheduled in order To prevent speaking the wrong line.
        ; The final parameter To scheduleFunction kills the timer On key press and On event.
        scheduleFunction("sayLine", 1, True)
        ;CaretMovedEvent(Unit_Line_Prior)
    EndIf
    Return
EndIf
;ensure that extended ASCII and Unicode characters are announced as they gain focus.
If globalRealWindowName == wn_symbol
&& c_WordFocus.ObjectSubType == wt_bitmap
    PriorLine()
    sayCharacter()
    Return
EndIf
performScript sayPriorLine() ; default
EndScript

Int Function getControlGroupsForSpellCheckerWithSplitButtons(Object UIA, Object treewalker,
    Object byRef notInDictionaryGroup, Object byRef suggestionsGroup, Object byRef otherActionsGroup)
If !UIA || !treewalker Return False EndIf
Var Int scope = TREESCOPE_DESCENDANTS
Var Object splitButtonCondition = UIA.CreateIntPropertyCondition(UIA_ControlTypePropertyId, UIA_SplitButtonControlTypeId)
Var Object buttonCondition = UIA.CreateIntPropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
If !splitButtonCondition || !ButtonCondition Return False EndIf
If !treewalker.gotoParent() || treewalker.currentElement.controlType != UIA_GroupControlTypeId Return False EndIf
; notInDictionaryGroup contains the current sentence read-only edit and the Read Current Sentence buttons:
While treewalker.currentElement.controlType == UIA_GroupControlTypeId
&& !stringContains(treewalker.currentElement.name, wn_Proofing_Pane_Grammar)
&& !stringContains(treewalker.currentElement.name, wn_Proofing_Pane_Spelling)
&& treeWalker.goToPriorSibling()
EndWhile
If treewalker.currentElement.controlType != UIA_GroupControlTypeId
|| (!stringContains(treewalker.currentElement.name, wn_Proofing_Pane_Grammar)
&& !stringContains(treewalker.currentElement.name, wn_Proofing_Pane_Spelling))
    Return False
EndIf
notInDictionaryGroup = treewalker.currentElement.buildUpdatedCache()
; suggestionsGroup contains the split buttons where each suggestion is its own split button
If !treewalker.gotoNextSibling() Return False EndIf
; where "No suggestions" are found:
Var Object tmp = treeWalker.currentElement.findAll(TREESCOPE_Children, UIA.CreateRawViewCondition())
If tmp.count == 1
&& tmp(0).ClassName == "NetUIGroupHeader"
    suggestionsGroup = treewalker.CurrentElement
EndIf
While !suggestionsGroup
&& treewalker.currentElement.controlType == UIA_GroupControlTypeId
&& !treewalker.currentElement.findFirst(scope, splitButtonCondition)
&& treewalker.gotoNextSibling()
EndWhile
If treewalker.currentElement.controlType != UIA_GroupControlTypeId Return False EndIf
suggestionsGroup = treewalker.CurrentElement.buildUpdatedCache()
; other actions group is all buttons
If !treewalker.gotoNextSibling() Return False EndIf
While treewalker.currentElement.controlType == UIA_GroupControlTypeId
&& !treewalker.currentElement.findFirst(scope, buttonCondition)
&& treewalker.gotoNextSibling()
EndWhile
If treewalker.currentElement.controlType != UIA_GroupControlTypeId Return False EndIf
otherActionsGroup = treewalker.CurrentElement.buildUpdatedCache()
Return True
EndFunction

Int Function SpellProofingPaneSuggestionSplitButton()
If SayCursorMovementException(UnitMove_CURRENT) Then Return False EndIf
If !c_WordFocus.InProofingPaneSpellCheck Return False EndIf
Var Object element = FSUIAGetFocusedElement() ; focus On the split button and Not the pane:
If !element || element.controlType != UIA_SplitButtonControlTypeId Return False EndIf
; Microsoft separates the suggestion from the reference information with a comma.
; This is the same as has been done For a While in ReadProofingPaneWithSplitButtons Function.
Var String suggestion = stringSegment(element.name, ", ", 1); separate suggestion from reference info:
If !stringIsBlank(suggestion)
    spellString(suggestion)
    Return True
else
    Return False
EndIf
EndFunction

Void Function spellWord()
If SpellProofingPaneSuggestionSplitButton() Return EndIf
Return spellWord()
EndFunction

Void Function SpellLine()
If SpellProofingPaneSuggestionSplitButton() Return EndIf
Return spellLine()
EndFunction

Script OpenListBox()
If IsPcCursor()
    If inRibbons() Then PerformScript OpenListBox() Return EndIf
    If GlobalMenuMode
    && !IsVirtualRibbonActive()
        TypeKey(cksAltDownArrow)
        Pause()
        SayFormattedMessageWithVoice(vctx_message, ot_status, cmsg41_L, cmsgSilent) ;open list box
        SayFormattedMessage(ot_text, getObjectValue()) ; only say the contents of the edit combo without the prompt
        Return
    ElIf WindowCategoryIsWordDocument()
        Var Int subtypeCode = c_WordFocus.ObjectSubType
        If IsFormField()
        && (subtypeCode == wt_comboBox
        || subtypeCode == wt_DateTime
        || subtypeCode ==wt_Menu)
            ; TypeKey being assigned To an alt combination seems To be problematic.
            ; While typeKey("alt+downArrow") should rightfully work, it seems that MSWord
            ; behaves differently when JAWS is running because even passKeyThrough doesn't
            ; work. We will Use the mouse instead.
            saveCursor()
            JAWSCursor()
            saveCursor()
            RouteJAWSToPc()
            LeftMouseButton()
            pause()
            restoreCursor() ; Restore the JAWS cursor
            restoreCursor() ; restore the original cursor.
        ElIf subtypeCode == wt_comboBox
        || subtypeCode == wt_DateTime
        || subtypeCode ==wt_Menu
            ; the case where the form field context flag is Not On.
            TypeKey(cksAltDownArrow)
        else
            PerformScript OpenListBox ()
        EndIf
        Return
    EndIf
EndIf
If c_WordFocus.InProofingPaneSpellCheck
    TypeKey(cksAltDownArrow)
    Pause()
    SayFormattedMessageWithVoice(vctx_message, ot_status, cmsg41_L, cmsgSilent) ;open list box
    Return
EndIf
PerformScript OpenListBox()
EndScript

Script CloseListBox()
If IsPcCursor()
    If inRibbons() Then PerformScript CloseListBox() Return EndIf
    If GlobalMenuMode
    && !IsVirtualRibbonActive()
        TypeKey(cksAltUpArrow)
        SayFormattedMessageWithVoice(vctx_message, ot_status, cmsg42_L, cmsgSilent) ;close list box
        Return
    ElIf WindowCategoryIsWordDocument()
        Var Int subtypeCode = c_WordFocus.ObjectSubType
        If IsFormField()
        && (subtypeCode == wt_comboBox
        || subtypeCode == wt_DateTime
        || subtypeCode ==wt_Menu)
            TypeKey(cksAltUpArrow)
        ElIf subtypeCode == wt_comboBox
        || subtypeCode == wt_DateTime
        || subtypeCode ==wt_Menu
            ; the case where the form field context flag is Not On.
            TypeKey(cksAltUpArrow)
        else
            PerformScript CloseListBox ()
        EndIf
        Return
    EndIf
EndIf
PerformScript CloseListBox()
EndScript

Script SayNextSentence()
If IsPCCursor()
&& !IsVirtualPCCursor()
    If (WindowCategoryIsWordDocument() && ActiveDocumentProtectionType() <= 0)
    || IsEmailMessage()
        SetDocumentCaretMovementType(Unit_Sentence_Next)
        NextSentence()
        Return
    EndIf
EndIf
PerformScript SayNextSentence()
EndScript

Script SayPriorSentence()
If IsPCCursor()
&& !IsVirtualPCCursor()
    If (WindowCategoryIsWordDocument() && ActiveDocumentProtectionType() <= 0)
    || IsEmailMessage()
        SetDocumentCaretMovementType(Unit_Sentence_Prior)
        PriorSentence()
        Return
    EndIf
EndIf
PerformScript SayPriorSentence()
EndScript

Script SayNextParagraph()
If SayAllInProgress()
    SetSayAllRestart()
EndIf
If quickNavKeyTrapping()
    If !WindowCategoryIsWordDocument()
        Return
    EndIf
EndIf
If isPCCursor()
&& !IsVirtualPCCursor()
    If (WindowCategoryIsWordDocument() && ActiveDocumentProtectionType() <= 0)
    || IsEmailMessage()
        If IsExtendedSelectionModeWatchActive()
            nSaySelectAfter = True
            SelectingText(True)
            typeKey(cksControlDownArrow)
            SelectingText(False)
            nSaySelectAfter = False
            Return
        EndIf
        If IncludeBlankParagraphsForParagraphNavigation()
            ;This navigation type is Not recognized by CaretMovedEvent,
            ;so add the extra parameter To SetDocumentCaretMovementType which will force the recognition of this movement:
            SetDocumentCaretMovementType(Unit_Paragraph_Next, Unit_Paragraph_Next)
            typeKey(cksControlDownArrow)
        else
            SetDocumentCaretMovementType(Unit_Paragraph_Next)
            NextParagraph()
        EndIf
        Return
    EndIf
EndIf
performScript sayNextParagraph()
EndScript

Script SayPriorParagraph()
If SayAllInProgress()
    SetSayAllRestart()
EndIf
If quickNavKeyTrapping()
    If c_WordFocus.windowCategory!= wCat_document
        Return
    EndIf
EndIf
If isPCCursor()
&& !IsVirtualPCCursor()
    If (c_WordFocus.windowCategory == wCat_document&& ActiveDocumentProtectionType() <= 0)
    || IsEmailMessage()
        If IsExtendedSelectionModeWatchActive()
            nSaySelectAfter = True
            SelectingText(True)
            typeKey(cksControlUpArrow)
            SelectingText(False)
            nSaySelectAfter = False
            Return
        EndIf
        If IncludeBlankParagraphsForParagraphNavigation()
            ;This navigation type is Not recognized by CaretMovedEvent,
            ;so add the extra parameter To SetDocumentCaretMovementType which will force the recognition of this movement:
            SetDocumentCaretMovementType(Unit_Paragraph_Prior, Unit_Paragraph_Prior)
            typeKey(cksControlUpArrow)
        else
            SetDocumentCaretMovementType(Unit_Paragraph_Prior)
            PriorParagraph()
        EndIf
        Return
    EndIf
EndIf
performScript sayPriorParagraph()
EndScript

Script NextItem()
If dialogActive()
    PerformScript NextDocumentWindowByPage()
    Return
EndIf
If !InDocument()
&& !DialogActive()
    IndicateControlType(wt_MDIClient, cscSpace, msgScrnSensitiveHelp1_s)
    Return
EndIf
If isPCCursor()
&& WindowCategoryIsWordDocument()
    If QuickNavKeyTrapping()
        SetFindItemToPage()
    EndIf
    Var String sMsg = FormatString(msgNextItem, GetFindItemTypeString())
    SayFormattedMessageWithVoice(vctx_message, ot_help, sMsg, cmsgSilent)
    If BrowserTargetIsPage()
        ;The PageSectionColumnChangedEvent Function will speak the line when the page actually changes.
        SetDocumentCaretMovementType(Unit_Page_Next)
        TypeKey(ksCtrlPageDown)
    else
        TypeKey(ksCtrlPageDown)
        delay(2, True)
        SayLine()
    EndIf
    Return
EndIf
PerformScript NextDocumentWindow()
EndScript

Script PreviousItem()
If dialogActive()
    PerformScript PreviousDocumentWindowByPage()
    Return
EndIf
If !InDocument()
&& !DialogActive()
    IndicateControlType(wt_MDIClient, cscSpace, msgScrnSensitiveHelp1_s)
    Return
EndIf
If IsPCCursor()
&& WindowCategoryIsWordDocument()
    If QuickNavKeyTrapping()
        SetFindItemToPage()
    EndIf
    Var String smsg=FormatString(msgPrevItem, GetFindItemTypeString())
    SayFormattedMessageWithVoice(vctx_message, ot_help, sMsg, cMsgSilent)
    If BrowserTargetIsPage()
        ;The PageSectionColumnChangedEvent Function will speak the line when the page actually changes.
        SetDocumentCaretMovementType(Unit_Page_Prior)
        TypeKey(ksCtrlPageUp)
    else
        TypeKey(ksCtrlPageUp)
        delay(2, True)
        SayLine()
    EndIf
    Return
EndIf
PerformScript PreviousDocumentWindow()
EndScript

Script TopOfFile()
If IsPCCursor()
&& !isVirtualPCCursor()
&& !InHJDialog()
&& WindowCategoryIsWordDocument()
&& !UserBufferIsActive()
    SetDocumentCaretMovementType(Unit_Line_First)
    JAWSTopOfFile()
    Return
EndIf
PerformScript TopOfFile()
EndScript

Script BottomOfFile()
If IsPCCursor()
&& !isVirtualPCCursor()
&& !InHJDialog()
&& WindowCategoryIsWordDocument()
&& !UserBufferIsActive()
    SetDocumentCaretMovementType(Unit_Line_Last)
    JAWSBottomOfFile()
    Return
EndIf
PerformScript BottomOfFile()
EndScript

Void Function SayWindowTitleForApplication(Handle hAppWnd, Handle hRealWnd, Handle hCurWnd, Int iTypeCode)
Var
    String sMessageShort,
    String sMessageLong,
    String sAppTitle,
    String sPaneTitle,
    String sDocView,
    Handle hWnd,
    String sClass
; Outlook already overrides this Function where it needs To, Then calls Word where it doesn't.
GetAppUIAWindowAndPaneTitles(sAppTitle, sPaneTitle)
If WindowCategoryIsWordDocument()
&& !OutlookIsActive()
    sDocView = GetActiveDocumentViewName()
    sMessageShort = FormatString(cMsg29_S, sAppTitle,
        FormatString(msgDocumentView_s, sDocView))
    sMessageLong = FormatString(cmsg29_L, sAppTitle,
        FormatString(msgDocumentView_l, sDocView))
ElIf (c_WordFocus.windowCategory!= WCAT_UNKNOWN && c_WordFocus.windowCategory!= WCAT_SPELL_CHECKER)
|| OnFileTabButton()
|| OnRibbonButton()
|| OnBackstageViewPane()
|| InNUIDialogWindow()
    If sPaneTitle
        sMessageShort = FormatString(cMsg29_S, sAppTitle, sPaneTitle)
        sMessageLong = FormatString(cmsg29_L, sAppTitle, sPaneTitle)
    EndIf
EndIf
If sMessageShort
|| sMessageLong
    SayFormattedMessage(ot_user_requested_information, sMessageLong, sMessageShort)
else
    SayWindowTitleForApplication(hAppWnd, hRealWnd, hCurWnd, iTypeCode)
EndIf
EndFunction

Script UpALevel()
If !IsWordDocumentActive()
    ;For handling active user buffer.
    ;Call down the stack, but do Not restrict the scope:
    performScript UpALevel()
    Return
EndIf
If UserBufferIsActive()
    performScript UpALevel()
    self::sayFocusedWindow()
    If QuickNavKeyTrapping()
    && c_WordFocus.WindowClass == wc_WordMainDocumentWindow
        SetQuickKeyNavigationState(1)
    EndIf
    Return
EndIf
SayCurrentScriptKeyLabel()
; isDropdown is used For special menu types Not recognised by menuModeEvent such as the Insert Table, Insert Excel worksheet and insert column menu buttons
Var Int isDropdown =(c_WordFocus.WindowClass ==wc_MSOCommandBar
        && globalMenuMode==menubar_active)
EscapeKey()
If c_WordFocus.WindowClass == wc_WordMainDocumentWindow
    If !isSelectionModeActive()
    && IsExtendedSelectionModeWatchActive()
        SayFormattedMessageWithVoice(vctx_message, ot_status, msgSelectionModeOff1_L, cmsgSilent)
        StopExtendedSelectionModeWatch()
    EndIf
EndIf
EndScript

Script WindowKeysHelp()
If UserBufferIsActive()
    UserBufferDeactivate()
EndIf
SayFormattedMessage(OT_USER_BUFFER, cmsgWindowKeysHelpOfficeQuickSearch+cscBufferNewLine+msgWinKeysHelp1_L,
    cmsgWindowKeysHelpOfficeQuickSearch+cscBufferNewLine+msgWinKeysHelp1_S)
UserBufferAddText(cscBufferNewLine+cmsgBuffExit)
EndScript

Int Function WinwordHotKeyHelp()
If !getRunningFSProducts() & product_JAWS
    Return
EndIf
Var String strPage
If c_WordFocus.RealWindowName == wn_TemplatesAndAddIns
    SayFormattedMessage(OT_USER_BUFFER, msgWHotKeyHelp1_L, msgWHotKeyHelp1_S)
    Return True
ElIf c_WordFocus.RealWindowName == wn_PageSetup
    strPage = GetDialogPageName()
    If strPage == wn_Margins
        SayFormattedMessage(OT_USER_BUFFER, msgWHotKeyHelp2_L, msgWHotKeyHelp2_S)
    ElIf strPage == wn_PaperSize
        SayFormattedMessage(OT_USER_BUFFER, msgWHotKeyHelp3_L, msgWHotKeyHelp3_S)
    ElIf strPage == wn_PaperSource
        SayFormattedMessage(OT_USER_BUFFER, msgWHotKeyHelp4_L, msgWHotKeyHelp4_S)
    ElIf strPage == wn_Layout
        SayFormattedMessage(OT_USER_BUFFER, msgWHotKeyHelp5_L, msgWHotKeyHelp5_S)
    EndIf
    Return True
ElIf c_WordFocus.RealWindowName == wn_InsertTable
    SayFormattedMessage(OT_USER_BUFFER, msgWHotKeyHelp6_L, msgWHotKeyHelp6_S)
    Return True
ElIf c_WordFocus.RealWindowName == wn_Formula
    SayFormattedMessage(OT_USER_BUFFER, msgWHotKeyHelp7_L, msgWHotKeyHelp7_S)
    Return True
ElIf c_WordFocus.RealWindowName == wn_Font
    strPage = GetDialogPageName()
    If strPage == wn_CharacterSpacing
        SayFormattedMessage(OT_USER_BUFFER, msgWHotKeyHelp8_L, msgWHotKeyHelp8_S)
    else
        SayFormattedMessage(OT_USER_BUFFER, msgWHotKeyHelp9_L, msgWHotKeyHelp9_S)
    EndIf
    Return True
ElIf c_WordFocus.RealWindowName ==wn_Open
    SayFormattedMessage(OT_USER_BUFFER, msgWHotKeyHelp10_L, msgWHotKeyHelp10_S)
    ; save as and open Use same msgs_L here
    SayFormattedMessage(OT_USER_BUFFER, msgWHotKeyHelp11_L, msgWHotKeyHelp11_S)
    Return True
ElIf c_WordFocus.RealWindowName ==wn_SaveAs
    SayFormattedMessage(OT_USER_BUFFER, msgWHotKeyHelp12_L, msgWHotKeyHelp12_S)
    SayFormattedMessage(OT_USER_BUFFER, msgWHotKeyHelp14_L, msgWHotKeyHelp14_S)
    SayFormattedMessage(OT_USER_BUFFER, msgWHotKeyHelp15_L, msgWHotKeyHelp15_S)
    Return True
ElIf stringContains(c_WordFocus.RealWindowName, wn_SpellingAndGrammar)
|| stringContains(c_WordFocus.RealWindowName, wn_Spelling)
    SayFormattedMessage(OT_USER_BUFFER, msgWHotkeyHelp16_L, msgWHotkeyHelp16_S)
    Return True
else
    Return False
EndIf
EndFunction

Script HotKeyHelp()
If TouchNavigationHotKeys()
|| !getRunningFSProducts() & product_JAWS
    Return
EndIf
If MenusActive()
|| inHjDialog()
    performScript HotKeyHelp()
    Return
EndIf
Var
    Handle hwnd,
    String sOwner
If UserBufferIsActive()
    UserBufferDeactivate()
EndIf
hwnd = GetFocus()
If WindowCategoryIsWordDocument()
&& quickNavState()
&& !isVirtualPcCursor()
    If IsWordDocumentActive()
        SayFormattedMessage(ot_user_buffer, msgOutlookQuickKeys)
    else
        SayFormattedMessage(ot_user_buffer, msgQuickKeys)
    EndIf
    UserBufferAddText(cScBufferNewLine)
EndIf
If stringContains(c_WordFocus.RealWindowName, wn_SpellingAndGrammar)
|| stringContains(c_WordFocus.RealWindowName, wn_Spelling)
    SayFormattedMessage(OT_USER_BUFFER, msgJHotkeyHelp1_L, msgJHotkeyHelp1_S)
    UserBufferAddText(cScBufferNewLine)
    WinwordHotKeyHelp()
    UserBufferAddText(cscBufferNewLine+cmsgBuffexit)
    Return
EndIf
;For Outlook email Messages:
;Want To display keys that relate To header fields.
sOwner = GetWindowOwner(hwnd)
If StringContains(StringSegment(sOwner, cscDoubleBackSlash, StringSegmentCount(sOwner, cscDoubleBackslash)), an_envelope)
    SayFormattedMessage(OT_USER_BUFFER, msgHotKeyHelpEmailMessageCompose)
    AddHotKeyLinks()
    Return
EndIf
If OutlookIsActive()
    SayFormattedMessage(OT_USER_BUFFER, msgOutlookHotkeyHelp+cscBufferNewLine)
    AddAskFSCompanionHotKeyLink()
    UserBufferAddText(cscBufferNewLine+cMsgBuffExit)
    Return
EndIf
If isOutlineViewActive()
    SayFormattedMessage(OT_USER_BUFFER, msgJHotkeyHelpOutline+cscBufferNewLine)
EndIf
SayFormattedMessage(OT_USER_BUFFER, msgJHotkeyHelp3_L+cScBufferNewLine)
AddAskFSCompanionHotKeyLink()
SayMessage(OT_USER_BUFFER, cscBufferNewLine+cmsgBuffexit)
EndScript

Script ScreenSensitiveHelp()
If !getRunningFSProducts() & product_JAWS
    Return
EndIf
If IsSameScript()
    AppFileTopic(topic_Microsoft_Word)
    Return
EndIf
If UserBufferIsActive()
    UserBufferDeactivate()
    SayFormattedMessage(OT_USER_BUFFER, cMsgScreenSensitiveHelpBuf)
    Return
EndIf
If UsingShortNameOfMultiLevelListObject()
    SayFormattedMessage(OT_USER_BUFFER, GetObjectName())
    Return
EndIf
If ScreenSensitiveHelpForOffice()
    Return
EndIf
Var
    Handle WinHandle,
    String TheClass,
    Int CId
WinHandle = GetCurrentWindow()
TheClass = GetWindowClass(WinHandle)
If theClass == wc_wwf
    SayFormattedMessage(OT_USER_BUFFER, msgScrnSensitiveHelp1_L, msgScrnSensitiveHelp1_S)
    Return
ElIf WindowCategoryIsWordDocument()
    If IsActiveCursorOnMathContent()
        sayMessage(OT_USER_BUFFER, msgMathContentScreenSensitiveHelp)
    else
        sayDocumentWindowHelp()
    EndIf
    Return
EndIf
If theClass == wcF3Server
    ; we are focused On an inline shape.
    UserBufferClear()
    UserBufferActivate()
    sayInlineShapeHelp() ; change To user buffer add of the get String
    JAWSTopOfFile()
    SayAll(False)
    Return
EndIf
If StringContains(GetObjectName(), scBallon) ; help balloon
    SayFormattedMessage(ot_user_buffer, msgInformationBalloonScrnSensitiveHelp_l, msgInformationBalloonScrnSensitiveHelp_s)
    Return
ElIf IsExtendedSelectionModeWatchActive()
&& stringContains(c_WordFocus.RealWindowName, wn_FindAndReplace)
    If GetSelectedCharCount()
        SayFormattedMessage(OT_USER_BUFFER, FormatString(msgExtSelModeFindHelp1_L, GetSelectionInfo()))
    else ;nothing is selected
        SayFormattedMessage(OT_USER_BUFFER, msgExtSelModeFindHelp2_L)
    EndIf
    Return
EndIf
If !inOptionsDialog(winHandle)
    If GlobalMenuMode == MENUBAR_ACTIVE
        SayFormattedMessage(OT_USER_BUFFER, msgScrnSensitiveHelp4_L, msgScrnSensitiveHelp4_S)
        Return
    EndIf
EndIf
If GlobalMenuMode == MENU_ACTIVE
    self::ScreenSensitiveHelpForKnownClasses(wt_menu)
    Return
EndIf
PerformScript ScreenSensitiveHelp()
EndScript

String Function GetCustomTutorMessage()
If !getRunningFSProducts() & product_JAWS
    Return cscNull
EndIf
Var
    Handle hwnd,
    Int iObjType,
    String sClass,
    Int iWinType,
    String sObjName,
    Int iState,
    String sValue
hwnd = GetFocus()
Var Int typeCode = getObjectTypeCode(True) ; For edit fields
If OnEditFieldWithSuggestion()
    Return msgSpellCheckSentenceTutor
EndIf
If isResearchToolbar(hwnd)
    Return self::GetCustomTutorMessage()
EndIf
iObjType = c_WordFocus.ObjectSubType
sClass = c_WordFocus.WindowClass
iWinType = c_WordFocus.WindowSubtype
If StringContains(GetObjectName(), scBallon)
    Return msgInformationBalloonTutorHelp
ElIf globalMenuMode
&& iObjType == wt_combobox
&& iWinType == wt_Edit
    Return msgScreenSensitiveHelpEditCombo
ElIf isStatusBarToolBar()
    sObjName=GetObjectName()
    If sObjName == wn_PageNumber
        GetObjectInfoByName(hWnd, sObjName, 1, iObjType, iState, sValue)
        Return sValue+cscSpace+self::GetCustomTutorMessage()
    ElIf sObjName == WN_WordCount
        GetObjectInfoByName(hWnd, sObjName, 1, iObjType, iState, sValue)
        Return sValue+cscSpace+self::GetCustomTutorMessage()
    EndIf
    Return self::GetCustomTutorMessage()
Else
    Return self::GetCustomTutorMessage()
EndIf
EndFunction

String Function GetBasicLayerHelpTextMSWord()
Var
    String sHeading,
    String sMsg
sHeading = MarkupLayerHelpSectionTextAsHeading(msgBasicLayerHelpScreen_Heading_MSWord)
sMsg = ConvertTextToLinesWithHTMLLineBreak(msgBasicLayerHelpScreen_MSWord)
Return sHeading+"<br/>"+sMsg+"<br/>"
EndFunction

String Function GetBasicLayerHelpScreenText()
Return GetBasicLayerHelpTextMSWord()
    +GetBasicLayerHelpTextGeneral()
    +GetBasicLayerHelpTextMessaging()
    +GetBasicLayerHelpTextSecondaryLayer()
EndFunction

Int Function DoAcceleratorsForSuggestionsGroup(Object UIA, String keyName, Object group)
If !group Return False EndIf
If keyName != ksChange && keyName != ksChangeAll Return False EndIf
Var Object tmp = group.findAll(TREESCOPE_Children, UIA.CreateRawViewCondition())
If tmp.count == 1
&& tmp(0).ClassName == "NetUIGroupHeader"
    sayMessage(OT_ERROR, msgNoSuggestions1_L)
    Return
EndIf
If keyName == ksChangeAll
    sayMessage(OT_ERROR, msgChangeAllError)
    Return True
EndIf
If c_WordFocus.ObjectSubType == WT_SPLITBUTTON
    enterKey()
    Return True
EndIf
Var Object condition = FSUIACreateIntPropertyCondition(UIA_ControlTypePropertyId, UIA_SplitButtonControlTypeId)
If !condition Return False EndIf
Var Object element = group.findFirst(TREESCOPE_SUBTREE, condition)
If !element Return False EndIf
Var Object pattern = element.GetInvokePattern()
If !pattern Return False EndIf
If !pattern.Invoke() Return False EndIf
oSuggestionSplitButton = null()
If getObjectTypeCode() == WT_EDIT
    ; User pressed one of these buttons in the Current Sentence read-only edit box.
    oSuggestionSplitButton = null()
EndIf
Return True
EndFunction

Int Function doAcceleratorsForOtherActionsGroup(String keyName, Object group)
If !group Return False EndIf
If keyName != ksAddToDictionary
&& keyName != ksIgnore
&& keyName != ksIgnoreAll
    Return False
EndIf
Var Object condition = FSUIACreateIntPropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
If !condition Return False EndIf
Var Object buttons = group.findAll(TREESCOPE_SUBTREE, condition)
If !buttons.count Return False EndIf
Var Object element
If keyName == ksIgnore
    element = buttons(0)
ElIf keyName == ksIgnoreAll
    element = buttons(1)
ElIf keyName == ksAddToDictionary
    element = buttons(2)
EndIf
If !element || !element.isEnabled Return False EndIf
Var Object pattern = element.GetInvokePattern()
If !pattern Return False EndIf
If !pattern.Invoke()
    pattern = element.GetLegacyIAccessiblePattern()
    If pattern.defaultAction
        pattern.doDefaultAction()
    else
        Return False ; no action was taken On button, Let default keystroke pass through.
    EndIf
EndIf
If getObjectTypeCode() == WT_EDIT
    ; User pressed one of these buttons in the Current Sentence read-only edit box.
    oSuggestionSplitButton = null()
EndIf
Return True
EndFunction

Int Function doAcceleratorsForSpellCheckerWithSplitButtons(String keyName)
Var Object UIA = CreateObjectEx("FreedomSci.UIA", 0, "UIAScriptAPI.x.manifest" )
If !UIA Return False EndIf
Var Object focusElement = UIA.GetFocusedElement().buildUpdatedCache()
If !focusElement Return False EndIf
Var Object treewalker = UIA.RawViewWalker()
If !treewalker Return False EndIf
treewalker.currentElement = focusElement
Var
    Object notInDictionaryGroup,
    Object suggestionsGroup,
    Object otherActionsGroup
If !getControlGroupsForSpellCheckerWithSplitButtons(UIA, treewalker,
        notInDictionaryGroup, suggestionsGroup, otherActionsGroup)
    Return False
EndIf
If keyName == ksChange || keyName == ksChangeAll
    Return DoAcceleratorsForSuggestionsGroup(UIA, keyName, suggestionsGroup)
ElIf keyName == ksAddToDictionary || keyName == ksIgnore || keyName == ksIgnoreAll
    Return doAcceleratorsForOtherActionsGroup(keyName, otherActionsGroup)
EndIf
Return False
EndFunction

Script SpellCheckAccelerators()
Var String keyName = stringLower(getCurrentScriptKeyName())
;For all accelerators from within Spellcheck dialog such as Change, Ignore, Change All, Ignore All, etc.
SayCurrentScriptKeyLabel()
If c_WordFocus.InProofingPaneSpellCheckWithSplitButtons
    If doAcceleratorsForSpellCheckerWithSplitButtons(keyName)
        Return
    EndIf
EndIf
typeCurrentScriptKey()
If c_WordFocus.windowCategory == WCAT_TASK_PANE
&& c_WordFocus.ObjectSubType == WT_BUTTON
    If c_WordFocus.InProofingPaneSpellCheck
        ;These accelerators don't work, so need To speak a message To that effect:
        sayMessage(OT_ERROR, msgProofingAcceleratorsNotAvailable)
    EndIf
EndIf
EndScript

String Function GetHeaderForNewAddressListField ()
Var
    Object oElement,
    Object oHeaderItemCondition,
    Object oHeaderItem,
    Object oHeaderItems,
    Object oRealWindow,
    Int iHeaderXCoordinate,
    Int iHeaderYCoordinate,
    Int x,
    Int y
oRealWindow = FSUIAGetElementFromHandle (GetRealWindow (GetCurrentWindow ()))
oElement = FSUIAGetFocusedElement ()
oHeaderItemCondition = FSUIACreateIntPropertyCondition (UIA_ControlTypePropertyId, UIA_HeaderItemControlTypeId)
oHeaderItems = oRealWindow.findAll(TreeScope_Descendants, OHeaderItemCondition)
oHeaderItem = GetFirstObjectWithClickablePoint (oHeaderItems)
oElement.GetClickablePoint( intRef(x), intRef(y))
oHeaderItem.GetClickablePoint(intRef(iHeaderXCoordinate), intRef(iHeaderYCoordinate))
oHeaderItem = FSUIAGetElementFromPoint (x, iHeaderYCoordinate)
Return oHeaderItem.name
EndFunction

Object Function GetFirstObjectWithClickablePoint (Object oArray)
Var
    Object oElement,
    Int x,
    Int y
ForEach oElement in oArray
    oElement.GetClickablePoint(intRef(x), intRef(y))
    If x != 0
    && y != 0
        Return oElement
    EndIf
EndForEach
Return Null()
EndFunction

Script SpeakPlaceMarkers()
If c_WordFocus.windowCategory == WCAT_DOCUMENT
&& isPCCursor()
    performScript ReturnToMarkedPlace()
    else
    performScript SpeakPlaceMarkers()
    EndIf
EndScript

Int Function ShouldIncludeView(String viewName)
If stringLeft(viewName, 11) == cWordPerfectPrefixJBSBase Then
    Return False
EndIf
If viewName == cWordClassicJBSBase Then
    Return False
EndIf

Return True
EndFunction

Script PictureSmartWithControl (optional Int serviceOptions)
Var Int forceCursor = c_WordFocus.IsWordDocumentActive > 0
PictureSmartWithControlCommon (PSServiceOptions_Single | serviceOptions, forceCursor)
EndScript

Script PictureSmartWithControlMultiService (optional Int serviceOptions)
Var Int forceCursor = c_WordFocus.IsWordDocumentActive > 0
PictureSmartWithControlCommon (PSServiceOptions_Multi | serviceOptions, forceCursor)
EndScript

Int Function InEmptyCopilotEditWithSuggestions()
If GetObjectAutomationId(0) != AutomationID_COPILOT_PROMPT
    && !StringIsBlank(GetObjectValue ())
    Return False
EndIf
    
Var Object menu
menu = FSUIAGetFocusedElement().ControllerFor(0)
If !menu
    Return False
EndIf

Return True
EndFunction

Int Function ShouldIgnoreSaySecondaryFocusSelectedItem()
If InEmptyCopilotEditWithSuggestions() Then
    Return False
EndIf

Return ShouldIgnoreSaySecondaryFocusSelectedItem()
EndFunction

Void Function SpeakSuggestionsAvailable()
If !InEmptyCopilotEditWithSuggestions()
    Return
EndIf
    
Var String text = GetSecondaryFocusSelectionText()
If !text Then
    SayUsingVoice (VCTX_MESSAGE, msgSuggestionsAvailable, OT_line)
EndIf
EndFunction