AutoHotkey Script for Precision Hotkey Mouse Movement in Windows Graphics Programs (Beginning Hotkeys Part 15)

This Short AutoHotkey App Adds Pixel Level Precision to Mouse Cursor Movement in Any Windows Graphics Program. Plus, Best Practices When Creating Hotkeys and More.

From time to time I use various Windows graphics programs. I regularly open Irfanview as my default image reader and occasionally use the built-in Windows Snipping Tool for screen capture. But my favorite graphics program is the free Paint.Net image and photo editing software for PCs. I usually design Web ads and cleanup embedded images with Paint.Net. However, there is one annoying factor when working with virtually any graphics software. Using a mouse for selection and alignment tends to be inaccurate and sloppy. It’s very difficult to move the mouse cursor with pixel level exactness—at least not without massively magnifying the image size.

ComputorEdge AutoHotkey E-Books*         *          *

This beginning Hotkey blog builds upon the discussions in the previous parts. If you find any of the information too confusing, then reviewing earlier blogs may be worthwhile.

New to AutoHotkey? See “Introduction to AutoHotkey: A Review and Guide for Beginners.”

*          *          *

Inaccurate Mousing

The problem is that a pixel is so small that the slightest movement of the mouse while either pressing or releasing the left mouse button causes the cursor to jump one or two pixels in any random direction. Whenever I attempt to position the mouse cursor while holding the left button down, I either miss the mark or my finger accidentally slips and/or releases the button. Most graphics programs do allow limited use of the cursor keys for the incremental relocation of certain objects and selections, but it’s not universal and often limited to only one or two tools. Pixel level accuracy provided by the cursor keys comes in handy anytime you would normally hold down the left mouse button while dragging across an image—whether drawing an object, moving a selection, or aligning parts of an image.

Keypad
In the final MousePrecise.ahk script, movement of the mouse cursor one pixel at a time maps to the numeric keypad. Pressing the Numpad0 key toggles the left mouse button up and down for dragging.

The short AutoHotkey script I offer does just that by creating a set of Hotkeys which moves the mouse cursor one pixel at a time in the desired direction while holding down (hands-free) the left mouse button. As a convenience for large movements, the mouse continues to operate normally, but when looking for extreme accuracy before programmatically releasing the left mouse button, the arrow keys increment the mouse cursor pixel-by-pixel. The beauty of this script is that it works with any graphic tool that requires the left mouse click-and-drag maneuver—which happens to include almost all of them. Plus, it works with any Windows graphic app you add to the script without interfering with programs where those Hotkeys would be deemed useless.

Reader’s Note: This series (which I suspect will be at least three blogs long) about the MousePrecise.ahk script takes you through the Hotkey script building process. It combines many of the AutoHotkey techniques discussed in previous blogs (and books) while offering a couple of Hotkey creation Best Practices and a few AutoHotkey tips and tricks. While the final MousePrecise.ahk script does not appear in this blog, it is available for download at the ComputorEdge Free AutoHotkey Scripts page. I’ve already found this script useful while breaking in the tool with the graphics in this blog.

Arrow Keys for Exact Mouse Cursor Location

I start the script development with a modification of a barebones script I found online, then make a few improvements:

!up::MouseMove, 0, -1, 0, R   ; Move cursor upward
!Down::MouseMove, 0, 1, 0, R  ; Move cursor downward
!Left::MouseMove, -1, 0, 0, R ; Move cursor to the left
!Right::MouseMove, 1, 0, 0, R ; Move cursor to the right

Numpad0::Send % (toggle := !toggle) 
     ? "{LButton Down}" 
     : "{LButton Up}"

#If toggle ;disable the left mouse button
   LButton::Return
#If

In the above script the arrow keys in combination with the ALT key (!Up, !Down, !Left, and !Right) get mapped as Hotkeys with the MouseMove command repositioning the mouse one pixel at a time in each respective direction. It doesn’t get more precise than that! Next time, I plan to add a remapping of the numeric keypad allowing more movement directions (as shown in the image above).

