Internet Explorer: check if caret is visible (IHTMLCaret IsVisible) Topic is solved

Get help with using AutoHotkey and its commands and hotkeys
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Internet Explorer: check if caret is visible (IHTMLCaret IsVisible)

08 Nov 2017, 10:46

I was wondering if there was a way to retrieve whether caret browsing is on or off in Internet Explorer (or in Internet Explorer_Server controls generally).

This looks like a possibility:
IsVisible method (Windows)
https://msdn.microsoft.com/en-us/librar ... s.85).aspx

Some things I've tried which are giving me information about the caret, but not the visibility state:

Code: Select all

;[Acc functions]
;Acc library (MSAA) and AccViewer download links - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=26201

q:: ;caret - get information via GetGUIThreadInfo
ControlGetFocus, vCtlClassNN, A
ControlGet, hCtl, Hwnd,, % vCtlClassNN, A
VarSetCapacity(GUITHREADINFO, A_PtrSize=8?72:48, 0)
NumPut(A_PtrSize=8?72:48, &GUITHREADINFO, 0, "UInt") ;cbSize
vTID := DllCall("user32\GetWindowThreadProcessId", Ptr,hCtl, UIntP,0, UInt)
DllCall("user32\GetGUIThreadInfo", UInt,vTID, Ptr,&GUITHREADINFO)
vFlags := NumGet(&GUITHREADINFO, 4, "UInt") ;flags
hWndCaret := NumGet(&GUITHREADINFO, A_PtrSize=8?48:28, "Ptr") ;hwndCaret
WinGetClass, vWinClass, % "ahk_id " hWndCaret
vPosX := NumGet(&GUITHREADINFO, A_PtrSize=8?56:32, "Int") ;rcCaret ;x
vPosY := NumGet(&GUITHREADINFO, A_PtrSize=8?60:36, "Int") ;rcCaret ;y
vPosW := NumGet(&GUITHREADINFO, A_PtrSize=8?60:40, "Int") - vPosX ;rcCaret ;r
vPosH := NumGet(&GUITHREADINFO, A_PtrSize=8?60:44, "Int") - vPosY ;rcCaret ;b
ToolTip, % "class: " vWinClass
. "`r`n" Format("{} y{} w{} h{}", vPosX, vPosY, vPosW, vPosH)
. "`r`n" Format("flags: 0x{:X}", vFlags)
return

w:: ;caret - get information via Acc
ControlGetFocus, vCtlClassNN, A
ControlGet, hCtl, Hwnd,, % vCtlClassNN, A
WinGetClass, vWinClass, % "ahk_id " hCtl
;OBJID_CARET := -8
oCaret := Acc_ObjectFromWindow(hCtl, 0xFFFFFFF8)
oRect := Acc_Location(oCaret)
ToolTip, % "class: " vWinClass
. "`r`n" Format("{} y{} w{} h{}", oRect.x, oRect.y, oRect.w, oRect.h)
. "`r`n" "role: " Acc_Role(oCaret)
. "`r`n" "state: " Acc_State(oCaret)
. "`r`n" "state: " Format("0x{:X}", oCaret.accState(0))
. "`r`n" "description: " oCaret.accDescription(0)
return
Press F7 to toggle caret browsing in Internet Explorer.

Here's a script to toggle caret browsing in HTML Help:

Code: Select all

#IfWinActive, ahk_class HH Parent
F7:: ;html help - toggle caret browsing
PostMessage, 0x111, 3460,, Shell DocObject View1, A ;WM_COMMAND := 0x111 ;Caret browsing
;PostMessage, 0x111, 3460,, Shell Embedding1, A ;WM_COMMAND := 0x111 ;Caret browsing ;this also works
return
#IfWinActive
Thanks for reading.

