AutoHotkey Community

It is currently May 27th, 2012, 10:31 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 21 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: ScrollMomentum
PostPosted: October 5th, 2007, 8:57 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
ScrollMomentum

Applies "momentum" to scroll bars. Works with:
  • most standard windows scrollbars
  • Internet Explorer's scroll bars (tested on IE7.)
Thanks to Sean for his help and excellent COM scripts, and FireGirl for the idea and insisting that I add IE support. ;)

Requires Standard Library COM.ahk

Known Issues:
  • Doesn't work in Explorer (i.e. the file browser; at least on Vista; let me know if this is not the case for your version of Windows.)
  • Doesn't work in Microsoft Document Explorer's Index.
  • There is a delay when grabbing Internet Explorer scroll bars before the script starts working. This is usually around 100-140 ms for the initial "grab," and 30-60 ms for subsequent "grabs."


Code:
;
; AutoHotkey Version: 1.0.47 (MINIMUM), tested on 1.0.47.06.L
; Language:       English
; Platform:       Windows 98 and later? (REQUIRED), tested on Windows Vista (IE7).
; Author:         Lexikos
;
; Momentum-related code and ideas were developed for a different script by various users at:
;   http://www.autohotkey.com/forum/viewtopic.php?t=19773
;
; Script Function:
;   Apply momentum to scroll bars.
;
; Idea by FireGirl:
;   http://www.autohotkey.com/forum/viewtopic.php?t=21790

#NoEnv
CoordMode, Mouse, Screen

;
; CONFIGURATION
;

UPDATE_RATE = 10 ; milliseconds
SENSITIVITY = 0.5
INERTIA = 0.95

;
; WIN32 DEFINES
;
; SetWinEventHook Flags
WINEVENT_OUTOFCONTEXT       = 0x0000
; Events
EVENT_SYSTEM_SCROLLINGSTART = 0x0012
EVENT_SYSTEM_SCROLLINGEND   = 0x0013
; Scrollbar Constants
SB_HORZ = 0
SB_VERT = 1

;
; INITIALIZATION
;

SpeedA := 1 - SENSITIVITY

; Register callback proc.
cbOnScrollEvent := RegisterCallback("OnScrollEvent")
; Set scrolling start/end hook to call OnScrollEvent().
hScrollHook := DllCall("SetWinEventHook"
    , "uint", EVENT_SYSTEM_SCROLLINGSTART   ; eventMin
    , "uint", EVENT_SYSTEM_SCROLLINGEND     ; eventMax
    , "uint", 0                             ; hmodWinEventProc (only for in-context hooks)
    , "uint", cbOnScrollEvent               ; lpfnWinEventProc
    , "uint", 0                             ; idProcess (0 = all processes)
    , "uint", 0                             ; idThread (0 = all threads)
    , "uint", WINEVENT_OUTOFCONTEXT)        ; dwflags

if (!hScrollHook)
    MsgBox, 48, Error, SetWinEventHook failed. Standard Windows scrollbars will not have momentum applied.

; IE support init.
WM_HTML_GETOBJECT := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
COM_CoInitialize()

OnExit, CleanupAndExit

return


CleanupAndExit:
    ; May not be necessary; but for good measure...
    if hScrollHook
        DllCall("UnhookWinEvent", "uint", hScrollHook)
ExitApp


ContinueScroll:
    Scroll_Speed *= INERTIA
   
    ; Continue until
    ;   the scroll bar slows to a stop,
    ;   the window is closed,
    ;   or something else moves the scroll bar.

    if (Abs(Scroll_Speed)>0.01
        && GetAbstractScrollInfo(Scroll_Container, Scroll_Type, Scroll_Pos_Int)
        && Scroll_Pos_Int = Last_Pos)
    {
        ; Apply momentum.
        Scroll_Pos += Scroll_Speed
        ; Check if it hit the end.
        if (Scroll_Pos <  Scroll_Min)
            Scroll_Pos := Scroll_Min
        if (Scroll_Pos >  Scroll_Max)
            Scroll_Pos := Scroll_Max
        ; If it has come to a stop, stop the timer.
        if (Scroll_Pos = Last_Pos) {
            Scroll_Speed = 0
            SetTimer, ContinueScroll, Off
            return
        }
        ; Move scroll bar.
        if SetAbstractScrollPos(Scroll_Container, Scroll_Type, Round(Scroll_Pos))
        {   ; Update position (to detect if something else moves the bar.)
            GetAbstractScrollInfo(Scroll_Container, Scroll_Type, Last_Pos)
            return
        }
    }
    Scroll_Speed = 0
    SetTimer, ContinueScroll, Off
    gosub ReleaseScrollContainerIfNecessary
