Jump to content

AutoIt3Wrapper question - IUAutomation


jackchen
 Share

Recommended Posts

I've tried to make a script "Chrome_KeepLastTab.au3" to prevent Chrome from exit if the last tab is closed.

This script monitors the mouse click.If the mouse clicks on the close button on the last tab, it opens a new tab and then close the previous tab.

This script works but not stable.Can somebody point me out what I am wrong?

OK,I've made my "Chrome_KeepLastTab.au3" work.This script adds some features to Chrome browser:

1. Double click on a tab to close the tab.

2. Keep last tab:This script monitors your mouse clicks and hotkeys,if you are about to close the last tab within Chrome(click close button on the last tab, middle click/double click on the last tab or press Ctrl + w or Ctrl + {F4}), a new tab will be open and then the old tab be closed.

#include <WindowsConstants.au3>
#include <WinAPI.au3>
#include "CUIAutomation2.au3"

#AutoIt3Wrapper_UseX64=Y ;Should be used for stuff like tagpoint having right struct etc. when running on a 64 bits os

ConsoleWrite("@OSArch: " & @OSArch & ", @AutoItX64: " & @AutoItX64 & @CRLF)

Global $DoubleClickTime = 500
Global $UIA_oUIAutomation ; The main library core CUI automation reference
Global $hMouseEvent, $hMouseHook
Global $aMouseEvent[2]

Global $KeepLastTab = True ; settings from ini file


If $KeepLastTab Then
    ;The main object with acces to the windows automation api 3.0
    $UIA_oUIAutomation = ObjCreateInterface($sCLSID_CUIAutomation, $sIID_IUIAutomation, $dtagIUIAutomation)
    If IsObj($UIA_oUIAutomation) Then

        HotKeySet("^w", "Hotkey_Event") ; Ctrl + w to close tab
        HotKeySet("^{F4}", "Hotkey_Event") ; Ctrl + {F4} to close tab

        $DoubleClickTime = DllCall("user32.dll", "uint", "GetDoubleClickTime")[0]
        OnAutoItExitRegister("UnhookMouse")
        ; Register mouse events callback
        $hMouseEvent = DllCallbackRegister("Mouse_Event", "int", "int;ptr;ptr")
        $hMouseHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, DllCallbackGetPtr($hMouseEvent), _WinAPI_GetModuleHandle(0))
    EndIf
EndIf


While 1
    Sleep(100)
WEnd
ToolTip("")


; https://www.autoitscript.com/forum/topic/103362-monitoring-mouse-events/
Func Mouse_Event($nCode, $wParam, $lParam)
    Local $info, $mouseData, $time, $timeDiff
    If $nCode < 0 Then
        Return _WinAPI_CallNextHookEx($hMouseHook, $nCode, $wParam, $lParam) ; Continue processing
    EndIf

    $tPoint = _WinAPI_GetMousePos()
    $hWnd = _WinAPI_WindowFromPoint($tPoint)
    ; if mouse is on the widget window(class: Chrome_RenderWidgetHostHWND),
    ; use $hWnd = _WinAPI_GetParent($hWnd) to get the parent Chrome window

    If Not StringInStr(_WinAPI_GetClassName($hWnd), "Chrome_WidgetWin_") Then
        ; Chrome_WidgetWin_1: Chrome window
        ; Chrome_WidgetWin_2: Chrome menu
        ; ignore non Chrome window
        Return _WinAPI_CallNextHookEx($hMouseHook, $nCode, $wParam, $lParam)
    EndIf
    ToolTip($hWnd & " - " & _WinAPI_GetClassName($hWnd))

    ;$tagPOINT = "struct;long X;long Y;endstruct"
    Local Const $MSLLHOOKSTRUCT = $tagPOINT & ";dword mouseData;dword flags;dword time;ulong_ptr dwExtraInfo"
    $info = DllStructCreate($MSLLHOOKSTRUCT, $lParam)
    $mouseData = DllStructGetData($info, 3)
    $time = DllStructGetData($info, 5)
    $timeDiff = $time - $aMouseEvent[1]
    Local $block
    Switch $wParam
        Case $WM_LBUTTONUP
            $aMouseEvent[1] = $time
            If $aMouseEvent[0] = "LClick" And ($timeDiff) < $DoubleClickTime Then
                $aMouseEvent[0] = "LDClick"
            Else
                $aMouseEvent[0] = "LClick"
            EndIf
            $block = KeepLastTab($hWnd, $aMouseEvent[0])

        Case $WM_MBUTTONUP
            $aMouseEvent[1] = $time
            If $aMouseEvent[0] = "MClick" And ($timeDiff) < $DoubleClickTime Then
                $aMouseEvent[0] = "MDClick"
            Else
                $aMouseEvent[0] = "MClick"
                $block = KeepLastTab($hWnd, $aMouseEvent[0])
            EndIf
    EndSwitch

    If Not $block Then
        _WinAPI_CallNextHookEx($hMouseHook, $nCode, $wParam, $lParam) ; Continue processing
    EndIf