To simulate a mouse drag with the left button down, the Numpad0 key is set up as a toggling switch for holding the LButton Down, then on the next press LButton Up. (More detailed explanation of how this toggle works follows in the next blog.)

Note: For display purposes, the Numpad0 line of code uses AutoHotkey line continuation to break the statement into three lines. When used in a script, it may appear as one continuous line.

Then, the #If directive evaluates the variable toggle. If true (LButton Down), the left mouse button is disabled (LButton::Return). When the variable toggle switches to false (LButton Up), the left mouse button is unblocked.

This simple script works, but there are a number of improvements yet to come. First, we look at a couple of best practices which should be considered when implementing any Hotkeys.

Hotkey Best Practice #1 (#IfWinActive Directive)

While there are many Hotkeys which you may want universally available all of the time (e.g. launching Windows apps, opening Web sites), whenever possible isolate Hotkey function to only in those programs where you need them. For example, this script is ideal for graphics programs (e.g. photo and image editors), but it doesn’t serve any purpose in most other types of programs (e.g. word processors and Web Browsers). By limiting Hotkeys to specific apps through the #IfWinActive directive, the new key combinations won’t affect other programs and Windows in general. This lowers the odds of an inadvertent Hotkey conflict:

#IfWinActive ahk_class MSPaintApp  ;only works in Paint

!up::MouseMove, 0, -1, 0, R   ; Move cursor upward
!Down::MouseMove, 0, 1, 0, R  ; Move cursor downward
!Left::MouseMove, -1, 0, 0, R ; Move cursor to the left
!Right::MouseMove, 1, 0, 0, R ; Move cursor to the right

Numpad0::Send % (toggle := !toggle) 
 ? "{LButton Down}" 
 : "{LButton Up}"

#IfWinActive

#If toggle ;disable the left mouse button
 LButton::Return
#If

The Hotkeys now only operate when a Windows Paint window is active. All other open apps and the Windows system itself go unaffected. See “AutoHotkey #Directives for Context-Sensitive Hotkeys—#IfWinActive (Beginning Hotkeys Part 3)” for more information on the #IfWinActive directive.

Best Practice Tip: As a general rule, you should enclose your set of #IfWinActive (ahk_class app name) Hotkeys with a terminating #IfWinActive (no parameter). The lone #IfWinActive directive turns off the effect of any previous #IfWinActive (ahk_class app name) directives for all following Hotkeys and Hotstrings. Although, this enclosing #IfWinActive is not required when the Hotkeys appear at the end of a file, including the code in a larger script without the terminating line could cause problems.

The current form of the script only supports Windows Paint windows, but there are certainly more programs which could use the same set of Hotkeys. We might continue to add more #IfWinActive directives with each new program class, but that would require the repeating of all the Hotkey definitions. The #If directive which can accept expressions is an option, but since commands offer more flexibility than #directives, we look to the GroupAdd command.

Hotkey Best Practice #2 (GroupAdd Command)

Since the #IfWinActive directive does not support adding multiple classes to the same line, the best way to add more apps to the list is through the GroupAdd command. This saves repeating each Hotkey definition for each window class. Plus, GroupAdd makes it easier to add more program window classes—even while the script is running. In fact, I would be tempted to always include GroupAdd when writing Hotkey scripts—even if initially nothing gets included in the group. It’s easy to add to the group later.

Since GroupAdd is a command, it must appear either in the auto-execute section of the script or the running portion of a subroutine. In this case, GroupAdd executes in the auto-execute section of the script. If you want to combine this script with another one of your scripts, then be sure to move this first command section to the auto-execute section at the beginning of the new script:

; Add to auto-execute section of script
GroupAdd, Graphics, ahk_class MSPaintApp
GroupAdd, Graphics, ahk_class IrfanView
; End of auto-execute section of script