return

TrackScrollBar:
    ; Update scroll position.
    if GetAbstractScrollInfo(Scroll_Container, Scroll_Type, Scroll_Pos)
    {   ; Recalculate velocity.
        Scroll_Speed := Scroll_Speed*SpeedA + (Scroll_Pos-Last_Pos)*SENSITIVITY
        Last_Pos := Scroll_Pos
    }
    else
    {   ; Error: maybe the window closed?
        SetTimer, TrackScrollBar, Off
        gosub ReleaseScrollContainerIfNecessary
    }
return

ReleaseScrollContainerIfNecessary:
    if Scroll_Type in scrollbarHThumb,scrollbarVThumb
        COM_Release(Scroll_Container)
    Scroll_Container = 0
return

~LButton::
    gosub GetIEDocumentAtMouse
    if !pDoc
        return
    pWin := COM_Invoke(pDoc, "parentWindow"), COM_Release(pDoc), pDoc := 0
    if !pWin
        return

    ; Currently only one scroll bar can be moving at a time.
    SetTimer, ContinueScroll, Off
    gosub ReleaseScrollContainerIfNecessary

    MouseGetPos, x, y

    if (GetDeepestScrollElement(pWin, x, y, Scroll_Container, pElementWin))
    {   ; Hit-test for scrollbarHThumb or scrollbarVThumb.
        cx:=COM_Invoke(pElementWin,"screenLeft"), cy:=COM_Invoke(pElementWin,"screenTop"), pWin!=pElementWin ? (cx-=2, cy-=2) : ""
        Scroll_Type := COM_Invoke(Scroll_Container,"componentFromPoint",x-cx,y-cy)
        if Scroll_Type not in scrollbarHThumb,scrollbarVThumb
            COM_Release(Scroll_Container),Scroll_Container:=0, Scroll_Type:=""
        pElementWin!=pWin ? COM_Release(pElementWin) . pElementWin:=0 : ""
    }
    COM_Release(pWin), pWin:=0
   
    if !Scroll_Container
        return

    GetAbstractScrollInfo(Scroll_Container, Scroll_Type, Scroll_Pos, Scroll_Min, Scroll_Max)
    Last_Pos := Scroll_Pos
    Scroll_Speed := 0

    ; Set the tracking timer.
    SetTimer, TrackScrollBar, %UPDATE_RATE%

    KeyWait, LButton
   
    ; Scrolling has stopped, so stop tracking the scroll position.
    SetTimer, TrackScrollBar, Off
   
    if Scroll_Container
    {   ; Apply momentum.
        SetTimer, ContinueScroll, %UPDATE_RATE%
        ; Update Last_Pos in case it has changed since the last TrackScrollBar iteration.
        GetAbstractScrollInfo(Scroll_Container, Scroll_Type, Last_Pos)
    }
return


