ZoomSoftware.jss
JAWS Script Language -- Complete ZoomSoftware.jss file
; Basic Scripts For the Zoom Conferencing Client.
; Prepared and updated by Brian Hartgen, Hartgen Consultancy, 27 January 2022.
; Tested against Zoom Meetings Version 5, 9, 3, 3169
; JAWS version 2022.2201.54
; New comments preceeded by a double at sign.
Include "hjconst.jsh" ; default constants, also includes HjIni.jsh For default section and key names
Include "hjglobal.jsh"
Include "MSAAConst.jsh"
Include "common.jsm"
Include "ZoomSoftware.jsm"
Import "Say.jsd"
Const
ZoomNotificationWindowClass = "zoom_acc_notify_wnd",
ZoomSchedulerComboBoxClass = "ZPWndSchedulerClass",
ZoomSettingsComboBoxClass = "ZPSettingWndClass",
ZoomChatClass = "ZPPTMainFrmWndClassEx"
Globals
Int ZoomFirstTime, ; because we're Not storing settings any longer.
Collection customBrailleComboBoxData,
Int zUseTypeKey,
String zRepeat,
Int ZAlert,
String zNotificationOutput,
Int zChat,
String SSpeakerName,
Int HasSpokenCategory,
Int Participants,
String ObjectName,
String PrevListOutput,
Int Line,
String ListOutput,
String zSText,
Int focusInChatEdit
; @@ For Notification Manager exclusions.
; For forcing refresh when MSAA alerts are received:
; We don't receive any events For some buttons where the name changes when the buttons is pressed To toggles something, one example is the Mute button in meetings.
; We will Use the MSAAAlertEvent as a trigger To attempt To detect a name change For these buttons by performing an MSAARefresh.
; But, performing an MSAARefresh now may cause both a focusChangedEvent and a NameChangedEvent, and this together with the MSAA alert announcement results in too many speech announcements.
; In cases where an alert is received immediately after a key press On a button, we do Not allow the MSAAAlertEvent code To continue processing but instead start watching For other events--focus change and name change.
; In the NameChangedEvent, If this event occurs within the time limit of the watch, and If the name change matches the button name,
; we tell the watcher that the NameChangedEvent code did the speaking;
; otherwise, the NameChangedEvent code will process as usual but will Not tell the event watcher that the desired speech output occurred.
; In FocusChangedEvent, If the watch For extra events is active and the focus did Not change,
; we assume that this focus change should be ignored and we do Not Handle speech output here.
; Finally, If the watch time expires and no events were detected To Handle the speech For the MSAAAlertEvent, we call the MSAAAlertEvent helper Function To process the alert which we would have ignored If some other event handled speaking it.
Const
MSAAAlertSinceKeyPressMaxTime = 200 ;maximum number of ticks For associating an MSAA alert with being caused by a key press
Globals
Int ConcludeWaitingForExtraEventsFromRefreshID, ;the schedule id of the Function ConcludeWaitingForExtraEventsFromRefreshID,
;which was set because we believe that an MSAA alert indicates that a button needs an MSAA refresh.
;The MSAARefresh will trigger other events, which we want To watch For and Handle For this special case.
; See functions: IsWaitingOnExtraEventsFromRefresh, MarkSpeechAsHandledInExtraEventFromRefresh, ConcludeWaitingForExtraEventsFromRefresh, MSAAAlertEvent, NameChangedEvent, FocusChangedEvent.
Int CountOfExtraEventsSinceRefresh, ;Used To determine If events likely caused by MSAARefresh are fired.
Collection ZoomDelayedMSAAAlertEventData ; Holds the params passed To MSAAAlertEvent, so that the event helper can be fired If needed when the watch For events expires.
Void Function AutoStartEvent ()
focusInChatEdit = False
Var String JAWSLanguage = stringLower (GetJFWLang ())
; preserve {} functionality For English users who potentially Use Dragon.
zUseTypeKey = (JAWSLanguage != "enu")
ShowSoundMixerDiscoveryDialog()
EndFunction
Void Function LoadNonJCFOptions ()
; Load preferences.
; @@ Older code commented out in the event there is a strategy change later down the road. But For now, we're Not retaining preferences.
; @@ When we restart JAWS, we must enable all alerts. Otherwise, keep the user's preference even when switching out of Zoom and back.
If ZoomFirstTime == 0 Then
Let ZoomFirstTime = 1
ZAlert = 1 ; @@ We only want To set it To a value of 1 If JAWS is restarted.
; For now, we don't want this as it stores a preference.
; ZAlert = getNonJCFOption ("ZAlert")
Let zChat = 0
; For now, we don't want this as it stores a preference.
; zChat = getNonJCFOption ("Chat")
EndIf ; End of Zoom first time run.
LoadNonJCFOptions () ; defaults
EndFunction
; To accompany Script To remind users as To what they've got.
Function SettingsReminder ()
If ZAlert== 0 Then
SayUsingVoice (VCTX_Message, MSGAlertsDisabled, ot_user_requested_information)
else
SayUsingVoice (VCTX_Message, MSGAlertsEnabled, ot_user_requested_information)
EndIf
If zChat == 1 Then
SayUsingVoice (VCTX_Message, MSGExtendedChat, ot_user_requested_information)
else
SayUsingVoice (VCTX_Message, MSGExtendedAlerts, ot_user_requested_information)
EndIf
EndFunction
Int Function IsWaitingOnExtraEventsFromRefresh()
Return ConcludeWaitingForExtraEventsFromRefreshID != 0
EndFunction
Void Function MarkSpeechAsHandledInExtraEventFromRefresh()
CountOfExtraEventsSinceRefresh = CountOfExtraEventsSinceRefresh + 1
EndFunction
Void Function CancelWaitingForExtraEventsFromRefresh()
If ConcludeWaitingForExtraEventsFromRefreshID
UnScheduleFunction (ConcludeWaitingForExtraEventsFromRefreshID)
ConcludeWaitingForExtraEventsFromRefreshID = 0
CollectionRemoveAll(ZoomDelayedMSAAAlertEventData)
CountOfExtraEventsSinceRefresh = 0
EndIf
EndFunction
Void Function ConcludeWaitingForExtraEventsFromRefresh()
ConcludeWaitingForExtraEventsFromRefreshID = 0
If !CountOfExtraEventsSinceRefresh
;We did Not detect any events where speech output was handled, so pass On the data recieved by MSAAAlertEvent To its handler:
MSAAAlertEventHelper(ZoomDelayedMSAAAlertEventData.hwnd, ZoomDelayedMSAAAlertEventData.nTime, ZoomDelayedMSAAAlertEventData.SText, ZoomDelayedMSAAAlertEventData.nAlertLevel, ZoomDelayedMSAAAlertEventData.appName)
CollectionRemoveAll(ZoomDelayedMSAAAlertEventData)
Return
EndIf
CountOfExtraEventsSinceRefresh = 0
; We assume whatever desired announcement was handled in one of the extra events.
EndFunction
Void Function MSAAAlertEvent(Handle hwnd, Int nTime, String SText, Int nAlertLevel, String appName)
If getWindowClass (hwnd) != ZoomNotificationWindowClass Then; Not a Zoom Alert.
Return MSAAAlertEvent (hwnd, nTime, SText, nAlertLevel, appName)
EndIf ; End of default Alert.
; See comment For forcing refresh when MSAA alerts are received:
If GetObjectRole() == role_system_PushButton
&& GetTickCount()-GetLastKeyPressTime() <= MSAAAlertSinceKeyPressMaxTime
If !ZoomDelayedMSAAAlertEventData ZoomDelayedMSAAAlertEventData = New Collection EndIf
ZoomDelayedMSAAAlertEventData.hwnd = hwnd
ZoomDelayedMSAAAlertEventData.nTime = nTime
ZoomDelayedMSAAAlertEventData.SText = SText
ZoomDelayedMSAAAlertEventData.nAlertLevel = nAlertLevel
ZoomDelayedMSAAAlertEventData.appName = appName
ConcludeWaitingForExtraEventsFromRefreshID = ScheduleFunction("ConcludeWaitingForExtraEventsFromRefresh", 10)
MSAARefresh()
Return
EndIf
MSAAAlertEventHelper(hwnd, nTime, SText, nAlertLevel, appName)
EndFunction
Void Function MSAAAlertEventHelper(Handle hwnd, Int nTime, String SText, Int nAlertLevel, String appName)
Var
String sMsgLong,
String sMsgShort;
Let sMsgLong = SText
; Process the alerts and chats.
Let ZRepeat = SText ; Store the Alert For processing and output.
If StringContains (SText, MSGBandwidth) Then ; For when Zoom erroneously reports bandwidth is low
Return
EndIf
; Are we recording or is recording paused?
; Because synthetic speech announcing the recording status is now automatically transmitted To audience participants, we only need To say this If all alerts are enabled; If the user has specifically requested it, otherwise it is overbaring.
If ZAlert == 1 Then ; Alerts are enabled
If StringContains (SText, MSGRecord)
|| StringContains (SText, MSGPause) Then
; Change speech Messages. There is Braille output with this type.
; @@ For Notifications Manager.
Var Collection NotificationRuleActions = ProcessNotification(sText, appName)
SayNotification (notificationRuleActions, ot_help)
If !notificationRuleActions.ExcludeFromNotificationHistory Then
storeSpokenNotificationForRepeat (SText, appName) ; For New insert+Space&N keystroke.
EndIf
; @@ End of Notifications Manager
Return
EndIf ; Whether the user wants To hear this.
EndIf ; End of anything related To recording.
; Talking requires special handling.
If StringContains (SText, MSGTalking) Then ; Is the placeholder vacant or is someone actually talking.
Let SSpeakerName = SText
ProcessNameOfSpeaker () ; separate Function To ensure this is less cluttered.
Return
EndIf ; end of someone talking.
; User preference For incoming Messages.
If ZChat == 1 Then ; Chat Messages only are required.
SpeakMessagesOnly ()
Return
EndIf ; end of user preference For chat Messages.
If StringIsBlank (zNotificationOutput) Then ; we have nothing.
Let zNotificationOutput = ZRepeat
else ; add it To what we've got.
Let zNotificationOutput = zNotificationOutput+"|"+ZRepeat
EndIf ; end of notification capture.
; If we've got this far and the user wants To hear Alerts Then send them To output.
If ZAlert == 1 Then
; Change speech Messages. There is Braille output with this type.
; @@ For Notifications Manager
notificationRuleActions = ProcessNotification(zRepeat, appName)
SayNotification (notificationRuleActions, ot_help)
; We don't want To save chat Messages, or alerts excluded from history by the user
If !NotificationRuleActions.ExcludeFromNotificationHistory && (!StringStartsWith(zRepeat, scChatMessageIndicator) && !StringStartsWith(zRepeat, scPersonalChatMessageIndicator)) Then
StoreSpokenNotificationForRepeat(zRepeat, appName)
EndIf
; @@ End of Notifications Manager
EndIf ; end of Alert notifications If the user has selected them.
EndFunction
; special handling For speaker names.
Function ProcessNameOfSpeaker ()
Let SSpeakerName = StringTrimTrailingBlanks (SSpeakerName); avoid trailing space.
; StringsEqual is no longer necessary.
If SSpeakerName == MSGTalking Then ; Zoom has Not detected a speaker.
SayUsingVoice (VCTX_Message, MSGSpeakerNotDetected, ot_user_requested_information)
else ; we have a speaker but the word Talking is unnecessary.
Let SSpeakerName = StringReplaceSubstrings (SSpeakerName , MSGTalking, " ")
Let SSpeakerName = StringTrimLeadingBlanks (SSpeakerName) ; clean output.
; Change speech Messages. There is Braille output with this type.
SayFormattedMessage (ot_help, SSpeakerName, SSpeakerName)
EndIf ; end of whether we have legitimate name.
EndFunction
Void Function SpeakMessagesOnly ()
If StringStartsWith(zRepeat, scChatMessageIndicator) Then ; we want it If the user has selected chat only.
If StringIsBlank (zNotificationOutput) Then ; we've got nothing so far.
Let zNotificationOutput = zRepeat
else ; add it To what we've got.
Let zNotificationOutput = zNotificationOutput+"|"+zRepeat
EndIf ; end of whether we have a chat message.
; Change speech Messages. There is Braille output with this type.
SayFormattedMessage (ot_help, ZRepeat, ZRepeat)
EndIf ; whether the Alert contains a chat.
EndFunction
; older code For the time being.
Script SayAlert ()
If StringIsBlank (zRepeat) Then
sayMessage (OT_ERROR, MSGNoAlertsAvailable)
else
SayMessage (OT_USER_REQUESTED_INFORMATION, zRepeat)
EndIf
EndScript
Script ToggleAlerts ()
; @@ New For January 2022.
If ZAlert== 0 Then
Let ZAlert= 1
SayUsingVoice (VCTX_Message, MSGAlertsEnabled, OT_STATUS)
else
Let ZAlert= 0
SayUsingVoice (VCTX_Message, MSGAlertsDisabled, OT_STATUS)
EndIf
; @@ We're Not retaining this For now.
; WriteSettingInteger (Section_NonJCFOptions, "ZAlert", ZAlert, FT_CURRENT_JCF)
EndScript
Script ToggleChatMessages ()
If zChat == 0 Then
Let zChat = 1
SayUsingVoice (VCTX_Message, MSGExtendedChat, ot_user_requested_information)
else
Let zChat = 0
SayUsingVoice (VCTX_Message, MSGExtendedAlerts, ot_user_requested_information)
EndIf
; @@ We're Not retaining this For now.
; WriteSettingInteger (Section_NonJCFOptions, "Chat", zChat, FT_CURRENT_JCF)
EndScript
Void Function SayAlertInfo ()
; A regular alert is produced here so If the user has disabled these we should ignore the request.
If ZAlert== 0 Then
Say (zRepeat, OT_USER_REQUESTED_INFORMATION)
EndIf
EndFunction
Script ScriptFileName()
ScriptAndAppNames (msgAppName)
EndScript
Script HotkeyHelp ()
If UserBufferIsActive () Then
UserBufferDeactivate ()
EndIf
UserBufferClear ()
SayFormattedMessage (Ot_User_Buffer, MSGHotkeyHelp+cscBufferNewLine+cscBufferNewLine)
SayFormattedMessage (Ot_User_Buffer, MSGPressEscape)
EndScript
Void Function sayZoomNotification (Int notificationNumber)
; we're doing stringSegments from the right, so subtract from 0 To make it a negative number
notificationNumber = (0-notificationNumber)
Var
String output
Let output = StringSegment (zNotificationOutput, "|", notificationNumber)
If StringIsBlank (output) Then
sayMessage (OT_ERROR, MSGNoAlertsAvailable)
Return
EndIf
If IsSameScript () Then
SayFormattedMessage (Ot_User_Buffer, output)
SayFormattedMessage (Ot_User_Buffer, MSGPressEscape)
else
Say (output, OT_USER_REQUESTED_INFORMATION)
EndIf
EndFunction
Script SayNotification1 ()
sayZoomNotification (1)
EndScript
Script SayNotification2 ()
sayZoomNotification (2)
EndScript
Script SayNotification3 ()
sayZoomNotification (3)
EndScript
Script SayNotification4 ()
sayZoomNotification (4)
EndScript
Script SayNotification5 ()
sayZoomNotification (5)
EndScript
Script SayNotification6 ()
sayZoomNotification (6)
EndScript
Script SayNotification7 ()
sayZoomNotification (7)
EndScript
Script SayNotification8 ()
sayZoomNotification (8)
EndScript
Script SayNotification9 ()
sayZoomNotification (9)
EndScript
Script SayNotification10 ()
sayZoomNotification (10)
EndScript
; Detect Participants List.
Function IsParticipantsList ()
Var
Handle grip,
String SParticipants
Let grip = GetFocus ()
Let SParticipants = GetWindowName (grip)
If StringContains (SParticipants, MSGParticipant)
|| StringContains (SParticipants, MSGAttendee) Then ; this is the correct area but is it the List Box?
If GetObjectType ()== "list box item" Then ; this is the Participants List.
Return True
else
Return False
EndIf
EndIf
EndFunction
Function IsChatList ()
Var
Handle grip,
String SChats
Let grip = GetFocus ()
Let SChats= GetWindowName (grip)
If StringContains (SChats, MSGChat)
&& GetObjectType ()== "list box item" Then ; this is the Chat List.
Return True
else
Return False
EndIf
EndFunction
Void Function focusChangedEvent(Handle hwnd, Handle hwndPrev)
; Suppress unwanted speech, temporary measure.
If hwnd == hwndPrev
If focusInChatEdit && IsFocusInChatEdit()
Return
ElIf IsWaitingOnExtraEventsFromRefresh()
Return
EndIf
EndIf
focusInChatEdit = IsFocusInChatEdit()
If IsParticipantsList ()
|| IsChatList () Then
Return
EndIf
; Default.
focusChangedEvent(hwnd, hwndPrev)
EndFunction
Int Function handleCustomWindows (Handle FocusWindow)
Var
Handle realWindow,
Int type,
String realWindowName,
String SObjectName,
String output,
Int WindowHierarchyX,
; For SayControlEX Function:
String controlName,
String controlType = getObjectType (),
String controlValue
customBrailleComboBoxData = New Collection ; clear previously cached combo items
type = getObjectSubtypeCode ()
; identify the various controls
realWindow = GetRealWindow (focusWindow)
realWindowName = GetWindowName (realWindow)
WindowHierarchyX = GetWindowHierarchyX (focusWindow)
; Is this the Settings dialog?
If type == WT_LISTBOXITEM
&& RealWindowName == MSGSettings Then ; it is the Settings List Box.
If HasSpokenCategory == 0 Then ; speak the prompt To Let the user know the location.
SayUsingVoice (VCTX_Message, MSGCategoryList, Ot_User_Requested_Information)
EndIf ; End of whether we should say the prompt.
Let HasSpokenCategory = 1 ; Set the flag so we don't say it again.
else
Let HasSpokenCategory = 0 ; We can say the prompt now.
EndIf ; End of Settings List Box.
If GetObjectName(SOURCE_CACHED_DATA, 0)== MSGScreenShare Then ; Screen share is active but there is no focus.
PerformScript Tab ()
Return
EndIf ; end of screen share.
If type != WT_COMBOBOX
; outside of meeting scheduler or Not On troublesome combo boxes.
Return handleCustomWindows (focusWindow)
EndIf
Var String objectClassName = getObjectClassName ()
If WindowHierarchyX == 1 Then
controlName = MSGDate
controlValue = GetObjectValue(SOURCE_CACHED_DATA)
ElIf WindowHierarchyX == 2 Then
controlName = MSGTime
controlValue = GetObjectValue(SOURCE_CACHED_DATA)
ElIf WindowHierarchyX == 3 Then
controlName = MSGHours
controlValue = GetObjectValue(SOURCE_CACHED_DATA)
ElIf WindowHierarchyX == 4 Then
controlName = MSGMinutes
controlValue = GetObjectValue(SOURCE_CACHED_DATA)
ElIf objectClassName == ZoomSchedulerComboBoxClass
|| objectClassName == ZoomSettingsComboBoxClass Then
getDataFromCustomComboBoxes (controlName, controlValue)
EndIf ; end of timezone
If stringIsBlank (controlName) Then
Return handleCustomWindows (focusWindow)
EndIf
; just For code readability, the following variables are empty:
Var String controlState, String containerName, String containerType;
sayControlEX (focusWindow, controlName, controlType, controlState, containerName, containerType, controlValue)
Return True
EndFunction
Void Function getDataFromCustomComboBoxes (String byRef name, String byRef value)
Var String text = getObjectName ()
If ! stringContains (text, "(") && ! stringContains (text, ")") Then
name = text
value = getObjectValue (SOURCE_CACHED_DATA)
Return
EndIf
name = stringSegment (text, "(", 1)
text = stringChopLeft (text, stringLength (name))
value = stringSegment (text, ")", 1)+")"
name = stringTrimTrailingBlanks (name)
value = stringTrimLeadingBlanks (value)
; Now remove extra content from Name component by substituting:
If stringContains (name, wnTimeZone) Then
name = msgTimeZone
ElIf StringContains (name, wnMicrophone) Then
name = msgMicrophone
ElIf stringContains (name, wnSpeakers) Then
name = msgSpeakers
EndIf
EndFunction
Int Function BrailleCallbackObjectIdentify ()
Var
Int typeCode = getObjectTypeCode (),
String objectClassName = getObjectClassName (),
String controlName, String controlValue
If typeCode == WT_DIALOG Then
; could be dialog or dialog page:
Return WT_STATIC
ElIf ! typeCode && getObjectClassName () == "ZPFTEWndClass" Then
; a static whose name is relevant:
Return WT_STATIC
EndIf
If objectClassName == ZoomSchedulerComboBoxClass
|| objectClassName == ZoomSettingsComboBoxClass Then
; can't automatically pass Collection items into a param, so Use the local variables first:
getDataFromCustomComboBoxes (controlName, controlValue)
customBrailleComboBoxData.controlName = controlName
customBrailleComboBoxData.ControlValue = controlValue
EndIf
If (focusInChatEdit)
Return WT_EDIT
EndIf
Return BrailleCallbackObjectIdentify ()
EndFunction
Int Function BrailleAddObjectName (Int subtypeCode)
If (focusInChatEdit)
Return True
EndIf
If subtypeCode != WT_COMBOBOX
|| ! CollectionItemCount (customBrailleComboBoxData) Then
Return BrailleAddObjectName (subtypeCode)
EndIf
BrailleAddString (customBrailleComboBoxData.ControlName, 0, 0, 0)
Return True
EndFunction
Int Function BrailleAddObjectValue (Int subtypeCode)
If subtypeCode == WT_COMBOBOX
&& CollectionItemCount (customBrailleComboBoxData) Then
BrailleAddString (customBrailleComboBoxData.ControlValue, 0, 0, 0)
Return True
EndIf
; Handle edits.
; The Zoom Cloud Meeting app uses a single window containing all controls.
;It does Not appear To support the UIA text pattern.
;Text in the window is rendered in the OSM and JAWS can track the caret.
;We thus add the focused line If the subtype code is WT_EDIT and the window class is ZPFTEWndClass etc.
If subtypeCode==WT_EDIT Then
Var String class = GetWindowClass(GetFocus())
If class=="ZPFTEWndClass" ; main window
|| class=="zWaitHostWndClass" ; Meeting ID or name field.
|| class=="ZPConfChatWndClass" ; meeting chat area.
|| class=="ConfMeetingInfoWndClass" Then
BrailleAddFocusLine();
Return True
EndIf
EndIf
If (focusInChatEdit)
BrailleAddFocusLine();
Return True
EndIf
If subtypeCode != WT_STATIC Then
Return BrailleAddObjectValue (subtypeCode)
EndIf
; where we have a dialog or dialog page with focus, and Braille would otherwise be empty:
Var String text = GetObjectName(SOURCE_CACHED_DATA)
If ! stringIsBlank (text) Then
BrailleAddString (text, 0, 0, 0)
Return True
EndIf
Return BrailleAddObjectValue (subtypeCode)
EndFunction
Script WindowKeysHelp ()
Var String help = msgWindowKeysHelp+cscBufferNewLine+cscBufferNewLine+cMsgBuffExit
If UserBufferIsActive () Then
UserBufferDeactivate ()
EndIf
UserBufferClear ()
sayMessage (OT_USER_BUFFER, help)
EndScript
Script ZoomNotifyCurrentSpeaker ()
; The Zoom keystroke is control+2, which conflicts with our notifications.
; We're Not doing anything but send the key, Zoom is responsible To push the notification back To us / any accessibility software when the keystroke is sent.
TypeKey (ksNotifyCurrentSpeaker)
; That's all we're doing now because the alert is dealt with elsewhere.
EndScript
Script AnnounceJAWSSettingsForZoom ()
; Now assigned To Control+F9. Included in Hotkey Help.
SettingsReminder()
EndScript
; Added For Settings Dialog.
Script ScreenSensitiveHelp ()
If HasSpokenCategory == 1 Then ;; We are in the appropriate category list in the Settings dialog.
If UserBufferIsActive () Then
UserBufferDeactivate ()
EndIf
UserBufferClear ()
SayFormattedMessage(ot_user_buffer, MSGZoomCategoryList+cscBufferNewLine+cscBufferNewLine)
SayFormattedMessage(ot_user_buffer, MSGPressEscape)
else ; Default
performScript ScreenSensitiveHelp()
EndIf
EndScript
; The following scripts are required To facilitate access To Participant and Chat Lists. Temporary measure.
Script Tab ()
CancelWaitingForExtraEventsFromRefresh()
performscript tab ()
pause ()
If IsParticipantsList () Then
SayUsingVoice (VCTX_Message, MSGParticipantsList, ot_user_requested_information)
sayline ()
EndIf
If IsChatList () Then
SayUsingVoice (VCTX_Message, MSGChatList, ot_user_requested_information)
sayline ()
EndIf
EndScript
Script ShiftTab()
CancelWaitingForExtraEventsFromRefresh()
performscript ShiftTab()
pause ()
If IsParticipantsList () Then
SayUsingVoice (VCTX_Message, MSGParticipantsList, ot_user_requested_information)
sayline ()
EndIf
If IsChatList () Then
SayUsingVoice (VCTX_Message, MSGChatList, ot_user_requested_information)
sayline ()
EndIf
EndScript
Script SayNextLine ()
CancelWaitingForExtraEventsFromRefresh()
If IsParticipantsList ()
|| IsChatList () Then
If IsPCCursor () Then
PerformScript SayNextLine ()
pause ()
SayLine ()
else
PerformScript SayNextLine ()
EndIf
else
PerformScript SayNextLine ()
EndIf
EndScript
Script SayPriorLine()
CancelWaitingForExtraEventsFromRefresh()
If IsParticipantsList ()
|| IsChatList () Then
If IsPCCursor () Then
PerformScript SayPriorLine ()
pause ()
SayLine ()
else
PerformScript SayPriorLine ()
EndIf
else
PerformScript SayPriorLine ()
EndIf
EndScript
Script JAWSHome ()
CancelWaitingForExtraEventsFromRefresh()
PerformScript JAWSHome ()
If IsParticipantsList ()
|| IsChatList () Then
If IsPCCursor () Then
pause ()
SayLine ()
EndIf
EndIf
EndScript
Script JAWSEnd ()
CancelWaitingForExtraEventsFromRefresh()
PerformScript JAWSEnd ()
If IsParticipantsList ()
|| IsChatList () Then
If IsPCCursor () Then
pause ()
SayLine ()
EndIf
EndIf
EndScript
Int Function IsFocusInChatEdit()
If (!GetObjectIsEditable ())
Return False
EndIf
Var String currentClass = GetWindowClass (GetFocus ())
If (currentClass != ZoomChatClass)
Return False
EndIf
Return True
EndFunction
Void Function NameChangedEvent (Handle hwnd, Int objId, Int childId, Int nObjType,
String sOldName, String sNewName)
If IsWaitingOnExtraEventsFromRefresh()
&& GetObjectSubtypeCode() == wt_button
&& sNewName == getObjectname()
; We are assuming an MSAARefresh coincides with a name change For the button in focus, and that this is the event we want To speak.
MarkSpeechAsHandledInExtraEventFromRefresh()
EndIf
If (focusInChatEdit)
Return ; do nothing here To prevent default from running
EndIf
NameChangedEvent (hwnd, objId, childId, nObjType, sOldName, sNewName)
EndFunction
Void Function SayObjectTypeAndText(optional Int nLevel, Int includeContainerName, Int drawHighLight)
If (focusInChatEdit)
Return IndicateControlType (WT_EDIT, cscNull, GetLine())
EndIf
SayObjectTypeAndText(nLevel, includeContainerName, drawHighLight)
EndFunction
Int Function GetMeetingShareRect(Int byref left, Int byref top, Int byref right, Int byref bottom)
Var Handle hApp = GetAppMainWindow(GetFocus())
Var Handle hShare = FindWindow(hApp, cscNull, wnMeetingShare)
If !hShare || !GetWindowRect (hShare, left, right, top, bottom) Then
Return False
EndIf
If !IsValidRect(left, top, right, bottom)
Return False
EndIf
Var Handle hTools = FindWindow(hApp, cscNull, wnMeetingTools)
If hTools && IsWindowVisible(hTools) Then
Var Int mtLeft, Int mtTop, Int mtRight, Int mtBottom
If GetWindowRect (hTools, mtLeft, mtRight, mtTop, mtBottom) Then
bottom = min(bottom, mtTop)
EndIf
EndIf
Return True
EndFunction
Void Function PictureSmartAllInOneZoom (Int serviceOptions)
Var
Int left, Int top, Int right, Int bottom
If GetMeetingShareRect(left, top, right, bottom)
PictureSmartWithAreaShared(serviceOptions, left, top, right, bottom)
Return
EndIf
PerformScript PictureSmartWithControl(serviceOptions)
EndFunction
Script PictureSmartAllInOne (optional Int serviceOptions)
PictureSmartAllInOneZoom (PSServiceOptions_Single | serviceOptions)
EndScript
Script PictureSmartAllInOneMultiService (optional Int serviceOptions)
PictureSmartAllInOneZoom (PSServiceOptions_Multi | serviceOptions)
EndScript
Int Function SetCustomBackgroundOCRRect()
Var
Int iLeft, Int iRight, Int iTop, Int iBottom
If !GetMeetingShareRect(iLeft, iTop, iRight, iBottom)
Return False
EndIf
Return UpdateBackgroundOCRRectCollection(iLeft, iTop, iRight, iBottom)
EndFunction