Hi Sean,
you asked about the hook and I will insert a step by step instruction. But
meanwhile I thought about your problem and now think it could be done without
using a hook.
You could use the TrapKeys function of JAWS. This "traps" all the keys not
assigned to scripts. Since you are using only one letter keystrokes this should
be fine for you. I've tried this out myself on Explorer and inserted the code I
used too (at the end of the mail).
The difference between the TrapKey function and the Hook is that you trapping
keys not attached to scripts with TrapKey and on the other hand have full
control over scripts with the hook function.
First here are the steps for using a hook:
1. Make a script to start the hook
Script StartHook ()
AddHook (HK_SCRIPT, "KeyboardHookFunction")
EndScript
2. Make a script to stop the hook
Script StopHook ()
RemoveHook (HK_SCRIPT, "KeyboardHookFunction")
EndScript
3. Make a function that is called every time a script was executed
After starting the hook the function we made as the second parameter
("KeyboardHookFunction") is called every time we start a script. In this
function we can decide if we want a script to run or to stop. If we return true
the script is allowed to run and if we return false the script is stopped.
int Function KeyboardHookFunction (string ScriptName)
If ScriptName == "StopHook" then
SayString ("Stop script now")
Return True
EndIf
; All other Script are not allowed
Return False
EndFunction
4. Trap the keys
To trap the keys not assigned to scripts we start trapping in the start hook
script and stop trapping in the stop hook script: So we add the lines to the
script:
Script StartHook ()
AddHook (HK_SCRIPT, "KeyboardHookFunction")
; trap the keys
TrapKeys (True, True)
EndScript
Script StopHook ()
RemoveHook (HK_SCRIPT, "KeyboardHookFunction")
; Don't trap the keys any longer
TrapKeys (False)
EndScript
5. React on key pressing
To react to keys being pressed we should remember if the hook function is
running. Therefore we save this in a global variable:
globals
int giHookActive
Script StartHook ()
AddHook (HK_SCRIPT, "KeyboardHookFunction")
TrapKeys (True, True)
; remember the hook is active
giHookActive = True
EndScript
Script StopHook ()
RemoveHook (HK_SCRIPT, "KeyboardHookFunction")
TrapKeys (False)
; remember the hook is no longer active
giHookActive = False
EndScript
6. No we can use a key press event of JAWS to react on keys being pressed:
Void Function KeyPressedEvent (int nKey, string strKeyName, int nIsBrailleKey,
int nIsScriptKey)
If giHookActive then
; speak the key being pressed
SayString (strKeyName)
EndIf
; react on pressing Escape (only if
; the hook is active)
if strKeyName == "Escape" && giHookActive then
PerformScript StopHook ()
EndIf
; pass the key pressed event to other functions
KeyPressedEvent (nKey,strKeyName,nIsBrailleKey,nIsScriptKey)
EndFunction
These are the steps if you want to use a keyboard hook.
Now a little example of doing one-letter navigation (here Explorer in Windows).
If there are many tree items the script will be very slow. But it should give
you a hint how to do this:
<Code start>
globals
int giTrapKeys
; Script to activate trapping of keys
Script TrapMyKeys ()
; trap keys not assigned to a script
TrapKeys (True)
; say the trap mode is on
; (you can delete the line after testing the script
; if you want)
SayString ("trapping keys")
; remember in a global variable that
; trapping keys is running
giTrapKeys = True
EndScript
; script to deactivate trapping of keys
Script DontTrapMyKeys ()
; Don't trap keys any longer
TrapKeys (False)
; say that trapping keys is ending
SayString ("trapping keys is off")
; and remember this in a global variable
giTrapKeys = False
EndScript
; function is called every time a key is pressed
Void Function ProcessKeyPressed (int nKey, string strKeyName, int
nIsBrailleKey, int nIsScriptKey)
var
int iCharValue
; If we are trapping keys
If giTrapKeys then
; check if the string is 1 char of length
If StringLength (strKeyName) == 1 then
; Get ASCII-value of this char
iCharValue = GetCharacterValue (strKeyName)
; If the ASCII value is between A and Z
If (iCharValue > 64) && (iCharValue < 91)
; run search function (with char as parameter)
DoCharSearch (strKeyName)
EndIf ; If (iCharValue > 64) && (iCharValue < 91)
EndIf ; If StringLength (strKeyName) == 1 then
EndIf
; pas event to other functions
ProcessKeyPressed(nKey,strKeyName,nIsBrailleKey,nIsScriptKey)
EndFunction
; search function
void Function DoCharSearch (string sChar)
var
object oUIA = CreateObjectEx ("FreedomSci.UIA", 0, "UIAScriptAPI.x.manifest"),
object oFocusElement = oUIA.GetFocusedElement().BuildUpdatedCache(),
object oElement = oUIA.GetElementFromHandle(GetAppMainWindow (GetFocus())),
object oElements,
object oCondition,
object oEntry,
int iBegin = False,
int i
; search for tree items
oCondition = oUIA.CreateIntPropertyCondition (UIA_ControlTypePropertyId,
UIA_TreeItemControlTypeId)
; search the whole app
oElements = oElement.FindAll (TreeScope_Descendants, oCondition)
; Loop over all tree items
; (For each loop only runs the first time so later we use
; for loop)
ForEach oEntry in oElements
; Since we are search at the current position
; we will begin if "iBegin" is set to true
if iBegin then
; If the first char of the name is our searched char
If StringLeft (oEntry.Name, 1) == sChar then
; focus it
oEntry.SetFocus ()
SayString ("found")
; and leave the funciton
Return
EndIf
EndIf ; If iBegin then
; here we check if the item of the loop is
; the item being focused if we started the script
If oUIA.CompareElements (oFocusElement, oEntry) then
; If yes then set iBegin to true
iBegin = True
EndIf ; If oUIA.CompareElements (oFocusElement, oEntry) then
EndForEach
; if the function still runs here we didn't find something
; beneath the focused item so we start the
; search at the beginning
SayString ("Nothing found yet")
; This time we use a for loop because
; ForEach loop only runs one time in a script
for i=0 to oElements.Count-1
; if the first char of the name is our search char
If StringLeft (oElements(i).Name, 1) == sChar then
; focus it
oElements(i).SetFocus ()
SayString ("gefunden")
; and leave the function
Return
EndIf
EndFor
; if the function is still running to this point
; we have found nothing
SayString ("Nothing found in the whole tree")
EndFunction
; Here we use a FocusChangedEvenht to
; automatically start the script and stop it
void function FocusChangedEventEx (
handle hwndFocus, int nObject, int nChild,
handle hwndPrevFocus, int nPrevObject, int nPrevChild,
int nChangeDepth)
var
object oUIA = CreateObjectEx ("FreedomSci.UIA", 0, "UIAScriptAPI.x.manifest"),
object oFocusElement = oUIA.GetFocusedElement().BuildUpdatedCache()
; if the control type of the focused element is a tree item
If oFocusElement.ControlType == UIA_TreeItemControlTypeId then
; we can start the trapping of keys
PerformScript TrapMyKeys ()
else
; in the other case stop trapping of keys
PerformScript DontTrapMyKeys ()
EndIf
; Pass event to other functions
FocusChangedEventEx (hwndFocus, nObject, nChild, hwndPrevFocus, nPrevObject,
nPrevChild, nChangeDepth)
EndFunction
; And very important
; Stop trapping of keys if you leave your app
void Function AutoFinishEvent ()
PerformScript DontTrapMyKeys ()
EndFunction
<Code End>
Hope this helps. And I hope the mails clients didn't mix the lines so the
compiler is angry 😉
Udo
Am 08.11.2020 um 15:24 schrieb Sean Farrow <sean.farrow@xxxxxxxxxxxxxxxx>:
Hi,
The tree view is a custom control, using the .Net framework and more
specifically WinForms. It kind of supports MSAA, so can be traversed.
A hook sounds like the best bet, but it would be good to find out more about
how you'd do it.
Thanks,
Sean.
-----Original Message-----
From: jawsscripts-bounce@xxxxxxxxxxxxx <jawsscripts-bounce@xxxxxxxxxxxxx> On
Behalf Of Udo Egner-Walter
Sent: 08 November 2020 08:36
To: jawsscripts@xxxxxxxxxxxxx
Subject: [jawsscripts] Re: Implementing first-letter navigation
Hi Sean,
there are some ways to do this and all of them have some advantages and
disadvantages. Here are some thoughts about this:
First of all the question is this a SysTreeView32 or another control? Does
the treeview support UIA?
In case of first-letter navigation there are some ways:
1. Using one of the JAWS keyboard events or keyboard event helpers, for
example KeyPressedEvent (). So you can react on the pressing of a specific
key. One disadvantage is here that you can't stop sending the key to the app.
If you app uses a key being pressed the app will execute the command assigned
to the key. For single keystrokes this rather unusual but you should keep
this in mind.
2. You can install a keyboard hook. If you do this you can trap all keys and
decide in your script which one should pass and which one not. One
disadvantage here is you might not be able to stop the keyboard hook and the
keys and scripts being trapped and you can't work no longer till you release
the keyboard hook.
3. You can implement some kind of virtual keys. If you do this your scripts
control the keys till you are pressing a key to end this virtual mode. I know
two ways of doing this:
a) Using the layered keys in combination with a * at the end of the key. So
the keys are still active till you press a key without * in the layered keys
section.
b) Load another key section from an ini-file where you can assign single keys
to you scripts.
This is only an overview and the possibilities I know. if you want more
details please let me know and I try to explain this in details and with
examples.
But implementing the first-letter navigation makes only sense if you can
focus your tree nodes by script. Therefore my questions at the beginning of
the mail.
Hope this helps
Udo
Am 07.11.2020 um 17:01 schrieb Sean Farrow <sean.farrow@xxxxxxxxxxxxxxxx>:
Hi all,
I've got a tree view that does not natively implement first-letter
navigation, what is the best way of doing this effectively.
Any help appreciated.
Thanks,
Sean.
__________
View the list's information and change your settings at
http://www.freelists.org/list/jawsscripts
__________
View the list's information and change your settings at
http://www.freelists.org/list/jawsscripts
__________�
View the list's information and change your settings at
http://www.freelists.org/list/jawsscripts