;
; CALLBACK - Standard Windows Scrollbars
;
OnScrollEvent(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime)
{
    global
    local trackpos
    static lbutton_state
   
    static OBJID_VSCROLL = 0xFFFFFFFB, OBJID_HSCROLL = 0xFFFFFFFA
   
    if (event = EVENT_SYSTEM_SCROLLINGSTART) && (lbutton_state:=GetKeyState("LButton"))
    {
        gosub ReleaseScrollContainerIfNecessary
       
        Scroll_Container := hwnd
        Scroll_Type := (idObject=OBJID_HSCROLL) ? SB_HORZ : SB_VERT
       
        ; Get this scroll bar's parameters.
        GetScrollInfo(Scroll_Container, Scroll_Type, Scroll_Pos, trackpos, Scroll_Min, Scroll_Max, Scroll_Page)
        Last_Pos := Scroll_Pos
       
        ; Set the tracking timer.
        SetTimer, TrackScrollBar, %UPDATE_RATE%
        ; Currently only one scroll bar can be moving at a time.
        SetTimer, ContinueScroll, Off
    }
    else if (event = EVENT_SYSTEM_SCROLLINGEND) && lbutton_state
    {
        ; Scrolling has stopped, so stop tracking the scroll position.
        SetTimer, TrackScrollBar, Off
        ; Apply momentum.
        SetTimer, ContinueScroll, %UPDATE_RATE%
        ; Update Last_Pos in case it has changed since the last TrackScrollBar iteration.
        GetScrollInfo(Scroll_Container, Scroll_Type, Last_Pos)
    }
}


;
; FUNCTIONS - Standard Windows Scrollbars
;
GetScrollInfo(hwnd, fnBar, ByRef nPos=0, ByRef nTrackPos=0, ByRef nMin=0, ByRef nMax=0, ByRef nPage=0)
{
    WinGet, Style, Style, ahk_id %hwnd%
    if !(Style & (fnBar ? 0x200000 : 0x100000))
        return false ; Fix for some controls which report {min:0,max:100} even though scroll bar doesn't exist.

    VarSetCapacity(si, 28, 0) ; SCROLLINFO si
    NumPut(28  , si, 0) ; si.cbSize := sizeof(SCROLLINFO)
    NumPut(0x17, si, 4) ; si.fMask := SIF_ALL
   
    if ! DllCall("GetScrollInfo", "uint", hwnd, "int", fnBar, "uint", &si)
        return false
   
    nPos        := NumGet(si, 20)
    nTrackPos   := NumGet(si, 24)
    nMin        := NumGet(si,  8)
    nMax        := NumGet(si, 12)
    nPage       := NumGet(si, 16)
    return true
}

SetScrollPos(hwnd, fnBar, nPos)
{
    VarSetCapacity(si, 28, 0) ; SCROLLINFO si
    NumPut(28  , si,  0)    ; si.cbSize := sizeof(SCROLLINFO)
    NumPut(0x4 , si,  4)    ; si.fMask := SIF_POS
    NumPut(nPos, si, 20)    ; si.nPos := nPos
 
    ; Use SetScrollInfo first because it supports 32-bit positions.
    ; If an application supports positions < 0 or > 65535, it most likely
    ; ignores WM_#SCROLL's wParam and uses GetScrollPos or GetScrollInfo
    ; to get the actual scroll position.
    DllCall("SetScrollInfo", "uint", hwnd, "int", fnBar, "uint", &si, "int", 0)
   
    ; WM_HSCROLL or WM_VSCROLL must be sent for the window to update it's contents.
    msg := (fnBar=0) ? 0x114 : 0x115
    wParam := 4 ; SB_THUMBPOSITION
        | ((nPos&0xFFFF)<<16)
    SendMessage, msg, wParam,,, ahk_id %hwnd%
   
    return (ErrorLevel != "FAIL")
}


;
; ABSTRACT FUNCTIONS - for both standard Windows scrollbar and IE scrollbar support.
;
GetAbstractScrollInfo(Container, Type, ByRef Pos=0, ByRef Min=0, ByRef Max=0)
{
    if !Container
        return false
    if Type in 0,1 ; SB_HORZ,SB_VERT
        return GetScrollInfo(Container, Type, Pos, track_pos, Min, Max)
    if Type = scrollbarHThumb
        Pos:=COM_Invoke(Container,"scrollLeft"),  Max:=COM_Invoke(Container,"scrollWidth"),  Min:=0
    else if Type = scrollbarVThumb
        Pos:=COM_Invoke(Container,"scrollTop"),  Max:=COM_Invoke(Container,"scrollHeight"),  Min:=0
    return Pos!=""
}
SetAbstractScrollPos(Container, Type, Pos)
{
    if !Container
        return false
    if Type in 0,1 ; SB_HORZ,SB_VERT
        return SetScrollPos(Container, Type, Pos)
    ; TODO: determine success or failure for assignment.
    if Type = scrollbarHThumb
        return true, COM_Invoke(Container,"scrollLeft=",Pos)
    else if Type = scrollbarVThumb
        return true, COM_Invoke(Container,"scrollTop=",Pos)
    return false
}


