Good ways to determine if a text field is present?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
kunkel321
Posts: 1194
Joined: 30 Nov 2015, 21:19

Good ways to determine if a text field is present?

30 May 2021, 13:49

Like for when you want to send text with a script, but you also want to ensure that there is an active text field to "accept" the sent text.

I've googled this a couple of times, and there doesn't seem to be a great way to do this... I've been using the following:

Code: Select all

WinGetActiveTitle, myWinTarget 
GoodTargets := "Web-based IEP|Untitled|RE|Inbox" 
ControlGetFocus, fieldFocus, A
If InStr(fieldFocus, "edi") || If RegExMatch(myWinTarget, GoodTargets)
; etc...
It's better than nothing. I've also seen where people tried to use the current cursor image, but that's not foolproof either.

Just now I thought of this:

Code: Select all

!+f::
Clipboard := ""
Send, xx{Shift down}{Left}{Left}{Shift up}^x
ifequal, Clipboard, xx
	MsgBox, It is an active text field.
else
	MsgBox, Text field not present.
return
It does work, but it's super kludgy. Does anyone else have clever ideas for how to handle this?
ste(phen|ve) kunkel
AHKStudent
Posts: 1472
Joined: 05 May 2018, 12:23

Re: Good ways to determine if a text field is present?

30 May 2021, 15:00

how about using acc and checking if the role is "editable text"?
teadrinker
Posts: 4412
Joined: 29 Mar 2015, 09:41
Contact:

Re: Good ways to determine if a text field is present?

30 May 2021, 15:03

AHKStudent wrote:
30 May 2021, 15:00
how about using acc and checking if the role is "editable text"?
And STATE_SYSTEM_FOCUSED.
User avatar
kunkel321
Posts: 1194
Joined: 30 Nov 2015, 21:19

Re: Good ways to determine if a text field is present?

30 May 2021, 17:54

Thanks for the replies. Is this
https://autohotkey.com/board/topic/77303-acc-library-ahk-l-updated-09272012/
the thread I should be reading?

Edit: Actually that download link is bad, but this one works:
https://www.autohotkey.com/boards/viewtopic.php?t=26201

EDIT2: WOW!!!! It even seems to differentiate editable form fields that are in web forms in Chrome Browser... From what I've read in other places, that is impossible...

EDIT3: Oh dear... I'm checking Jeeswg's list here
https://www.autohotkey.com/boards/viewtopic.php?f=6&t=32039
and it appears that the answer is..... 42.
ste(phen|ve) kunkel
AHKStudent
Posts: 1472
Joined: 05 May 2018, 12:23

Re: Good ways to determine if a text field is present?

30 May 2021, 21:09

kunkel321 wrote:
30 May 2021, 17:54
Thanks for the replies. Is this
https://autohotkey.com/board/topic/77303-acc-library-ahk-l-updated-09272012/
the thread I should be reading?

Edit: Actually that download link is bad, but this one works:
https://www.autohotkey.com/boards/viewtopic.php?t=26201

EDIT2: WOW!!!! It even seems to differentiate editable form fields that are in web forms in Chrome Browser... From what I've read in other places, that is impossible...

EDIT3: Oh dear... I'm checking Jeeswg's list here
https://www.autohotkey.com/boards/viewtopic.php?f=6&t=32039
and it appears that the answer is..... 42.
yes
User avatar
kunkel321
Posts: 1194
Joined: 30 Nov 2015, 21:19

Re: Good ways to determine if a text field is present?

31 May 2021, 12:00

Okay do you guys know of any scripts out there that use the Acc library in the way I'm trying to? I checked out some of the (many) tutorials that Jeeswg posted here https://www.autohotkey.com/boards/viewtopic.php?f=7&t=40590 but they are really beyond my skill level.

