Windows 7 – autohotkey scrolling & middle click & mouse acceleration

Problems

Assume a Windows 7 machine, especially a laptop.

  1. No mouse driver allows holding down the right mouse button and moving the mouse to scroll, and yet retain the right mouse button functionality. This is useful if you do not have a middle button.
  2. Mouse drivers do not work for some applications, and some like UltraNav feel very jerky for most applications where they work.
  3. The UltraNav driver for the ThinkPad does not allow the middle button to function as a middle-click at the same time as allowing scrolling by holding it down and moving the mouse.
  4. The UltraNav driver also does not allow click-and-drag at the same time as scrolling, which is extremely useful in editing documents.
  5. Accelerated scrolling is impossible on a wheel-mouse and poorly done by the UltraNav driver.
  6. With the default mouse driver the fastest possible pointer speed might still be much too slow and tiring especially for ThinkPad trackpoints.

What I desired was an AutoHotkey script to solve all these problems, but nothing I have found online have come close to even solving a few of them.After two years I have developed a complete solution below. Of course some techniques that I used were adapted from various posts on the internet, but often each post had only one or two of the methods, and so they do not work for many applications.

Comments are welcome! However, please understand that I may not have the time to implement suggestions or troubleshoot if it does not work for you. Thanks!

Solution:

I designed my own AutoHotkey script that uses a low level mouse hook to solve all the above problems. The code is too long so see the other answer for the code.

Important instructions

Use the 32-bit version of AutoHotkey, even if you are using 64-bit Windows, otherwise it just will not work in some places! Run the script on login with highest possible privileges for the user, using Task Scheduler, otherwise it will not work for an admin user in applications running with full admin rights. If you have UltraNav installed, select “Smooth” for the middle mouse button, otherwise it will interfere with the script for some unknown reason and scrolling will not work.

On rare occasions something goes wrong with the mouse hook, especially if you try to scroll while an application is changing its GUI. I suspect it is because I am not running it at real-time priority but I think it’s too risky because if it gets stuck then there may be no way to stop it. Currently it is set to run at high priority. If anything goes wrong, try the following hotkeys in order.

LCtrl-RCtrl: Reload.RCtrl-LCtrl: Disable mouse hook. (If your mouse now works, Reload.)RCtrl-Esc: Disable the whole script. (You’ll need to run it again.)

Features

  1. By default scrolling is performed when the middle mouse button is held down and the mouse is moved. One can set rightbuttonscroll:=1 to use the right mouse button instead (especially for laptops which don’t have a middle mouse button), in which case to get the original right-click-drag functionality one might have to press an additional Ctrl/Shift/Alt before that, depending on the specific application. (In most applications at least one of these combinations does the same as the original right-click.)
  2. If one has no middle mouse button, one can also set leftrighttomiddle:=1, and then pressing both the left and right mouse buttons within clicklimit (milliseconds) generates the middle button press, and releasing both generates the middle button release. To keep the generated middle button down it is enough to keep just one of the two real buttons pressed.
  3. Scrolling functions independently of other mouse-buttons, so for example one can scroll any time while holding down the left mouse button during a selection operation, as long as the application supports it. (Some applications do not allow scrolling while selecting for some strange reason.)
  4. By default, after pressing and releasing the scroll-button (whether middle or right mouse button) within clicklimit generates the original scroll-button click. If the scroll-button is held longer than that, scrolling is enabled and releasing the scroll-button will not generate any click. To enable scrolling even during that initial delay, set scrollbeforeclick:=1. With this setting, clicking is possible even if slight scrolling has already been done, as long as it does not exceed scrolllimit.
  5. Scrolling is slightly sticky, meaning that if one accidentally releases the scroll-button during scrolling for less than resetdelay, then it is treated as if it did not occur and scrolling continues. In particular this means that accidentally clicking at the end of scrolling will not generate the original scroll-button click.
  6. Clicking is also slightly sticky, meaning that if one presses a mouse button within resetdelay after releasing a mouse button, then it is assumed that one
  7. Some applications are very sluggish in handling scrolling and so we cannot pump too many commands to them to perform scrolling. interval is the interval between batches of scrolling-related commands sent to the application. In each interval all scrolling actions by the user are combined into one. Decreasing the interval makes scrolling more responsive to the user but may choke poorly designed applications. If fine control is desired one can always set a default value at the start of gettarget and adjust it depending on the application.
  8. Some applications really take too long to process scrolling commands, and so if a command is not processed within timelimit, all the remaining commands in the batch for that interval are aborted.
  9. One can fine-tune the scrolling by editing scrollamount to change the scroll speed given the speed of the mouse or editing scrolladjust to change the way scrolling is performed given the accumulated scroll amounts. By default scrolling is snapped to the vertical or horizontal if the scroll amount in that direction is more than 5 times that in the other direction.
  10. One can also fine-tune the mouse speed and acceleration. Press LCtrl-Ralt-D to show the current mouse speed, LCtrl-Ralt-S to decrease the speed and LCtrl-Ralt-F to increase the speed. It will change the pointer speed that is in the Mouse settings. Edit moveadjust to change the way pointer movements are converted into mouse movements. By default, low speeds remain the same and high speeds are multiplied by 3, and there is a smooth transition in between, and also every mouse movement is spread over the current one and the next one, because at high pointer speeds the hardware or default mouse driver produces choppy output. Make sure moveadjust runs fast!

Methods

There are 11 different methods of scrolling that I have discovered in various applications. Some applications only respond to one of these, which is quite annoying. The methods are described in the comments in the code itself, but there is no reliable way to determine the correct method to use, and so one has to manually customize gettarget to choose the method for each application that does not work with the default wheel messages. Try the methods in the order they occur in scroll. For each method, you might have to experiment with changing the targets of the messages, namely ctrl,window,parent as appropriate.

To toggle debugging, press LCtrl-AppMenu. It shows the raw movements of the mouse the adjusted amounts, for both normal movement and scrolling. If you hold down the scroll-button without moving the mouse, it shows the ancestry of both the target under the mouse and the control chosen by gettarget. I sometimes had to also use Spy++ to see the control hierarchy and guess where to send the messages to.

Comments

The 64-bit AutoHotkey causes my script to fail for Programmer’s Notepad, while the 32-bit AutoHotkey works perfectly, and I don’t know why. Other applications seem to have no such problem. If it’s a bug in my script, I’d be glad to know!