;
; IE FUNCTIONS & SUBROUTINES
;
GetDeepestScrollElement(pWin, x, y, ByRef pElement, ByRef pElementWin)
{
    ; AddRef so we don't release pWin below. (Caller may still need it.)
    COM_AddRef(win:=pWin)
    Loop {
        if (!win)
            break ; Error
        if !(doc:=COM_Invoke(win,"document"))
            break ; Error
        if !(element:=COM_Invoke(doc,"elementFromPoint",x-COM_Invoke(win,"screenLeft"),y-COM_Invoke(win,"screenTop")))
            break ; Error
        if (tag:=COM_Invoke(element,"tagName")) != "FRAME"
        {   ; return element.isScrollable ? element : frame.body
            scrollHeight:=COM_Invoke(element,"scrollHeight"), clientHeight:=COM_Invoke(element,"clientHeight")
            if !(clientHeight && clientHeight < scrollHeight)
                COM_Release(element), element:=COM_Invoke(doc,"body")
            break
        }
        COM_Release(doc), doc:=0,  COM_Release(win), win:=0
        if !(win:=COM_Invoke(element,"contentWindow"))
        {
            COM_Release(element), element:=0
            break ; Error
        }
    }
    if doc
        COM_Release(doc), doc:=0
    if (win && !element)
        COM_Release(win), win:=0
   
    pElement := element
    pElementWin := win
    return pElement
}

GetIEDocumentAtMouse:
    MouseGetPos,,,, hIESvr, 2
    WinGetClass, class, ahk_id %hIESvr%
    if (!hIESvr or class != "Internet Explorer_Server")
    {   ; Try again with alternate method (for "Microsoft Document Explorer" support.)
        MouseGetPos,,,, hIESvr, 3
        WinGetClass, class, ahk_id %hIESvr%
        if (!hIESvr or class != "Internet Explorer_Server")
            return
    }
   
    SendMessage, WM_HTML_GETOBJECT,,,, ahk_id %hIESvr%
    lResult := ErrorLevel
    DllCall("oleacc\ObjectFromLresult", "uint", lResult
        , "uint", COM_GUID4String(IID_IHTMLDocument2,"{332C4425-26CB-11D0-B483-00C04FD90119}")
        , "int", 0, "uint*", pDoc)
return



!Up::
    Scroll_Type = 1
    Scroll_Speed_Boost = -2
goto KickActiveScrollBar
!Down::
    Scroll_Type = 1
    Scroll_Speed_Boost = +2
goto KickActiveScrollBar
!Left::
    Scroll_Type = 0
    Scroll_Speed_Boost = -10
goto KickActiveScrollBar
!Right::
    Scroll_Type = 0
    Scroll_Speed_Boost = +10
goto KickActiveScrollBar

