Search code examples
windowsmouseeventkeyboard-shortcutsautohotkeykey-bindings

Simple conditional pass through


Wondering if I might be missing something basic in AHK: Is there a way to do a simple conditional pass-through for any mouse or keyboard action, so that if the conditions fail, the action just passes through?

Something like:

LButton::
if(WinActive("ahk_class Notepad")) {
    ; Do something cool
    }
else { 
     ; Pass through
     }

What is giving me particular trouble is a case where a LButton must be passed through. The "cleanest" technique seems to fail (see the non-working script at the bottom) when the left click is the start of a dragging action. I have a workaround, but it is verbose.

What I have tried

I have a working solution, but it's rather verbose. Below, I've adapted it to a simple Notepad example for demo purposes. What the demo script does:

  • In Notepad, if you click in the text box, you get an alert and your click is disabled. However, you can click menus.
  • Everywhere else, clicking functions normally.

I have also tried an approach with the $ modifier that is not working (please see at the bottom).

Notes

  • The script uses Click Down rather than Click because otherwise drag actions are impossible. These are needed in the actual app and can be tested in Notepad by resizing the window.
  • I didn't wrap LButton in a If WinActive because 'LButton Up` needs to apply for all classes. Why? When you shift from Notepad to another app, the click down passes the Notepad test, but the click up fails as you're now in a different window.

Working Script

#NoEnv  ; Recommended for all scripts. Avoids checking empty variables to see if they are environment variables.

LButton::
if(WinActive("ahk_class Notepad")) {
    MouseGetPos, x, y, ovw, control
    if(control = "Edit1") {
      SplashTextOn 300, 100, AutoHotkey Message, You can play with the menus`,`nbut not the text box. 
      Sleep 3000 
      SplashTextOff
      }
   else { ; pass the click through
        ; The reason we Click down is that a plain Click doesn't work
        ; for actions where hold the button down in order to drag.
        Click down
       }
   }
 else { 
      Click down
      }
Return

; The LButton section holds the down state, so we need to allow it Up
LButton Up::Click up  

Non-Working Script using $

This approach is not working because the Notepad window can no longer be resized: the "pass-through" seems to click, rather than clicking down when that is the need (dragging action).

#NoEnv  ; Recommended for all scripts. Avoids checking empty variables to see if they are environment variables.
#IfWinActive ahk_class Notepad
$LButton::
MouseGetPos, x, y, ovw, control
    if(control = "Edit1") {
        SplashTextOn 300, 100, AutoHotkey Message, You can play with the menus`,`nbut not the text box. 
        Sleep 3000 
        SplashTextOff
      }
     else {  ; pass the click through
             Send {LButton}
          }
Return
#IfWinActive

Solution

  • #If... directives are used to make a hotkey only trigger under certain conditions. This of course means: If the given condition is not met, the hotkey routine will not be called and the keys will pass through (and they will pass through like native key events at that).

    Your example:

    ; $ prevents the hotkey from triggering itself
    $LButton::
      if(WinActive("ahk_class Notepad")) {
          ; Do something cool
      } else { 
          ; Pass through
          Send, LButton
      }
    return
    

    Can easily be written as:

    #IfWinActive, ahk_class Notepad
    LButton::
       ; Only the cool stuff goes here
    return
    #IfWinActive
    

    More specific to your problem, you can also use #If in conjunction with an expression in order to determine a combination of arbritrary conditions, namely to check if the user is trying to click into the text box in a Notepad window:

    #If WinActive("ahk_class Notepad") && MouseOver() = "Edit1"
    LButton::
        SplashTextOn 300, 100, AutoHotkey Message, You can play with the menus`,`nbut not the text box. 
        Sleep 3000 
        SplashTextOff
    Return
    #If
    
    MouseOver() {
        MouseGetPos, , , , curControl
        return curControl
    }