[EDIT:] Some interesting links:
.net - Is it possible to get the index (start position) for the selected text in a WebBrowser control? - Stack Overflow
https://stackoverflow.com/questions/183 ... -in-a-webb
html - Identify HtmlElement under cursor in WebBrowser - Stack Overflow
https://stackoverflow.com/questions/425 ... webbrowser
c# - Get the links id for the current cursor position in the webrowser control - Stack Overflow
https://stackoverflow.com/questions/492 ... er-control
c# - How to change position of caret in MSHTML during mouse click? - Stack Overflow
https://stackoverflow.com/questions/136 ... 19#1410119
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
qwerty12
Posts: 468
Joined: 04 Mar 2016, 04:33
GitHub: qwerty12

Re: Internet Explorer: check if caret is visible (IHTMLCaret IsVisible)  Topic is solved

02 Dec 2017, 18:17

In response to your PM:

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.

OLECMDF_SUPPORTED := 0x1
OLECMDF_ENABLED := 0x2
OLECMDF_LATCHED := 0x4

VarSetCapacity(CGID_MSHTML, 16)
DllCall("ole32\CLSIDFromString", "WStr", "{de4ba900-59ca-11cf-9592-444553540000}", "Ptr", &CGID_MSHTML)

q::
oWB := WBGet("ahk_id " . WinExist("A"))
; https://msdn.microsoft.com/en-us/library/cc849093(v=vs.85).aspx
IOleCommandTarget := ComObjQuery(oWB.Document, "{b722bccb-4e68-101b-a2bc-00aa00404770}")
VarSetCapacity(OLECMD, 8, 0), NumPut(IDM_CARETBROWSINGMODE := 2436, OLECMD,, "UInt")
if (DllCall(NumGet(NumGet(IOleCommandTarget+0)+3*A_PtrSize), "Ptr", IOleCommandTarget, "Ptr", &CGID_MSHTML, "UInt", 1, "Ptr", &OLECMD, "Ptr", 0) >= 0)
	MsgBox % "Caret browsing active: " . (NumGet(OLECMD, 4, "UInt") & OLECMDF_LATCHED ? "True" : "False")

newSetting := -1 ; -1: toggle, False: disable, True:enable
if (newSetting == -1) {
	pVar := 0
} else {
	VarSetCapacity(VARIANT, 24, 0)
	NumPut(VT_BOOL := 11, VARIANT,, "UShort")
	NumPut(newSetting ? -1 : False, VARIANT, 8, "Short")
	pVar := &VARIANT
}
DllCall(NumGet(NumGet(IOleCommandTarget+0)+4*A_PtrSize), "Ptr", IOleCommandTarget, "Ptr", &CGID_MSHTML, "UInt", IDM_CARETBROWSINGMODE, "UInt", OLECMDEXECOPT_DONTPROMPTUSER := 2, "Ptr", pVar, "Ptr", 0)
ObjRelease(IOleCommandTarget)
oWB := ""
return

;[WBGet function for AHK v1.1]
;WBGet function - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=39869

WBGet(WinTitle="ahk_class IEFrame", Svr#=1) {               ;// based on ComObjQuery docs
   static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
        , IID := "{0002DF05-0000-0000-C000-000000000046}"   ;// IID_IWebBrowserApp
;//     , IID := "{332C4427-26CB-11D0-B483-00C04FD90119}"   ;// IID_IHTMLWindow2
   SendMessage msg, 0, 0, Internet Explorer_Server%Svr#%, %WinTitle%
   if (ErrorLevel != "FAIL") {
      lResult:=ErrorLevel, VarSetCapacity(GUID,16,0)
      if DllCall("ole32\CLSIDFromString", "wstr","{332C4425-26CB-11D0-B483-00C04FD90119}", "ptr",&GUID) >= 0 {
         DllCall("oleacc\ObjectFromLresult", "ptr",lResult, "ptr",&GUID, "ptr",0, "ptr*",pdoc)
         return ComObj(9,ComObjQuery(pdoc,IID,IID),1), ObjRelease(pdoc)
      }
   }
}
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Internet Explorer: check if caret is visible (IHTMLCaret IsVisible)