; Scroll_Type should be set to 0 (horz) or 1 (vert) before calling this subroutine.
; Scroll_Speed should be set to:
;   a scalar value with decimal point (it is multiplied by (Scroll_Max-Scroll_Min))
; or
;   an absolute value with no decimal point.
KickActiveScrollBar:
    ControlGetFocus, ctl, A
    ControlGet, hCtl, Hwnd,, %ctl%, A
   
    SetTimer, ContinueScroll, Off
    gosub ReleaseScrollContainerIfNecessary
   
    ; Internet Explorer scrollbars.
    if InStr(ctl,"Internet Explorer_Server")
    {   ; Get the document object of this IE control.
        SendMessage, WM_HTML_GETOBJECT,,,, ahk_id %hCtl%
        lResult := ErrorLevel ; necessary because COM_GUID4String() changes ErrorLevel.
        DllCall("oleacc\ObjectFromLresult", "uint",lResult
            , "uint",COM_GUID4String(IID_IHTMLDocument2,"{332C4425-26CB-11D0-B483-00C04FD90119}")
            , "int",0, "uint*",pDoc)
       
        if (pDoc && (pWin:=COM_Invoke(pDoc,"parentWindow"), COM_Release(pDoc),pDoc:=0))
            if (pElement:=GetActiveScrollElement(pWin)),  COM_Release(pWin),pWin:=0
            {
                Scroll_Container := pElement
                Scroll_Type := Scroll_Type ? "scrollbarVThumb" : "scrollbarHThumb"
                GetAbstractScrollInfo(Scroll_Container, Scroll_Type, Scroll_Pos, Scroll_Min, Scroll_Max)
            }
    }

    ; Standard Windows scrollbars.
    if !Scroll_Container
    {
        Scroll_Container := hCtl
        Loop
            if GetScrollInfo(Scroll_Container, Scroll_Type, Scroll_Pos, trackpos, Scroll_Min, Scroll_Max, Scroll_Page)
                && Scroll_Min != Scroll_Max
                break
            else
                Scroll_Container := DllCall("GetParent","uint",Scroll_Container)
    }

    Last_Pos := Scroll_Pos
;     if InStr(Scroll_Speed,".")
;         Scroll_Speed *= Scroll_Max-Scroll_Min
    if Abs(Scroll_Speed_Boost) < 1
        Scroll_Speed_Boost *= Scroll_Max-Scroll_Min
    if Abs(Scroll_Speed) < 1
        Scroll_Speed = 0
    Scroll_Speed += Scroll_Speed_Boost

    ; Apply momentum.
    SetTimer, ContinueScroll, %UPDATE_RATE%
return


GetActiveScrollElement(win)
{
    if !win
        return 0
    COM_AddRef(win) ; caller is responsible for releasing win
    Loop {
        if (!win)
            break ; Error
        if !(doc:=COM_Invoke(win,"document")),  COM_Release(win),win:=0
            break ; Error
        if !(element:=COM_Invoke(doc,"activeElement"))
            break ; Error
        if (tag:=COM_Invoke(element,"tagName")) != "FRAME"
        {   ; return element.isScrollable ? element : frame.body
            scrollHeight:=COM_Invoke(element,"scrollHeight"), clientHeight:=COM_Invoke(element,"clientHeight")
            if !(clientHeight && clientHeight < scrollHeight)
                COM_Release(element), element:=COM_Invoke(doc,"body")
            break
        }
        COM_Release(doc),doc:=0
        if !(win:=COM_Invoke(element,"contentWindow"))
        {
            COM_Release(element), element:=0
            break ; Error
        }
    }
    doc ? COM_Release(doc) . doc:=0 : ""
   
    return element
}

2007-10-12
Made a few misc changes. Scrolling now halts "glide" of standard Windows scrollbars.
2007-10-13
Fixed a couple potential "reference leaks."
2007-10-14
Fixed GetDeepestScrollElement() attempting to release an invalid object when the script fails to retrieve the contentWindow of a frame.
Fixed potential "reference leak" in ~LButton hotkey.

2008-12-30
Released script under Lexikos' default copyright license.

2009-01-01
Added Alt+Arrow "kicker" hotkeys which I had posted elsewhere. Also fixed them to "cascade" properly - i.e. scroll the active control if possible, otherwise its parent, its grandparent, etc.
Changed GetScrollInfo to return false if WS_VSCROLL or WS_HSCROLL style (as applicable) is not set. This fixes kicker cascading for some applications.
Other misc changes.


Last edited by Lexikos on January 1st, 2009, 6:25 am, edited 8 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 5th, 2007, 11:41 am 
Offline

