source: cprs/trunk/CPRS-Chart/JAWS Support Files/VA508JAWS.jss@ 1768

Last change on this file since 1768 was 830, checked in by Kevin Toppenberg, 14 years ago

Upgrading to version 27

File size: 133.5 KB
RevLine 
[830]1; $Id: va508jaws.jss,v 1.171 2008/05/30 13:48:38 dlee Exp $
2/* Data Communication for this framework is provided through hidden windows
3Written for the VA508 Script project
4Original scripts by: JMerrill
5Updated: June, 2007 - JAvila and DLee, for Freedom Scientific
6Updated: October, 2007 by DLee
7JAWS 7.1 and 8.0
8The top line of this file should be preserved for CVS purposes
9The framework requires the jaws.SR and VA508JAWSDispatcher.exe files in addition to the FSAPI 1.0 com library in the shared folder of the JAWS program
10*/
11
12; Default includes from JAWS
13include "HjConst.jsh"
14include "hjglobal.jsh"
15include "common.jsm"
16
17; constants are differentiated by underscores between words
18Const
19; Not used by any code in this file, but read by JAWS.SR from this file to determine if the script file should be updated with a newer version
20 VA508_Script_Version = 1137,
21
22; Maximum property cache lifespan in milliseconds
23 VA508_Cache_Mils = 2000, ; 2 seconds
24
25; iCacheHandling values for VA508getComponentProp()
26; See that function for more about these constants.
27 VA508_Cache_Use = 0, ; Use the cache but don't force it to update
28 VA508_Cache_Update = 1, ; Update the cache, then use it
29 VA508_Cache_Skip = 2, ; Don't touch the cache at all, just pull straight from Framework
30; Constant used to indicate that the framework sent a null property value explicitly.
31; When a cache property value is actually null, it means the framework did not send a value for that property at all.
32; This means either there was an error (VA508_QueryCode_Error dataStatus bit set)
33; or the property has no value in the framework (appropriate VA508_QueryCode_* dataStatus bit for the property NOT set).
34 VA508_Cache_Explicit_Null = " ",
35
36; Used by AutoStartEvent only.to get the msg id used to communicate with sendMessage
37 VA508_Reg_Msg_ID = "VA 508 / Freedom Scientific - JAWS Communication Message ID",
38
39; Used only by VA508EnsureInitialized
40 VA508_DLL_Dispatcher_Hidden_Window_Class = "TfrmVA508JawsDispatcherHiddenWindow",
41 VA508_DLL_Hidden_Main_Window_Class = "TfrmVA508HiddenJawsMainWindow",
42 VA508_Message_Get_DLL_With_Focus = 1,
43; Not used by any code.
44 VA508_DLL_Dispatcher_Hidden_Window_Title = "VA 508 JAWS Dispatcher Window",
45 VA508_DLL_Hidden_Data_Window_Class = "TfrmVA508HiddenJawsDataWindow",
46
47; General data format = prefix : next window handle : data
48; See VA508GetApplicationData() for more info on the data structure.
49 VA508_DLL_Data_Window_Delim = ":",
50; Next two used only by VA508GetStringValue.
51 VA508_DLL_Data_Offset = "=",
52 VA508_DLL_Data_Length = ",",
53
54; Names of data structure elements, found in the data structure itself (gsVA508varData).
55; Pass these to VA508GetStringValue() to get values by name.
56 VA508_FieldName_Caption = "Caption",
57 VA508_FieldName_Value = "Value",
58 VA508_FieldName_Control_Type = "ControlType",
59 VA508_FieldName_State = "State",
60 VA508_FieldName_Instructions = "Instructions",
61 VA508_FieldName_Item_Instructions = "ItemInstructions",
62 VA508_FieldName_Data_Status = "DataStatus",
63
64; Query bits to retrieve each of the above items except Data_Status.
65; These are passed to VA508GetApplicationData().
66; iDataStatus comes back with the same flags to indicate what was actually retrieved.
67 VA508_QueryCode_Caption = 0x00000001L,
68 VA508_QueryCode_Value = 0x00000002L,
69 VA508_QueryCode_Control_Type = 0x00000004L,
70 VA508_QueryCode_State = 0x00000008L,
71 VA508_QueryCode_Instructions = 0x00000010L, ;16
72 VA508_QueryCode_Item_Instructions = 0x00000020L, ;32
73 VA508_QueryCode_Data = 0x00000040L, ;64
74; Query code to retrieve all of the above at once.
75 VA508_QueryCode_All = 0x0000007FL, ; 127
76; Extra bits that can be sent to the VA508ChangeEvent
77 VA508_Data_Change_Event = 0x00001000L, ; 4096
78 VA508_DataItem_Change_Event = 0x00002000L, ;8192
79; If this comes back from a query, it means the sent hwnd was not in the framework's list of windows
80; This can happen if
81; - The hwnd is to another application, or
82; - The hwnd is to a system-generated window, such as SysHeader32 under a ListView or Edit under an edit combo.
83 VA508_QueryCode_Error = 0x00800000L,
84
85; Keystroke constants
86 Key_F4 = "F4", ; Key to close an open combo box.
87 ksRightArrow = "RightArrow",
88 ksLeftArrow = "LeftArrow",
89; Window class constants
90 wcComboLBox = "ComboLBox", ; Window class of a normal combo box's list window.
91 wcTMaskEdit = "TMaskEdit",
92 wcTTabControl = "TTabControl",
93 wcTTabSheet = "TTabSheet",
94 wcTUpDown = "TUpDown",
95 wcTTreeView = "TTreeView",
96 wcTStringGrid = "TStringGrid",
97 wcTComboBox = "TComboBox",
98 wcEdit = "Edit",
99; ControlTypes
100 ctSpinBox = "SpinBox",
101; Window Styles
102 window_style_tabsWithButtons = 0x100,
103; MSAA constans
104 ChildID_Self = 0,
105 SELFLAG_TAKEFOCUS = 0x1L,
106 SELFLAG_TAKESELECTION = 0x2L,
107 ROLE_SYSTEM_PAGETABLIST = 0x3cL,
108 ROLE_SYSTEM_PAGETAB = 0x25L,
109 ROLE_SYSTEM_LIST = 0x21L,
110 STATE_SYSTEM_SELECTED = 0x00000002L,
111 STATE_SYSTEM_FOCUSED = 0x00000004L,
112 STATE_SYSTEM_FOCUSABLE = 0x00100000L,
113 STATE_SYSTEM_SELECTABLE = 0x00200000L,
114 STATE_SYSTEM_CHECKED = 0x00000010L,
115; Messages
116 msgPage = "Page",
117 msgNotSelected = "not selected",
118 msgDataOnly = "data only",
119 msgRowAndColumnNumbers = "row and column numbers",
120 msgRowAndColumnHeaders = "row and column headers",
121 msgRowAndColumnHeadersAndNumbers = "row and column headers and numbers",
122 msgScriptSetName = "V A 508 Scripts",
123 msgSpace = " ",
124 msgLoadingSettings = "loading settings",
125 msgPersonalSettingsSaved = "personal settings saved",
126 msgPersonalSettingsNotSaved = "personal settings not saved",
127 msgChecked = "checked",
128 msgNull = "",
129 msgBlank = "blank",
130 msgLevel = "Level ",
131 msgColumn = "Column",
132 msgRow = "Row",
133; Personalized settings
134 hKey_GridSpeechMode = "GridSpeechMode", ; ini key name
135 hKey_GridBrailleMode = "GridBrailleMode", ; ini key name
136 jvToggleGridSpeechMode="|ToggleGridSpeechMode:Grid Speech", ; function name then shown description
137 jvToggleGridBrailleMode="|ToggleGridBrailleMode:Grid Braille", ; function name then shown description
138 Section_ControlTypes = "ControlTypes",
139 Section_BrailleClasses = "BrailleClasses",
140; General Constants
141 string_delim = "|",
142 gi_mag_draw_highlights = 1, ; for magic
143 LB_COUNT = 0x018B,
144 LB_getcursel = 0x0188,
145 TVGN_CARET = 0x0009,
146 TVGN_NEXT = 0x0001,
147 TVGN_PREVIOUS = 0x0002,
148 TVM_EDITLABELA = 0x110E,
149 TVM_EDITLABELW = 0x1141,
150 TVM_GETNEXTITEM = 0x110A
151
152Messages
153@msgPosMOfN
154%1 of %2
155@@
156@msgItemCount1
157%1 item
158@@
159@msgItemCount2
160%1 items
161@@
162EndMessages
163
164
165; All global variables start with "g" and a lowercase letter indicating their type string, int, handle or boolean
166Globals
167; True for debugging enabled (see autoStartEvent)
168 int inDebugging,
169; True for framework debugging
170 int fwDebug,
171; Property cache
172; GetTickCount() value at the time of the last full cache update
173 int giVA508cacheTick,
174; Handle of window to which the cache now applies
175 handle ghVA508cacheHwnd,
176; Properties cached
177 string gsVA508cacheCaption,
178 string gsVA508cacheValue,
179 string gsVA508cacheControlType,
180 string gsVA508cacheState,
181 string gsVA508cacheInstructions,
182 string gsVA508cacheItemInstructions,
183 int giVA508cacheDataStatus,
184; Cache of grid data for string grids
185; "valid" is not passed by the DLL; it is set (along with all the rest of these) by VA508GetGridData().
186; The rest are passed in a ^-delimited string from the DLL in the Value field.
187 string gsVA508cacheGridColHdr,
188 int giVA508cacheGridColNum,
189 int giVA508cacheGridColCnt,
190 string gsVA508cacheGridRowHdr,
191 int giVA508cacheGridRowNum,
192 int giVA508cacheGridRowCnt,
193 string gsVA508cacheGridCellVal,
194 int giVA508cacheGridCellNum,
195 int giVA508cacheGridCellCnt,
196; Handle of the window of the DLL for the application in focus.
197 handle ghVA508DLLWindow,
198; ID of registered VA508_Reg_Msg_ID Windows message.
199; Sent to the dispatch window and DLL-specific windows, obtained by RegisterWindowMessage
200 int giVA508messageID,
201; True if the app-specific DLL link has not yet been established.
202; This link is remade every time a VA508 app receives focus.
203 int gbVA508needToLinkToDLL,
204 string gsVA508TutorMessage, ; saves a global tutor message variable that will be announced by JAWS when getCustomTutorMessage is automatically called if the user settings ask for it
205 int giVA508TutorReturnValue,
206 handle ghVA508tutorWindow, ; handle of the window where there was a custom tutor message
207 string gsVA508dataWindowTitle,
208 int giVA508dataWindowTitleLen,
209; Data field names and values for the last-queried control.
210 string gsVA508varData,
211 string gsVA508data,
212; A flag to suppress speech at certain times.
213 int gbVA508suppressEcho,
214 int glbSuppressFocusChange,
215; Custom braille types
216 string glbsTable,
217 string glbsTable2,
218; Custom control types for speech
219 string glbsTable3,
220 string glbsTable4,
221; personalized settings for how row and column headers are displayed in a table
222 int giGridSpeechMode,
223 int giGridBrailleMode,
224 int giAppHasBeenLoaded, ; keeps track of if the app has been loaded before so we don't need to pull the ini settings for personalized grids
225; Globals for ChangeEvent speaking
226 int giSuppressCaption, ; use custom caption when event occurs but focus did not move
227 int giSuppressControlType,
228 int giSuppressState,
229 int giSuppressValue,
230 int giSuppressInstructions,
231 int giSuppressItemInstructions,
232 int giDidFocusChange, ; did the focus event fire after the changeEvent did? If so, scrap speaking anything becuase handleCustomWindows will announce it
233 handle ghFromChangeEvent, ; handle of window that last called changeEvent
234 int lt_suppressHighlight,
235 int giCancelEvent,
236 int giSpokeCellUnit,
237 int giDebugMode
238
239;**************************************************************
240; Conversion functionality (cast of any type to any other type within reason)
241;**************************************************************
242Variant Function VA508Cast (variant Value)
243 return Value
244EndFunction
245
246;**************************************************************
247; Dodge for a stringSegmentCount anomaly in at least JAWS 8:
248; If the string ends with the delimiter, the final null segment is not counted.
249; This causes it to be counted.
250;**************************************************************
251int function VA508stringSegmentCount(string s, string sDelim)
252var
253 int segcount
254let segcount = stringSegmentCount(s, sDelim)
255if stringRight(s, 1) == sDelim then
256 let segcount = segcount +1
257endIf
258return segcount
259endFunction
260
261;**************************************************************
262; Classification of list types: lb=listbox, lv=listview, lx=extended-select, lm=multiselect.
263;**************************************************************
264string function getListType(int typeCode)
265if typeCode == WT_ListView || typeCode == wt_listboxItem then
266 return "lv"
267elif typeCode == WT_ListBox then
268 return "lb"
269elif typeCode == WT_MultiSelect_ListBox then
270 return "lm"
271elif typeCode == WT_ExtendedSelect_ListBox then
272 return "lx"
273endIf
274; Return non-null, or things like stringContains("lb lm lx", getListType(typeCode)) will return 1!
275return "--"
276endFunction
277
278;**************************************************************
279; Detection of special focus situations.
280;**************************************************************
281int function isSpecialFocus(int includeAllDialogs)
282if menusActive() || userBufferIsActive() || inHJDialog() then
283 return True
284endIf
285if includeAllDialogs && dialogActive() then
286 return True
287endIf
288if (getWindowClass(getFocus()) == "#32771"
289&& getObjectTypeCode(getFocus()) == WT_ListBoxItem) then
290 ; This is the Alt+Tab window.
291 return True
292endIf
293return False
294endFunction
295
296globals
297 object goCountDict,
298 string gsCountList
299;**************************************************************
300; Reports execution counts of functions/code blocks.
301;**************************************************************
302Void function watchCount(string sKey)
303var
304 int resetting,
305 string sKey1
306if !inDebugging then
307 return
308endIf
309
310let resetting = False
311if sKey == "*" then
312 let sKey = stringChopLeft(sKey, 1)
313 let resetting = True
314endIf
315
316if !sKey || resetting then
317 ; Internal or external call to speak and reset counts.
318 var int i
319 let i = 1
320 while i
321 let sKey1 = stringSegment(gsCountList, "|", i+1)
322 if sKey1 then
323 if goCountDict(sKey1) then
324 sayMessage(OT_Message, formatString("%1 %2", sKey1, goCountDict(sKey1)))
325 dictSet(goCountDict, sKey1, 0)
326 endIf
327 let i = i +1
328 else
329 let i = 0 ; exits loop
330 endIf
331 endWhile
332 if !sKey then
333 return
334 endIf
335endIf
336
337; External call to count.
338if stringLeft(gsCountList, 1) != "|" then
339 let goCountDict = createObjectEx("Scripting.Dictionary", False)
340 let gsCountList = "|"
341endIf
342if !goCountDict then
343 return
344endIf
345dictDelta(goCountDict, sKey, 1)
346if !stringContains(gsCountList, "|"+sKey+"|") then
347 let gsCountList = gsCountList +sKey +"|"
348endIf
349scheduleFunction("watchCount", 8)
350endFunction
351
352;***************************************************************
353; Sends Message to hidden window, and retrieves result from window caption.
354; Has build in retry attempts and timeout
355;***************************************************************
356int Function VA508SendMessage(Handle Window, int wParam, int lParam)
357 var
358 int Result,
359 int working,
360 int pendingCount,
361 int pendingMax,
362 int retryCount,
363 int idx1,
364 int idx2,
365 int doSend,
366 string header1,
367 string header2,
368 string value
369
370 let Result = 0
371 if (Window != 0) then
372 let working = TRUE
373 let retryCount = 2 ; was 3
374 let pendingMax = 3 ; was 4
375 let doSend = TRUE
376
377 let header1 = GetWindowName(Window)
378 while working
379 if doSend then
380 ; This condition should avoid "Unknown function call to VA508GetApplicationData" messages on application shutdown.
381 ; The idea is to stop trying to send messages when the application closes.
382 ; Otherwise, this function delays even the AutoFinishEvent for several seconds.
383 ; GetAppFileName includes an extension and getActiveConfiguration does not,
384 ; but == stops at the end of the shortest string, so it works.
385 ; [DGL, 2007-05-24]
386 if getAppFileName() == getActiveConfiguration() && !InHJDialog () then
387 SendMessage(Window, giVA508messageID, wParam, lParam)
388 else
389 return 0
390 endIf
391 let doSend = FALSE
392 let pendingCount = pendingMax
393 endIf ; doSend
394
395 let header2 = GetWindowName(Window)
396 ; messageBox(getWindowName(StringToInt(StringSegment(header2, VA508_DLL_Data_Window_Delim, 3)))) ; ":"
397 if StringCompare(header1, header2, TRUE) == 0 then ; they are equal
398; beep()
399 Delay(1,true)
400 let pendingCount = pendingCount - 1
401 if pendingCount < 1 then
402 let retryCount = retryCount - 1
403 if retryCount < 1 then
404 let working = FALSE
405 else
406 let doSend = TRUE
407 endIf
408 endIf
409 else ; headers are not equal so we have a new one
410 let working = false
411 let value = StringSegment(header2, VA508_DLL_Data_Window_Delim, 3) ; ":"
412 let Result = StringToInt(value)
413 endIf
414 endWhile
415 endIf ; is window handle valid
416 return Result
417EndFunction
418
419
420;**************************************************************
421; Uses MSAA to return a window name up to 4 K long even though getWindowName stops at 255 characters.
422; MSAA is only used when it seems necessary; getWindowName is used otherwise for efficiency.
423;**************************************************************
424string Function Get4KName(handle hWnd)
425var
426 string wName,
427 string mName,
428 int cutoffLen
429
430; Window names can reach 255 characters, but we choose an earlier cutoff for safety.
431let cutoffLen = 240
432
433let wName = GetWindowName(HWnd)
434if stringLength(wName) > cutoffLen
435|| (hasTitleBar(hwnd) && stringLength(wName) == 0) then
436 var
437 int childID,
438 object obj
439 let obj = GetObjectFromEvent(HWnd, -4, 0, childID) ; -4 = ObjID_Client
440 let mName = obj.accName(0)
441 if stringLength(mName) > cutoffLen then
442 return mName
443 endIf
444endIf
445return wName
446EndFunction
447
448
449;***********************************************************************
450; Gets a value by its name from the data structure saved in gsVA508varData and gsVA508data.
451;***********************************************************************
452String Function VA508GetStringValue(string VarName)
453var
454 string Search,
455 string Result,
456 int idx,
457 int idx2,
458 int idx3,
459 int max,
460 int offset,
461 int len
462
463 let Result = ""
464 let Search = VA508_DLL_Data_Window_Delim + VarName + VA508_DLL_Data_Offset ; something like ":Caption="
465 let idx = StringContains(gsVA508varData, Search) ; returns starting character position
466
467 if idx > 0 then ; we found a match
468 let max = idx + 50 ; just in case of bad data - prevents infinite loop lock up
469 let idx = idx + StringLength(Search)
470 let idx2 = idx+1
471 while (SubString(gsVA508varData, idx2, 1) != VA508_DLL_Data_Length) && (idx2 < max)
472 let idx2 = idx2 + 1
473 endWhile
474 let idx3 = idx2 + 1
475 while (SubString(gsVA508varData, idx3, 1) != VA508_DLL_Data_Window_Delim) && (idx2 < max)
476 let idx3 = idx3 + 1
477 endWhile
478 let offset = StringToInt(SubString(gsVA508varData, idx, idx2-idx)) + 1
479 let len = StringToInt(SubString(gsVA508varData, idx2+1, idx3-idx2-1))
480 if len > 0 then
481 let Result = SubString(gsVA508data, offset, len)
482 EndIf
483 EndIf
484 return Result
485EndFunction
486
487;***********************************************************************
488; Retrieves one or more data items, as indicated by iQueryCode, for the given window.
489; Data ends up in gsVA508varData (names/indices) and gsVA508data (values).
490; hwnd is the handle of the window for which info is wanted
491; iQueryCode indicates what is wanted (VA508_QueryCode_* constants)
492;
493;gsVA508dataWindowTitle = caption:
494; caption:[next window handle]:varlen:var=offset,length:var=offset,len:data
495; varlen = from first to last :
496;***********************************************************************
497globals string gsVA508GetAppDataDebugBuf
498Void Function VA508GetApplicationData(handle hwnd, int iQueryCode)
499watchCount("*appData")
500var
501 handle hWindow,
502 handle nullHandle,
503 string sCaption,
504 string sSubTitle,
505 int idx,
506 int len,
507 string sData
508
509 let gsVA508varData = ""
510 let gsVA508data = ""
511let gsVA508GetAppDataDebugBuf = ""
512 let sData= ""
513
514 if fwDebug then
515 let gsVA508GetAppDataDebugBuf = gsVA508GetAppDataDebugBuf
516 +formatString(
517 "VA508GetApplicationData execution info:\13\10Invocation: handle %1, iQueryCode %2",
518 intToString(hwnd), intToString(iQueryCode)
519 )
520 endIf
521
522 ; hWindow becomes handle of data window received from dll window
523 let hWindow = VA508Cast(VA508SendMessage(ghVA508DLLWindow, hwnd, iQueryCode))
524 if fwDebug then
525 let gsVA508GetAppDataDebugBuf = gsVA508GetAppDataDebugBuf +formatString(
526 "\13\10VA508SendMessage(%1, %2) returns %3",
527 intToString(ghVA508DLLWindow), intToString(iQueryCode), intToString(hWindow)
528 )
529 endIf
530
531 ; if more than 4k or 255char windows are chained together and window contains next windows hwnd like a linked list
532
533 while (hWindow != 0) && (hWindow != 1)
534
535 let sCaption= Get4KName(hWindow) ; uses MSAA to get the name of the dll Window
536 if fwDebug then
537 let gsVA508GetAppDataDebugBuf = gsVA508GetAppDataDebugBuf +formatString(
538 "\13\10sCaption from window %1: '%2'",
539 intToString(hWindow), sCaption
540 )
541 endIf
542 let hWindow = nullHandle
543
544 ; Data window title and len are set in Initialization function
545 let sSubTitle = SubString(sCaption,1,giVA508dataWindowTitleLen)
546 if fwDebug then
547 let gsVA508GetAppDataDebugBuf = gsVA508GetAppDataDebugBuf +formatString(
548 "\13\10sSubtitle from caption: '%1'",
549 sSubtitle
550 )
551 endIf
552
553 if StringCompare(sSubTitle, gsVA508dataWindowTitle , TRUE) == 0 then ; just checking to make sure we have proper window
554 if fwDebug then
555 let gsVA508GetAppDataDebugBuf = gsVA508GetAppDataDebugBuf +"\13\10Data window title recognized"
556 endIf
557 let sCaption= StringChopLeft(sCaption, giVA508dataWindowTitleLen) ; get everything after the title
558 let idx = StringContains(sCaption, VA508_DLL_Data_Window_Delim) ; ":"
559 if idx > 1 then ; see if we have a handle embedded in caption
560 let hWindow = VA508Cast(StringToInt(SubString(sCaption, 1, idx-1)))
561 if fwDebug then
562 let gsVA508GetAppDataDebugBuf = gsVA508GetAppDataDebugBuf +formatString(
563 "\13\10Next window: %1", intToString(hWindow))
564 endIf
565 else
566 if fwDebug then
567 let gsVA508GetAppDataDebugBuf = gsVA508GetAppDataDebugBuf +"\13\10No next window"
568 endIf
569 endIf
570
571 let sCaption = StringChopLeft(sCaption, idx) ; pull out everything after handle
572 if fwDebug then
573 let gsVA508GetAppDataDebugBuf = gsVA508GetAppDataDebugBuf +formatString(
574 "\13\10Caption text saved (idx %1): '%2'",
575 intToString(idx), sCaption
576 )
577 endIf
578 let sData=sData+sCaption ; save what we pulled out into sData variable
579 endIf
580 EndWhile
581
582 if StringLength(sData) > 0 then ; we have valid data
583 let idx = StringContains(sData, VA508_DLL_Data_Window_Delim) ; ":"
584 if idx > 1 then ; get data
585 let len = StringToInt(SubString(sData, 1, idx-1)) ; length is first delimiter, length is length of vars, var length/pos, and data
586 let sData = StringChopLeft(sData,idx-1) ; get data
587 let gsVA508varData = StringLeft(sData,len) ; variable data
588 ; MessageBox(gsVA508varData) ; contains position and length of each property :Caption=0,2:
589 let gsVA508data = StringChopLeft(sData,len) ; actual data
590 ; messageBox(gsva508data)
591 endIf
592 else
593 if fwDebug then
594 let gsVA508GetAppDataDebugBuf = gsVA508GetAppDataDebugBuf +"\13\10No data to return."
595 endIf
596 EndIf
597EndFunction
598
599;***********************************************************************
600; this function is called from AutoStartEvent and AutoFinishEvent to reset all global variables for privacy reasons
601;***********************************************************************
602Void Function VA508ResetGlobals ()
603 let ghVA508DLLWindow = VA508cast(0)
604 let gsVA508dataWindowTitle = ""
605 let gsVA508tutorMessage = ""
606 let ghVA508tutorWindow = VA508cast(0)
607 let giVA508TutorReturnValue = 0
608 ; Clear the cache of framework data.
609 VA508cacheUpdate(0)
610 let gbVA508suppressEcho = FALSE
611 endFunction
612
613;***********************************************************************
614Void Function VA508EnsureInitialized ()
615var
616 int InstanceID,
617 handle DispatchWindow,
618 string className
619
620 if gbVA508needToLinkToDLL then ; CHECK FOR DLL LINK
621 let DispatchWindow = FindTopLevelWindow(VA508_DLL_Dispatcher_Hidden_Window_Class, "")
622 if DispatchWindow then ; CHECK FOR DISPATCH WINDOW
623 let ghVA508DLLWindow = VA508Cast(VA508SendMessage(DispatchWindow, VA508_Message_Get_DLL_With_Focus, 0))
624; sayInteger(ghVA508DLLWindow)
625 if (ghVA508DLLWindow != 0) && (ghVA508DLLWindow != 1) then ; CHECK FOR VALID DLL WINDOW HANDLE
626 let className = GetWindowClass(ghVA508DLLWindow)
627 If StringCompare(className, VA508_DLL_Hidden_Main_Window_Class, TRUE) == 0 then ; dll window and main window are one in the same
628 ; the dll window contains the name of the data window
629 let gsVA508dataWindowTitle = Get4KName(ghVA508DLLWindow)
630 let gsVA508dataWindowTitle = StringSegment(gsVA508dataWindowTitle, VA508_DLL_Data_Window_Delim, 1) + VA508_DLL_Data_Window_Delim
631 let giVA508dataWindowTitleLen = StringLength(gsVA508dataWindowTitle)
632 ; sayString("linked")
633 let gbVA508needToLinkToDLL = FALSE
634 endIf ; check CLASS name
635 endIf ; check DLL window handle
636
637 endIf ; check for existence of DISPATCH window
638 endIf ; only call if we need to link2DLL
639
640 if gbVA508needToLinkToDLL then ; if not linked then clear and try again
641 let ghVA508DLLWindow = VA508cast(0)
642; keep this delay at 1 or first field may not function on startup
643 ScheduleFunction("VA508EnsureInitialized",1)
644 EndIf
645EndFunction
646
647;***********************************************************************
648; Get a property value from the cache.
649; iQueryCode: The VA508_QueryCode_* constant indicating the wanted property.
650; sVal: On return, the property value or null.
651; Returns 1 if the wanted property is found, 0 if not, and -1 on error.
652; On a return of 1, sVal is the property value; otherwise, it is null.
653;***********************************************************************
654int function VA508cacheGetVal(int iQueryCode, string byRef sVal)
655let sVal = ""
656if giVA508cacheDataStatus & VA508_QueryCode_Error then
657 return -1
658elif !(giVA508cacheDataStatus & iQueryCode) then
659 return 0
660elif iQueryCode == VA508_QueryCode_Caption then
661 let sVal = gsVA508cacheCaption
662elif iQueryCode == VA508_QueryCode_Value then
663 let sVal = gsVA508cacheValue
664elif iQueryCode == VA508_QueryCode_Control_Type then
665 let sVal = gsVA508cacheControlType
666elif iQueryCode == VA508_QueryCode_State then
667 let sVal = gsVA508cacheState
668elif iQueryCode == VA508_QueryCode_Instructions then
669 let sVal = gsVA508cacheInstructions
670elif iQueryCode == VA508_QueryCode_Item_Instructions then
671 let sVal = gsVA508cacheItemInstructions
672else
673 ; This should not happen in production and indicates a programming error.
674 beep()
675 return -1
676endIf
677return 1
678endFunction
679
680;***********************************************************************
681; Update the property cache. Called only by VA508getComponentProp() and VA508 ResetGlobals
682; hwnd: The window handle of interest, or 0 to clear the cache.
683;***********************************************************************
684Void Function VA508CacheUpdate (handle hwnd)
685var
686 int iQueryCode,
687 int iStatus,
688 string sVal
689let iQueryCode = 0
690if hwnd then
691 let iQueryCode = VA508_QueryCode_All
692endIf
693
694; Clear the cache first.
695let giVA508cacheTick = 0
696let ghVA508cacheHwnd = VA508cast(0)
697let gsVA508cacheCaption = ""
698let gsVA508cacheValue = ""
699let gsVA508cacheControlType = ""
700let gsVA508cacheState = ""
701let gsVA508cacheInstructions = ""
702let gsVA508cacheItemInstructions = ""
703let giVA508cacheDataStatus = 0
704; Clear grid data also.
705VA508getGridData("",0)
706
707; If we're just clearing the cache, we're done.
708if iQueryCode == 0 then
709 return
710endIf
711
712; Replace the just-cleared cache from the framework.
713; VA508getApplicationData should have been called by the caller already.
714let iStatus = StringToInt(VA508GetStringValue(VA508_FieldName_Data_Status))
715let giVA508cacheTick = getTickCount()
716let ghVA508cacheHwnd = hwnd
717let giVA508cacheDataStatus = iStatus
718if giVA508cacheDataStatus & VA508_QueryCode_Caption then
719 let gsVA508cacheCaption = VA508GetStringValue(VA508_FieldName_Caption)
720endIf
721if giVA508cacheDataStatus & VA508_QueryCode_Value then
722 let gsVA508cacheValue = VA508GetStringValue(VA508_FieldName_Value)
723 ; Grid data shows up in Value, so only try to get it if there's something to get.
724 VA508getGridData(gsVA508cacheValue, 1)
725endIf
726if giVA508cacheDataStatus & VA508_QueryCode_Control_Type then
727 let gsVA508cacheControlType = VA508GetStringValue(VA508_FieldName_Control_Type)
728endIf
729if giVA508cacheDataStatus & VA508_QueryCode_State then
730 let gsVA508cacheState = VA508GetStringValue(VA508_FieldName_State)
731endIf
732if giVA508cacheDataStatus & VA508_QueryCode_Instructions then
733 let gsVA508cacheInstructions = VA508GetStringValue(VA508_FieldName_Instructions)
734endIf
735if giVA508cacheDataStatus & VA508_QueryCode_Item_Instructions then
736 let gsVA508cacheItemInstructions = VA508GetStringValue(VA508_FieldName_Item_Instructions)
737endIf
738EndFunction
739
740;***********************************************************************
741; Return the framework field name corresponding to the given query code.
742;***********************************************************************
743string function VA508FieldNameFromQueryCode(int iQueryCode)
744var
745 string sFieldName
746if iQueryCode == VA508_QueryCode_Caption then
747 let sFieldName = VA508_FieldName_Caption
748elif iQueryCode == VA508_QueryCode_Value then
749 let sFieldName = VA508_FieldName_Value
750elif iQueryCode == VA508_QueryCode_Control_Type then
751 let sFieldName = VA508_FieldName_Control_Type
752elif iQueryCode == VA508_QueryCode_State then
753 let sFieldName = VA508_FieldName_State
754elif iQueryCode == VA508_QueryCode_Instructions then
755 let sFieldName = VA508_FieldName_Instructions
756elif iQueryCode == VA508_QueryCode_Item_Instructions then
757 let sFieldName = VA508_FieldName_Item_Instructions
758else
759 ; This should not happen in production and indicates a programming error.
760 beep()
761 return 0
762endIf
763return sFieldName
764endFunction
765
766;***********************************************************************
767; Return the query code corresponding to the given framework field name.
768;***********************************************************************
769int function VA508QueryCodeFromFieldName(string sFieldName)
770var
771 int iQueryCode
772if sFieldName == VA508_FieldName_Caption then
773 let iQueryCode = VA508_QueryCode_Caption
774elif sFieldName == VA508_FieldName_Value then
775 let iQueryCode = VA508_QueryCode_Value
776elif sFieldName == VA508_FieldName_Control_Type then
777 let iQueryCode = VA508_QueryCode_Control_Type
778elif sFieldName == VA508_FieldName_State then
779 let iQueryCode = VA508_QueryCode_State
780elif sFieldName == VA508_FieldName_Instructions then
781 let iQueryCode = VA508_QueryCode_Instructions
782elif sFieldName == VA508_FieldName_Item_Instructions then
783 let iQueryCode = VA508_QueryCode_Item_Instructions
784else
785 ; This should not happen in production and indicates a programming error.
786 beep()
787 return 0
788endIf
789return iQueryCode
790endFunction
791
792;***********************************************************************
793; Gets a single component property immediately.
794; hwnd: Window about which to ask.
795; xProp: VA508_QueryCode_* or VA508_FieldName_* constant indicating or naming the wanted property.
796; iCacheHandling: A VA508_Cache_* constant determining how to handle the property cache on this call.
797; sVal: On return, the value of the property if found, otherwise undefined.
798; Returns 1 if the property has a custom value, 0 if not, and -1 on error.
799; iCacheHandling constant usage in detail:
800; VA508_Cache_Use:
801; If hwnd is the window cached already and the cache is not too old, pull the property from the cache and don't ask the framework.
802; If hwnd is not the cached window or the cache is too old, rebuild the cache completely while getting the property.
803; VA508_Cache_Update: Rebuild the cache unconditionally from the framework while getting the property.
804; VA508_Cache_Skip:
805; Get the property directly from the framework.
806; If hwnd is the cached window, update the cache entry for the property in the process.
807; Called by VA508SayData for Speech and controlPropGet for Braille
808;***********************************************************************
809int Function VA508GetComponentProp(handle hWnd, variant xProp, int iCacheHandling, string byRef sVal)
810Var
811 string sProp,
812 int iQueryCode,
813 Int iDataStatus
814
815; ***** Code from here to the next short set of stars can be called 40 or more times per second by Braille code.
816; For efficiency, frequent callers should pass a query code, not a field name here.
817
818if stringToInt(xProp) then
819 let iQueryCode = VA508cast(xProp)
820 let sProp = "" ; Don't figure that one out unless we need it.
821else
822 let sProp = VA508cast(xProp)
823 let iQueryCode = VA508QueryCodeFromFieldName(sProp)
824endIf
825
826; Optimize by far the most frequent call case.
827let sVal = ""
828if iCacheHandling == VA508_Cache_Use
829&& hwnd == ghVA508cacheHwnd
830&& getTickCount() -giVA508cacheTick < VA508_Cache_Mils then
831 ; Use the cached value and don't call on the framework at all this time.
832 watchCount("cacheUse")
833 return VA508cacheGetVal(iQueryCode, sVal)
834
835; ***** End of 40-time-per-second code block.
836
837elif iCacheHandling == VA508_Cache_Skip then
838 ; Always go to the framework for these. We'll need the field name for that.
839 if !sProp then
840 let sProp = VA508FieldNameFromQueryCode(iQueryCode)
841 endIf
842 watchCount("cacheSkip")
843 VA508GetApplicationData(hWnd, iQueryCode)
844 let iDataStatus = StringToInt(VA508GetStringValue(VA508_FieldName_Data_Status)) ;"DataStatus"
845
846 if iDataStatus & iQueryCode then
847 let sVal = VA508GetStringValue(sProp)
848 if hwnd == ghVA508cacheHwnd then
849 ; A trick to re-use VA508cacheSetVals for this.
850 ; Makes sure the dataStatus bit is set and sets the property value.
851 VA508cacheSetVals(iQueryCode, iDataStatus, sVal, sVal, sVal, sVal, sVal, sVal)
852 endIf
853 return 1
854 elif iDataStatus & VA508_QueryCode_Error then
855 ; Should not happen, but force the next call to update the cache if it does.
856 if hwnd == ghVA508cacheHwnd then
857 let giVA508cacheTick = 0
858 endIf
859 return -1
860 else
861 ; Property not handled by the framework.
862 if hwnd == ghVA508cacheHwnd then
863 if giVA508cacheDataStatus & iQueryCode then
864 ; Property removed from framework (probably never happens).
865 ; Remove the status bit from the cache as well.
866 ; let giVA508cacheDataStatus = giVA508cacheDataStatus -iQueryCode
867 endIf
868 endIf
869 return 0
870 endIf
871endIf
872
873; All remaining use cases are rebuild-cache cases.
874
875; Clear the cache first.
876VA508cacheUpdate(0)
877
878; Get all properties from the framework.
879watchCount("cacheUpdate")
880VA508GetApplicationData(hWnd, VA508_QueryCode_All)
881
882; Update all properties in the cache.
883VA508cacheUpdate(hwnd)
884
885; Return the property sought in the first place.
886
887return VA508cacheGetVal(iQueryCode, sVal)
888EndFunction
889
890;**********************************************************************
891; Update the property cache when the framework sends an event indicating property changes.
892; Called only from VA508ChangeEvent and getComponentProp with skip
893; should update only items that have changed and getcomponentProp
894;**********************************************************************
895Void Function VA508CacheSetVals (handle hwnd, int iDataStatus, string sCaption, string sValue, string sControlType, string sState, string sInstructions, string sItemInstructions)
896; Don't mess with the cache if it doesn't apply to this window.
897if hwnd != ghVA508cacheHwnd then
898 return
899endIf
900
901; This is in case the framework suddenly decides to include a property not previously included by tossing it at us in an event call.
902; This will probably never happen, but this line shouldn't hurt anything anyway.
903let giVA508cacheDataStatus = giVA508cacheDataStatus | iDataStatus
904
905; Hand out property changes based on what we're told changed.
906if iDataStatus & VA508_QueryCode_Caption then
907 let gsVA508cacheCaption = sCaption
908endIf
909if iDataStatus & VA508_QueryCode_Value then
910 let gsVA508cacheValue = sValue
911endIf
912if iDataStatus & VA508_QueryCode_Control_Type then
913 let gsVA508cacheControlType = sControlType
914endIf
915if iDataStatus & VA508_QueryCode_State then
916 let gsVA508cacheState = sState
917endIf
918if iDataStatus & VA508_QueryCode_Instructions then
919 let gsVA508cacheInstructions = sInstructions
920endIf
921if iDataStatus & VA508_QueryCode_Item_Instructions then
922 let gsVA508cacheItemInstructions = sItemInstructions
923endIf
924EndFunction
925
926;**********************************************************************
927; Fills the VA508cacheGrid* globals.
928; called by va508ChacheUpdate
929; fromWhere: Hwnd of window to query (presumably a grid), or Value field already obtained from such a window.
930; Returns True if this is a grid and False otherwise.
931; Side effects: Modifies all g?VA508cacheGrid* globals.
932; TODO: If a row or column header or cell value contains a ^, False will be returned and no grid data will be set.
933;**********************************************************************
934int Function VA508GetGridData (variant fromWhere, int dontCheck)
935watchCount("grid")
936var
937 int iResult,
938 string sVal
939
940; It's not a grid until we say it's a grid...
941let gsVA508cacheGridColHdr = ""
942let giVA508cacheGridColNum = 0
943let giVA508cacheGridColCnt = 0
944let gsVA508cacheGridRowHdr = ""
945let giVA508cacheGridRowNum = 0
946let giVA508cacheGridRowCnt = 0
947let giVA508cacheGridCellNum = 0
948let giVA508cacheGridCellCnt = 0
949let gsVA508cacheGridCellVal = ""
950if !fromWhere then
951 return False
952endIf
953
954if stringToInt(fromWhere) && !stringContains(fromWhere, "^") && !dontCheck then
955; A window handle.
956; sayString("grid check")
957 let iResult = VA508GetComponentProp(fromWhere, VA508_FieldName_Value, VA508_Cache_Skip, sVal)
958 If iResult < 1 then
959 return False
960 endIf
961else
962 ; A value property already obtained from somewhere.
963 let sVal = fromWhere
964endIf
965
966if VA508stringSegmentCount(sVal, "^") != 9 then
967 ; Got a value, but it's not grid data.
968 return False
969endIf
970
971; sayString("valid grid found by ggd")
972let gsVA508cacheGridColHdr = stringSegment(sVal, "^", 1)
973let giVA508cacheGridColNum = stringToInt(stringSegment(sVal, "^", 2))
974let giVA508cacheGridColCnt = stringToInt(stringSegment(sVal, "^", 3))
975let gsVA508cacheGridRowHdr = stringSegment(sVal, "^", 4)
976let giVA508cacheGridRowNum = stringToInt(stringSegment(sVal, "^", 5))
977let giVA508cacheGridRowCnt = stringToInt(stringSegment(sVal, "^", 6))
978; The cell value is at the end of the string from the DLL.
979let giVA508cacheGridCellNum = stringToInt(stringSegment(sVal, "^", 7))
980let giVA508cacheGridCellCnt = stringToInt(stringSegment(sVal, "^", 8))
981let gsVA508cacheGridCellVal = stringSegment(sVal, "^", 9)
982return True
983EndFunction
984
985;***********************************************************************
986; this function is called from handleCustomWindows and should get called whenever tab, insert+tab are pressed. It also may get called by sayLine and Braille functions
987; Returns False if we should use default and True if this function announced the control and we don't need to do anything else
988;***********************************************************************
989int Function VA508SayData(handle hwnd)
990var
991 int iResult,
992 int iResultInstructions,
993 int iResultValue,
994 int iResultState,
995 int bUseDefault,
996 string Caption,
997 string Value,
998 string ControlType,
999 string State,
1000 string Instructions,
1001 string ItemInstructions,
1002 string Text,
1003 handle tempHandle,
1004 int TypeCode,
1005 int subTypeCode,
1006 string StaticText,
1007 string position,
1008 string Grouping,
1009 string GroupingType,
1010 int special,
1011 string newControlType,
1012 int iDataStatus
1013
1014 ; clear global variables, this should happen every time tab is pressed
1015 let gsVA508tutorMessage = ""
1016 let ghVA508tutorWindow = tempHandle ; which is now null
1017 let giVA508TutorReturnValue = 0
1018
1019 let special = FALSE
1020
1021 if gbVA508needToLinkToDLL then
1022 return False
1023 endIf
1024 ; the assumption is made that if the return value is 0 or less, that "" will be returned and not garbage
1025
1026 let iResult = VA508getComponentProp(hwnd, VA508_QueryCode_Caption, VA508_Cache_Update, Caption)
1027
1028 if iResult >= 0 then ; Framework has nothing for this window, -1 means error, if 0 this passes
1029 let bUseDefault = (iResult <= 0)
1030 let iResult = VA508getComponentProp(hwnd, VA508_QueryCode_Value, VA508_Cache_Use, Value)
1031 let iResultValue = iResult
1032 let bUseDefault = bUseDefault && (iResult <= 0)
1033 let iResult = VA508getComponentProp(hwnd, VA508_QueryCode_Control_Type, VA508_Cache_Use, ControlType)
1034 let bUseDefault = bUseDefault && (iResult <= 0)
1035 let iResult = VA508getComponentProp(hwnd, VA508_QueryCode_State, VA508_Cache_Use, State)
1036 let iResultState = iResult
1037 let bUseDefault = bUseDefault && (iResult <= 0)
1038 let iResultInstructions = VA508getComponentProp(hwnd, VA508_QueryCode_Instructions, VA508_Cache_Use, Instructions)
1039 let iResult = VA508getComponentProp(hwnd, VA508_QueryCode_Item_Instructions, VA508_Cache_Use, ItemInstructions)
1040 else
1041 let bUseDefault = TRUE ; because caption had error we can assume we should use default unless a special case below is needed
1042 endif
1043
1044 let TypeCode = GetWindowTypeCode(hWnd)
1045 if !typeCode then
1046 let typeCode = getObjectSubTypeCode()
1047 Endif
1048
1049 if isSpinBox(hwnd) then ; standard delphi spinboxes are not announced correctly
1050 if VA508getComponentProp(hwnd, VA508_QueryCode_Control_Type, VA508_Cache_Use, ControlType) < 1 then
1051 let ControlType = ctSpinBox
1052 let special = true
1053 Endif ; check for presence of custom controlType
1054 elif TypeCode == wt_listbox || TypeCode == wt_listView then ; position in group is wrong for standard delphi list boxes
1055 let special = true
1056 elif getWindowClass(hwnd) == wcTTreeView then ; to remove unchecked from value
1057 let special = true
1058 elif getWindowClass(hwnd) == "TORComboEdit" || getWindowClass(hwnd) == "TORComboBox" then
1059 let special = True
1060 endif ; check for spinBox
1061
1062 if bUseDefault == FALSE || special then
1063 if VA508getGridData(getFocus(),0) > 0 && isPcCursor() && !userBufferIsActive() then
1064 let value = getCurrentCellHeadersData()
1065 elif typeCode == wt_listBox || typecode == wt_listView then
1066 if iResultValue < 1 then ; the framework either return nothing or an error
1067 let value = getAccName()
1068 Endif
1069 if iResultState < 1 then ; the framework either return nothing or an error
1070 if !getObjectState() then
1071 let state = getAccState()
1072 endif
1073 Endif
1074 elif typeCode == wt_treeview then
1075 if iResultValue < 1 then
1076 let value = getAccValue()
1077 Endif
1078 ; add this state even if another state exists and no matter where the value came from
1079 let state = tvGetFocusItemExpandStateString (hwnd) + " " + state
1080 Endif ; end check for special control types
1081
1082 if ControlType && ControlTypeFound(ControlType, newControlType) then
1083 let ControlType = newControlType
1084 EndIf ; end custom spoken control type
1085 sayControlEx(hwnd, Caption, ControlType, State, Grouping, GroupingType, Value, PositionInGroup(), StaticText)
1086 else ; use default
1087 return False
1088 EndIf ; use default?
1089
1090 ;Say(ItemInstructions,OT_TUTOR) ; should always say item instructions if they exist?
1091 ; See JAWS 8's tutorialHelp.jss::sayTutorialHelp() for the rationale for using this SayUsingVoice call.
1092 ; TODO: This may speak in a few undesirable places depending on user settings.
1093 var
1094 int ot
1095 let ot = OT_Tutor
1096 if !shouldItemSpeak(OT_Tutor) && False then
1097 ; TODO: "False" above should be "code invoked from script", but I see no way to establish that.
1098 let ot = OT_Line
1099 endIf
1100 sayUsingVoice(VCTX_Message, itemInstructions, ot)
1101 If iResultInstructions > 0 then
1102 let ghVA508tutorWindow = hWnd
1103 let gsVA508tutorMessage = Instructions
1104 let giVA508TutorReturnValue = iResultInstructions
1105 EndIf ; instructions
1106 return True
1107EndFunction
1108
1109;***************************************************************************
1110; updated to announce custom information for listview/listbox type controls
1111; spoken order for listbox and listview = value or name, state, then position
1112; the name of the control is not announced here for listboxes
1113; customType = caption,type,value,state
1114; checkbox = caption,type,state
1115; radioButton = caption, type,state
1116; button = caption,type, state (use default)
1117; link = caption, type, state
1118; comboBox = value, position
1119; edit = name, type, value, state (use default)
1120; spinner = name, type, value, state (use default)
1121; multiline edit = current line
1122; page tab = all page tabs
1123; list item = state, value, position
1124; tree item = value, state, position,
1125; listbox/listview = not possible
1126; treeview = not possible
1127; dialog = not possible
1128; grid = caption, type, value, state
1129; menu = use default
1130; slider = caption, type, value
1131; progressBar = caption, type, value
1132; groupbox = not possible
1133;***************************************************************************
1134Script SayLine()
1135var
1136 int theTypeCode,
1137 string strVal,
1138 string strState,
1139 handle hwnd,
1140 string strControlType
1141
1142;sayString("sayline")
1143if !isPcCursor() || isSpecialFocus(False) then
1144 performScript sayLine()
1145 return
1146Endif
1147
1148/*
1149; Update the cache
1150VA508GetComponentProp(hwnd, VA508_FieldName_Value, VA508_Cache_Update, strVal)
1151
1152let hwnd = getFocus()
1153Let TheTypeCode = GetWindowSubTypeCode (GetFocus ())
1154If !TheTypeCode then ; if any unknown typeCode then get the sub type code from MSAA
1155 Let TheTypeCode = GetObjectSubTypeCode ()
1156EndIf
1157
1158; if we have a custom control type, then we really don't know how much or little information should be spoken, so say it all!
1159if theTypeCode == wt_unknown && VA508GetComponentProp(hwnd, VA508_FieldName_Control_Type, VA508_Cache_Use, strControlType) > 0 then ; make assumption that anything that has a value has child objects, doesn't cover case where it isn't a list but has a custom state but not a custom value
1160 VA508SayData(hwnd)
1161 return
1162Endif
1163
1164; this only applies to list boxes
1165if stringContains("lb lm lx", getListType(theTypeCode)) ; doesn't apply to listview, should pick up tree with custom value
1166&& !VA508GetGridData(hwnd) then ; grids should be handled differently though, so if value but grid don't use this code, use code in sayLine function
1167 ; BOTH value and state are custom
1168 if VA508GetComponentProp(hwnd, VA508_FieldName_Value, VA508_Cache_Use, strVal) > 0 &&
1169 VA508GetComponentProp(hwnd, VA508_FieldName_State, VA508_Cache_Use, strState) > 0 then
1170 SayMessage (OT_LINE, strVal)
1171 SayMessage (OT_item_state, strState) ; custom expanded/collapsed states should be handled by the framework
1172 SayMessage (OT_POSITION, PositionInGroup ())
1173 return
1174 Endif
1175 ; only VALUE is custom, use state from jaws
1176 if VA508GetComponentProp(hwnd, VA508_FieldName_Value, VA508_Cache_Use, strVal) > 0 &&
1177 VA508GetComponentProp(hwnd, VA508_FieldName_State, VA508_Cache_Use, strState) < 1 then
1178 SayMessage (OT_line, strVal)
1179 If (theTypeCode == WT_TREEVIEW || theTypecode == WT_TREEVIEWITEM) then
1180 SayTVFocusItemExpandState (hwnd) ; getObjectState() doesn't return correct info for tree views
1181 Else
1182 SayMessage (ot_item_state,getObjectState())
1183 endif
1184 SayMessage (OT_POSITION, PositionInGroup ())
1185 return
1186 Endif
1187 ; only STATE is custom - current case for checklist box
1188 if VA508GetComponentProp(hwnd, VA508_FieldName_State, VA508_Cache_Use, strState) > 0 &&
1189 VA508GetComponentProp(hwnd, VA508_FieldName_Value, VA508_Cache_Use, strVal) < 1 then
1190 Let strVal = GetAccName()
1191 SayMessage (OT_line, strVal)
1192 SayMessage (OT_item_State, strState)
1193 SayMessage (OT_POSITION, PositionInGroup ())
1194 return
1195 EndIf ; only state
1196Endif ; are we on a listbox or a custom control that has it's value set
1197
1198; another special case for listboxes
1199; no custom state or value found but need to use msaa for listboxes
1200; for standard listboxes that JAWS has trouble announcing not selected for
1201if stringContains("lb lm lx", getListType(theTypeCode)) then ; doesn't apply to listview, only listbox, should pick up tree with custom value
1202 say(getAccState(),ot_item_state)
1203 say(getAccName(),ot_selected_item) ; uses msaa for list item, falls back on getObjectValue()
1204 SayMessage (OT_POSITION, PositionInGroup ())
1205 return
1206Endif
1207*/
1208; performScript sayLine() ; this function in default is likely to call the function sayLine below
1209sayLine()
1210EndScript
1211
1212;*****************************************************************************************
1213String Function tvGetFocusItemExpandStateString (handle hwnd)
1214 if tvGetFocusItemExpandState (hwnd) then
1215 return "opened"
1216 else
1217 return "closed"
1218 Endif
1219EndFunction
1220
1221;*****************************************************************************************
1222; also called by control+home and control+end in grid
1223; called by script sayLine for edits and buttons when sayLine command is pressed
1224void Function SayLine(int iDrawHighlights)
1225var
1226 int typeCode,
1227 int subTypeCode,
1228 handle hwnd,
1229 string strState,
1230 string strCaption,
1231 string strValue,
1232 string strControlType,
1233 string strPosition,
1234 int special
1235
1236;sayString("sayline")
1237if !isPCCursor() || isSpecialFocus(False) then
1238 return sayLine(iDrawHighlights)
1239endIf
1240let hwnd = getFocus()
1241let typeCode = getWindowTypeCode(hwnd)
1242; sayInteger(typeCode)
1243let subTypeCode = getWindowSubTypeCode(hwnd)
1244
1245if stringContains("lb lm lx", getListType(TypeCode)) then
1246 let special = true ; for listbox without customizations we need this for msaa names to be announced
1247elif getObjectTypeCode() == wt_listboxItem then ; for list view
1248 let special = true ; for listview without customizations we need this for position in group to be spoken
1249elif (getWindowClass(hwnd) == "TORComboEdit" || getWindowClass(hwnd) == "TORComboBox") && positionInGroup() then
1250 let special = True
1251EndIf
1252
1253; simple call to update the cache
1254VA508GetComponentProp(getFocus(), VA508_FieldName_Control_Type, VA508_Cache_Update, strControlType)
1255
1256; added jda 4-22-08 to make standard edit combos announce blank when empty and nothing else, also prevents speaking of caption on standard edit combos when sayLine is pressed
1257if getWindowClass(hwnd) == wcEdit && getWindowClass(getParent(hwnd)) == wcTComboBox then
1258 let typeCode = wt_editCombo
1259endif
1260
1261; combo boxes should not have their name spoken
1262if (typeCode == wt_edit && subTypeCode != wt_multiline_edit) ; also covers edit comboes, and spinboxes because they have a typeCode of edit
1263|| typeCode == wt_button then ; also handles edit & edit comboes
1264 ; sayInteger(subTypeCode)
1265 if VA508SayData(hwnd) then
1266 return
1267 else ; else fall through to regular sayline
1268 sayLine(iDrawHighlights) ; calls internal sayline function as default has no sayline function
1269 return
1270 endIf
1271; if we have a custom control type, then we really don't know how much or little information should be spoken, so say it all!
1272elif TypeCode == wt_unknown && VA508GetComponentProp(hwnd, VA508_FieldName_Control_Type, VA508_Cache_Use, strControlType) > 0 then ; make assumption that anything that has a value has child objects, doesn't cover case where it isn't a list but has a custom state but not a custom value
1273 VA508SayData(hwnd)
1274 return
1275elif VA508getGridData(getFocus(),0) > 0 then ; GRID
1276 say(getCurrentCellHeadersData(),ot_line)
1277 return
1278elif VA508GetComponentProp(getFocus(), VA508_FieldName_Caption, VA508_Cache_Use, strCaption) < 1 &&
1279VA508GetComponentProp(getFocus(), VA508_FieldName_Control_Type, VA508_Cache_Use, strControlType) < 1 &&
1280VA508GetComponentProp(getFocus(), VA508_FieldName_Value, VA508_Cache_Use, strValue) < 1 &&
1281VA508GetComponentProp(getFocus(), VA508_FieldName_State, VA508_Cache_Use, strState) < 1 &&
1282!special then
1283 sayLine(iDrawHighlights) ; calls internal sayline function as default has no sayline function
1284 return
1285elif subTypeCode == wt_multiline_Edit then
1286 sayLine(iDrawHighlights) ; calls internal sayline function as default has no sayline function
1287 return
1288endIf
1289
1290; now we have at least one custom property and it is stored in our local variable or we are special
1291
1292let strPosition = PositionInGroup()
1293if getWindowClass(hwnd) == "TORComboEdit" then
1294 let typeCode = WT_EditCombo
1295elif getWindowClass(hwnd) == "TORComboBox" then
1296 let typeCode = WT_ComboBox
1297endIf
1298
1299; now let's set everything from default if there wasn't a custom framework property
1300if VA508GetComponentProp(getFocus(), VA508_FieldName_Caption, VA508_Cache_Use, strCaption) < 1 then
1301 ;let strCaption = getAccName()
1302 let strCaption = getObjectName() ; don't need to worry about child objects
1303Endif
1304if VA508GetComponentProp(getFocus(), VA508_FieldName_Control_Type, VA508_Cache_Use, strControlType) < 1 then
1305 let strControlType = getObjectType()
1306Endif
1307if VA508GetComponentProp(getFocus(), VA508_FieldName_Value, VA508_Cache_Use, strValue) < 1 then
1308 let strValue = getAccValue()
1309Endif
1310if VA508GetComponentProp(getFocus(), VA508_FieldName_State, VA508_Cache_Use, strState) < 1 then
1311 let strState = getObjectState()
1312Endif
1313if typeCode == wt_treeview then
1314 let strState = tvGetFocusItemExpandStateString (hwnd) + " " + strState
1315Endif
1316
1317; caption is typically not announced here, so no custom caption is announced unless we think we are on a control with no children and no value
1318; ControlType is typically not announced here, so no custom control type is announced
1319; controls with custom values should be handled by sayLine script and thus are not handled here
1320; instructions and item instructions are typically not announced when sayLine is pressed that is why custom ones are not set here
1321
1322if typeCode == wt_checkbox ||
1323typeCode == wt_radiobutton then
1324 say(strCaption,ot_control_name)
1325 say(strControlType,ot_control_type)
1326 say(strState,ot_item_state)
1327Elif typeCode == wt_comboBox || typeCode == WT_EditCombo then
1328 if !strValue then
1329 let strValue = " "
1330 endIf
1331 say(strValue,ot_line)
1332 ; jda added 4-22-08 if statement to prevent position in group from being announced when tor edit combo box is empty
1333 if !(strValue == " " && stringLength(strValue)) then
1334 say(strPosition,ot_position)
1335 Endif
1336Elif typeCode == wt_slider ||
1337typeCode == wt_progressBar then
1338 say(strCaption,ot_control_name)
1339 say(strControlType,ot_control_type)
1340 say(strValue,ot_selected_item)
1341elif stringContains("lb lm lx", getListType(typeCode)) then
1342 say(strValue,ot_selected_item)
1343 say(strState,ot_item_state)
1344 say(strPosition,ot_position)
1345elif typecode == wt_listview then ; for list views
1346 say(strValue,ot_selected_item)
1347 say(strState,ot_item_state)
1348 say(strPosition,ot_position)
1349elif typeCode == wt_treeview then
1350 ; no level needs to be announced here
1351 say(strValue,ot_selected_item)
1352 say(strState,ot_item_state)
1353 say(strPosition,ot_position)
1354Else ; for anything else speak everything
1355 if VA508SayData(hwnd) then
1356 return
1357 else
1358 sayLine(iDrawHighlights) ; this should never get called, here as backup!
1359 endif
1360Endif
1361EndFunction
1362
1363;****************************************
1364; this function should replace sayObjectTypeAndText
1365int Function HandleCustomWindows(handle hwnd)
1366; sayString(getWindowClass(hwnd))
1367
1368 if getWindowClass(hwnd) == wcTComboBox && getWindowClass(getFirstChild(hwnd)) == wcEdit then
1369 return True
1370 endif
1371
1372 if glbSuppressFocusChange then
1373 let glbSuppressFocusChange = FALSE
1374 return true
1375 endif
1376
1377 ; don't waste our time processing
1378 if hWnd == 0 || getWindowClass(hWnd) == "Invalid" then
1379 return true
1380 Endif
1381
1382 if VA508SayData(hwnd) then
1383 ; sayString("custom")
1384 return true ; customizations were announced
1385 else
1386 ; sayString("use default")
1387 return false ; we are using default code in JAWS
1388 endIf
1389EndFunction
1390
1391; called first
1392;************************************************************************
1393void Function SayTutorialHelp (int iSubType, int flag)
1394 If (GetCurrentWindow() == ghVA508tutorWindow) then
1395 If giVA508TutorReturnValue > 0 then ; if we have a global tutor message announce it
1396 if gsVa508tutorMessage == " " && stringLength(gsva508tutorMessage) == 1 then
1397 return ; prevents blank from being announced when custom tutor message is " "
1398 endif
1399 Endif
1400 Endif
1401 SayTutorialHelp (iSubType, flag)
1402EndFunction
1403
1404;***********************************************************************
1405; JAWS internally calls this function... in JAWS 7.1 and higher
1406;***********************************************************************
1407String Function GetCustomTutorMessage ()
1408 If (GetCurrentWindow() == ghVA508tutorWindow) then
1409 If giVA508TutorReturnValue > 0 then ; if we have a global tutor message announce it
1410 Return gsVA508tutorMessage ; if " " then JAWS may announce blank when insert+tab is pressed
1411 EndIf
1412 EndIf
1413 Return getCustomTutorMessage()
1414EndFunction
1415
1416;**********************************************************************
1417; initialize variables and tell code to perform handshake with dispatch window. Reset any globals in case other application left them in memory which should not be the case though
1418;**********************************************************************
1419Void Function AutoStartEvent ()
1420let inDebugging = False
1421let fwDebug = False
1422let giDebugMode = 0
1423if fileExists(getJAWSSettingsDirectory() +"\\debug.ini") then
1424 let inDebugging = True
1425endIf
1426if fileExists(getJAWSSettingsDirectory() +"\\fwdebug.ini") then
1427 let fwDebug = True
1428endIf
1429 let gbVA508needToLinkToDLL = TRUE
1430 let giVA508messageID = RegisterWindowMessage(VA508_Reg_Msg_ID)
1431 VA508ResetGlobals()
1432 VA508EnsureInitialized()
1433 UpdateBrailleClasses()
1434 UpdateControlTypes()
1435If !giAppHasBeenLoaded Then
1436 LoadPersonalSettings() ; load personal settings
1437 let giAppHasBeenLoaded=TRUE
1438EndIf
1439
1440EndFunction
1441
1442;**********************************************************************
1443; called when user alt+tabs out of application, resets all global variables and forces the application to re-initialize next time. This helps to ensure patient privacy as no patient data is left in hidden windows.
1444;**********************************************************************
1445Void Function AutoFinishEvent()
1446var
1447 object nullObject
1448
1449 let gbVA508needToLinkToDLL = TRUE
1450 VA508ResetGlobals()
1451EndFunction
1452
1453;**********************************************************************
1454; called when JAWSKey+Q is pressed to announce script file settings that are loaded and module file name that is being used
1455;**********************************************************************
1456Script ScriptFileName()
1457; one line of debugging code
1458if !giDebugMode then
1459 ScriptAndAppNames(msgScriptSetName)
1460Else ; start debug mode
1461 DisplayDebugData()
1462Endif ; end debug mode
1463EndScript
1464
1465;***********************************************************************
1466; added by jda 4-22-08
1467;***********************************************************************
1468void Function DisplayDebugData()
1469var
1470 string strCaption,
1471 string strControlType,
1472 string strValue,
1473 string strState,
1474 string strInstructions,
1475 string strItemInstructions,
1476 int iCustomInfo,
1477 string sDisplayText
1478
1479let sDisplayText = ""
1480if VA508GetComponentProp(getFocus(), VA508_FieldName_Caption, VA508_Cache_Use, strCaption) > 0 then
1481 ;say("has custom name",ot_jaws_message)
1482 ;say(strCaption,ot_control_name)
1483 let sDisplayText = sDisplayText + "Custom Name: " + strCaption + "\n"
1484 let iCustomInfo = true
1485Endif
1486if VA508GetComponentProp(getFocus(), VA508_FieldName_Control_Type, VA508_Cache_Use, strControlType) > 0 then
1487 ;say("has custom type",ot_jaws_message)
1488 ;say(strControlType,ot_control_type)
1489 let sDisplayText = sDisplayText + "Custom Type: " + strControlType + "\n"
1490 let iCustomInfo = true
1491Endif
1492if VA508GetComponentProp(getFocus(), VA508_FieldName_Value, VA508_Cache_Use, strValue) > 0 then
1493 ;say("has custom value",ot_jaws_message)
1494 ;say(strValue,ot_selected_item)
1495 let sDisplayText = sDisplayText + "Custom Value: " + strValue + "\n"
1496 let iCustomInfo = true
1497Endif
1498if VA508GetComponentProp(getFocus(), VA508_FieldName_State, VA508_Cache_Use, strState) > 0 then
1499 ;say("has custom state",ot_jaws_message)
1500 ;say(strState,ot_item_state)
1501 let sDisplayText = sDisplayText + "Custom State: " + strState + "\n"
1502 let iCustomInfo = true
1503Endif
1504if VA508GetComponentProp(getFocus(),VA508_FieldName_Instructions, VA508_Cache_Use, strInstructions) > 0 then
1505 ;say("has custom instructions",ot_jaws_message)
1506 ;say(strInstructions,ot_line)
1507 let sDisplayText = sDisplayText + "Custom Instructions: " + strInstructions + "\n"
1508 let iCustomInfo = true
1509Endif
1510if VA508GetComponentProp(getFocus(), VA508_FieldName_Item_Instructions, VA508_Cache_Use, strItemInstructions) > 0 then
1511 ;say("has custom item instructions",ot_jaws_message)
1512 ;say(strItemInstructions,ot_line)
1513 let sDisplayText = sDisplayText + "Custom Item Instructions: " + strItemInstructions + "\n"
1514 let iCustomInfo = true
1515Endif
1516if !iCustomInfo then
1517 ;say("No custom information found",ot_Jaws_message)
1518 let sDisplayText = "no custom information found\n"
1519Endif
1520
1521va508getApplicationData(getFocus(),va508_queryCode_all)
1522;copyToClipboard("Status:" + VA508GetStringValue(va508_fieldname_data_status)+ " Data: " + gsva508data)
1523let sDisplayText = sDisplayText + "Status:" + VA508GetStringValue(va508_fieldname_data_status)+ " Data: " + gsva508data + "\n" + "DLL handle: " + IntToString(ghVA508DLLWindow) + "\n" + "Need to link to DLL?: " + IntToString(gbVA508needToLinkToDLL) + "\n" + "Data Windows Title: " + gsVA508dataWindowTitle + "\n"
1524;sayMessage(ot_message,"data copied to clipboard")
1525If UserBufferIsActive() then UserBufferDeActivate() Endif
1526UserBufferClear()
1527sayMessage(ot_user_buffer,sDisplayText)
1528EndFunction
1529
1530;**********************************************************************
1531int function abs(int n)
1532; Absolute value
1533if n < 0 then
1534 return 0-n
1535endIf
1536return n
1537endFunction
1538
1539;**********************************************************************
1540; Get position and count from TORComboBox windows.
1541;**********************************************************************
1542int function getTorComboInfo(int byRef pos, int byRef count)
1543var
1544 handle hwnd,
1545 object o, int childID
1546let hwnd = getCurrentWindow()
1547if !hwnd then
1548 return False
1549endIf
1550if getWindowClass(hwnd) == "TorComboEdit" then
1551 let hwnd = getParent(hwnd)
1552endIf
1553if getWindowClass(hwnd) != "TorComboBox" then
1554 return False
1555endIf
1556let o = getObjectFromEvent(hwnd, -4, 0, childID) ; -4 = ObjID_Client
1557if !o then
1558 return False
1559endIf
1560let o = o.accNavigate(8, childID) ; 8 = NavDir_LastChild
1561if !o then
1562 return False
1563endIf
1564if o.accRole(0) == 9 then ; 9 = Role_System_Window
1565 let o = o.accChild(-4)
1566 if !o then
1567 return False
1568 endIf
1569endIf
1570if o.accRole(0) != 33 ; 33 = Role_System_List
1571&& isPCCursor() && getWindowTypeCode(getFirstChild(getFocus())) == WT_Button then
1572 let hwnd = getFirstChild(findTopLevelWindow("TORDropPanel", ""))
1573 if getWindowClass(hwnd) != "TORListBox"
1574 || abs(getWindowLeft(hwnd) -getWindowLeft(getFocus())) > 5
1575 || abs(getWindowTop(hwnd) -getWindowBottom(getFocus())) > 5 then
1576 return False
1577 endIf
1578 let o = getObjectFromEvent(hwnd, -4, 0, childID) ; -4 = ObjID_Client
1579 if !o then
1580 return False
1581 endIf
1582 if o.accRole(0) != 33 then ; 33 = Role_System_List
1583 return False
1584 endIf
1585endIf
1586let count = o.accChildCount +0
1587let pos = o.accSelection +0
1588return True
1589endFunction
1590
1591;**********************************************************************
1592; add proper speaking of position in group information for standard delphi listboxes, listviews already work correctly
1593; called by sayTreeViewLevel from activeItemChangedEvent
1594String Function PositionInGroup ()
1595var
1596 handle hwnd,
1597 int hItem,
1598 int hOrigItem,
1599 int count,
1600 int count1,
1601 int pos,
1602 string str
1603
1604 let hwnd = getFocus()
1605 let pos = 0
1606 let count = 0
1607 if getObjectTypeCode() == wt_listboxitem then ; this is actually for list views which return a type code of listbox item
1608 let pos = lvGetFocusItem(hwnd)
1609 let count = lvGetItemCount (hwnd)
1610 elif getObjectTypeCode() == wt_listbox then
1611 let pos = SendMessage(hwnd,LB_GETCURSEL,0,0)+1
1612 let count = SendMessage(hwnd,LB_COUNT,0,0)
1613 elif getWindowClass(hwnd) == "TorComboEdit"
1614 || (getWindowClass(hwnd) == "TorComboBox" && !positionInGroup())
1615 then
1616 if !getTorComboInfo(pos, count) then
1617 let pos = 0
1618 let count = 0
1619 endIf
1620 elif getObjectTypeCode() == wt_treeview && !(StringContains(StringLower(PositionInGroup()),"of") ||
1621 StringContains(StringLower(PositionInGroup()),"item")) then
1622 ; sayString(positioninGroup())
1623 ; use custom
1624 let hItem = sendMessage(hWnd,TVM_GETNEXTITEM,TVGN_CARET,0)
1625 if hItem then
1626 let hOrigItem = hItem
1627 let count = 0
1628 while hItem != 0 && count < 200 ; should always go through once
1629 let hItem = sendMessage(hWnd,TVM_GETNEXTITEM,TVGN_PREVIOUS,hItem)
1630 let count = count + 1
1631 EndWhile
1632 let hItem = hOrigItem
1633 let count1 = -1
1634 while hItem != 0 && count1 < 200 ; should always go through once
1635 let hItem = sendMessage(hWnd,TVM_GETNEXTITEM,TVGN_NEXT,hItem)
1636 let count1 = count1 + 1
1637 EndWhile
1638 let pos = count
1639 let count = count+count1
1640 Endif ; if we a valid handle for the item
1641 endif ; if we have a valid position
1642 if count then
1643 if pos == 0 then
1644 if count == 1 then
1645 let str = formatString(msgItemCount1, intToString(count))
1646 else
1647 let str = formatString(msgItemCount2, intToString(count))
1648 endIf
1649 else
1650 let str = formatString(msgPosMOfN, intToString(pos), intToString(count))
1651 endIf
1652 endIf
1653 if stringLength(str) then
1654 return str
1655 endIf
1656 return PositionInGroup()
1657EndFunction
1658
1659;**********************************************************************
1660;**********************************************************************
1661Script Test()
1662var
1663 string str
1664
1665; get4kName(getCurrentWindow())
1666; sayInteger(RegisterWindowMessage("VA 508 / Freedom Scientific - JAWS Communication Message ID"))
1667EndScript
1668
1669;**********************************************************************
1670; Test function for getting and speaking and/or displaying all DLL framework data for any window.
1671; Requires BX to be loaded.
1672; Usage:
1673; First select a window via the BX Window Navigation map.
1674; Then from inside or outside of BX, type BXQuickKey T (for Test) <num>.
1675; <num> is a number or number plus other keys that determine what to query for and speak or show, as follows:
1676; - 0 for query and speak all,
1677; - Ctrl+Shift+3 for query and show-all (in JAWS virtual viewer),
1678; - 1-7 for query and speak caption, value, controlType, state, instructions, itemInstructions, or data individually,
1679; - 8-9 to send query bit 8 or 9 and speak result,
1680; - Shift+0-9 to send one of query bits 10-19 and speak result,
1681; - Ctrl+0-9 to send one of query bits 20-29 and speak result,
1682; - Ctrl+Shift+0-2 to send one of query bits 30-32 and speak result, or
1683; - Ctrl+Shift+4-9 for query and show caption, value, controlType, state, instructions, or itemInstructions individually.
1684; Parameter n is set to 0-9 for keys 0-9, 10-19 for Shift+0-9, 20-29 for Ctrl+0-9, and 30-39 for Ctrl+Shift+0-9.
1685; This function calls VA508GetApplicationData and VA508GetGridData but does all other parsing internally.
1686;**********************************************************************
1687void function bxTestNum(int n)
1688var
1689 handle hwnd,
1690 int iQueryCode,
1691 string fmt,
1692 string varData, string data,
1693 string delim,
1694 string seg,
1695 string varName, int varStart, int varLen, string varVal,
1696 int i,
1697 string debugBuf,
1698 string buf
1699/*
1700let hwnd = VA508Cast(bxGetWindow())
1701if !hwnd then
1702 bxSayString("No window selected", "")
1703 return
1704endIf
1705*/
1706let hwnd = getCurrentWindow()
1707let fmt = ""
1708if n >= 32 then
1709 let n = n -33
1710 let fmt = fmt +"v"
1711endIf
1712if n then
1713 let iQueryCode = 1 << (n-1)
1714else
1715 let iQueryCode = VA508_QueryCode_All
1716endIf
1717VA508GetApplicationData(hwnd, iQueryCode)
1718let debugBuf = gsVA508GetAppDataDebugBuf
1719
1720let varData = gsVA508varData
1721let data = gsVA508data
1722let delim = stringLeft(varData, 1)
1723let buf = ""
1724let buf = buf +formatString(
1725 ;"VA508 data for window of class %1:\13\10Delimiter: '%2'\13\10",
1726 "VA508 data for window of class %1:\13\10",
1727 getWindowClass(hwnd),
1728 delim
1729 )
1730let i = 1
1731while i
1732 let i = i +1
1733 let seg = stringSegment(varData, delim, i)
1734 if stringLength(seg) then
1735 let varName = stringSegment(seg, "=,", 1)
1736 let varVal = ""
1737 let varStart = stringToInt(stringSegment(seg, "=,", 2)) +1
1738 let varLen = stringToInt(stringSegment(seg, "=,", 3))
1739 if varStart && varLen then
1740 let varVal = substring(data, varStart, varLen)
1741 endIf
1742 if stringLength(varVal) then
1743 let buf = buf +formatString("\13\10%1: %2", varName, varVal)
1744 if varName == "value" then
1745 ; Include grid data where appropriate.
1746 if VA508getGridData(varVal,0) then
1747 let buf = buf +formatString(
1748 "\13\10Grid data:\13\10Column %1 (%2 of %3)\13\10Row %4 (%5 of %6)\13\10Cell %7 (%8 of %9)",
1749 gsVA508cacheGridColHdr, intToString(giVA508cacheGridColNum), intToString(giVA508cacheGridColCnt),
1750 gsVA508cacheGridRowHdr, intToString(giVA508cacheGridRowNum), intToString(giVA508cacheGridRowCnt),
1751 gsVA508cacheGridCellVal, intToString(giVA508cacheGridCellNum), intToString(giVA508cacheGridCellCnt))
1752 endIf
1753 elif varName == "dataStatus" then
1754 ; Some of these bits are obsolete but can still be passed, so they are named here.
1755 ; Obsolete bits: CheckForStateChanges through ItemChangeSpeakValues, except for ItemChanged.
1756 ; [DGL, 2007-05-31]
1757 let buf = buf +formatString(" (%1)",
1758 VA508Cast(olStringFlags(stringToInt(varVal),
1759 "|Caption|Value|ControlType|State|Instructions|ItemInstructions|Data||CheckForStateChanges|CheckForItemChanges|GetOnlyIfStateChanged|GetOnlyIfItemChanged|StateChanged|ItemChanged|ItemChangeSpeakValues|||||||||Error"))
1760 )
1761 endIf
1762 endIf
1763 else
1764 let i = 0 ; exits loop
1765 endIf
1766endWhile
1767if fwDebug then
1768 let buf = buf +formatString("\13\10\13\10VarData: %1\13\10Data: %2",
1769 varData, data)
1770 if debugBuf then
1771 let buf = buf +"\13\10\13\10" +debugBuf
1772 endIf
1773endIf ; fwDebug
1774bxSayString(buf, fmt)
1775endFunction
1776
1777;**********************************************************************
1778; Automatically close a combo box if one is open when tab or shift+tab is pressed
1779; Without this, tab and shift+tab in an open combo box do nothing.
1780;**********************************************************************
1781void function autoCloseIfOpenCombo()
1782var
1783 string class,
1784 handle hWnd
1785 let hWnd = getFocus()
1786 if getWindowClass(hWnd) == wcComboLBox then
1787 TypeKey(Key_F4)
1788 endIf
1789endFunction
1790
1791;**********************************************************************
1792Script Tab()
1793if isSpecialFocus(False) then
1794 autoCloseIfOpenCombo()
1795endIf
1796 PerformScript Tab()
1797EndScript
1798
1799;**********************************************************************
1800Script ShiftTab()
1801if isSpecialFocus(False) then
1802 autoCloseIfOpenCombo()
1803endIf
1804 PerformScript ShiftTab()
1805EndScript
1806
1807;**********************************************************************
1808; Avoids double speech in edit combo boxes.
1809;**********************************************************************
1810Void Function ValueChangedEvent (handle hwnd, int objId, int childId, int nObjType, string sObjName, string sObjValue,int bIsFocusObject)
1811; A fix borrowed from JAWS 9...
1812if nObjType == WT_Edit
1813&& getObjectSubtypeCode() == WT_EditCombo then
1814 ; This seems to happen at random;
1815 ; nObjType should normally be WT_EditCombo also. [DGL, 2007-10-03]
1816 let nObjType = WT_EditCombo
1817endIf
1818 ValueChangedEvent (hwnd, objId, childId, nObjType, sObjName, sObjValue, bIsFocusObject)
1819 if nObjType == wt_editCombo && bIsFocusObject && sObjValue then
1820 ; we can assume it was spoken so suppress sayHighLightedText
1821 let gbVA508suppressEcho = true
1822 endIf
1823EndFunction
1824
1825;**********************************************************************
1826; Overwrite of default to prevent double speaking in edit comboes and other places
1827;**********************************************************************
1828Void Function SayHighLightedText (handle hwnd, string buffer)
1829 if lt_suppressHighlight then
1830 scheduleFunction("lt_clearSuppressHighlight", 3)
1831 return
1832 endIf
1833
1834 ; sayInteger(GetWindowSubTypeCode(hwnd))
1835 ; prevent double speaking in open edit comboes
1836 if getWindowClass(getFocus()) == wcComboLBox then
1837 if getWindowSubTypeCode(hwnd) == wt_editcombo || getWindowClass(hwnd) == "TORComboEdit" then
1838 return
1839 endIf
1840 EndIf
1841 ; prevent double speaking in TORComboEdit boxes, which seem to stay open.
1842if (hwnd == getFocus() || getWindowClass(hwnd) == "TORListBox")
1843&& getWindowClass(getFocus()) == "TORComboEdit" then
1844 return
1845endIf
1846;sayString(getWindowClass(hwnd) +" " +getWindowClass(getFocus()))
1847 if getWindowClass(hwnd) == wcTMaskEdit then
1848 return
1849 Endif
1850 ; added to suppress echo when valueChangedEvent works in closed editComboes
1851 if gbVA508suppressEcho then
1852 let gbVA508suppressEcho = false
1853 return
1854 EndIf
1855 if getWindowClass(hwnd) == wcTStringGrid && hwnd != getFocus() then
1856 return ; prevent speaking of highlight in grid when focus is not in that control
1857 Endif
1858
1859 SayHighLightedText (hwnd, buffer)
1860EndFunction
1861
1862;**********************************************************************
1863; Handles custom translations of types and states for output.
1864; Also completely defines the structure and location of translation tables.
1865; sTable: Braille for Braille translations.
1866; Other tables such as "Speech" could be defined if necessary.
1867; iQueryCode: Properties to look up in the table.
1868; %1 and %2 in sKeyFormat become initial Type and State values, respectively.
1869; sTypeVal and sStateVal: Initial values on entry, initial or translated as appropriate on exit.
1870; Returns True if anything was changed and False if not.
1871;
1872; Table location: All in <app>.jcf (initially VA508APP.jcf).
1873; Table section names: [<name> Translations] (e.g., <name>=Braille)
1874; Keys (LHS in file): <prop1name>[|<prop2name>...] <propVal1>[|<propVal2>...]
1875; where prop<n>name = e.g. ControlType or State.
1876; Examples: "ControlType checkbox" or "ControlType|State Checkbox|Checked"
1877; Values (RHS in file): <delim><prop1val>[|<prop2val>...]
1878; Examples: "|lbx" or "|lbx|<x>"
1879; Full example:
1880; [Braille Translations]
1881; ControlType|State checkListBox|checked=|lbx|<x>
1882; makes the type "lbx" and the state "<x>" for a checked listbox item.
1883; Called by controlPropGet
1884;**********************************************************************
1885int function VA508TranslateProps(string sTable, int iQueryCode, string byRef sTypeVal, string byRef sStateVal)
1886var
1887 string sFile,
1888 string sSect,
1889 string sKeyFormat1, string sKeyFormat2, string sKeyFormat,
1890 string sKey,
1891 string sTran,
1892 string sDelim,
1893 int i,
1894 int iChanged
1895let iChanged = False
1896
1897; Set file and section.
1898let sFile = findJAWSSettingsFile(getActiveConfiguration() +".jcf")
1899if !fileExists(sFile) then
1900 ; No file, no translations.
1901 return False
1902endIf
1903let sSect = formatString("%1 Translations", sTable)
1904
1905; Set key by constructing it based on iQueryCode.
1906let sKeyFormat1 = ""
1907let sKeyFormat2 = ""
1908if iQueryCode & VA508_QueryCode_Control_Type then
1909 let sKeyFormat1 = sKeyFormat1 +"|ControlType"
1910 let sKeyFormat2 = sKeyFormat2 +"|%1"
1911endIf
1912if iQueryCode & VA508_QueryCode_State then
1913 let sKeyFormat1 = sKeyFormat1 +"|State"
1914 let sKeyFormat2 = sKeyFormat2 +"|%2"
1915endIf
1916let sKeyFormat = stringChopLeft(sKeyFormat1, 1) +msgSpace +stringChopLeft(sKeyFormat2, 1)
1917let sKey = formatString(sKeyFormat, sTypeVal, sStateVal)
1918
1919; Look up the key and abort if not found.
1920let sTran = iniReadString(sSect, sKey, "<NoTranslation>", sFile)
1921if stringCompare(sTran, "<NoTranslation>", True) == 0 then
1922 return False
1923endIf
1924
1925; A translation was found; interpret it.
1926let sDelim = stringLeft(sTran, 1)
1927let i = 1
1928if stringContains(sKeyFormat, "%1") then
1929 ; There is a Type translation.
1930 let i = i +1
1931 let sTypeVal = stringSegment(sTran, sDelim, i)
1932 let iChanged = True
1933endIf
1934if stringContains(sKeyFormat, "%2") then
1935 ; There is a State translation.
1936 let i = i +1
1937 let sStateVal = stringSegment(sTran, sDelim, i)
1938 let iChanged = True
1939endIf
1940return iChanged
1941endFunction
1942
1943;**********************************************************************
1944; Handles all control property requests.
1945; Called only by BraillePropHelper
1946; Returns 1 when a property has a custom value, 0 when not, and below 0 on error.
1947; This function defines the accepted list of JAWS control property names.
1948; Most of them come from the names of the BrailleAddObject* functions built in to JAWS.
1949; sOrigin can be current, focus, or hwnd<handle>.
1950; whichProp is the name of the property sought.
1951; whichProp can end in .brl for a Braille-specific answer.
1952; sVal is the returned property value if the function returns 1, undefined otherwise.
1953;**********************************************************************
1954int function controlpropGet(string sOrigin, string whichProp, int nSubtype, string byRef sVal)
1955var
1956 handle hwnd,
1957 int iCacheHandling,
1958 int isBraille,
1959 int iResult
1960
1961; sayString("control prop")
1962; Get hwnd, iCacheHandling, and nSubtype worked out.
1963let iCacheHandling = VA508_Cache_Skip
1964if sOrigin == "focus"
1965|| (sOrigin == "current" && isPCCursor()) then
1966 let hwnd = getFocus()
1967 let iCacheHandling = VA508_Cache_Use
1968 if !nSubtype then
1969 let nSubtype = getObjectSubtypeCode()
1970 endIf
1971elif sOrigin == "current" then
1972 let hwnd = getCurrentWindow()
1973 if !nSubtype then
1974 let nSubtype = getObjectSubtypeCode()
1975 endIf
1976elif sOrigin == "hwnd" then
1977 let hwnd = stringToHandle(stringChopLeft(sOrigin, 4))
1978 if hwnd == getFocus() then
1979 let iCacheHandling = VA508_Cache_Use
1980 endIf
1981 if !nSubtype then
1982 let nSubtype = getWindowSubtypeCode(hwnd)
1983 endIf
1984else
1985 ; Not supported at this time.
1986 return 0
1987endIf
1988
1989; Now for isBraille and whichProp.
1990let isBraille = False
1991if stringRight(whichProp, 4) == ".brl" then
1992 let whichProp = stringChopRight(whichProp, 4)
1993 let isBraille = True
1994endIf
1995
1996; Check the framework for custom values.
1997if whichProp == "Name" then
1998 return VA508GetComponentProp(hwnd, VA508_FieldName_Caption, iCacheHandling, sVal)
1999elif whichProp == "Type" || whichProp == "State" then
2000 var
2001 int iTypeRet, string sTypeVal,
2002 int iStateRet, string sStateVal
2003 let iTypeRet = VA508GetComponentProp(hwnd, VA508_FieldName_Control_Type, iCacheHandling, sTypeVal)
2004 let iStateRet = VA508GetComponentProp(hwnd, VA508_FieldName_State, iCacheHandling, sStateVal)
2005 if isBraille then
2006 if iTypeRet > 0 && iStateRet > 0 then
2007 VA508TranslateProps("Braille", VA508_QueryCode_Control_Type +VA508_QueryCode_State, sTypeVal, sStateVal)
2008 endIf
2009 if iTypeRet > 0 then
2010 VA508TranslateProps("Braille", VA508_QueryCode_Control_Type, sTypeVal, sStateVal)
2011 endIf
2012 if iStateRet > 0 then
2013 VA508TranslateProps("Braille", VA508_QueryCode_State, sTypeVal, sStateVal)
2014 endIf
2015 endIf ; isBraille
2016 if whichProp == "Type" then
2017 let sVal = sTypeVal
2018 return iTypeRet
2019 else ; State
2020 let sVal = sStateVal
2021 return iStateRet
2022 endIf
2023elif whichProp == "Value" then
2024 var int iValFound
2025 let iValFound = VA508GetComponentProp(hwnd, VA508_FieldName_Value, iCacheHandling, sVal) > 0
2026 if iValFound > 0 && VA508GetGridData(sVal,0) then ; GRID
2027 if isBraille then
2028 let sVal = ""
2029 if giGridBrailleMode == 1 || giGridBrailleMode == 3 then
2030 let sVal = "r"+IntToString(giVA508CacheGridRowNum)+"c"+intToString(giVa508CacheGridcolNum)+msgSpace
2031 Endif
2032 if giGridBrailleMode == 1 || giGridBrailleMode == 2 then
2033 let sVal = sVal + gsVA508cacheGridRowHdr +msgSpace +gsVA508CacheGridColHdr +msgSpace
2034 endif
2035 if gsVA508CacheGridCellVal == "" then
2036 let gsVA508CacheGridCellVal = "-"
2037 Endif
2038 else ; NOT BRAILLE
2039 let sVal = ""
2040 endIf ; isBraille
2041 let sVal = sVal + gsVA508CacheGridCellVal ;always show cell
2042 return true
2043 elif nSubType == wt_progressBar then
2044 if iValFound < 1 then
2045 let sVal = getObjectValue()
2046 return true
2047 Endif
2048 endif
2049 return iValFound
2050; TODO: Many of the rest are not handled yet.
2051elif whichProp == "ContainerName" then
2052 ; Generally a group box name.
2053elif whichProp == "ContainerType" then
2054 ; Not sure how often this one gets used.
2055elif whichProp == "Position" then
2056 ; e.g., "1 of 4" or "4 items" for lists and trees.
2057elif whichProp == "DlgPageName" then
2058 ; Name of active tab.
2059elif whichProp == "DlgText" then
2060 ; Dialog static text.
2061elif whichProp == "ContextHelp" then
2062 ; TODO: This could be Instructions or Item_Instructions.
2063elif whichProp == "Time" then
2064 ; This may not be used at all.
2065elif whichProp == "Level" then
2066 ; Tree level.
2067endIf
2068return 0 ; no custom value for this property
2069endFunction
2070
2071; Braille Support
2072;**********************************************************************
2073int function BraillePropHelper(string whichProp, int nSubtype)
2074; Logic for BrailleAddObject* functions to use.
2075var
2076 int x, int y,
2077 int tc,
2078 int iResult,
2079 string sVal,
2080 int nWindowSubTypeCode
2081
2082let nWindowSubTypeCode = getWindowSubtypeCode(getFocus())
2083if nWindowSubTypeCode == wt_unknown then
2084 let nWindowSubTypeCode = getObjectSubTypeCode()
2085endif
2086
2087if nWindowSubTypeCode != nSubtype then
2088 ; BrailleAddObject* function(s) called on a parent (e.g., dialog) control.
2089 ; We currently have no way to handle this, so let JAWS do it.
2090 return False
2091endIf
2092
2093let iResult = controlpropGet("focus", whichProp +".brl", nSubType, sVal)
2094if iResult > 0 then
2095 if whichProp != "name" then ; prevents cursor from being placed on label instead of value in edit fields
2096 let x = getCursorCol()
2097 let y = getCursorRow()
2098 Endif
2099 BrailleAddString(sVal, x,y, 0)
2100 return True
2101endIf
2102return False
2103endFunction
2104
2105;************************************************************************
2106int Function BrailleClassFound(string ControlType, int byref nType)
2107var
2108 int i,
2109 int count
2110
2111 let i = StringSegmentIndex (glbsTable, string_delim, StringLower(msgSpace+ControlType), true)
2112 if i then
2113 let nType = StringToInt(StringSegment(glbsTable2,string_delim,i))
2114 return true
2115 endif
2116return false
2117EndFunction
2118
2119;************************************************************************
2120int function BrailleCallbackObjectIdentify()
2121var
2122 int nType,
2123 string controlType
2124
2125if isSpinBox(getCurrentWindow()) then
2126 return wt_spinbox
2127Endif
2128if VA508GetComponentProp(getCurrentWindow(),VA508_FieldName_Control_Type,VA508_Cache_Use,controlType) > 0 then
2129 let nType = 0
2130 if BrailleClassFound(ControlType, nType) then
2131 return nType
2132 EndIf
2133Endif
2134return BrailleCallBackObjectIdentify()
2135EndFunction
2136
2137; added so spinbox sub type code can make nSubType code passed to BrailleAddObject functions
2138; what is returned in getWindowSubTypeCode must matach what is returned in BrailleCallBackObjectIdentify for the BraillePropHelper to show any custom information
2139;************************************************************************
2140int Function getWindowSubTypeCode (handle hwnd)
2141var
2142 int nType,
2143 string ControlType,
2144 int cacheHandling
2145
2146; sayString("get window sub type code")
2147
2148if isSpinBox(hwnd) then
2149 return wt_spinbox
2150Endif
2151if hwnd == getFocus() then
2152 let cacheHandling = VA508_Cache_Use
2153else
2154 let cacheHandling = VA508_Cache_Skip
2155endIf
2156if VA508GetComponentProp(getCurrentWindow(),VA508_FieldName_Control_Type,cacheHandling,controlType) > 0 then
2157 if BrailleClassFound(ControlType, nType) then
2158 return nType
2159 EndIf
2160Endif
2161return getWindowSubTypeCode(hwnd)
2162EndFunction
2163
2164;************************************************************************
2165; These are all the BrailleAddObject* functions internally recognized as of JAWS 8.0.
2166int function BrailleAddObjectName(int nSubtype)
2167return BraillePropHelper("Name", nSubtype)
2168endFunction
2169
2170;************************************************************************
2171int function BrailleAddObjectType(int nSubtype)
2172return BraillePropHelper("Type", nSubtype)
2173endFunction
2174
2175;************************************************************************
2176int function BrailleAddObjectState(int nSubtype)
2177return BraillePropHelper("State", nSubtype)
2178endFunction
2179
2180;************************************************************************
2181int function BrailleAddObjectValue(int nSubtype)
2182return BraillePropHelper("Value", nSubtype)
2183endFunction
2184
2185;************************************************************************
2186int function BrailleAddObjectContainerName(int nSubtype)
2187return BraillePropHelper("ContainerName", nSubtype)
2188endFunction
2189
2190;************************************************************************
2191int function BrailleAddObjectContainerType(int nSubtype)
2192return BraillePropHelper("ContainerType", nSubtype)
2193endFunction
2194
2195;************************************************************************
2196int function BrailleAddObjectPosition(int nSubtype)
2197return BraillePropHelper("Position", nSubtype)
2198endFunction
2199
2200;************************************************************************
2201int function BrailleAddObjectDlgPageName(int nSubtype)
2202return BraillePropHelper("DlgPageName", nSubtype)
2203endFunction
2204
2205;************************************************************************
2206int function BrailleAddObjectDlgText(int nSubtype)
2207return BraillePropHelper("DlgText", nSubtype)
2208endFunction
2209
2210;************************************************************************
2211int function BrailleAddObjectContextHelp(int nSubtype)
2212return BraillePropHelper("ContextHelp", nSubtype)
2213endFunction
2214
2215;************************************************************************
2216int function BrailleAddObjectTime(int nSubtype)
2217return BraillePropHelper("Time", nSubtype)
2218endFunction
2219
2220;************************************************************************
2221int function BrailleAddObjectLevel(int nSubtype)
2222return BraillePropHelper("Level", nSubtype)
2223endFunction
2224
2225;**********************************************************************
2226; Allows JAWS ListView commands like Ctrl+JAWSKey+numbers to work with custom but functional ListView controls
2227; Only affects JAWS 7.1 and later.
2228;**********************************************************************
2229int function isTrueListView(handle hwnd)
2230var
2231 int result
2232let result = isTrueListView(hwnd)
2233if result then
2234 return result
2235endIf
2236if stringContains(stringLower(getWindowClass(hwnd)), "list")
2237&& lvGetNumOfColumns(hwnd) > 0 then
2238 return True
2239endIf
2240return False
2241endFunction
2242
2243;**********************************************************************
2244; Makes F2 edit the current tree node as a left-click does
2245;**********************************************************************
2246Script f2editTreeNode ()
2247var
2248 int hItem,
2249 handle hWnd
2250
2251sayCurrentScriptKeyLabel()
2252let hwnd = getFocus()
2253if getWindowClass(hWnd) == wcTTreeView then
2254 let hItem = sendMessage(hWnd,TVM_GETNEXTITEM,TVGN_CARET,0)
2255 if hItem then
2256 sendMessage(hWnd,TVM_EDITLABELW,0,hitem)
2257 return
2258 Endif
2259elif getWindowTypeCode(hwnd) == WT_TREEVIEW then ; we have a tree that's not a TTreeView then it might not have an api so use mouse
2260 saveCursor() JAWSCursor() saveCursor()
2261 routeJAWSToPC()
2262 leftMouseButton()
2263 return
2264endIf
2265typeCurrentScriptKey()
2266
2267EndScript
2268
2269;**********************************************************************
2270; Called by JAWS.SR when things happen to a window in the active VA508 application.
2271; This is the only function/script in this file called externally.
2272; ControlTypes are only sent for custom types and are always sent regardless of whether the type changes, it is doubtful that a type will actually change
2273; This function gets called before focusChangedEvent, thus 3ms schedule functions were used
2274;**********************************************************************
2275void function VA508ChangeEvent(handle hwnd, int iDataStatus, string sCaption, string sValue, string sControlType,
2276 string sState, string sInstructions, string sItemInstructions)
2277
2278; sayString("called")
2279
2280if giCancelEvent == true then
2281 return
2282Endif
2283
2284let ghFromChangeEvent = hwnd
2285let giDidFocusChange = false ; used to ensure that we don't have double speaking when the event comes in before handleCustomWindows has a change to speak it
2286if iDataStatus & VA508_Data_Change_Event then
2287 let iDataStatus = iDataStatus - VA508_Data_Change_Event ; not needed so let's remove
2288Endif
2289if iDataStatus & VA508_QueryCode_Control_Type then
2290 let iDataStatus = iDataStatus - VA508_QueryCode_Control_Type ; not needed
2291Endif
2292
2293; Update the cache so Braille will update immediately.
2294VA508CacheSetVals(hwnd, iDataStatus, sCaption, sValue, sControlType,
2295 sState, sInstructions, sItemInstructions)
2296BrailleRefresh() ;for an instant update rather than waiting up to 2 seconds to see the change, or in the case of braille viewer instead of waiting 30 seconds
2297/*
2298sayString(formatString(
2299"Event %1 vals %2 %3 %4 %5 %6 %7",
2300decToHex(iDataStatus), sCaption, sValue, sControlType,
2301 sState, sInstructions, sItemInstructions
2302))
2303*/
2304
2305; Don't speak changes to non-focused windows.
2306if hwnd != getFocus() then
2307 if inDebugging then bxGauge(3, 0) Endif
2308 return
2309endIf
2310watchCount("change")
2311
2312; was a grid cell changed?
2313; jda 9-14-07
2314
2315if VA508GetGridData(sValue,0) && !giSpokeCellUnit then
2316 say(gsVA508cacheGridColHdr,ot_control_name)
2317 say(gsVA508cacheGridRowHdr,ot_control_name)
2318 if gsVA508cacheGridCellVal == "" then
2319 let gsVA508cacheGridCellVal = " " ; so blank will be spoken
2320 Endif
2321 say(gsVA508cacheGridCellVal,ot_line)
2322 say("column " + intToString(giVA508cacheGridColNum),ot_position)
2323 say("row " + intToString(giVA508cacheGridRowNum),ot_position)
2324 return
2325Endif
2326
2327; For some one-thing-only changes, just speak what changed.
2328; Since changes are spoken individually this might affect reading order preferences that users have set when arrow keys are used
2329if iDataStatus & VA508_QueryCode_Caption && sCaption then
2330 let giSuppressCaption = true
2331Endif
2332; this is always set and thus would always be announced, thus it is filtered out and should not get called
2333if iDataStatus & VA508_QueryCode_Control_Type && sControlType then
2334 let giSuppressControlType = true
2335endIf
2336if iDataStatus & VA508_QueryCode_State && sState then
2337 let giSuppressState = true
2338Endif
2339if iDataStatus & VA508_QueryCode_Value && sValue && !VA508GetGridData(hwnd,0) then
2340 let giSuppressValue = true
2341Endif
2342if iDataStatus & VA508_QueryCode_Instructions && sInstructions then
2343 let giSuppressInstructions = true
2344Endif
2345if iDataStatus & VA508_QueryCode_Item_instructions && sItemInstructions then
2346 let giSuppressItemInstructions = true
2347Endif
2348ScheduleFunction("AnnounceEvent",3)
2349
2350endFunction
2351
2352;*********************************************************************************************************
2353; Called by the Announce* functions below.
2354;*********************************************************************************************************
2355Void Function AnnounceProp(int iQueryCode, int outputType, int byRef propGlobalFlag)
2356var
2357 string prop
2358
2359if propGlobalFlag && giDidFocusChange == false then
2360 if VA508getComponentProp(ghFromChangeEvent, iQueryCode, VA508_Cache_Use, prop) > 0 then
2361 sayMessage(outputType, prop)
2362 Endif
2363Endif
2364let propGlobalFlag = false
2365EndFunction
2366
2367;*********************************************************************************************************
2368; All these are called by va508ChangeEvent
2369;*********************************************************************************************************
2370Void Function AnnounceEvent()
2371AnnounceProp(VA508_QueryCode_Caption, OT_Control_Name, giSuppressCaption)
2372AnnounceProp(VA508_QueryCode_Control_Type, OT_Control_Type, giSuppressControlType)
2373AnnounceProp(VA508_QueryCode_State, OT_Item_State, giSuppressState)
2374AnnounceProp(VA508_QueryCode_Value, OT_Selected_Item, giSuppressValue)
2375AnnounceProp(VA508_QueryCode_Instructions, OT_Tutor, giSuppressInstructions)
2376AnnounceProp(VA508_QueryCode_Item_Instructions, OT_Tutor, giSuppressItemInstructions)
2377endFunction
2378
2379;*********************************************************************************************************
2380; overwrite of default to allow control+tab to be used to change tabs in Delphi applications
2381Script NextDocumentWindow ()
2382 ChangeDocumentWindow(1)
2383EndScript
2384
2385;*********************************************************************************************************
2386; overwrite of default to allow control_shift+tab to be used to change tabs in Delphi applications
2387Script PreviousDocumentWindow ()
2388 ChangeDocumentWindow(0)
2389EndScript
2390
2391;*********************************************************************************************************
2392; allows control tab when pressed on a child object of a page tab to announce the change in page
2393; allows control tab to announce the correct tab when focus in on page tab control and style is set to button or flat button
2394;*********************************************************************************************************
2395Void Function ChangeDocumentWindow(int direction)
2396var
2397 string pageName,
2398 handle hwnd
2399
2400 if isSpecialFocus(False) then
2401 if direction == 1 then
2402 PerformScript NextDocumentWindow()
2403 elif direction == 0 then
2404 PerformScript PreviousDocumentWindow()
2405 Endif
2406 return
2407 endIf
2408
2409 let hwnd = getFocus()
2410 ; store to see if page changed
2411 let PageName = getDialogPageName()
2412
2413 ; cause tab to change
2414 if getWindowClass(hwnd) == wcTTabControl then ; this control doesn't natively support control+shift+tab
2415 if direction == 1 then
2416 typeKey(ksRightArrow)
2417 elif direction == 0 then
2418 typeKey(ksLeftArrow)
2419 endif
2420 elif getWindowClass(getParent(hwnd)) == wcTTabControl ||
2421 getWindowClass(getParent(getParent(hwnd))) == wcTTabControl then ; this control doesn't natively support control+shift+tab
2422 SelectTab(direction)
2423 endif
2424
2425 if direction == 1 then
2426 PerformScript NextDocumentWindow()
2427 elif direction == 0 then
2428 PerformScript PreviousDocumentWindow()
2429 Endif
2430
2431 let hwnd = getFocus() ; have to get focus again because it may have changed???
2432 ; announce change when focus is on special type of TPageControl tab with buttons
2433 if getObjectTypeCode() == wt_tabcontrol then
2434 if getWindowStyleBits(hwnd) & window_style_tabsWithButtons then ; tabs with buttons or flat buttons, control+tab doesn't work correctly here
2435 let glbSuppressFocusChange = true
2436 delay(1, True)
2437 SayControlEx (hwnd, getDialogPageName(), "", "", "", "", "", "", "")
2438 ScheduleFunction("ClearSuppressFocusChange",3)
2439 return
2440 endif
2441 ; announce change when focus is on child of page tab
2442 elif PageName != getDialogPageName() && getDialogPageName() then
2443 say(getDialogPageName()+msgSpace+MsgPage,ot_controL_name)
2444 endif
2445EndFunction
2446
2447;*********************************************************************************************************
2448; overwrite of default function to return proper page names in Delphi windows
2449String Function GetDialogPageName()
2450var
2451 string page,
2452 object o,
2453 int cid,
2454 handle hwnd
2455
2456 let hwnd = getFocus()
2457 let page = getDialogPageName()
2458 if page == "" then
2459 if getWindowClass(getParent(hwnd)) == wcTTabSheet ||
2460 getWindowClass(getParent(getParent(hwnd))) == wcTTabSheet then ; for TPageControl when child or granchild has focus
2461 if getWindowTypeCode(getParent(hwnd)) == wt_tabControl then
2462 let page = getWindowName(getParent(hwnd))
2463 elif getWindowTypeCode(getParent(getParent(hwnd))) == wt_tabControl then
2464 let page = getWindowName(getParent(getParent(hwnd)))
2465 endif
2466 ; TTabControl not handled here
2467 elif getWindowClass(getParent(hwnd)) == wcTTabControl ||
2468 getWindowClass(getParent(getParent(hwnd))) == wcTTabControl then ; forTTabControl when child or grandchild has focus
2469 let page = getSelectedTab()
2470 elif getObjectTypeCode() == wt_tabControl then ; for TTabControl and TPageControl
2471 ; getObjectName() can return the wrong name
2472 let o = getFocusObject(cid)
2473 if o then
2474 let page = o.accName(cid)
2475 endif
2476 endif
2477 endif
2478 return page
2479EndFunction
2480
2481; gets the selected tab from a TTabControl when a child control is in focus
2482;***************************************************************************
2483String Function getSelectedTab()
2484var
2485 object o,
2486 int cid,
2487 int count
2488
2489if getWindowClass(getParent(getFocus())) == wcTTabControl then ; forTTabControl
2490 let o = getFocusObject(cid) ; full child control
2491 let count = 1
2492 while o && count < 10 && o.accRole(childId_self) != role_system_pagetablist
2493 let o = o.accParent() ; window
2494 let count = count + 1
2495 EndWhile
2496
2497 if o && o.accRole(childId_self) == role_system_pagetablist then
2498 let count = 1
2499 while count <= o.accChildCount()
2500 if o.accState(count) & state_system_selected then
2501 return o.accName(count)
2502 endif
2503 let count = count + 1
2504 EndWhile
2505 endif
2506Endif
2507EndFunction
2508
2509;***************************************************************************
2510; 1 for next
2511; 0 for previous
2512; Used for TTabControl to activate a new tab using MSAA
2513;***************************************************************************
2514Void Function SelectTab(int direction)
2515var
2516 object o,
2517 int cid,
2518 int childCount,
2519 int count
2520
2521; msaa structure includes all control in page under page tab list.... troubling
2522; only works when groupbox or panel is not used
2523if getWindowClass(getParent(getFocus())) == wcTTabControl then ; forTTabControl
2524 let o = getFocusObject(cid)
2525 let count = 1
2526 ; find the page tab list
2527 while o && count < 10 && o.accRole(childId_self) != role_system_pagetablist
2528 let o = o.accParent() ; window
2529 let count = count + 1
2530 EndWhile
2531 ; find the selected child
2532 if o && o.accRole(childId_self) == role_system_pagetablist then
2533 let childCount = o.accChildCount()
2534 let count = 1
2535 while count <= o.accChildCount()
2536 if o.accState(count) & state_system_selected then
2537 let cid = count
2538 endif
2539 let count = count + 1
2540 EndWhile
2541 ; set focus to the next or prior child
2542 if direction == 1 then
2543 if o.accRole(cid+1) != role_system_pagetab then
2544 let cid = 0
2545 endif ; role page tab
2546 o.accSelect(selflag_takeSelection,cid+1)
2547 elif direction == 0 then
2548 if cid > 1 then
2549 o.accSelect(selflag_takeSelection,cid-1)
2550 else ; just sit on first tab
2551 endif
2552 Endif ; direction
2553 EndIf ; role page tab list
2554Endif ; TTabControl
2555EndFunction
2556
2557;***************************************************************************
2558; resets the global variable that suppress focus changes from being announced
2559Void Function ClearSuppressFocusChange()
2560 let glbSuppressFocusChange = FALSE
2561EndFunction
2562
2563;***************************************************************************
2564int Function isSpinBox (handle hwnd)
2565if getObjectTypeCode() == wt_edit && getWindowClass(getNextWindow(hwnd)) == wcTUpDown then
2566 return true
2567endif
2568return false
2569EndFunction
2570
2571;***************************************************************************
2572; get value for element from framework, falls back on getObjectValue()
2573String Function getValue()
2574var
2575 string value
2576
2577if VA508GetComponentProp(getFocus(),VA508_FieldName_Value,VA508_Cache_Update,value) <= 0 then ; no custom property returned
2578 let value = getObjectValue()
2579endif
2580return value ; could be null from either getObjectValue or from framework if it was set to null on purpose
2581EndFunction
2582
2583;***************************************************************************
2584; updated for grid support
2585int function moveByLine(int forward)
2586var
2587 handle hwnd
2588let hwnd = getFocus()
2589if isPCCursor() && !isSpecialFocus(False) then
2590 if isSpinBox(hwnd)
2591 || getWindowClass(hwnd) == "TORComboEdit"
2592 || getWindowClass(hwnd) == "TORComboBox" then
2593 if forward then
2594 nextLine()
2595 else
2596 priorLine()
2597 endIf
2598 if isSpinBox(hwnd)
2599 || getWindowClass(hwnd) == "TORComboEdit" then
2600 say(getValue(),ot_selected_item)
2601 endIf
2602 return True
2603 elif SpeakCellUnit("downArrow") then
2604 return True
2605 endIf
2606endIf
2607return False
2608endFunction
2609
2610Script SayNextLine()
2611if !moveByLine(True) then
2612 performScript sayNextLine()
2613endIf
2614EndScript
2615
2616Script SayPriorLine()
2617if !moveByLine(False) then
2618 performScript sayPriorLine()
2619endIf
2620EndScript
2621
2622;***************************************************************************
2623; updated for grid support
2624Script SayNextCharacter()
2625if SpeakCellUnit("rightArrow") then
2626 return
2627Endif
2628performScript sayNextCharacter()
2629EndScript
2630
2631;***************************************************************************
2632; updated to allow correct announcement in grids
2633;***************************************************************************
2634Script SayPriorCharacter()
2635 if SpeakCellUnit("leftArrow") then
2636 return
2637 Endif
2638 performScript sayPriorCharacter()
2639EndScript
2640
2641;******************************************************************
2642function clearSpokeCellUnit()
2643 let giSpokeCellUnit = false
2644EndFunction
2645
2646;******************************************************************
2647; Speaks the aspects of a cell that are different from the last cell visited
2648int Function SpeakCellUnit(string str)
2649var
2650 string strVal,
2651 string buildString
2652
2653;sayString("speak cell unit")
2654let giSpokeCellUnit = true
2655scheduleFunction("clearSpokeCellUnit",2) ; prevent double speaking by changeEvent
2656
2657if !isPCCursor() || isSpecialFocus(False) then
2658 return 0
2659elif VA508getGridData(getFocus(),0) > 0 then ; IN GRID
2660 TypeKey(str)
2661 delay(1, True)
2662 ; Update the cache.
2663 VA508GetComponentProp(getFocus(), VA508_FieldName_Value, VA508_Cache_Update, strVal)
2664 VA508GetGridData(strVal,0) ; have to call here to refresh view when Braille is not being used
2665 if gsVA508cacheGridCellVal == "" then
2666 let gsVA508cacheGridCellVal = " " ; so it will say blank with ot_line
2667 Endif
2668 if !giGridSpeechMode then
2669 say(gsVA508cacheGridCellVal,ot_line) ; DATA ONLY
2670 return 1
2671 elif str == "leftArrow" || str == "rightArrow" || str == "home" || str == "end" then
2672 ; COLUMN CHANGE
2673 if giGridSpeechMode == 1 || giGridSpeechMode == 2 then
2674 ; don't use ot_line here incase it is blank we dont' want blank spoken
2675 sayUsingVoice(VCTX_MESSAGE,gsVA508cacheGridColHdr,ot_control_name)
2676 Endif
2677 say(gsVA508cacheGridCellVal,ot_line)
2678 if giGridSpeechMode == 1 || giGridSpeechMode == 3 then
2679 say("column " + intToString(giVA508cacheGridColNum),ot_position)
2680 Endif
2681 return 1
2682 elif str == "upArrow" || str == "downArrow" || str == "pageUp" || str == "pageDown" then
2683 ; Row change
2684 if giGridSpeechMode == 1 || giGridSpeechMode == 2 then
2685 ; don't use ot_line here incase it is blank we dont' want blank spoken
2686 sayUsingVoice(VCTX_MESSAGE,gsVA508cacheGridRowHdr,ot_control_name)
2687 Endif
2688 say(gsVA508cacheGridCellVal,ot_line)
2689 if giGridSpeechMode == 1 || giGridSpeechMode == 3 then
2690 say("row " + intToString(giVA508cacheGridRowNum),ot_position)
2691 Endif
2692 return 1
2693 endif
2694; IN TAB CONTROL
2695elif getObjectTypeCode() == wt_tabcontrol && getWindowStyleBits(getCurrentWindow()) & window_style_tabsWithButtons then ; tabs with buttons or flat buttons
2696 let glbSuppressFocusChange = true
2697 TypeKey(str)
2698 delay(1, True)
2699 sayControlEx(getCurrentWindow(), getObjectName(), getObjectSubtype(), getAccState())
2700 ScheduleFunction("ClearSuppressFocusChange",3)
2701 return 1
2702endif
2703return 0
2704EndFunction
2705
2706;******************************************************************
2707; returns the full string of col number, row number, column name, row name, and cell data for the current table cell
2708; used by sayLine, tab, shift+tab, insert+tab and control+home, and control+end
2709string Function getCurrentCellHeadersData ()
2710var
2711 string str
2712
2713VA508GetGridData(getFocus(),0) ; have to call here to refresh view when Braille is not being used
2714let str = "column" + msgSpace + IntToString(giVA508CacheGridColNum) + "row" + msgSpace + IntToString(giVA508CacheGridRowNum) + msgSpace
2715let str = str + gsVA508cacheGridColHdr + msgSpace + gsVA508cacheGridRowHdr + msgSpace + gsVA508cacheGridCellVal
2716return str
2717EndFunction
2718
2719;home and end in grid
2720
2721;*********************************************************************
2722; updated for grid support
2723Script JAWSHome()
2724 if SpeakCellUnit("home") then
2725 return
2726 Endif
2727 performScript JAWSHome()
2728EndScript
2729
2730;*********************************************************************
2731; updated for grid support
2732Script JAWSEnd()
2733 if SpeakCellUnit("end") then
2734 return
2735 Endif
2736 performScript JAWSEnd()
2737EndScript
2738
2739;*********************************************************************
2740; updated for grid support
2741Script JAWSPageDown()
2742 if SpeakCellUnit("pageDown") then
2743 return
2744 Endif
2745 performScript JAWSPageDown()
2746EndScript
2747
2748;*********************************************************************
2749; updated for grid support
2750Script JAWSPageUp()
2751 if SpeakCellUnit("pageUp") then
2752 return
2753 Endif
2754 performScript JAWSPageUp()
2755EndScript
2756
2757;*********************************************************************
2758Int Function UpdateBrailleClasses()
2759var
2760 string sFile,
2761 string sTable,
2762 int i,
2763 int count
2764
2765let glbsTable = ""
2766let glbsTable2 = ""
2767let sFile = findJAWSSettingsFile(getActiveConfiguration() +".jcf") ; get applicatio specific jcf file
2768if !fileExists(sFile) then
2769 ; No file, no translations.
2770 return False
2771endIf
2772; file exists
2773; this line adds a space at the beginning of each item in the list that is returned because of a bug in StringSegmentIndex
2774let glbsTable = msgSpace + StringReplaceSubStrings(StringLower(IniReadSectionKeys (section_BrailleClasses, sFile)),string_delim, string_delim+MsgSpace) ; msgSpace need for first item to match
2775let count = VA508StringSegmentCount (glbsTable, string_delim)
2776let i = 1
2777while i <= count
2778 let glbsTable2 = glbsTable2 + IntToString(IniReadInteger (section_BrailleClasses, StringChopLeft(StringSegment(glbsTable,string_delim,count),1), 0, sFile)) + string_delim
2779 let i = i + 1
2780endWhile
2781if glbsTable2 then
2782 let glbsTable2 = stringChopRight (glbsTable2, 1)
2783Endif
2784return True
2785EndFunction
2786
2787;*****************************************************************************************************
2788Int Function UpdateControlTypes()
2789var
2790 string sFile,
2791 string sTable,
2792 int i,
2793 int count
2794
2795let glbsTable3 = ""
2796let glbsTable4 = ""
2797let sFile = findJAWSSettingsFile(getActiveConfiguration() +".jcf")
2798if !fileExists(sFile) then
2799 ; No file, no translations.
2800 return False
2801endIf
2802let glbsTable3 = msgSpace + StringReplaceSubStrings(StringLower(IniReadSectionKeys (section_ControlTypes, sFile)),string_delim, string_delim+msgSpace)
2803let count = VA508StringSegmentCount (glbsTable3, string_delim)
2804let i = 1
2805while i <= count
2806 let glbsTable4 = glbsTable4 + IniReadString (section_ControlTypes, StringChopLeft(StringSegment(glbsTable3,string_delim,count),1), msgNull, sFile) + string_delim
2807 let i = i + 1
2808endWhile
2809if glbsTable4 then
2810 let glbsTable4 = stringChopRight (glbsTable4, 1)
2811Endif
2812return True
2813EndFunction
2814
2815;************************************************************************
2816int Function ControlTypeFound (string ControlType, string ByRef newControlType)
2817var
2818 int i,
2819 int count
2820
2821 let i = StringSegmentIndex (glbsTable3, string_delim, StringLower(msgSpace+ControlType), true)
2822 if i then
2823 let newControlType = StringSegment(glbsTable4,string_delim,i)
2824 return true
2825 endif
2826return false
2827EndFunction
2828
2829
2830/* Start - Personal settings */
2831
2832;*******************************************************************************************
2833; called by JAWS verbosity dialog to flip or return status
2834String Function ToggleGridSpeechMode (int iRetVal)
2835If not iRetVal Then ; flip only if space pressed
2836 Let giGridSpeechMode = giGridSpeechMode + 1
2837 if giGridSpeechMode > 3 then
2838 let giGridSpeechMode = 0
2839 Endif
2840EndIf ; update it
2841
2842; return state, used to build visual list of current settings
2843If giGridSpeechMode == 1 Then
2844 return msgRowAndColumnHeadersAndNumbers
2845elif giGridSpeechMode == 2 then
2846 return msgRowAndColumnHeaders
2847elif giGridSpeechMode == 3 then
2848 return msgRowAndColumnNumbers
2849Else ; 0
2850 return msgDataOnly
2851EndIf
2852EndFunction
2853
2854;*******************************************************************************************
2855; called by JAWS verbosity dialog to flip or return status
2856String Function ToggleGridBrailleMode (int iRetVal)
2857If not iRetVal Then ; flip only if space pressed
2858 Let giGridBrailleMode = giGridBrailleMode + 1
2859 if giGridBrailleMode > 3 then
2860 let giGridBrailleMode = 0
2861 Endif
2862EndIf ; update it
2863; return state
2864If giGridBrailleMode == 1 Then
2865 return msgRowAndColumnHeadersAndNumbers
2866elif giGridBrailleMode == 2 then
2867 return msgRowAndColumnHeaders
2868elif giGridBrailleMode == 3 then
2869 return msgRowAndColumnNumbers
2870Else ; 0
2871 return msgDataOnly
2872EndIf
2873EndFunction
2874
2875;*******************************************************************************************
2876Void Function LoadPersonalSettings ()
2877var
2878 string sFile
2879
2880; Load personal preferences
2881; SayUsingVoice(VCTX_MESSAGE,msgLoadingSettings,OT_USER_REQUESTED_INFORMATION)
2882let sFile = findJAWSSettingsFile(getActiveConfiguration() +".jsi")
2883let giGridSpeechMode = IniReadInteger (Section_Options, hKey_GridSpeechMode, 1, sFile)
2884let giGridBrailleMode = IniReadInteger (Section_Options, hKey_GridBrailleMode, 1, sFile)
2885EndFunction
2886
2887;*******************************************************************************************
2888Int Function SavePersonalSettings ()
2889; save personal preferences
2890Var
2891 int iResult,
2892 string sFile
2893
2894let sFile = findJAWSSettingsFile(getActiveConfiguration() +".jsi")
2895let iResult =IniWriteInteger (Section_Options, hKey_GridSpeechMode, giGridSpeechMode, sFile)
2896let iResult = IResult | IniWriteInteger (Section_Options, hKey_GridBrailleMode, giGridBrailleMode, sFile)
2897return iResult
2898EndFunction
2899
2900;*******************************************************************************************
2901; modified to include personalized settings for automatically speaking buddies as the sign in and incoming messages
2902Script AdjustJAWSVerbosity ()
2903Var
2904 int iPrevGridSpeechMode,
2905 int iPrevGridBrailleMode,
2906 string sList
2907
2908; save the current values
2909let iPrevGridSpeechMode = giGridSpeechMode
2910let iPrevGridBrailleMode = giGridBrailleMode
2911
2912let sList=jvToggleGridSpeechMode
2913 + jvToggleGridBrailleMode
2914
2915JAWSVerbosityCore (sList) ; call default
2916
2917; If any values changed, save them...
2918If iPrevGridSpeechMode != giGridSpeechMode
2919|| iPrevGridBrailleMode != giGridBrailleMode then
2920 If savePersonalSettings() then
2921 SayUsingVoice(VCTX_MESSAGE, msgPersonalSettingsSaved,OT_STATUS)
2922 Else
2923 SayFormattedMessage(ot_error, msgPersonalSettingsNotSaved)
2924 EndIf
2925EndIf
2926
2927EndScript
2928
2929/* End - Personal settings */
2930
2931;***************************************************************************************
2932; getObjectName() is often wrong and this can be used to get the real msaa name as long as the msaa cache is up-to-date in JAWS
2933; if no msaa name is returned then fall back on getObjectName and getObjectValue which use other methods in addition to MSAA to determine the name or value (name of list item)
2934; called on listboxes and listviews
2935;***************************************************************************************
2936string Function getAccName ()
2937var
2938 object o,
2939 int cid,
2940 string str
2941
2942let o = getFocusObject(cid)
2943if o then
2944 if getObjectTypeCode() == wt_listbox || getObjectTypeCode() == wt_listview || getObjectTypeCode() == wt_listboxItem then
2945 let str = o.accName(cid)
2946 Else
2947 let str = getObjectName()
2948 Endif
2949 if o.accRole(cid) == role_system_list then ; we are on parent not simple child, should cover listView and listbox
2950 let str = o.accName(1) ; announce first item if nothing is focused
2951 Endif
2952Endif ; object exists?
2953if !str then
2954 if getObjectTypeCode() == wt_listbox || getObjectTypeCode() == wt_listview || getObjectTypeCode() == wt_listboxItem then
2955 let str = getObjectValue()
2956 else
2957 let str = getObjectName()
2958 EndIf
2959Endif
2960return str
2961EndFunction
2962
2963;***************************************************************************
2964string Function getAccValue ()
2965var
2966 object o,
2967 int cid,
2968 string str
2969
2970let o = getFocusObject(cid)
2971if o then
2972 if getObjectTypeCode() == wt_listbox || getObjectTypeCode() == wt_listview || getObjectTypeCode() == wt_listboxItem ||
2973 getObjectTypeCode() == wt_treeview then
2974 let str = o.accName(cid)
2975 else
2976 ; let str = o.accValue(cid)
2977 let str = getObjectValue()
2978 Endif
2979 if o.accRole(cid) == role_system_list then ; we are on parent not simple child, should cover listView and listbox
2980 let str = o.accName(1) ; announce first item if nothing is focused
2981 Endif
2982Endif ; object exists?
2983if !str then
2984 let str = getObjectValue()
2985Endif
2986return str
2987EndFunction
2988
2989;***************************************************************************************
2990; currently only returns checked and/or not selected
2991; getObjectName() is often wrong and this can be used to get the real msaa name as long as the msaa cache is up-to-date in JAWS
2992string Function getAccState ()
2993var
2994 object o,
2995 int cid,
2996 int ret,
2997 string str
2998
2999let o = getFocusObject(cid)
3000if o then
3001 let ret = o.accState(cid)
3002EndIf
3003if ret & state_system_focused && ret & state_system_selectable && !(ret & state_system_selected) then
3004 let str = msgNotSelected
3005endif
3006if ret & state_system_checked then
3007 let str = str + msgSpace + msgChecked
3008Endif
3009return str
3010EndFunction
3011
3012;****************************************************************************************************
3013; use to overwrite default speech for itmes when arrow keys are used and custom properties exist
3014; for listbox when focus changes within object
3015; arrow, home, end in listbox
3016; arrows, home, end in listview
3017;****************************************************************************************************
3018Void Function sayObjectActiveItem(int speakPositionInfo)
3019var
3020 string strValue,
3021 string strState,
3022 int iResultValue,
3023 int iResultState
3024
3025; sayString("sayObjectActiveItem")
3026
3027 if getObjectTypeCode() == wt_tabcontrol && getWindowStyleBits(getCurrentWindow()) & window_style_tabsWithButtons then ; tabs with buttons or flat buttons
3028 say(getAccState(),ot_item_state) ; Makes JAWS say "not selected" when a tab is in focus but not selected (possible on this type of tab control)
3029 endif
3030
3031 if stringContains("lb lm lx lv", getListType(getObjectSubtypeCode())) then
3032 let iResultValue = VA508GetComponentProp(getFocus(), VA508_FieldName_Value, VA508_Cache_Update, strValue)
3033 let iResultState = VA508GetComponentProp(getFocus(), VA508_FieldName_State, VA508_Cache_Use, strState)
3034 if iResultValue > 0 then
3035 if giSuppressValue then
3036 let giSuppressValue = false
3037 Endif
3038 say(strValue,ot_selected_item)
3039 Else
3040 say(getAccName(),ot_selected_item) ; getObjectValue() is wrong when extended selection is on
3041 Endif
3042 if iResultState > 0 then
3043 if giSuppressState then
3044 let giSuppressState = false
3045 Endif
3046 say(strState,ot_item_state)
3047 Else
3048 say(getAccState(),ot_item_state) ; will announce not selected if the item is not selected in extended selection mode
3049 Endif
3050 if speakPositionInfo then
3051 sayMessage(ot_position,PositionInGroup ())
3052 Endif
3053 return
3054 endif
3055 sayObjectActiveItem(speakPositionInfo)
3056EndFunction
3057
3058;****************************************************************************************************
3059; use to overwrite default speech for itmes when arrow keys are used and custom properties exist
3060; arrows, home, end in treeview
3061; currently doesn't handle custom states, position, level, information etc.
3062;****************************************************************************************************
3063Void Function ActiveItemChangedEvent (handle curHwnd, int curObjectId, int curChildId,
3064 handle prevHwnd, int prevObjectId, int prevChildId)
3065var
3066 int iObjType,
3067 int level,
3068 string strValue,
3069 string strState,
3070 int iResultValue,
3071 int iResultState
3072
3073; sayString("active item changed")
3074Let iObjType = GetObjectSubtypeCode ()
3075
3076If (WT_TREEVIEW == iObjType || WT_TREEVIEWITEM == iObjType) && !MenusActive() then
3077 ;SayTreeViewLevel (true) ; calls sayTreeViewItem even though you would not expect it to to say name, level, also says position in group
3078 ; level change
3079 let iResultValue = VA508GetComponentProp(getFocus(), VA508_FieldName_Value, VA508_Cache_Update, strValue)
3080 let iResultState = VA508GetComponentProp(getFocus(), VA508_FieldName_State, VA508_Cache_Use, strState)
3081
3082 let level = getTreeViewLevel()
3083 if level != PreviousTreeviewLevel then
3084 sayMessage(ot_position,msgLevel + IntToString(level), IntToString(level))
3085 let PreviousTreeviewLevel = level
3086 Endif
3087 ; value
3088 if !giSuppressValue then ; don't announce value because ChangeEvent will catch it
3089 if iResultValue > 0 then
3090 say(strValue,ot_selected_item)
3091 Else
3092 say(getAccValue(),ot_selected_item) ;also contains state
3093 Endif
3094 Else
3095 if iResultValue > 0 then
3096 say(strValue,ot_selected_item)
3097 let giSuppressValue = false
3098 Endif
3099 Endif
3100 ; never suppress open/closed states on tree views even if the framework has state data
3101 SayTVFocusItemExpandState (curhwnd)
3102 if giSuppressState then
3103 if iResultState > 0 then
3104 say(strState,ot_item_state)
3105 let giSuppressState = false
3106 Endif
3107 Else ; if we have a custom state but the event didn't fire still speak it
3108 if iResultState > 0 then
3109 say(strState,ot_item_state)
3110 Endif
3111 Endif
3112 ; position info, always speak it, never get it from the framework
3113 SayMessage(ot_position, PositionInGroup())
3114 return
3115Endif
3116ActiveItemChangedEvent (curHwnd, curObjectId, curChildId, prevHwnd, prevObjectId, prevChildId)
3117Endfunction
3118
3119;**********************************************************************************************************
3120; overwritten so when this function is called from saytree viewLevel in ActivateItemChangedEvent the item will not be spoken because we have a custom value that represents a custom name for the focused tree view item
3121void function SayTreeViewItem()
3122if giSuppressValue then ; don't announce value because ChangeEvent will catch it
3123 return
3124Endif
3125sayTreeViewItem()
3126EndFunction
3127
3128;*****************************************************************************************************
3129Void Function FocusChangedEvent (handle FocusWindow, handle PrevWindow)
3130 let giCancelEvent = true
3131 let giDidFocusChange = true
3132 FocusChangedEvent (FocusWindow, PrevWindow)
3133EndFunction
3134
3135;********************************************************************************************************
3136Void Function KeyPressedEvent (int nKey, string strKeyName, int nIsBrailleKey, int nIsScriptKey)
3137 let giCancelEvent = false
3138 ; sayInteger(nkey)
3139 ;if nKey == 69206331 then
3140 if nKey == 2097467 then
3141 if giDebugMode then
3142 let giDebugMode = 0
3143 Else
3144 let giDebugMode = 1
3145 Endif
3146 Endif
3147 KeyPressedEvent (nKey, strKeyName, nIsBrailleKey, nIsScriptKey)
3148EndFunction
3149
3150;********************************************************************************************************
3151void Function MouseButtonEvent (int eventID, int x, int y)
3152 let giCancelEvent = false
3153 MouseButtonEvent (eventID, x, y)
3154EndFunction
3155
3156
3157;********** ListView navigation with Ctrl+Alt+arrows/Home/End.
3158; Borrowed from freely available code written by Doug Lee
3159
3160; Original CVS Id: listtbl.jss,v 1.7 2006/01/11 13:22:22 dgl Exp
3161; Module Prefix: lt/lt_
3162; Purpose: Makes JAWS ctrl+alt commands navigate ListViews as if they were tables. Drop in (ahead of default) and enjoy.
3163;
3164; Interface: No callable functions inside.
3165; Overrides: scripts down/up/prior/next/sayCell, first/lastCellInTable, moveToTop/BottomOfColumn, moveToStart/EndOfRow.
3166;
3167; Author: Doug Lee
3168;
3169; Revision History: See CVS.
3170
3171globals
3172 int lt_suppressHighlight,
3173 handle lt_lastWin,
3174 int lt_lastCol
3175
3176string function lt_stringCast(variant v)
3177; Cast of anything to string, to make the compiler happy in a few places.
3178return v
3179endFunction
3180
3181string function lt_stringSegmentWithMultiCharDelim(string s, string sep, int idx)
3182; Same as stringSegment but with multi-character delimiters.
3183; Used in breaking up MSAA accDescription strings containing multiple ListView column names/values.
3184var
3185 int pos
3186let idx = idx -1
3187while stringLength(s) && idx
3188 let pos = stringContains(s, sep)
3189 if !pos then
3190 return ""
3191 endIf
3192 let s = stringChopLeft(s, pos+stringLength(sep) -1)
3193 let idx = idx -1
3194endWhile
3195let pos = stringContains(s, sep)
3196if pos then
3197 let s = stringLeft(s, pos-1)
3198endIf
3199return s
3200endFunction
3201
3202int function lt_canTryLVCalls()
3203; Returns True if it is ok to try the lv* functions, which became available in JAWS 5.10.
3204;return (getJfwVersion() >= 510000)
3205return False
3206endFunction
3207
3208int function lt_getMSAARect(object o, int childID, int byRef left, int byRef right, int byRef top, int byRef bottom)
3209; Get the bounding rectangle for the given MSAA object and childID.
3210; The rectangle is returned 1-based, as JAWS likes its rectangles.
3211; MSAA provides 0-based left/top/width/height.
3212o.accLocation(intRef(left), intRef(top), intRef(right), intRef(bottom), childID)
3213if !left && !right && !top && !bottom then
3214 return False
3215endIf
3216; but we want 1-based left/right/top/bottom.
3217let left = left +1
3218let top = top +1
3219let right = left +right
3220let bottom = top +bottom
3221return True
3222endFunction
3223
3224int function lt_move(string where)
3225; Move to and announce the requested "cell" of the focused ListView control,
3226; or left-click or right-click the current cell or its header.
3227; Where:
3228; - Left/right/up/down to move one cell.
3229; - Home/end for start/end of row.
3230; - Top/bottom for top/bottom of current column.
3231; - First/last for first/last cell in view.
3232; - Here for current cell.
3233; - (Cell|Header)Click(Left|Right) to left- or right-click the current cell or its header.
3234var
3235 int useLV, string moveFunc,
3236 handle hwndList, handle hwndHeader,
3237 object oList, int rowIdx, int rowCount,
3238 object oHeader, int colIdx, int colCount,
3239 int sayRow, int sayCol, int sayCell,
3240 int rowSaid,
3241 string buf, int pos,
3242 int sayColPos, int sayRowPos
3243
3244if !isPCCursor() || userBufferIsActive() || menusActive() then
3245 return False
3246endIf
3247let hwndList = getFocus()
3248
3249; Figure out if this is a control with which we can do anything useful.
3250; Also figure out if we can use JAWS 5.10+ lv* calls or whether we must use MSAA instead.
3251let useLV = lt_canTryLVCalls()
3252if useLV then
3253 let useLV = (lvGetNumOfColumns(hwndList))
3254endIf
3255if !useLV && getWindowTypeCode(hwndList) != WT_ListView then
3256 return False
3257endIf
3258
3259; Reset the column index when we move from one list to another.
3260if lt_lastWin != hwndList then
3261 let lt_lastWin = hwndList
3262 let lt_lastCol = 1
3263endIf
3264
3265; Get the list's MSAA object even if we will be using lv* calls.
3266; Reason: lvSetFocusItem() and setCurrentItem() seem unreliable; they can return 1 but still change nothing.
3267; This is just in case we need to use accSelect.
3268let oList = getObjectFromEvent(hwndList, 0-4, 0, rowIdx)
3269if !oList then
3270 sayMessage(OT_Error, "List access error")
3271 return True ; don't go on to try a table access
3272endIf
3273
3274; Get the current list item and header info.
3275if useLV then
3276 let rowIdx = getCurrentItem(hwndList)
3277 if !rowIdx then
3278 sayMessage(OT_Error, "Nothing selected")
3279 return True
3280 endIf
3281 let rowCount = getItemCount(hwndList)
3282 let colIdx = lt_lastCol
3283 ; May be 0 or out of range; leave it that way for now.
3284 let colCount = lvGetNumOfColumns(hwndList)
3285else ; use MSAA
3286 ; List info
3287 let rowIdx = oList.accFocus +0
3288 if !rowIdx then
3289 sayMessage(OT_Error, "Nothing selected")
3290 return True
3291 endIf
3292 let rowCount = oList.accChildCount -1 ; -1 to account for the header object
3293
3294 ; Header info
3295 let hwndHeader = getFirstChild(hwndList)
3296 if !hwndHeader then
3297 sayMessage(OT_Error, "List headers not found")
3298 return True
3299 endIf
3300 let oHeader = getObjectFromEvent(hwndHeader, 0-4, 0, colIdx)
3301 if !oHeader then
3302 sayMessage(OT_Error, "List header access error")
3303 return True
3304 endIf
3305 let colIdx = lt_lastCol
3306 ; May be 0 or out of range; leave it that way for now.
3307 let colCount = oHeader.accChildCount +0
3308endIf
3309
3310; Set rowIdx, colIdx, sayCol, sayRow, sayColPos, sayRowPos, and sayCell based on the navigation request.
3311; Also set moveFunc if the list item is changing.
3312let sayCol = False
3313let sayRow = False
3314let sayColPos = False
3315let sayRowPos = False
3316let sayCell = True
3317 let moveFunc = ""
3318if where == "left" then
3319 let colIdx = colIdx -1
3320 let sayCol = True
3321elif where == "right" then
3322 let colIdx = colIdx +1
3323 let sayCol = True
3324elif where == "up" then
3325 let rowIdx = rowIdx -1
3326 let sayRow = True
3327 let moveFunc = "priorLine"
3328elif where == "down" then
3329 let rowIdx = rowIdx +1
3330 let sayRow = True
3331 let moveFunc = "nextLine"
3332elif where == "home" then
3333 let colIdx = 1
3334 let sayCol = True
3335elif where == "end" then
3336 let colIdx = colCount
3337 let sayCol = True
3338elif where == "top" then
3339 let rowIdx = 1
3340 let sayRow = True
3341 let moveFunc = "JAWSHome"
3342elif where == "bottom" then
3343 let rowIdx = rowCount
3344 let sayRow = True
3345 let moveFunc = "JAWSEnd"
3346elif where == "first" then
3347 let rowIdx = 1
3348 let colIdx = 1
3349 let sayCol = True
3350 let sayRow = True
3351 let moveFunc = "JAWSHome"
3352elif where == "last" then
3353 let rowIdx = rowCount
3354 let colIdx = colCount
3355 let sayCol = True
3356 let sayRow = True
3357 let moveFunc = "JAWSEnd"
3358elif where == "here" then
3359 ; No navigation.
3360 let sayCol = True
3361 let sayRow = True
3362 let sayColPos = True
3363 let sayRowPos = True
3364elif where == "cellClick" then ; left or right
3365 ; SayCell already set.
3366elif where == "headerClick" then ; left or right
3367 let sayCell = False
3368 let sayCol = True
3369else
3370 sayMessage(OT_Error, "Unknown navigation: " +where)
3371 return True
3372endIf
3373
3374; Enforce boundaries and update the remembered last-visited column index.
3375if !moveFunc then
3376 ; Row boundaries are determined by the control itself when key sending is used to move focus; see below.
3377 if rowIdx < 1 then
3378 beep()
3379 let rowIdx = 1
3380 let moveFunc = ""
3381 elif rowIdx > rowCount then
3382 beep()
3383 let rowIdx = rowCount
3384 let moveFunc = ""
3385 endIf
3386endIf
3387if colIdx < 1 then
3388 beep()
3389 let colIdx = 1
3390elif colIdx > colCount then
3391 beep()
3392 let colIdx = colCount
3393endIf
3394let lt_lastCol = colIdx
3395
3396; Move focus if necessary but prevent the speaking of highlighting.
3397if moveFunc then
3398 let lt_suppressHighlight = True
3399 if moveFunc then
3400 ; This is the preferred way of changing focus: It's what the app will expect, and it won't focus something without scrolling it into view.
3401 if formatStringWithEmbeddedFunctions("<" +moveFunc +">") == 0 then
3402 beep()
3403 endIf
3404 elif useLV then
3405 ; LvSetFocusItem() and setCurrentItem() seem unreliable; they can return 1 but still change nothing.
3406 ; We therefore still use MSAA here, which is why we got the MSAA object earlier regardless of useLV. [DGL, 2006-01-11, JAWS 6.20]
3407 ;SetCurrentItem(hwndList, rowIdx)
3408 oList.accSelect(3, rowIdx)
3409 else
3410 oList.accSelect(3, rowIdx)
3411 endIf
3412 pause()
3413 ; The stopSpeech is still here even though we suppress highlighting via the global lt_suppressHighlight variable.
3414 ; This is because app-specific scripts with their own sayHighlightedText functions can (and often do) speak their own highlighting, thus defeating the lt_suppressHighlight approach.
3415 ; For some reason, using only stopSpeech seems to allow a split second of unwanted speech unless the lt_suppressHighlight method is also used.
3416 ; We therefore use both at once. [DGL, 2006-01-11]
3417 stopSpeech()
3418endIf
3419
3420; Click if a click was requested.
3421if stringContains(stringLower(where), "click") then
3422 var
3423 int isRight,
3424 int left, int right, int top, int bottom,
3425 int cx, int cy
3426 let isRight = (stringContains(stringLower(where), "right") > 0)
3427 ; lvGetItemColumnRect can crash the app against which it is called, so we use MSAA here.
3428 if !lt_getMSAARect(oHeader, colIdx, left, right, top, bottom) then
3429 beep()
3430 return False
3431 endIf
3432 let cx = (left+right) /2
3433 if where == "cellClick" then
3434 let cy = getCursorRow()
3435 elif where == "headerClick" then
3436 let cy = (top+bottom) /2
3437 endIf ; cell or header
3438 saveCursor() JAWSCursor() saveCursor()
3439 moveTo(cx, cy)
3440 if isRight then
3441 rightMouseButton()
3442 else
3443 leftMouseButton()
3444 endIf
3445 delay(1, True)
3446endIf ; click
3447
3448; Reset the row index to what's actually the case.
3449; This is to handle cases where arrows follow visual order but not item index order.
3450; Example: when a Windows Explorer Details view is sorted by type.
3451; This may also be needed when a list is resorted by a click.
3452if useLV then
3453let rowIdx = getCurrentItem(hwndList)
3454else
3455let rowIdx = oList.accFocus +0
3456endIf
3457
3458; Say row, column, and/or cell if appropriate.
3459if useLV then
3460 if sayRow then
3461 ;sayMessage(OT_Message, lt_stringCast(lvGetItemText(hwndList, rowIdx, 1)))
3462 ;let rowSaid = True
3463 endIf
3464 if sayCol then
3465 sayMessage(OT_Message, lvGetColumnHeader(hwndList, colIdx))
3466 endIf
3467 if sayCell then
3468 if colIdx == 1 then
3469 if !rowSaid then
3470 sayMessage(OT_Message, lvGetItemText(hwndList, rowIdx, colIdx))
3471 endIf
3472 else
3473 sayMessage(OT_Message, lvGetItemText(hwndList, rowIdx, colIdx))
3474 endIf
3475 endIf ; sayCell
3476else ; Use MSAA instead
3477 if sayRow then
3478 ;sayMessage(OT_Message, lt_stringCast(oList.accName(1)))
3479 ;let rowSaid = True
3480 endIf
3481 if sayCol then
3482 sayMessage(OT_Message, oHeader.accName(colIdx))
3483 endIf
3484 if sayCell then
3485 if colIdx == 1 then
3486 if !rowSaid then
3487 sayMessage(OT_Message, oList.accName(rowIdx))
3488 endIf
3489 else
3490 let buf = oList.accDescription(rowIdx)
3491 let pos = stringContains(buf, lt_stringCast(oHeader.accName(colIdx)) +":")
3492 if !pos then
3493 let buf = lt_stringSegmentWithMultiCharDelim(buf, ", ", colIdx-1) ; -1 because the first column is not included in accDescription
3494 if !stringLength(buf) then
3495 sayMessage(OT_Error, "Can't find column value")
3496 return True
3497 endIf
3498 else
3499 let buf = stringChopLeft(buf, pos +stringLength(oHeader.accName(colIdx)) +1)
3500 if colIdx < colCount then
3501 let pos = stringContains(buf, lt_stringCast(oHeader.accName(colIdx+1)) +":")
3502 if pos then
3503 let buf = stringLeft(buf, pos-1)
3504 else
3505 sayMessage(OT_Error, "Can't find end of cell value")
3506 ; allow the overly long value to speak though
3507 endIf
3508 endIf
3509 endIf
3510 sayMessage(OT_Message, buf)
3511 endIf
3512 endIf ; sayCell
3513endIf ; LV vs. MSAA
3514
3515if sayRowPos then
3516 sayMessage(OT_Position, "Row " +intToString(rowIdx) +" of " +intToString(rowCount))
3517endIf
3518if sayColPos then
3519 sayMessage(OT_Position, "Column " +intToString(colIdx) +" of " +intToString(colCount))
3520endIf
3521return True
3522endFunction
3523
3524void function lt_clearSuppressHighlight()
3525let lt_suppressHighlight = False
3526endFunction
3527
3528script downCell()
3529if !lt_move("down") then
3530 performScript downCell()
3531endIf
3532endScript
3533
3534script upCell()
3535if !lt_move("up") then
3536 performScript upCell()
3537endIf
3538endScript
3539
3540script priorCell()
3541if !lt_move("left") then
3542 performScript priorCell()
3543endIf
3544endScript
3545
3546script nextCell()
3547if !lt_move("right") then
3548 performScript nextCell()
3549endIf
3550endScript
3551
3552script moveToTopOfColumn()
3553if !lt_move("top") then
3554 performScript moveToTopOfColumn()
3555endIf
3556endScript
3557
3558script moveToBottomOfColumn()
3559if !lt_move("bottom") then
3560 performScript moveToBottomOfColumn()
3561endIf
3562endScript
3563
3564script moveToStartOfRow()
3565if !lt_move("home") then
3566 performScript moveToStartOfRow()
3567endIf
3568endScript
3569
3570script moveToEndOfRow()
3571if !lt_move("end") then
3572 performScript moveToEndOfRow()
3573endIf
3574endScript
3575
3576script firstCellInTable()
3577if !lt_move("first") then
3578 performScript firstCellInTable()
3579endIf
3580endScript
3581
3582script lastCellInTable()
3583if !lt_move("last") then
3584 performScript lastCellInTable()
3585endIf
3586endScript
3587
3588script sayCell()
3589if !lt_move("here") then
3590 performScript sayCell()
3591endIf
3592endScript
3593
3594script ltLeftClickCell()
3595if !lt_move("cellClickLeft") then
3596 sayCurrentScriptKeyLabel()
3597 typeCurrentScriptKey()
3598endIf
3599endScript
3600
3601script ltRightClickCell()
3602if !lt_move("cellClickRight") then
3603 sayCurrentScriptKeyLabel()
3604 typeCurrentScriptKey()
3605endIf
3606endScript
3607
3608script ltLeftClickHeader()
3609if !lt_move("headerClickLeft") then
3610 sayCurrentScriptKeyLabel()
3611 typeCurrentScriptKey()
3612endIf
3613endScript
3614
3615script ltRightClickHeader()
3616if !lt_move("headerClickRight") then
3617 sayCurrentScriptKeyLabel()
3618 typeCurrentScriptKey()
3619endIf
3620endScript
3621
3622;*******************************************
3623; called when left/right arrows are used in tree views
3624void function ObjStateChangedEvent(handle hObj, int iObjType, int nChangedState, int nState, int nOldState)
3625 if iObjType == wt_treeview || iObjType == wt_treeviewItem then
3626 sayLine(0)
3627 return
3628 endif
3629 ObjStateChangedEvent(hObj, iObjType, nChangedState, nState, nOldState)
3630EndFunction
3631
3632
3633;===============================================================================
3634;
3635; Code supporting custom commands sent directly to the framework by keystrokes listed in the app.jkm file.
3636; This code includes constants, a script called by all such keys, and overrides to provide help for these keys.
3637; Help for custom keys is located in the Custom Command Help section of the app.jcf file.
3638; Keys in this section take the form short1=..., long1=..., short2=..., etc.
3639; "Short" is the short (Synopsis) help text, and long is the longer (description) text.
3640; Warning: Each .jcf line should be less than 255 characters long.
3641;
3642; Overrides: Functions GetScriptSynopsis and GetScriptDescription.
3643; This section uses the VA508SendMessage function and the gbVA508needToLinkToDLL global variable.
3644
3645const
3646; Name of the below script
3647; jkm lines should look like, for example, F1=VA508SendCustomCommand(1)
3648 VA508_Custom_Command_Script = "VA508SendCustomCommand",
3649; Offset added to the cmdno passed to the script to get the LParam value for SendMessage.
3650 VA508_Custom_Command_Offset = 0x100000,
3651; app.jcf section name for help text
3652 VA508_Custom_Command_Help_Section = "Custom Command Help",
3653; Prefixes for command synopses and descriptions, the full key being one of these plus the command number.
3654 VA508_Custom_Command_Help_Prefix1 = "short",
3655 VA508_Custom_Command_Help_Prefix2 = "long"
3656
3657;*******************************************
3658; Called from the application .jkm file to send custom messages to the framework.
3659; Example jkm line: F1=VA508SendCustomCommand(1)
3660;*******************************************
3661script VA508SendCustomCommand(int cmdno)
3662var
3663 handle hwnd,
3664 int WParam,
3665 int LParam
3666if gbVA508needToLinkToDLL then
3667 sayMessage(OT_Error, "Framework not connected")
3668 return
3669endIf
3670let hwnd = ghVA508DLLWindow
3671let WParam = 0
3672let LParam = cmdno +VA508_Custom_Command_Offset
3673VA508SendMessage(hwnd, WParam, LParam)
3674endScript
3675
3676;*******************************************
3677; Retrieve help text for custom commands.
3678; Scr is the script name (VA508SendCustomCommand).
3679; Cmdno is the command number being queried.
3680; Extended is True for long (Description) text and False for short (Synopsis) text.
3681;*******************************************
3682string function getCustomScriptHelpText(string scr, int cmdno, int extended)
3683var
3684 string sSect,
3685 string sKey,
3686 string sFile,
3687 string helpBuf
3688let sFile = findJAWSSettingsFile(getActiveConfiguration() +".jcf")
3689if !fileExists(sFile) then
3690 ; No file, no custom help.
3691 return ""
3692endIf
3693let sSect = VA508_Custom_Command_Help_Section
3694if extended then
3695 let sKey = VA508_Custom_Command_Help_Prefix2
3696else
3697 let sKey = VA508_Custom_Command_Help_Prefix1
3698endIf
3699let sKey = sKey +intToString(cmdno)
3700let helpBuf = iniReadString(sSect, sKey, "", sFile)
3701return helpBuf
3702endFunction
3703
3704;*******************************************
3705; Pull the command number being queried from the jkm line for the just-pressed keystroke.
3706;*******************************************
3707int function getCustomCommandNumber()
3708var
3709 string keyName,
3710 string scr
3711; This pulls the current script name with parameters.
3712let keyName = getCurrentScriptKeyName()
3713let scr = getScriptAssignedTo(keyName)
3714; and this pulls out the number in parentheses.
3715let scr = stringChopLeft(scr, stringContains(scr, "("))
3716let scr = stringLeft(scr, stringContains(scr, ")") -1)
3717return stringToInt(scr)
3718endFunction
3719
3720;*******************************************
3721; Implements GetScriptSynopsis and GetScriptDescription below.
3722; Returns custom help if found and normal (jsd) help if not.
3723;*******************************************
3724string function getScriptHelpText(string scr, int extended)
3725var
3726 int cmdno,
3727 string helpBuf
3728let helpBuf = ""
3729if stringCompare(scr, VA508_Custom_Command_Script, False) == 0 then
3730 let cmdno = getCustomCommandNumber()
3731 let helpBuf = getCustomScriptHelpText(scr, cmdno, extended)
3732 if helpBuf then
3733 return helpBuf
3734 endIf
3735endIf
3736if extended then
3737 return getScriptDescription(scr)
3738else
3739 return getScriptSynopsis(scr)
3740endIf
3741endFunction
3742
3743;*******************************************
3744; Override of standard JAWS function.
3745;*******************************************
3746string function getScriptSynopsis(string scr)
3747 return getScriptHelpText(scr, False)
3748endFunction
3749
3750;*******************************************
3751; Override of standard JAWS function.
3752;*******************************************
3753string function getScriptDescription(string scr)
3754return getScriptHelpText(scr, True)
3755;va508getApplicationData(getFocus(),va508_queryCode_all)
3756;sayString(VA508GetStringValue(va508_fieldname_data_status))
3757;sayString(gsva508data)
3758endFunction
Note: See TracBrowser for help on using the repository browser.