EndFunc   ;==>Mouse_Event

Func UnhookMouse()
    _WinAPI_UnhookWindowsHookEx($hMouseHook)
    $hMouseHook = 0
    DllCallbackFree($hMouseEvent)
    $hMouseEvent = 0
EndFunc   ;==>UnhookMouse

Func Hotkey_Event()
    Local $block
    Local $hWnd = WinGetHandle(WinGetTitle("[ACTIVE]"))
    If StringInStr(_WinAPI_GetClassName($hWnd), "Chrome_WidgetWin_1") Then ; Chrome_WidgetWin_1, Chrome window
        $block = KeepLastTab($hWnd, "Hotkey")
    EndIf

    If Not $block Then
        HotKeySet("^w")
        Send(@HotKeyPressed)
        HotKeySet("^w", "Hotkey_Event")
    EndIf
EndFunc

Func KeepLastTab($hWnd, $action = "LClick")
    ; Possible $action value: LClick, LDClick, MClick, Hotkey

    ConsoleWrite(@CRLF & $action & " on a Chrome window: " & $hWnd & @CRLF)

    Local $aMousePos = MouseGetPos()
    Local $pChrome, $oChrome
    $UIA_oUIAutomation.ElementFromHandle($hWnd, $pChrome) ; Window
    $oChrome = ObjCreateInterface($pChrome, $sIID_IUIAutomationElement, $dtagIUIAutomationElement)
    If Not IsObj($oChrome) Then
        ConsoleWrite("Failed to get Chrome object from hWnd." & @CRLF)
        Return
    EndIf

    ;$UIA_ControlTypePropertyId = 30003
    $oChromeTabs = UIA_getFirstElement($oChrome, $UIA_ControlTypePropertyId, $UIA_TabControlTypeId, $treescope_subtree)
    If Not IsObj($oChromeTabs) Then
        ConsoleWrite("Failed to get Chrome tab bar object." & @CRLF)
        Return
    EndIf

    Local $t
    $oChromeTabs.GetCurrentPropertyValue($UIA_BoundingRectanglePropertyId, $t)
    If UBound($t) < 4 Then Return
    If $action <> "Hotkey" And ($aMousePos[0] < $t[0] Or $aMousePos[0] > $t[2]+$t[0] Or $aMousePos[1] < $t[1] Or $aMousePos[1] > $t[3]+$t[1]) Then
        ; Mouse not on tabs bar
        ConsoleWrite("Mouse is not on the tab bar. Ignore and return..." & @CRLF)
        Return
    EndIf

    Local $pTrueCondition, $pElements, $iLength, $oAutomationElementArray
    $UIA_oUIAutomation.CreateTrueCondition($pTrueCondition)
    $oCondition = ObjCreateInterface($pTrueCondition, $sIID_IUIAutomationCondition, $dtagIUIAutomationCondition)
    If Not IsObj($oCondition) Then Return

    $oChromeTabs.FindAll($treescope_children, $oCondition, $pElements)
    $oAutomationElementArray = ObjCreateInterface($pElements, $sIID_IUIAutomationElementArray, $dtagIUIAutomationElementArray)
    If Not IsObj($oAutomationElementArray) Then
        ConsoleWrite("Failed to find all Chrome tabs. " & @CRLF)
        Return
    EndIf
    $oAutomationElementArray.Length($iLength)
    Local $UIA_pUIElement, $oTab2
    Local $iTabs = $iLength - 1

    If $iTabs > 1 Then ; more than one tab
        If $action = "LDClick" Then
            ConsoleWrite("There are " & $iTabs & " tabs within Chrome window. " & @CRLF)
            For $i = 1 To $iTabs
                $oAutomationElementArray.GetElement($i, $UIA_pUIElement)
                $oTab2 = ObjCreateInterface($UIA_pUIElement, $sIID_IUIAutomationElement, $dtagIUIAutomationElement)
                If Not IsObj($oTab2) Then ContinueLoop
                $oTab2.GetCurrentPropertyValue($UIA_BoundingRectanglePropertyId, $t)
                If UBound($t) < 4 Then ContinueLoop
                If $aMousePos[0] >= $t[0] And $aMousePos[0] <= $t[2]+$t[0] And $aMousePos[1] >= $t[1] And $aMousePos[1] <= $t[3]+$t[1] Then
                    ConsoleWrite("You double clicked on one of " & $iTabs & " tabs. Close the tab and return..." & @CRLF)
                    HotKeySet("^w")
                    Send("^w")
                    HotKeySet("^w", "Hotkey_Event")
                    Return True
                EndIf
            Next
        EndIf
        Return
    EndIf

    ConsoleWrite("There is ONLY one tab within Chrome window. " & @CRLF)

    $oAutomationElementArray.GetElement(1, $UIA_pUIElement)
    $oTab = ObjCreateInterface($UIA_pUIElement, $sIID_IUIAutomationElement, $dtagIUIAutomationElement)
    If Not IsObj($oTab) Then
        ConsoleWrite("Failed to get the last tab object." & @CRLF)
        Return
    EndIf

    Local $rtTab
    $oTab.GetCurrentPropertyValue($UIA_BoundingRectanglePropertyId, $rtTab)
    If UBound($rtTab) < 4 Then Return

    If $action <> "Hotkey" And ($aMousePos[0] < $rtTab[0] Or $aMousePos[0] > $rtTab[2]+$rtTab[0] Or $aMousePos[1] < $rtTab[1] Or $aMousePos[1] > $rtTab[3]+$rtTab[1]) Then
        ; Mouse not on the last tab
        ConsoleWrite("Mouse is not on the last tab. Ignore and return..." & @CRLF)
        Return
    EndIf

    If $action = "LClick" Then
        $oTabClose = UIA_getFirstElement($oTab, $UIA_ControlTypePropertyId, $UIA_ButtonControlTypeId, $treescope_subtree)
        If Not IsObj($oTabClose) Then
            ConsoleWrite("Failed to get the last tab close object." & @CRLF)
            Return
        EndIf
        $oTabClose.GetCurrentPropertyValue($UIA_BoundingRectanglePropertyId, $t)
        If UBound($t) < 4 Then Return

        If $aMousePos[0] < $t[0] Or $aMousePos[0] > $t[2]+$t[0] Or $aMousePos[1] < $t[1] Or $aMousePos[1] > $t[3]+$t[1] Then
            ; Mouse not on the tab close button
            Return
        EndIf
    EndIf

    ; open a new tab within chrome
    ConsoleWrite("The last tab is about to be closed, so we have to open a new tab to prevent Chrome window from closing." & @CRLF)
    Send("^t")
    ConsoleWrite("A new tab created!" & @CRLF)
    Sleep(100)

    ConsoleWrite("Close the old tab and return..." & @CRLF)