Joined: June 26th, 2006, 6:14 pm
Posts: 1379
Location: USA
Hey, That is cool.

_________________
Image
ʞɔпɟ əɥʇ ʇɐɥʍ


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 5th, 2007, 7:58 pm 
Hello lexikos,

First off, very good job. When the momentum is on, it makes using the computer more cosy. I would consider running this all of the time if it worked for my major applications. I realize that this was not meant for me though.

It may be irrelevant, but I use firefox. It's not working with Firefox2.

I like the damper level you have set here. It's a good trade off considering how the speed varies depending on application.

What are your feelings on bouncing at the top and bottom, instead of dead stoping?

Thanks,
William


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: October 5th, 2007, 11:56 pm 
bouncing would be nice with this :) :) :) :)


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: October 6th, 2007, 1:22 am 
Offline

Joined: May 4th, 2007, 7:59 pm
Posts: 102
Truly outstanding work here!!! WOW!!!

Is adding this edge off bounce achievable?

I really can't think of anything else it would need to be *totally* perfectionist perfect.

Have a very great day! :D

%:FireGirl:%


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 6th, 2007, 4:10 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
William Sharkey wrote:
It may be irrelevant, but I use firefox. It's not working with Firefox2.
Yes, it's quite unfortunate. I use Firefox, but I don't know of any way to interact with its scroll bars (esp. from AutoHotkey.) Internet Explorer has its own COM interfaces.
Quote:
I like the damper level you have set here.
ManaUser deserves credit for that one. The speed calculation and inertia code is mostly from ManaUser's EasyGlide script (posted in this thread.)
Quote:
What are your feelings on bouncing at the top and bottom, instead of dead stoping?
It seems entirely unessential to me, but I'll probably add it eventually. :)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 6th, 2007, 5:15 am 
Offline

Joined: May 4th, 2007, 7:59 pm
Posts: 102
Thank you Sean & esp. lexikos, you are all the best. :)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 6th, 2007, 5:54 am 
Lexikos, I was fiddling with this and have some questions.

I noticed this works real smooth on notepad, but in Internet Explorer is extremely choppy and doesn't always grab, even if I hold down the mouse button. Kinda useless there.

I was trying to get the mouse tracking position of the scrollbar to see what is up, and noted when I inserted

Code:
    if (event = EVENT_SYSTEM_SCROLLINGSTART)
    {
        Scroll_Container := hwnd
        Scroll_Type := (idObject=OBJID_HSCROLL) ? SB_HORZ : SB_VERT
       
        ; Get this scroll bar's parameters.
        GetScrollInfo(Scroll_Container, Scroll_Type, Scroll_Pos, trackpos, Scroll_Min,

Scroll_Max, Scroll_Page)
        Last_Pos := Scroll_Pos
        MsgBox, %Last_Pos%
        ; Set the tracking timer.
        SetTimer, TrackScrollBar, %UPDATE_RATE%
        ; Currently only one scroll bar can be moving at a time.
        SetTimer, ContinueScroll, Off
    }


this chunk of code seems to be ignored on IE but in NotePad pops up. Is there something wrong that would be causing this? Really great overall concept however.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: October 6th, 2007, 6:14 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
That section of code is for standard Windows scroll bars only. IE's scroll bars do not raise those events (which are only for start/stop scroll) - the ~LButton hotkey is what detects IE's scroll bars. A better point to debug from would be TrackScrollBar, which calculates scroll speed, or ContinueScroll, which applies momentum. They are both used for both IE and standard Windows scroll bars. Use a ToolTip from either of those, or a MsgBox from ~LButton::
Quote:
in Internet Explorer is extremely choppy and doesn't always grab, even if I hold down the mouse button.
It's perfectly smooth for me, and always grabs if I hold down the mouse button before moving. Which version of IE are you using? By "doesn't always grab," I assume you mean it intermittently fails. If there is any specific page it doesn't work on, let me know.

Does anyone else have problems with the script in IE?

