Stop Accidental Deletions with the BlockInput Command (AutoHotkey Tip—Part Two)

AutoHotkey BlockInput Command May Cause Stuck Keys! Fix It with the KeyWait Command

In the last blog, we dealt with the issue of setting the privilege level required to use the BlockInput command. In the BackupText.ahk and IncrementalSaveText.ahk scripts, the AutoHotkey command prevents user mouse/keyboard input while the script selects and copies text to the Windows Clipboard, but it doesn’t work without Administrator privileges. After raising the script to a higher level, we demonstrated how to use Windows Task Manager to bypass the User Account Control (UAC) warning window.

At the end of the blog, I mentioned an additional problem where BlockInput causes keys (usually one or more from the Hotkey combination) to stick in the down position. Here’s the trouble.

If BlockInput goes into effect before releasing any of the keys in the Hotkey combination, Windows cannot receive the KeyUp message. When the key gets released during the mouse/keyboard hiatus (before turning off BlockInput), the key remains logically in the down position. Not good!

The relatively simple fix involves adding the KeyWait command to the script for each key in the Hotkey combination:

KeyWait, Control ; avoid sticky key 
KeyWait, Alt     ; avoid sticky key
KeyWait, b       ; avoid sticky key

The online documentation states that KeyWait command “waits for a key or mouse/joystick button to be released or pressed down.” Since the script does not begin until you press down all of the keys in the combination simultaneously, they necessarily start in the down position. By adding the KeyWait lines of code, the script pauses (before executing BlockInput) until each key reaches the up position.

When I first added BlockInput to the scripts, I didn’t encounter this stuck key problem because (as I pointed out last time) the BlockInput command wasn’t actually working—at least not until I upped the privilege level of the EXE file. After that, I started noticing the dead keys. However, the warning does appear in the documentation:

If BlockInput becomes active while the user is holding down keys, it might cause those keys to become “stuck down.”

That gives us two basic rules of thumb for properly implementing the BlockInput command:

  1. For the BlockInput command to take effect, compile the script, and elevate the privilege of the EXE file to Administrator—as discussed in the last blog. (If you want to bypass the pop-up warning window, use Windows Task Manager to run the EXE file.)
  2. Use the KeyWait command to ensure that no keys get stuck in the down position.

The full BackupText.ahk script:

^!B::
  KeyWait, Control ; avoid sticky key 
  KeyWait, Alt ; avoid sticky key
  KeyWait, b ; avoid sticky key
  BlockInput, On ; turns off mouse/keyboard
    Send, ^a ; select all
    Sleep, 100
    Send, ^c ; copy selection to keyboard
    Sleep, 100
    Click ; deselect all select
  BlockInput, Off
  IfExist, C:\Users\%A_UserName%\Documents\SaveEdit.txt
  {
    FileDelete, C:\Users\%A_UserName%\Documents\SaveEdit.txt 
  }
  FileAppend , %clipboard%, C:\Users\%A_UserName%\Documents\SaveEdit.txt
Return

The order of the key releases does not matter. The script pauses only as long as one of the group remains down—regardless of which one.

Alternative Use for KeyWait

SplashTextIt seemed obvious that the KeyWait command could offer another method for pausing a script. KeyWait gives you a tool for creating an indefinite pause in a script until you press a specific key. Yet, initially, I had trouble getting it to work. Based upon the documentation, I thought that the command by default waited for a key change of state. Not so!

More precisely, KeyWait pauses for a key release (default) only if already pressed. If detected in the up position, AutoHotkey ignores the command and moves on. The command only waits for a key press when you add the Down (D) option. In other words, the default mode of KeyWait (with no options) looks for a key release when it’s in the down position at the time of the command.

By adding a SplashText command for notification, KeyWait creates an indefinite pause:

SplashTextOn , 200, 40, Continue!, Press F to continue…
KeyWait, f, D
SplashTextOff

At first, the script didn’t pause because I had assumed that AutoHotkey waited for a change in key state. Once I added the D option, it worked.

