When we create a GUI with Edit, Button and ActiveX Shell.Explorer control, the TAB navigation is restricted to Edit & Button controls. We have to manually mouse click the WebControl before we can perform any key strokes on it
The following is ClassNN list for a above like GUI:
Code: Select all
Edit1 ( WS_TABSTOP )
Button1 ( WS_TABSTOP )
AtlAxWin1
Shell Embedding1 ( WS_TABSTOP )
Any attempt to style AtlAxWin with WS_TABSTOP will result in appcrash.
The correct way of enabling "Shell Embedding" to participate in TAB navigation is to style its parent AtlAxWin with WS_EX_CONTROLPARENT
Once an URL is loaded into Shell.Explorer object, additional child controls are created and ClassNN list will be:WS_EX_CONTROLPARENT 0x00010000L ( E0x10000 ) MSDN: goo.gl/8TsQaK
The window itself contains child windows that should take part in dialog box navigation.
If this style is specified, the dialog manager recurses into children of this window when
performing navigation operations such as handling the TAB key, an arrow key, or a keyboard
mnemonic.
Code: Select all
Edit1 ( WS_TABSTOP )
Button1 ( WS_TABSTOP )
AtlAxWin1
Shell Embedding1
Shell DocObject View1 ( WS_TABSTOP )
Internet Explorer_Server1
Attempts to transfer Tabstop to "Internet Explorer_Server1" does not enable it to receive focus.
Also, I checked IE 10. the above lying "Internet Explorer_Server1" is not styled WS_TABSTOP
The workaround I am suggesting/using is to detect when "Shell DocObject View" receives the focus, and transfer it immediately ( with ControlFocus ) to it child "Internet Explorer_Server"
We already have to handle WM_KEYDOWN & WM_KEYUP message for calling IOleInPlaceActiveObject::TranslateAccelerator method.
Placing the following code along, inside the OnMessage handler should be sufficient.
Code: Select all
If ( ClassName = "Shell DocObject View" && wParam = 0x09 ) {
WinGet, hIES, ControlListHwnd, ahk_id %hWnd% ; List children of 'Shell DocObject View'
ControlFocus,, ahk_id %hIES%
Return 0
}
That should be it, and should serve most of the needs... but,
If you open a webpage like http://ip.ahk4.me/ in any browser, you can immediately use Ctrl+A to select all text.
But the suggested implementation is not enough. The control will have focus but not any elements to focus on. Depending on needs one could use ControlClick instead of ControlFocus, but it will clear any selection already been made in the web content.
The correct way to handle these, would be to handle it in DocumentComplete() event. I don't know more on the subject but it will be like testing all frames and whether it has elements (enabled & visible) and set focus accordingly. If it does not have any, as the case with http://ip.ahk4.me/, one may use WB.Document.Body.Focus() to ready the document for Select All (Ctrl+A).
Example code ( adapted from Doc and rest of forum ):
Code: Select all
/*
__ __ __ __ __ __ __ _ __
/ /_ / /_/ /_____ _ / // /____ _/ /_ / /________________(_)___ / /_ ____ _______
/ __ \/ __/ __/ __ \(_) // // __ '/ __ \/ //_/ ___/ ___/ __/ / __ \/ __// __ \/ __/ _ \
/ / / / /_/ /_/ /_/ / / // // /_/ / / / / ,< (__ ) /__/ / / / /_/ / /__/ /_/ / / / // /
/_/ /_/\__/\__/ .___(_) // / \__,_/_/ /_/_/|_/____/\___/_/ /_/ .___/\__(_)____/_/ \__ /
/_/ /_//_/ /_/ (___/
Subject : [How To] Implement Tabstop for ActiveX > Shell.Explorer
Author : SKAN, for the technique described on topic.
Topic : http://ahkscript.org/boards/viewtopic.php?f=7&t=879
*/
#NoEnv
#SingleInstance, Force
SetWorkingDir %A_ScriptDir%
Gui Add, Edit, w930 r1 vURL, http://www.google.com/
Gui Add, Button, x+6 yp w44 Default, Go
Gui Add, ActiveX, xm w980 h640 E0x10000 vWB, Shell.Explorer
ComObjConnect(WB, WB_events)
IOleInPlaceActiveObject_Interface := "{00000117-0000-0000-C000-000000000046}"
pipa := ComObjQuery( WB, IOleInPlaceActiveObject_Interface )
TranslateAccelerator := NumGet( NumGet( pipa+0 ) + 20 )
OnMessage( 0x0100, "WM_KeyPress" ) ; WM_KEYDOWN
OnMessage( 0x0101, "WM_KeyPress" ) ; WM_KEYUP
OnExit, GuiClose
Gui Show
ButtonGo:
Gui Submit, NoHide
WB.Navigate(URL)
Return
class WB_events
{
NavigateComplete2(wb, NewURL)
{
GuiControl,, URL, %NewURL% ; Update the URL edit control.
}
DocumentComplete( WB, NewURL )
{
; check all frames and elements for input focus
; WB.Document.Body.Focus()
}
}
GuiClose:
ObjRelease( pipa )
OnExit
ExitApp
Return
WM_KeyPress( wParam, lParam, nMsg, hWnd ) {
Global WB, pipa, TranslateAccelerator
Static Vars := "hWnd | nMsg | wParam | lParam | A_EventInfo | A_GuiX | A_GuiY"
WinGetClass, ClassName, ahk_id %hWnd%
If ( ClassName = "Shell DocObject View" && wParam = 0x09 ) {
WinGet, hIES, ControlListHwnd, ahk_id %hWnd% ; Find child of 'Shell DocObject View'
ControlFocus,, ahk_id %hIES%
Return 0
}
If ( ClassName = "Internet Explorer_Server" ) {
VarSetCapacity( MSG, 28, 0 ) ; MSG STructure http://goo.gl/4bHD9Z
Loop, Parse, Vars, |, %A_Space%
NumPut( %A_LoopField%, MSG, ( A_Index-1 ) * 4 )
Loop 2 ; IOleInPlaceActiveObject::TranslateAccelerator method http://goo.gl/XkGZYt
r := DllCall( TranslateAccelerator, UInt,pipa, UInt,&MSG )
Until wParam != 9 || WB.document.activeElement != ""
IfEqual, R, 0, Return, 0 ; S_OK: the message was translated to an accelerator.
}
}