In the code here, you can see what I'm trying to do. I have my script in the same folder as the Acc and the Anchor ahk files. Once my script is running, I click in TED Notepad and press the hotkey. I know that the field is an "editable text" field, because AccViewer says it is. I can't figure out how to assess it in my one script though. Ideas? (By the way, the library is getting included... I don't get a "missing function" error. My sRole variable is simply empty.)

Code: Select all

#NoEnv ; For security
#SingleInstance force
#Persistent
#Include, Acc.ahk
#Include, Anchor.ahk

!+f::
Acc_GetRoleText(nRole)
;Acc_GetRoleText(hWnd)
;Acc_GetRoleText(42)
;;Acc_GetRoleText(STATE_SYSTEM_FOCUSED)
;Acc_GetRoleText(0x00000004)
MsgBox |%sRole%| ; I want it to return, "editable text".
ExitApp

;~ Acc_GetRoleText(nRole)
;~ {
	;~ nSize := DllCall("oleacc\GetRoleText", "Uint", nRole, "Ptr", 0, "Uint", 0)
	;~ VarSetCapacity(sRole, (A_IsUnicode?2:1)*nSize)
	;~ DllCall("oleacc\GetRoleText", "Uint", nRole, "str", sRole, "Uint", nSize+1)
	;~ Return	sRole
;~ }
ste(phen|ve) kunkel
teadrinker
Posts: 4412
Joined: 29 Mar 2015, 09:41
Contact:

Re: Good ways to determine if a text field is present?

31 May 2021, 14:35

kunkel321 wrote: My sRole variable is simply empty.

Code: Select all

ROLE_SYSTEM_TEXT := 0x2A
MsgBox, % Acc_GetRoleText(ROLE_SYSTEM_TEXT)

Acc_GetRoleText(nRole)
{
	len := DllCall("oleacc\GetRoleText", "UInt", nRole, "Ptr", 0, "UInt", 0)
	VarSetCapacity(sRole, size := (len + 1) << !!A_IsUnicode, 0)
	DllCall("oleacc\GetRoleText", "UInt", nRole, "Str", sRole, "UInt", size)
	Return sRole
}
kunkel321 wrote: I can't figure out how to assess it in my one script though.
You need to implement recursive element search, for example:

Code: Select all

SetBatchLines, -1
ROLE_SYSTEM_TEXT     := 0x0000002A
ROLE_SYSTEM_COMBOBOX := 0x0000002E
STATE_SYSTEM_FOCUSED := 0x00000004

text :=  { Role:  ROLE_SYSTEM_TEXT
         , State: STATE_SYSTEM_FOCUSED }
combo := { Role:  ROLE_SYSTEM_COMBOBOX
         , State: STATE_SYSTEM_FOCUSED }
Return
       
$F11::
   WinGet, processName, ProcessName, A
   hwnd := WinExist("A")
   if (processName ~= "i)^(chrome|msedge)\.exe")
      SendMessage, WM_GETOBJECT := 0x3D, 0, 1, Chrome_RenderWidgetHostHWND1, ahk_id %hWnd%
   AccObj := AccObjectFromWindow(hWnd)
   if !IsObject(AccObj)
      throw "Failed to get acc object from window"
   if SearchElement(AccObj, text) || SearchElement(AccObj, combo)
      MsgBox, There is a focused input field
   else
      MsgBox, Focused input field not found
   Return

SearchElement(parentElement, params)
{
   found := true
   for k, v in params {
      try {
         if (k = "State")
            (!(parentElement.accState(0)    & v) && found := false)
         else if (k ~= "^(Name|Value)$")
            (!(parentElement["acc" . k](0) ~= v) && found := false)
         else if (k = "ChildCount")
            (parentElement["acc" . k]      != v  && found := false)
         else
            (parentElement["acc" . k](0)   != v  && found := false)
      }
      catch 
         found := false
   } until !found
   if found
      Return parentElement
   
   try Children := AccChildren(parentElement)
   catch
      Return
   
   for k, v in Children
      if obj := SearchElement(v, params)
         Return obj
}

AccObjectFromWindow(hWnd, idObject = 0) {
   static IID_IDispatch   := "{00020400-0000-0000-C000-000000000046}"
		  , IID_IAccessible := "{618736E0-3C3D-11CF-810C-00AA00389B71}"
		  , OBJID_NATIVEOM  := 0xFFFFFFF0, VT_DISPATCH := 9, F_OWNVALUE := 1
		  , h := DllCall("LoadLibrary", "Str", "oleacc", "Ptr")
        
   VarSetCapacity(IID, 16), idObject &= 0xFFFFFFFF
   DllCall("ole32\CLSIDFromString", "Str", idObject = OBJID_NATIVEOM ? IID_IDispatch : IID_IAccessible, "Ptr", &IID)
   if DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject, "Ptr", &IID, "PtrP", pAcc) = 0
      Return ComObject(VT_DISPATCH, pAcc, F_OWNVALUE)
}