02 Dec 2017, 18:55

So I check my recent posts, the IE caret post, it's orange, qwerty12 ...

qwerty12, this is legendary, and it's not the first time.

Code: Select all

;WBGet function - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=39869

q:: ;internet explorer - get caret browsing on/off state for tabs
WinGet, hWnd, ID, ahk_class IEFrame
vOutput := ""
Loop
{
	ControlGet, hCtl, Hwnd,, % "Internet Explorer_Server" A_Index, % "ahk_id " hWnd
	if !hCtl
		break
	oWB := WBGet("ahk_id " hWnd, A_Index)
	vTitle := oWB.document.title
	vUrl := oWB.document.url
	vState := JEE_IntExpGetCaretBrowsingState(oWB)
	oWB := ""
	vOutput .= vState "`r`n" vTitle "`r`n" vUrl "`r`n`r`n"
}
vOutput := SubStr(vOutput, 1, -2)
Clipboard := vOutput
MsgBox, % vOutput
return

JEE_IntExpGetCaretBrowsingState(oWB)
{
	;based on code by qwerty12
	;Internet Explorer: check if caret is visible (IHTMLCaret IsVisible) - AutoHotkey Community
	;https://autohotkey.com/boards/viewtopic.php?f=5&t=39615&p=186265#p186265

	;CGID_MSHTML := "{de4ba900-59ca-11cf-9592-444553540000}"
	VarSetCapacity(CGID_MSHTML, 16)
	DllCall("ole32\CLSIDFromString", WStr,"{de4ba900-59ca-11cf-9592-444553540000}", Ptr,&CGID_MSHTML)

	;IID_IOleCommandTarget := "{b722bccb-4e68-101b-a2bc-00aa00404770}"
	IOleCommandTarget := ComObjQuery(oWB.Document, "{b722bccb-4e68-101b-a2bc-00aa00404770}")
	;IDM_CARETBROWSINGMODE := 2436
	VarSetCapacity(OLECMD, 8), NumPut(2436, &OLECMD,, "UInt")
	vRet := DllCall(NumGet(NumGet(IOleCommandTarget+0)+3*A_PtrSize), Ptr,IOleCommandTarget, Ptr,&CGID_MSHTML, UInt,1, Ptr,&OLECMD, Ptr,0)
	ObjRelease(IOleCommandTarget)
	if !(vRet >= 0)
		return
	else
		return !!(NumGet(OLECMD, 4, "UInt") & 0x4) ;OLECMDF_LATCHED := 0x4
}
Thanks so much for this, I knew if anyone could do this, it would be you, a 'qwerty12 special', and at least I did try my best using other methods. You've also given an interesting alternative method for setting the caret browsing state, which I will look at, and post here as a function.

I have stated the following 2 definitions, do notify me if these labels are incorrect in any way. I always like to include the GUIDs/IIDs for objects as comments.
CGID_MSHTML := "{de4ba900-59ca-11cf-9592-444553540000}"
IID_IOleCommandTarget := "{b722bccb-4e68-101b-a2bc-00aa00404770}"

Btw did you find any good reference material to help you reach this conclusion? Cheers.
Last edited by jeeswg on 02 Dec 2017, 21:13, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
qwerty12
Posts: 468
Joined: 04 Mar 2016, 04:33
GitHub: qwerty12

Re: Internet Explorer: check if caret is visible (IHTMLCaret IsVisible)

02 Dec 2017, 19:20

In JEE_IntExpGetCaretBrowsingState, IOleCommandTarget must be ObjReleased. The ownership of the object is ours, not AutoHotkey's.
jeeswg wrote:I have stated the following 2 definitions, do notify me if these labels are incorrect in any way.
They are correct.
Btw did you find any good reference material to help you reach this conclusion? Cheers.
ripgrep on the Windows SDK Includes brought up IDM_CARETBROWSINGMODE and Googling it took me to the MSDN page, which actually did include all the information needed on getting / setting the CB setting through that command ID.
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Internet Explorer: check if caret is visible (IHTMLCaret IsVisible)

