Replace Hotkeys with the AutoHotkey GetKeyState() Function

While Digging into On-Screen Graphic Line Generation, I Discovered a Number of New AutoHotkey Techniques to Add to the MouseMeasure.ahk Distance Capturing Script

Last time, I looked into adding a line drawn on-screen to visually represent a linear measurement (“Drawing Lines on Screens with AutoHotkey“). However, I didn’t feel that the drivers I used presented the result I wanted for the MouseMeasure.ahk script. The line jittered too erratically and I found holding down the left-mouse button while dragging awkward and lacking precision. Therefore, I didn’t post the final product—although I did provide a download for the curious.

I have since drawn upon the expertise of other AutoHotkey Forum users to revise the script and create a much more robust app. The new script includes the following improvements:

  1. Only one Hotkey combination (Ctrl+LButton) activates both the calibration and measuring subroutine.
  2. The script no longer requires holding down the left mouse button while positioning the end point of the measurement. The end-point remains attached to the moving mouse cursor.
  3. The more advanced GDIPlus graphics used to draw the line make the line smoother and more robust.

The MouseMeasure.ahk script now uses Windows GDIPlus graphics to draw a red line between the start and end points of the on-screen ruler. The end point of the line moves with the mouse cursor until pinned with either the Shift or Alt key.

I pulled these improvements from a number of sources.

Drawing the On-Screen Line

Library Benefits

I reviewed a number of GDIPlus on-screen line drawing scripts. Some scripts directly calling the DllCall() function proved too tedious for me to follow. The best examples placed the DLLCall() function inside separate user-defined functions—each achieving a specific result. One of the earliest GDIPlus libraries—along with example scripts—was initiated by the tic (Tariq Porter): GDIP Standard Library examples. The library GDIP_All.ahk looks like a good starting point for many of the AutoHotkey on-screen graphics routines.

However, since none of the examples specifically drew a single line, I moved on to a forum reply by the user Hellbent to the Forum post “[Gdip] How to draw lines and retrieve pixel length?” offering an example of a line generator. With a little modification, I implemented the Hellbent line drawing technique in my MouseMeasure.ahk script.

I plan to discuss these line-drawing techniques (and more) in future blogs, but this time I concentrate on another technique—specifically, how Hellbent eliminated (or at least minimized) the use of Hotkeys. This technique alone made the MouseMeasure.ahk script much more user friendly by simulating temporary Hotkeys using the GetKeyState() function.

Using the GetKeyState() Function to Eliminate Hotkeys

By adding the Hellbent approach to Hotkey elimination (or minimization), I significantly changed how the new MouseMeasure.ahk script works (as shown in this image):


Drag the scrollbar down (or click at the bottom of the image) to view the original four-Hotkey instructions. Drag up (or click at the top of the image) to view the new single-Hotkey method. In the new script, the Hotkey combination Ctrl+Left Mouse Button initiates the calibration/measurement subroutine. Next, to pin the line end point, press Alt for calibration or press Shift for measurement.

As near as I can determine, Hellbent prefers not to use Hotkeys at all. I completely understand that perspective. I usually look for ways to avoid Hotkeys (“Eliminate Hotkeys with AutoHotkey Menus“). In his sample script, Hellbent presented an alternative technique for creating a Hotkey-like response to the keyboard action. After initiating SetTimer action with a single Hotkey (Ctrl+LButton), the subroutine reacts to specific keyboard action using the GetKeyState() function before moving on:

^LButton::
	active_Draw:=1
	MyPen:=New_Pen("FF0000",,5)
	MouseGetPos,sx,sy
	SetTimer,DrawStuff,10
	return

DrawStuff:
	Gdip_GraphicsClear(GdipOBJ.G)
	MouseGetPos,ex,ey
	Gdip_DrawLine(GdipOBJ.G, myPen, sx, sy, ex, ey)
	UpdateLayeredWindow(GdipOBJ.hwnd, GdipOBJ.hdc)
	if(GETKEYSTATE("Shift")){
		active_Draw:=0
		SetTimer,DrawStuff,off
		tooltip,% "The lenght is " abs(Sqrt(((sx-ex)**2) + ((sy-ey)**2)))
		Gdip_DeletePen(myPen)
	}
	return