AccChildren(Acc) {
   static VT_DISPATCH := 9
   Loop 1  {
      if ComObjType(Acc, "Name") != "IAccessible"  {
         error := "Invalid IAccessible Object"
         break
      }
      try cChildren := Acc.accChildCount
      catch
         Return ""
      Children := []
      VarSetCapacity(varChildren, cChildren*(8 + A_PtrSize*2), 0)
      res := DllCall("oleacc\AccessibleChildren", "Ptr", ComObjValue(Acc), "Int", 0
																, "Int", cChildren, "Ptr", &varChildren, "IntP", cChildren)
      if (res != 0) {
         error := "AccessibleChildren DllCall Failed"
         break
      }
      Loop % cChildren  {
         i := (A_Index - 1)*(A_PtrSize*2 + 8)
         child := NumGet(varChildren, i + 8)
         Children.Push( (b := NumGet(varChildren, i) = VT_DISPATCH) ? AccQuery(child) : child )
         ( b && ObjRelease(child) )
      }
   }
   if error
      ErrorLevel := error
   else
      Return Children.MaxIndex() ? Children : ""
}

AccQuery(Acc) {
   static IAccessible := "{618736e0-3c3d-11cf-810c-00aa00389b71}", VT_DISPATCH := 9, F_OWNVALUE := 1
   try Return ComObject(VT_DISPATCH, ComObjQuery(Acc, IAccessible), F_OWNVALUE)
}
Perhaps, the search can be optimized.
User avatar
kunkel321
Posts: 1194
Joined: 30 Nov 2015, 21:19

Re: Good ways to determine if a text field is present?

31 May 2021, 17:37

Thanks Teadrinker!
Sorry for being such a newb. Each of these appears to be flagging anything/everything as editable text. Like even if I click on an un-editable webpage and press the hotkey, it says it's editable. (Or there is a focused input field.) Same with the Windows desktop.

I'm guessing that the shorter of the two you made would meet me needs (if I can get it to work). For the purposes of what I'm doing, only one element at a time needs to be assessed. The script doesn't need to "look for" an editable field... I merely activate the text expansion tool, and it remembers what window was active, then waits for it to be active again, and then sends the text. I merely want to add the ability to alert the user if an invalid location was selected when the hotkey was pressed. (Where invalid means something that you can't type into.)
ste(phen|ve) kunkel
AHKStudent
Posts: 1472
Joined: 05 May 2018, 12:23

Re: Good ways to determine if a text field is present?

31 May 2021, 18:08

kunkel321 wrote:
31 May 2021, 17:37
Thanks Teadrinker!
Sorry for being such a newb. Each of these appears to be flagging anything/everything as editable text. Like even if I click on an un-editable webpage and press the hotkey, it says it's editable. (Or there is a focused input field.) Same with the Windows desktop.

I'm guessing that the shorter of the two you made would meet me needs (if I can get it to work). For the purposes of what I'm doing, only one element at a time needs to be assessed. The script doesn't need to "look for" an editable field... I merely activate the text expansion tool, and it remembers what window was active, then waits for it to be active again, and then sends the text. I merely want to add the ability to alert the user if an invalid location was selected when the hotkey was pressed. (Where invalid means something that you can't type into.)
if that's the case you would have to get the acc path under the cursor, the scripts I found gives bad path info most times https://www.autohotkey.com/boards/viewtopic.php?t=56470
teadrinker
Posts: 4412
Joined: 29 Mar 2015, 09:41
Contact:

Re: Good ways to determine if a text field is present?

31 May 2021, 18:42

kunkel321 wrote: I'm guessing that the shorter of the two you made would meet me needs
But my first script does not search anything, it just translates the passed number into the corresponding text. :)
kunkel321 wrote: Like even if I click on an un-editable webpage and press the hotkey, it says it's editable.
The second script for me works correctly on most web pages.
User avatar
kunkel321
Posts: 1194
Joined: 30 Nov 2015, 21:19

Re: Good ways to determine if a text field is present?

01 Jun 2021, 12:11

teadrinker wrote:
31 May 2021, 18:42
The second script for me works correctly on most web pages.
Sorry, yes. It also works for me. I had pasted my autoexecute section into the top of it and stupidly pasted my hotkey at the top of it too. Once I removed that, it worked.

Very nice. As you mentioned though, it is a bit slow some of the time.

And thanks for the link AHKStudent... I will check that out.
ste(phen|ve) kunkel

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Bing [Bot], Mateusz53 and 158 guests