Caution: Take care when selecting an activation (resume) key. The F key used above causes the insertion of the letter f into any editing window active at the time you execute the script or routine. In fact, any key exhibits its usual behavior—depending upon the active window. Maybe, choose an innocuous key such as LEFT SHIFT (LShift). That way it’s unlikely that ending the pause will cause any collateral damage.

A better approach might be to assign a fake Hotkey combination using more than one key:

SplashTextOn , 200, 40, Continue!, Press CTRL+D to continue…
  KeyWait, Ctrl, D
  KeyWait, d, D
SplashTextOff

While it appears that CTRL+D acts as a Hotkey combination, in truth, AutoHotkey waits first for the CTRL key down, then the D key. Doing them as if a Hotkey combination works, while, unlike the default form of KeyWait (no options), pressing them separately in the wrong order does not. (Whichever keys you choose, ensure that they don’t comprise a real Hotkey combination or Windows shortcut.) This approach prevents random letters from appearing in your editing windows.

Tip (November 14, 2017): I can’t overemphasize the importance of picking a non-Windows shortcut. I ran this program as a test of other activity after selecting the file from Windows Explorer (File Explorer). When I used the CTRL+D combination, I accidentally deleted the script itself. I had to recover it from Windows 10 File History. It turns out that CTRL+D deletes files in Windows Explorer.

If no Hotkeys or Hotstrings appear in your script, you need to install the Keyboard Hook (#InstallKeybdHook) to make KeyWait operational. (Hotkeys and Hotstrings automatically install the Keyboard Hook.)

*          *          *

Next time, I’m moving on to take another look at an old script which I highlighted a number of years ago. While I add a couple of things to update it and implement a few tricks, the script highlights an important technique for tracking windows data on the fly.

*          *          *

Like anybody else, I have expenses and a need to make ends meet. As “Jack’s AutoHotkey Blog” increases in popularity, coding the test scripts and writing the blogs takes up more of my time. That means I’ve less time to pursue other income-earning opportunities. I don’t plan to ever move “Jack’s AutoHotkey Blog” behind a paywall, but if you think my efforts are worth a bit of your hard-earned cash, then you can offer a token of your appreciation by purchasing some of my AutoHotkey books. You may not need the references yourself, but you might know someone who can benefit from one or two of them.

Thank you,

jack

 

2 thoughts on “Stop Accidental Deletions with the BlockInput Command (AutoHotkey Tip—Part Two)

  1. Here’s some forum code I modified a bit with a suspend. DisplayName is the Title set or use ahk_id.

    KeyCombination:=””
    ExcludeKeys := “{Shift Up}{Control Up}{Alt Up}{WheelUp Up}{WheelDown Up}”

    ; Save active window
    WinGet, Wswitch, ID, A

    Suspend, On

    ; Battleeye workaround. Make the script the active window with hotkeys disabled. (Battleeye blocks autohotkey if it’s the active window)

    WinWait, %DisplayName%,
    IfWinNotActive, %DisplayName%, , WinActivate, %DisplayName%,
    WinWaitActive, %DisplayName%,
    ControlFocus,, %DisplayName%

    ; Battleeye workaround. Delay to disengage, you can take this out otherwise.
    Sleep, 50

    ; Get all the keys currently pressed
    Loop, 0xFF
    {
    If GetKeyState(Key:=Format(“VK{:02X}”,0x100-A_Index))
    {
    If !InStr(ExcludeKeys,Key:=”{” GetKeyName(Key) ” Up}”)
    KeyCombination .= RegexReplace(Key,”Numpad(\D+)”,”$1″)
    }
    }

    BlockInput, On
    SendInput, %KeyCombination%
    Suspend, Off

    ; ….. Do whatever here, all keys are blocked and up.

    ; This is as simple as I could get while getting around the Battleeye problem in Steam.

    Like

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 )

Facebook photo

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

Connecting to %s