#IfWinActive ahk_group Graphics  ;only works in Graphic group
!up::MouseMove, 0, -1, 0, R   ; Move cursor upward
!Down::MouseMove, 0, 1, 0, R  ; Move cursor downward
!Left::MouseMove, -1, 0, 0, R ; Move cursor to the left
!Right::MouseMove, 1, 0, 0, R ; Move cursor to the right

Numpad0::Send % (toggle := !toggle) 
 ? "{LButton Down}" 
 : "{LButton Up}"

#IfWinActive

#If toggle ;disable the left mouse button
   LButton::Return
#If

Now that the #IfWinActive directive uses the group Graphics (ahk_group Graphics), any program can be added to the list by inserting another GroupAdd command line calling the class of the new window. (For more information on GroupAdd, see “AutoHotkey GroupAdd Command Reduces Script Code (Beginning Hotkeys Part 4).”)

The AutoHotkey class of a window  may be identified with the Window Spy app (available with a right-click on any running .ahk script icon (not .exe) in the System Tray area of the Windows Taskbar). However, I discovered one slightly more complex situation where Window Spy won’t do the job, while my WindowProbe.ahk script easily gives me the class information I need.

WindowProbe Vs. Window Spy

Generally, Window Spy is all you need to identify the class of a window beneath the mouse cursor. But, when I was looking for the active windows used by the Windows Snipping Tool, the screen (and Window Spy) froze whenever initiating a new snip. Fortunately, the WindowProbe.ahk script (available for download at the ComputorEdge AutoHotkey download site in the file WindowProbe.zip) uses the Tooltip command which continues returning active data even when the screen is frozen by the Snipping Tool (see image below).

WindowProbeSnippingTool
After clicking “New” in the Snipping Tool window, the desktop fades and freezes for clipping. Window Spy (also frozen) no longer shows the active window class. Since WindowProbe uses the ToolTip command, it continues to return the class of the new active Snipping Tool capture window (Microsoft-Windows-Tablet-SnipperCaptureForm).

As it turns out, there are actually three window classes needed for the Hotkeys to work properly in the Snipping Tool:

GroupAdd, Graphics, ahk_class Microsoft-Windows-Tablet-SnipperToolbar
GroupAdd, Graphics, ahk_class Microsoft-Windows-Tablet-SnipperCaptureForm
GroupAdd, Graphics, ahk_class Microsoft-Windows-Tablet-SnipperEditor

The first is the main Snipping Tool window (ahk_class Microsoft-Windows-Tablet-SnipperToolbar); the second is the capture window active while selecting the clipping target (ahk_class Microsoft-Windows-Tablet-SnipperCaptureForm); and the third is the editor which automatically pops open after the snip (ahk_class Microsoft-Windows-Tablet-SnipperEditor). All three classes are necessary for the Hotkeys to work since the various windows are interdependent and any one of them may be active at any given point.

For more information on the ToolTip command and WindowProbe.ahk, see “Chapter Six: Hotkeys to Automate Right-click Menus” of AutoHotkey Tricks You Ought to Do with Windows.

There’s much more to be done with this script. The cursor keys are nice, but I plan to turn the numeric pad into the Hotkeys which will include four additional directions (up left, up right, down left, and down right) each moving in that direction one pixel at a time. Future blog topics include:

  1. Use Scan Codes to bypass numeric keypad NumLock issues.
  2. How to create a toggling Hotkey.
  3. Use ternary operator to create conditional shortcuts.
  4. Use Hotkey command to temporarily disable the left mouse button.
  5. Use Tooltip as a reminder that the left mouse button is down.
  6. Set up quick escape Hotkey to terminate LButton Down.
  7. Include a Hotkey to temporarily add the graphics Hotkeys to other active program windows while the script is running.

Next time, I’ll set up the Hotkeys on the numeric keypad as shown in the image at the top of this blog.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s