The SetTimer,DrawStuff,10 statement (line 5) initiates the DrawStuff subroutine relaunching it every 10 milliseconds. When GetKeyState() detects the Shift key (line 13), AutoHotkey stops the timer and displays the calculated distance in pixels between the start and stop points.

Note: I did observe that occasionally the subroutine would not detect the Shift key action—forcing me to press it again. I suspect that occurred because I happened to hit the key during the instant that SetTimer relaunched the subroutine—a minor inconvenience that seemed to lessen when I increased the cycle time to 50 milliseconds.

Using GetKeyState() in the MouseMeasure.ahk Script

I immediately recognized that I no longer needed to hold down the left-mouse button while dragging the line across the target span—tremendous relief for my index finger. Plus, it allowed me to add varied results for calibration and measurement (or any future action, i.e. multi-segment measurement). Losing the requirement to detect Shift & LButton Up and Ctrl & LButton Up represents progress.

I modified the MouseMeasure.ahk script as follows:

#If (active_Draw=0)
^LButton::
	active_Draw:=1
	MyPen:=New_Pen("FF0000",,5)
	MouseGetPos,sx,sy ; start position for measurement
	SetTimer, UpdatePos,50
	SetTimer,DrawStuff,50
Return
#If

By placing the Hotkey inside the #If (active_Draw=0) directive, the Hotkey deactivates while running the SetTimer routines.

Note: I could probably combine the UpdatePos subroutine (from “Capturing Computer Screen Measurements“) and DrawStuff subroutine but I want to wait until I add other features. I may need to combine them or prefer to keep them separate.

The DrawStuff subroutine appears as follows:

DrawStuff:
	Gdip_GraphicsClear(GdipOBJ.G)
	MouseGetPos,ex,ey
	Gdip_DrawLine(GdipOBJ.G, myPen, sx, sy, ex, ey)
	UpdateLayeredWindow(GdipOBJ.hwnd, GdipOBJ.hdc)
	if(GETKEYSTATE("Shift")){
		active_Draw:=0
		setTimer UpdatePos, off
		SetTimer,DrawStuff,off
		tooltip Distance measured is : %distCalibrated% %units%  
		clipboard := distCalibrated
		Gdip_DeletePen(myPen)
	}
	if(GETKEYSTATE("Alt")){
		active_Draw:=0
		setTimer UpdatePos, off
		SetTimer,DrawStuff,off
		ToolTip
		Gdip_GraphicsClear(GdipOBJ.G)
		UpdateLayeredWindow(GdipOBJ.hwnd, GdipOBJ.hdc)
		clipboard := distCalibrated
		GuiControl, Calibrate:, Pixels, %dist%
		Gui, Calibrate:Show, , Scale Calibration
	}
Return

This approach to detecting keyboard input using the GetKeyState() function (line 6 and line 13) eliminates three previous Hotkey combinations found in the original MouseMeasure.ahk script—as well as, the requirement to hold-and-drag the left-mouse button.

You can find the above changes (plus the new GDIPlus features and functions) in the currently posted version of the MouseMeasure.ahk script.

GDIPlus Graphics

I plan to discuss the GDIPlus graphics used in the MouseMeasure.ahk script in much greater detail. As I develop a better understanding of how they work and the methods for implementation, I’ll use changes in this script to demonstrate the limited ways I use the DLLCall() functions. While I don’t yet have it all figured out, I plan to:

  • Show how to use the GDIPlus functions provided by Hellbent to draw a line on an invisible screen cover—a mini tutorial.
  • Add connected lines for measuring non-straight distances with multiple legs using an array.
  • Add informational GDIPlus text for each leg of the measured distance.

As usual, I may deviate from the above plan.

Click the Follow button at the top of the sidebar on the right of this page for e-mail notification of new blogs. (If you’re reading this on a tablet or your phone, then you must scroll all the way to the end of the blog—pass any comments—to find the Follow button.)

jack

This post was proofread by Grammarly
(Any other mistakes are all mine.)

(Full disclosure: If you sign up for a free Grammarly account, I get 20¢. I use the spelling/grammar checking service all the time, but, then again, I write a lot more than most people. I recommend Grammarly because it works and it’s free.)

Find my AutoHotkey books at ComputorEdge E-Books!

Find quick-start AutoHotkey classes at “Robotic Desktop Automation with AutoHotkey“!

4 thoughts on “Replace Hotkeys with the AutoHotkey GetKeyState() Function

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s