Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

HoverScroll() - Vertical/Horizontal scroll without focus + Scrollwheel acceleration


  • Please log in to reply
79 replies to this topic
Scoox
  • Members
  • 194 posts
  • Last active: Apr 18 2016 07:18 AM
  • Joined: 28 Nov 2010

HoverScroll() is a function for scrolling any control directly under the mouse pointer, regardless of whether it has focus or not. This function started off as FocuslessScroll() somewhere in the middle of this thread, but I've decided to move it to a thread of its own to make it easier to find. Recently I have reviewed, enhanced and simplified the code and I'd like to share it.

 

Download: HoverScroll v1.04.zip   (includes ready-to-use example script demonstrating vertical scroll, horizontal scroll and zoom)

 

For best results configure your scrollwheel to scroll one line per step/notch in Windows > Control Panel > Mouse > Wheel > Vertical Scrolling:

 

2013-12-03-075326%20Wheel%20settings.png

 

The simplest way to use HoverScroll() is as follows:

;Scroll 1 line per notch.
;The first parameter tells the function how many lines to scroll per notch of the scroll wheel. A negative value reverses scroll direction.

WheelUp::HoverScroll(1) ;scroll up
WheelDown::HoverScroll(-1) ;scroll down

HoverScroll() accepts other parameters to fine-tune it's behaviour. All parameters are optional, and HoverScroll() assumes default values if any parameters are omitted. Please see HoverScroll.ahk for details.

 

Horizontal scroll:

;Horizontal scroll
;Make the second parameter = 1 for vertical scrolling, = 0 (or any other value) for horizontal scrolling
;If the second argument is omitted, HoverScroll() assumes vertical scrolling

;Vertical
WheelUp::HoverScroll(1, 1)    ;This is equivalent to HoverScroll(1)
WheelDown::HoverScroll(-1, 1) ;This is equivalent to HoverScroll(-1)

;Horizontal
!WheelUp::HoverScroll(1, 0)
!WheelDown::HoverScroll(-1, 0)

Focusless zoom:

;Focusless zoom
;If the third paramter is equal to 1, HoverScroll() will send Ctrl-Scroll, which is used for zooming in many applications.

;Any hotkey can be used to call HoverScroll(). This example enables us to zoom by means of either the traditional Ctrl-Scroll
;or by holding down XButton1 while scrolling.

XButton1 & WheelUp::
^WheelUp::
   HoverScroll(1,,1)
Return

XButton1 & WheelDown::
^WheelDown::
   HoverScroll(-1,,1)
Return

;NOTE: Some applications (e.g. MS Word, MS Visio) won't zoom unless you use Ctrl as the modifier.

;NOTE: Although in theory we could zoom at more than 1 line per notch, it is recommended you use a value of 1 because some
;applications will not respond predictably to other values. Again, you are free to experiment and specify per-application values.

Other modifiers:

msdn.microsoft.com/en-us/library/ms645617%28v=vs.85%29.aspx

HoverScroll() sends the WM_MOUSEWHEEL and WM_MOUSEHWHEEL messages to do its job. These messages only support sending of Ctrl and Shift, and to the best of my knowledge there is no easy way to overcome this limitation, maybe someone can chime in and prove me wrong.

;Third parameter = 1 sends Ctrl
;Forth parameter = 1 sends Shift

;Shift-Scroll
HoverScroll(1,,,1)
HoverScroll(-1)

;Shift-Ctrl combined
HoverScroll(1,,1,1)
HoverScroll(-1,,1,1)

Read my next post below for a description of scrollwheel acceleration using the supplied LinesPerNotch() functions.


RegJump() - Jump to registry path in Regedit

HoverScroll() - HoverScroll() - Scroll controls without focus


Scoox
  • Members
  • 194 posts
  • Last active: Apr 18 2016 07:18 AM
  • Joined: 28 Nov 2010

For those of you who need scrollwheel acceleration (that includes me), I have written ScrollLines(), included in HoverScroll.ahk (see previous post for download link), which returns the number of lines to scroll per notch based on how fast you turn the scrollwheel. The returned value can subsequently be passed to HoverScroll(), as shown below:

MinLines := 1 ;lines per step
MaxLines := 5 ;lines per step
Threshold := 50 ;Scrolling faster than one step every this many milliseconds engages acceleration 
AccelCurve := 1 ;0 = linear, 1 = parabolic

*WheelUp::
	Lines := ScrollLines(MinLines, MaxLines, Threshold, AccelCurve)
	HoverScroll(Lines)
Return