;~  Local $pPattern
;~  $oTabClose.GetCurrentPattern($UIA_InvokePatternId, $pPattern)
;~  $oPattern = ObjCreateInterface($pPattern, $sIID_IUIAutomationInvokePattern, $dtagIUIAutomationInvokePattern)
;~  If IsObj($oPattern) Then
;~      ConsoleWrite("Invoke to close the tab..." & @CRLF)
;~      $oTabClose.SetFocus()
;~      $oPattern.Invoke()
;~  EndIf

    _WinAPI_UnhookWindowsHookEx($hMouseHook)

    $aMousePos = MouseGetPos()
    If $aMousePos[0] >= $rtTab[0] And $aMousePos[0] <= $rtTab[2]+$rtTab[0] And $aMousePos[1] >= $rtTab[1] And $aMousePos[1] <= $rtTab[3]+$rtTab[1] Then
        MouseClick("middle", $aMousePos[0], $aMousePos[1], 1, 0)
    Else
        MouseClick("middle", $rtTab[0]+$rtTab[2]/2, $rtTab[1]+$rtTab[3]/2, 1, 0) ; close the tab
        MouseMove($aMousePos[0], $aMousePos[1], 0) ; move mouse back to previous position
    EndIf

;~  _WinAPI_Mouse_Event($MOUSEEVENTF_MIDDLEDOWN, $rtTab[0]+$rtTab[2]/2, $rtTab[1]+$rtTab[3]/2)
;~  Sleep(100)
;~  _WinAPI_Mouse_Event($MOUSEEVENTF_MIDDLEUP, $rtTab[0]+$rtTab[2]/2, $rtTab[1]+$rtTab[3]/2)


    $hMouseHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, DllCallbackGetPtr($hMouseEvent), _WinAPI_GetModuleHandle(0))

    Return True ; to block mouse click/hot key