Edit: It seems the screenLeft and screenTop properties of frames are off by 2 pixels. As a consequence, the script can't grab the top or left edge of a scrollbar that belongs to a frame.

Edit: I've applied a small "offset hack," now you can grab the top or left edge of a frame's scrollbar. Tested on XP (IE6) in Virtual PC and Vista (IE7). Both scroll very smoothly for me, btw.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 6th, 2007, 3:14 pm 
Precisely, I am running Windows XP SP2 with IE 6.0.2900.2180_SP2 (which I presume is the latest IE 6.0 build for XP).... Yes, it definitely seems to prevent me from grabbing the scrollbar properly (anyone else?), even if I hold down the mouse button for more than 1000ms it just ignores the grab, (except in notepad which is picture perfect and works like a true charm). It would be interesting to see if your additional mods makes a difference with that here...


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: October 7th, 2007, 3:15 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
Sunnybreeze wrote:
I am running Windows XP SP2 with IE 6.0.2900.2180_SP2
Same here, but from a fresh install (no updates) of Windows XP w/ SP2. Do you have any add-ons running?
Quote:
Yes, it definitely seems to prevent me from grabbing the scrollbar properly (anyone else?), even if I hold down the mouse button for more than 1000ms it just ignores the grab,
Every time, or intermittently? If the former, maybe some of IE's COM components are damaged?

If anything demands CPU time, the script usually stutters (not just IE...) You could try adding this at the top of the script:
Code:
SetBatchLines, -1


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 7th, 2007, 7:27 am 
I can try this again on a restarted machine running these version specs, I will report back what I see soon.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: October 11th, 2007, 7:10 pm 
To make sure this was a fair and responsible test I re-ran it on a fresh install of Windows ...., no extra plug-ins etc.... , on a stock Windows XP SP2 (latest latest)..., running V6.0 Internet Explorer latest v., the version mentioned in my last post, and also a test running latest V7.0 IE (which is 7.0.5730.13). 1GB ram and 3Ghz machine so should not be any power or conflict issues.

I am getting same result on V6 and V7! The scrolling either vertically or horizontally doesn't seem to hook-in or 'catch', ... usually after 5 or 6 attempts it may once in awhile and glide along......., but there doesn't seem to be a precise technique to make it work, very just choppy unlike the way it works for me under Notepad, which seems 100% right on :)

What could be going wrong I can test or look into, or some other parameter I should try to compensate?


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: October 12th, 2007, 3:08 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
Try downloading the script directly (right click.) There are sometimes copy-past errors on the forums (esp. with the "Copy" link), though it's doubtful that this is the problem.

I'm updating my (XP) virtual machine, to see if that has any negative impact. (Edit: no change.)

Actually, I have since tried it on another XP SP2 machine (I copied the script from the forum), with perfect results. I'm not sure how up to date it was, but it certainly wasn't a fresh install.

I assume you have the latest version of AutoHotkey?
Quote:
1GB ram and 3Ghz machine so should not be any power or conflict issues.
True, when you're not doing anything else. I have tried the script when, for instance, starting up Virtual PC and simultaneously verifying a DVD I just burnt; it's not a pretty sight. ;)
Quote:
I am getting same result on V6 and V7!
That doesn't surprise me. I get the same results on V6 and V7; the difference is that I get good results. :?
Quote:
What could be going wrong I can test or look into, or some other parameter I should try to compensate?
SetBatchLines as I suggested previously, and maybe Process (priority). I think it is more likely some issue with the COM/MSHTML*, in which case script settings aren't likely to help. (I'm not ruling out the possibility of something in the script causing issues with MSHTML...)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 12th, 2007, 4:38 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
I've been messing around with hotkeys to "kick" the scroll bars. They should work fairly consistently with Notepad, but the "force" may be off for other apps, depending on the scale of their "scrollbar units."

This should be added to the bottom of the most recent version of the script in my first post.
Code:
!Up::
    Scroll_Type = 1
    Scroll_Speed = -2
goto KickActiveScrollBar
!Down::
    Scroll_Type = 1
    Scroll_Speed = +2