*WheelDown::
	Lines := ScrollLines(MinLines, MaxLines, Threshold, AccelCurve)
	HoverScroll(-Lines) ;Note minus sign to scroll downwards!
Return

Three different methods are provided, each having its pros and cons. Full details given in the script comments:

  • ScrollLines_1() - Simplest (my favourite)
  • ScrollLines_2() - Hybrid of methods 1 and 3 (more complex but more flexible)
  • ScrollLines_3() - Uses Performance Counter (more precise), but uses a global variable

Two acceleration curves are supported: linear and parabolic. You can add more of your own if needed. A graphical representation is given below. The X axis is the time between scrollwheel events in milliseconds, and the Y axis is the number of lines scrolled per notch:

 

2013-12-15-145038%20Acceleration%20graph

 

 

You are encouraged to experiment with the above values and methods until you find a combination that works well for you.


RegJump() - Jump to registry path in Regedit

HoverScroll() - HoverScroll() - Scroll controls without focus


Scoox
  • Members
  • 194 posts
  • Last active: Apr 18 2016 07:18 AM
  • Joined: 28 Nov 2010

Alright, so that's what I've been up to recently. It probably needs testing, so have fun!


RegJump() - Jump to registry path in Regedit

HoverScroll() - HoverScroll() - Scroll controls without focus


iDrug
  • Members
  • 389 posts
  • Last active: Oct 11 2015 09:24 PM
  • Joined: 13 Oct 2009

*WheelUp::
	Lines := ScrollLinesPerStep(MinLines, MaxLines, Threshold, AccelCurve)
	HoverScroll(Lines)
Return

*WheelDown::
	Lines := ScrollLinesPerStep(MinLines, MaxLines, Threshold, AccelCurve)
	HoverScroll(-Lines) ;Note minus sign to scroll downwards!
Return

You don't need to assign those variables every time the hotkey works out: it's enough to do that once upon initiating the script. This code would do the same, except it would execute less commands.
Lines := ScrollLinesPerStep(MinLines, MaxLines, Threshold, AccelCurve)
*WheelUp::HoverScroll(Lines)
*WheelDown::HoverScroll(-Lines) ;Note minus sign to scroll downwards!


Scoox
  • Members
  • 194 posts
  • Last active: Apr 18 2016 07:18 AM
  • Joined: 28 Nov 2010

You don't need to assign those variables every time the hotkey works out: it's enough to do that once upon initiating the script. This code would do the same, except it would execute less commands.

Lines := ScrollLinesPerStep(MinLines, MaxLines, Threshold, AccelCurve)
*WheelUp::HoverScroll(Lines)
*WheelDown::HoverScroll(-Lines) ;Note minus sign to scroll downwards!

 

Incorrect. When using acceleration, the number of lines per step is calculated based on the time elapsed since the last hotkey, which will be different every time you scroll. If you specify Lines once at the beginning you will get a constant value of lines per step, and clearly using ScrollLinesPerStep() to calculate that wouldn't be a very sensible thing to do.


RegJump() - Jump to registry path in Regedit

HoverScroll() - HoverScroll() - Scroll controls without focus


iDrug
  • Members
  • 389 posts
  • Last active: Oct 11 2015 09:24 PM
  • Joined: 13 Oct 2009
Oh, right. My bad.
*WheelUp::
*WheelDown::
	Lines := ScrollLinesPerStep(MinLines, MaxLines, Threshold, AccelCurve)
	(A_ThisHotkey == "*WheelUp") ? HoverScroll(Lines) : HoverScroll(-Lines)
Return


Carrozza
  • Members
  • 214 posts
  • Last active: Mar 02 2016 09:51 AM
  • Joined: 05 Jul 2009

Interesting script; I like the added dynamic scroll speed feature, too.

 

After a brief test I'm testing these values:

 

HoverScrollMinLines := 1

HoverScrollMaxLines := 15
HoverScrollThreshold := 25
HoverScrollAccelCurve := 0


Scoox
  • Members
  • 194 posts
  • Last active: Apr 18 2016 07:18 AM
  • Joined: 28 Nov 2010

Sounds about right. I am using a very similar set of values:

HoverScrollMinLines := 1
HoverScrollMaxLines := 30
HoverScrollThreshold := 20
HoverScrollAccelCurve := 1

RegJump() - Jump to registry path in Regedit

HoverScroll() - HoverScroll() - Scroll controls without focus


budRich
  • Members
  • 146 posts
  • Last active: Aug 03 2015 08:33 PM
  • Joined: 09 Aug 2011

Excellent script. I've been using "WizMouse" and "X-Mouse Button Control", but both of them didn't work perfect together with hotkeys like:

RButton & WheelUp::

However, HoverScroll does. Thank you very much!

 

PS. See my signature ;)



Skrell
  • Members
  • 384 posts
  • Last active: Jul 07 2016 05:03 PM
  • Joined: 23 Aug 2011

maybe you don't want to carry the acceleration value from 1 window to another?   So if i'm scrolling fast on 1 window and then switch to another to start scrolling immediately it won't "jump" because of the last value?

 

EDIT:  Or does it already do this? 



Skrell
  • Members
  • 384 posts
  • Last active: Jul 07 2016 05:03 PM
  • Joined: 23 Aug 2011

Also the acceleration (parabolic anyway) doesn't feel smooth and jumps occasionally making it hard to follow the page as it scrolls by.  Is there any way you can "buffer" the values to smooth them out ?  Like maybe make it so that you have to cross the threshold value 3 times in a row before the acceleration kicks in to prevent it from accelerating if you accidentally scroll 1 time faster by accident?

 

I'm using your values:

HoverScrollMinLines := 1
HoverScrollMaxLines := 30
HoverScrollThreshold := 20
HoverScrollAccelCurve := 1


Scoox
  • Members
  • 194 posts
  • Last active: Apr 18 2016 07:18 AM
  • Joined: 28 Nov 2010

maybe you don't want to carry the acceleration value from 1 window to another?   So if i'm scrolling fast on 1 window and then switch to another to start scrolling immediately it won't "jump" because of the last value?

 

EDIT:  Or does it already do this? 

 

I never thought about that, but it would carry acceleration from one window or control to the next. Personally I've never felt the need for this feature because I have HoverScrollThreshold set to 20ms and, realistically, it takes more than 20ms to move the mouse from one point to another in a controlled fashion, unless you are just deliberately aimlessly throwing the mouse around the screen while scrolling.

 

It would be very easy to add this in though: you just need to store the last scrolled control HWND in a global or static variable, and next time you call the function you compare the current control with the previous one. For the sake of keeping the code lean and fast, I will refrain from adding this feature for now, but if you encounter a situation where it would be beneficial do let me know and I'll add it.


RegJump() - Jump to registry path in Regedit

HoverScroll() - HoverScroll() - Scroll controls without focus


Scoox
  • Members
  • 194 posts
  • Last active: Apr 18 2016 07:18 AM
  • Joined: 28 Nov 2010

 

Also the acceleration (parabolic anyway) doesn't feel smooth and jumps occasionally making it hard to follow the page as it scrolls by.  Is there any way you can "buffer" the values to smooth them out ?  Like maybe make it so that you have to cross the threshold value 3 times in a row before the acceleration kicks in to prevent it from accelerating if you accidentally scroll 1 time faster by accident?

 

Does this happen in all applications? You could try a lower value for HoverScrollMaxLines. Also, check that you've set Windows in the Control Panel to scroll one line per notch (you've probably done this already but just in case).


RegJump() - Jump to registry path in Regedit

HoverScroll() - HoverScroll() - Scroll controls without focus


Skrell
  • Members
  • 384 posts
  • Last active: Jul 07 2016 05:03 PM
  • Joined: 23 Aug 2011

I added Tooltips to my hotkeys like this to watch the value for Lines change:

WheelDown::
Tooltip
Lines := ScrollLinesPerStep(MinLines, MaxLines, Threshold, AccelCurve)
HoverScroll(-Lines)
Tooltip %Lines%
Return

What i noticed is that i see the same 3-4 numbers show up again and again.  This "jerkiness" happens in all applications btw and yes my mousewheel is set correctly.  I think you need to do something better with your algorithm for calculating lines.   Like maybe average the last 3 values of A_TimeSincePriorHotkey or something to add more values in between MinLines and MaxLines upon threshold being met. 



Skrell
  • Members
  • 384 posts
  • Last active: Jul 07 2016 05:03 PM
  • Joined: 23 Aug 2011

I added Tooltips to my hotkeys like this to watch the value for Lines change:

WheelDown::
Tooltip
Lines := ScrollLinesPerStep(MinLines, MaxLines, Threshold, AccelCurve)
HoverScroll(-Lines)
Tooltip %Lines%
Return

What i noticed is that i see the same 3-4 numbers show up again and again.  This "jerkiness" happens in all applications btw and yes my mousewheel is set correctly.  I think you need to do something better with your algorithm for calculating lines.   Like maybe average the last 3 values of A_TimeSincePriorHotkey or something to add more values in between MinLines and MaxLines upon threshold being met.