EndFunc


Func UIA_getFirstElement($obj, $propertyID, $tval, $treeScope)
    Local $pCondition, $oCondition
    $UIA_oUIAutomation.CreatePropertyCondition($propertyID, $tval, $pCondition)
    $oCondition = ObjCreateInterface($pCondition, $sIID_IUIAutomationPropertyCondition, $dtagIUIAutomationPropertyCondition)

    Local $UIA_oUIElement, $UIA_pUIElement
    $t = $obj.Findfirst($treeScope, $oCondition, $UIA_pUIElement)
    $UIA_oUIElement = ObjCreateInterface($UIA_pUIElement, $sIID_IUIAutomationElement, $dtagIUIAutomationElement)
    If IsObj($UIA_oUIElement) Then Return $UIA_oUIElement
    Return SetError(1, 0, "")
EndFunc   ;==>UIA_getFirstElement

My question is related to #AutoIt3Wrapper_UseX64 when run this script on 64-bit Win 7.

No mater I set #AutoIt3Wrapper_UseX64=Y or #AutoIt3Wrapper_UseX64=N, this script works very well on hotkey event, while mouse clicks sometimes works if #AutoIt3Wrapper_UseX64=N and sometimes works on Y. Can some one test this and finger out what's wrong?

Info from SciTe if #AutoIt3Wrapper_UseX64=Y :

@OSArch: X64, @AutoItX64: 1

Hotkey on a Chrome window: 0x0000000000140330
There is ONLY one tab within Chrome window. 
The last tab is about to be closed, so we have to open a new tab to prevent Chrome window from closing.
A new tab created!
Close the old tab and return...

LClick on a Chrome window: 0x0000000000140330
There is ONLY one tab within Chrome window. 
The last tab is about to be closed, so we have to open a new tab to prevent Chrome window from closing.
A new tab created!
Close the old tab and return...

Info if #AutoIt3Wrapper_UseX64=N or comment out this line:

@OSArch: X64, @AutoItX64: 0

Hotkey on a Chrome window: 0x00140330
There is ONLY one tab within Chrome window. 
The last tab is about to be closed, so we have to open a new tab to prevent Chrome window from closing.
A new tab created!
Close the old tab and return...

LClick on a Chrome window: 0x00140330
Failed to get Chrome tab bar object.

Hotkey events and mouse click events share the same function KeepLastTab($hWnd, $action = "LClick"),Why this function triggered by hotkey works on both 32-bit and 64-bit while that triggered by mouse events failed on 32-bit autoit?

Edited by jackchen
Link to comment
Share on other sites

  • Jos unpinned this topic

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...