02 Dec 2017, 21:27

I've fixed the code to use ObjRelease. The ObjRelease got lost when I split your original code in two, but it's back now.

A search for: Stack Overflow IHTMLCaret, brings up quite a few results, so I had thought that might be the way to go.

Using SearchMyFiles, I searched: C:\Program Files (x86)\Windows Kits\8.1 for 'caretbrowsing' and 'caret browsing', in .h files, and 3 had results, a few of the matching lines are listed below:

Code: Select all

MsHtmcid.h
#define IDM_CARETBROWSINGMODE           2436

WinUser.h
#define SPI_GETCARETBROWSING                0x104C

windows.ui.viewmanagement.h
    ( (This)->lpVtbl -> get_CaretBrowsingEnabled(This,value) ) 
The first, is one you mentioned, I don't know the significance of the other two. There is some interesting stuff in MsHtmcid.h re. IDM_ constants in general.

[EDIT:]
Some potentially interesting constants. I guess possible meanings, but they are only guesses. Anyone who's been annoyed by some IE limitation, would do well to take a look through the entire MsHtmcid.h list.

Code: Select all

;activate tab (my current workarounds are not ideal)
#define IDM_BRINGTOFRONT            11
#define IDM_TABORDER                41

;show find dialog? (I have a good workaround though)
#define IDM_FIND                    67

;move tab to new window? (I currently use AHK's MouseClickDrag command, with Acc to get the tab header coordinates, however, the tab header must be visible to do this)
#define IDM_NEW_TOPLEVELWINDOW      7050

;get zoom percentage? (I have a good workaround though)
For some things that I already know about, see:
jeeswg's Internet Explorer and HTML tutorial - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=31766
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Internet Explorer: check if caret is visible (IHTMLCaret IsVisible)

04 Dec 2017, 02:21

Here's a function to set the caret browsing state

Code: Select all

;WBGet function - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=39869

q:: ;internet explorer - toggle/set caret browsing on/off state for active tab
WinGet, hWnd, ID, A
oWB := WBGet("ahk_id " hWnd)
JEE_IntExpSetCaretBrowsingState(oWB, -1)
;JEE_IntExpSetCaretBrowsingState(oWB, 0)
;JEE_IntExpSetCaretBrowsingState(oWB, 1)
oWB := ""
return

;w:: ;internet explorer - toggle caret browsing on/off state for active tab
PostMessage, 0x111, 3460,, Shell DocObject View1, A ;WM_COMMAND := 0x111 ;Caret browsing
return

;vState: -1/0/1: toggle/off/on
JEE_IntExpSetCaretBrowsingState(oWB, vState)
{
	;based on code by qwerty12
	;Internet Explorer: check if caret is visible (IHTMLCaret IsVisible) - AutoHotkey Community
	;https://autohotkey.com/boards/viewtopic.php?f=5&t=39615&p=186265#p186265

	;CGID_MSHTML := "{de4ba900-59ca-11cf-9592-444553540000}"
	VarSetCapacity(CGID_MSHTML, 16)
	DllCall("ole32\CLSIDFromString", WStr,"{de4ba900-59ca-11cf-9592-444553540000}", Ptr,&CGID_MSHTML)

	;IID_IOleCommandTarget := "{b722bccb-4e68-101b-a2bc-00aa00404770}"
	IOleCommandTarget := ComObjQuery(oWB.Document, "{b722bccb-4e68-101b-a2bc-00aa00404770}")

	if (vState = -1)
		pVar := 0
	else
	{
		VarSetCapacity(VARIANT, 24, 0)
		NumPut(0xB, &VARIANT,, "UShort") ;VT_BOOL := 0xB
		NumPut(vState?-1:0, &VARIANT, 8, "Short")
		pVar := &VARIANT
	}
	;IDM_CARETBROWSINGMODE := 2436 ;OLECMDEXECOPT_DONTPROMPTUSER := 2
	DllCall(NumGet(NumGet(IOleCommandTarget+0)+4*A_PtrSize), Ptr,IOleCommandTarget, Ptr,&CGID_MSHTML, UInt,2436, UInt,2, Ptr,pVar, Ptr,0)
	ObjRelease(IOleCommandTarget)
}
I tried editing the code, replacing 2436 with some of the 'IDM' constants listed above, but it didn't do anything.

Btw is much connection between the approaches used for these caret browsing functions and the methods listed here, which I've used some of (example link provided), and where you can even use the methods by name:
IOleCommandTarget interface (COM)
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
OLECMDID enumeration (COM)
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
Internet Explorer get/set zoom/text size - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=26359

Also, I'm still not too sure how you managed to figure any of these things out, once you'd found the constant. Searching for some of these things online just gives list of constants.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
qwerty12
Posts: 468
Joined: 04 Mar 2016, 04:33
GitHub: qwerty12

Re: Internet Explorer: check if caret is visible (IHTMLCaret IsVisible)

04 Dec 2017, 18:18

jeeswg wrote:I tried editing the code, replacing 2436 with some of the 'IDM' constants listed above, but it didn't do anything.
Check with MSDN what command group the IDM command belongs to. And I think it's fair to assume not all of them are expecting a VT_BOOL VARIANT as pvaIn.
Btw is much connection between the approaches used for these caret browsing functions and the methods listed here, which I've used some of (example link provided), and where you can even use the methods by name:[...]
I wouldn't know. You're the one with many IE automation threads, after all. :) If you can get ExecWB to look at commands outside of the standard command group, you might be able to do it with that (thanks for the ComVar example).
Also, I'm still not too sure how you managed to figure any of these things out, once you'd found the constant. Searching for some of these things online just gives list of constants.
Like I said, Googling the constant took me to the MSDN page for it (which I linked inside the code I left). On that page, there's a nice "applies to" section. The page itself tells you what to set for each parameter. Even for me it could not have been easier. I went for IOleCommandTarget because:
  • It doesn't inherit from IDispatch.
  • Its ::Exec method actually had a parameter to decide what command group to look at
  • The MSDN page itself has a section named "IOleCommandTarget::Exec parameters"