goto KickActiveScrollBar
!Left::
    Scroll_Type = 0
    Scroll_Speed = -10
goto KickActiveScrollBar
!Right::
    Scroll_Type = 0
    Scroll_Speed = +10
goto KickActiveScrollBar

; Scroll_Type should be set to 0 (horz) or 1 (vert) before calling this subroutine.
; Scroll_Speed should be set to:
;   a scalar value with decimal point (it is multiplied by (Scroll_Max-Scroll_Min))
; or
;   an absolute value with no decimal point.
KickActiveScrollBar:
    ControlGetFocus, ctl, A
    ControlGet, hCtl, Hwnd,, %ctl%, A
   
    SetTimer, ContinueScroll, Off
    gosub ReleaseScrollContainerIfNecessary
   
    ; Internet Explorer scrollbars.
    if InStr(ctl,"Internet Explorer_Server")
    {   ; Get the document object of this IE control.
        SendMessage, WM_HTML_GETOBJECT,,,, ahk_id %hCtl%
        lResult := ErrorLevel ; necessary because COM_GUID4String() changes ErrorLevel.
        DllCall("oleacc\ObjectFromLresult", "uint",lResult
            , "uint",COM_GUID4String(IID_IHTMLDocument2,"{332C4425-26CB-11D0-B483-00C04FD90119}")
            , "int",0, "uint*",pDoc)
       
        if (pDoc && (pWin:=COM_Invoke(pDoc,"parentWindow"), COM_Release(pDoc),pDoc:=0))
            if (pElement:=GetActiveScrollElement(pWin)),  COM_Release(pWin),pWin:=0
            {
                Scroll_Container := pElement
                Scroll_Type := Scroll_Type ? "scrollbarVThumb" : "scrollbarHThumb"
                GetAbstractScrollInfo(Scroll_Container, Scroll_Type, Scroll_Pos, Scroll_Min, Scroll_Max)
            }
    }

    ; Standard Windows scrollbars.
    if !Scroll_Container
    {
        Scroll_Container := hCtl
        if ! GetScrollInfo(Scroll_Container, Scroll_Type, Scroll_Pos, trackpos, Scroll_Min, Scroll_Max, Scroll_Page)
        {
            Scroll_Container:=0, Scroll_Type:="", Scroll_Speed:=0
            return
        }
    }

    Last_Pos := Scroll_Pos
    if InStr(Scroll_Speed,".")
        Scroll_Speed *= Scroll_Max-Scroll_Min

    ; Apply momentum.
    SetTimer, ContinueScroll, %UPDATE_RATE%
return


GetActiveScrollElement(win)
{
    if !win
        return 0
    COM_AddRef(win) ; caller is responsible for releasing win
    Loop {
        if (!win)
            break ; Error
        if !(doc:=COM_Invoke(win,"document")),  COM_Release(win),win:=0
            break ; Error
        if !(element:=COM_Invoke(doc,"activeElement"))
            break ; Error
        if (tag:=COM_Invoke(element,"tagName")) != "FRAME"
        {   ; return element.isScrollable ? element : frame.body
            scrollHeight:=COM_Invoke(element,"scrollHeight"), clientHeight:=COM_Invoke(element,"clientHeight")
            if !(clientHeight && clientHeight < scrollHeight)
                COM_Release(element), element:=COM_Invoke(doc,"body")
            break
        }
        COM_Release(doc),doc:=0
        if !(win:=COM_Invoke(element,"contentWindow"))
        {
            COM_Release(element), element:=0
            break ; Error
        }
    }
    doc ? COM_Release(doc) . doc:=0 : ""
   
    return element
}
As described in the comments, Scroll_Speed should be set to an integer representing an absolute scroll speed, or a floating point (i.e. with decimal point) scalar value (which is automatically multiplied by the maximum scroll in scroll units, not pixels.)

(I don't plan on updating the autohotkey.net link from my previous post.)


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 21 posts ]  Go to page 1, 2  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 13 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group