The only bit I had trouble with was getting the GUID for CGID_MSHTML itself, as it wasn't in the headers like it is for IIDs etc.
I did something like this:
Spoiler
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Internet Explorer: check if caret is visible (IHTMLCaret IsVisible)

07 Dec 2017, 08:11

- So in this case you used ripgrep basically to search for text.
- It's a bit facepalm not to think of searching the .h files for 'caret browsing/CARETBROWSING' and then the Internet for 'MSDN IDM_CARETBROWSINGMODE', but then I'm so used to this stuff being undocumented that I didn't really consider it. [EDIT:] It appears that many of the 'IDM_' constants aren't documented.

[Ah OK, so IDM_CARETBROWSINGMODE is documented.]
IDM_CARETBROWSINGMODE Command ID ()
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
[As are some of the other 'IDM_' constants.]
MSHTML Command Identifiers
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
[Also, IDM_FIND is documented.]
IDM_FIND Command ID ()
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
[Hmm, not sure what this is. I'm interested in moving a window to a separate/existing window.]
IECMDID_BEFORENAVIGATE_DOEXTERNALBROWSE Command ID ()
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
[However these 3 are not documented AFAICS.]
IDM_BRINGTOFRONT
IDM_TABORDER
IDM_NEW_TOPLEVELWINDOW

- Btw, nice use of NumPut with blank parameters.
- Btw also, why the use of == instead of = with numbers?
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Ask For Help”

Who is online

Users browsing this forum: au6, BushMange, howardb1, MannyKSoSo, VACO BenQ, w0z and 187 guests