Jump to content
CarlD

Binding script to hotkey: Am I doing it correctly?

Recommended Posts

CarlD

I want to bind a script to hotkey "{NumPadAdd}" and do it within the script itself -- the equivalent of AutoHotkey's

NumPadAdd::

I've come up with this, and it works, but I'm wondering if there's a better way to do it. Upon being launched, my script opens an input box. In AHK, it pops up immediately; with AutoIt and the code below, there is a slight (~ 0.25 sec.) but still noticeable delay before the input box is displayed. Here's my code:

HotKeySet("{NumPadAdd}", "ToRun")

Func ToRun()
    Run(@ScriptFullPath)
EndFunc

Suggestions would be much appreciated.

Edited by CarlD

Share this post


Link to post
Share on other sites
argumentum

​This doesn't work for me. Hitting NumPadAdd does nothing.

​sowy, my bad.

#include <MsgBoxConstants.au3>
HotKeySet("{NumPadAdd}", "ToRun")
Func ToRun()
   ConsoleWrite( "Run(@ScriptFullPath)" &@CRLF)
   MsgBox($MB_TOPMOST,@ScriptName,"something happened at "&@HOUR&":"&@MIN&":"&@SEC&"."&@MSEC,2)
EndFunc
While 1
    Sleep(20)
WEnd

 

Share this post


Link to post
Share on other sites
Jos

What do you mean? Are you running the script and then pressing the + on the numericpad ?
Do you have any other application active?

Jos


Visit the SciTE4AutoIt3 Download page for the latest versions  - Beta files                                How to post scriptsource        Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites
CarlD

What do you mean? Are you running the script and then pressing the + on the numericpad ?
Do you have any other application active?

Jos

Sorry, my bad. There was another script assigned to NumPadAdd via properties in a desktop shortcut. I removed that, and argumentum's demo code now works.

I'm new to AutoIt and would appreciate understanding why the demo code works. How does ConsoleWrite( "Run(@ScriptFullPath)" &@CRLF) differ from Run(@ScriptFullPath)? And am I right that the endless loop is a way of pausing the script?

Also -- and this goes back to my original question of how to bind a script to a hotkey within the script itself -- I note that in the demo code the test action (displaying a MsgBox) is within the function "ToRun" itself. Does this mean that all actions to be bound to the hotkey must be scripted within the function referenced by HotKeySet()? I have a 4 KB script that I want to bind to NumPadAdd. Do I have to stuff the entire 4 KB of code  -- including UDF definitions -- into func "ToRun"? That would make the script a LOT less readable....

Share this post


Link to post
Share on other sites
Jos

What do you think will happen when you use Run(@ScriptFullPath) in the Func when NumPadAdd is pressed other than shelling the script again each time you press it?

Jos


Visit the SciTE4AutoIt3 Download page for the latest versions  - Beta files                                How to post scriptsource        Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites
CarlD

What do you think will happen when you use Run(@ScriptFullPath) in the Func when NumPadAdd is pressed other than shelling the script again each time you press it?

Jos

I guess I'm coming across as an idiot in need of Socratic tutoring. I know what Run() does. The Help file tells me that ConsoleWrite():

Writes data to the STDOUT stream. Some text editors can read this stream as can other programs which may be expecting data on this stream.

What this has to do with HotKeySet() is not immediately apparent -- well, at least to me as a newcomer to AutoIt trying to determine whether I should "migrate" from AutoHotkey. The Help screen for ConsoleWrite() doesn't mention HotKeySet() as a Related function, and both Example scripts have to do with writing stuff into text editors.

To go back (once again) to my original question, I would like to know whether AutoIt has the equivalent of AutoHotkey's [keyname]:: statement for binding a script -- i.e., the script in which the statement appears -- to a hotkey. If the answer is (1) Yes, then (a) what is that equivalent, and (b) if argumentum's code is that equivalent, then please confirm whether the entire script has to be stuffed into the function referenced in HotKeySet(). If the answer is (2) No, a simple "No" will suffice.

Share this post


Link to post
Share on other sites
Melba23

CarlD,

I guess I'm coming across as an idiot

No, but a little confused. let me try and clarify things: 

- 1. ConsoleWrite just copies its arguments to the local console - in the SciTE editor that is packaged with AutoIt that is the lower pane. So

ConsoleWrite( "Run(@ScriptFullPath)" &@CRLF)

will write the string "Run(@ScriptFullPath)" to that console. This is a common debugging tool where the desired code is just written rather than actually run.

- 2. AutoIt does not "bind" a script to a HotKey in the same way (as i understand from your description) as AHK. Doing what are you are trying to do will continually shell a new version of the whole script, which in AutoIt will eventually cause a "recursion overflow error" - see the Recursion tutorial in the Wiki if you need more explanation. What you need to do is place the code you wish to run inside a function which is then called by the HotKey whilst the main script remains active:

#include <MsgBoxConstants.au3>

; Set HotKey

HotKeySet("{NumPadAdd}", "_RunFunc")

Func _RunFunc()
    ; This is the code you wish to run
    MsgBox($MB_SYSTEMMODAL, @ScriptName, "something happened at " & @HOUR & ":" & @MIN & ":" & @SEC & "." & @MSEC, 2)
EndFunc   ;==>_RunFunc



; Keep script alive
While 1
    Sleep(10)
WEnd

The code you run is entirely inside the function and you run the function rather then the whole script when the HotKey is actioned.

Clearer now?

M23

 


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
CarlD

Clearer now?

M23

​Yes, much clearer, thank you. I am, frankly, disappointed that there is no equivalent to AHK's [keyname]:: and hope that it will be added to a future release of AutoIt. I'm not here to badmouth another program -- I like, use, and value AHK -- but I prefer AutoIt's syntax and overall functionality and, in a perfect world, would use it exclusively to automate common and not-so-common Windows tasks.

Thanks again for the clarification.

Share this post


Link to post
Share on other sites
Melba23

CarlD,

I have just been reading about that AHK function (oh how I hate that syntax!) and I think we have another misunderstanding. In your OP you had this code:

HotKeySet("{NumPadAdd}", "ToRun")

Func ToRun()
    Run(@ScriptFullPath)
EndFunc

In AutoIt syntax, @ScriptFullPath means the path of the script that is already running - which is why we suggested you would end up recursing yourself to an overflow error.  But there is nothing to prevent you from running another script from within that function:

HotKeySet("{NumPadAdd}", "ToRun")

Func ToRun()
    Run($sAnotherScriptFullPath)
EndFunc

This second script could either be a compiled exe or another au3/a3x file that you run via an existing interpreter.

Are we getting closer to what you required?

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
CarlD

... Are we getting closer to what you required?

​Closer, yes, but not quite there. Although I didn't make it clear in my OP, I was using a separate script to set the hotkey before I started this thread. However, as noted in my OP, there is a slight lag in the responsiveness of the hotkey compared to AHK's internal statement. In most situations this is probably not critical, but for my application it is. My app displays an input box and allows the user to enter a window-title fragment to switch to the window, a filename to open in its associated Windows application, or a command -- or an "alias" for any of the foregoing. (Aliases are associated with commands or window titles via an .ini file.) The alias can be as short as one character -- for example, "F" to switch focus to Firefox -- and when you use a prominent key such as NumPadAdd for the hotkey, the sequence -- NumPaddAdd - F - Enter -- can be typed very quickly. With the internal AHK hotkey assignment, I can type "F" immediately after hitting the hotkey, whereas with an external AutoIt script there is a slight lag that often results in the "F" being sent to the current window rather than the AutoIt script associated with the hotkey. That, precisely, is the shortfall that I wish I could overcome in AutoIt.

PS: Here's the AutoIt v3 version of my code:

#cs
    **********************************************************
    WinRun.au3 -- AutoIt v3 [CLD rev.6/6/2015]
    Open|Switch_to program, URL, folder, etc., etc.
    Create aliases (command abbreviatons) in WinRun.INI
    Enter "ini" (no quotes) to edit WinRun.INI
    Sample INI entry:
    MyR=[LibFile] MyRoutine ; runs "MyRoutine:" in WinRun-L.au3
    WinRun.txt has additional information
    Run AutoIt subroutines from WinRun-L.au3 library file
    **********************************************************
#ce
#include <MsgBoxConstants.au3>
; Input Box dimensions and screen position
; Can set on command line with WinRun.au3 [width] [height] [X] [Y]
Local $w = 330
Local $h = 150
; Leave empty to center Input Box on screen
Local $X = 720
Local $Y = 420
; X, Y settings for upper left-hand corner of desktop:
;Local $X = 0
;Local $Y = 0
; -----------------------------------------------
;
If $CmdLine[0] > 0 Then
    If $CmdLine[1] <> "." Then
        $w = $CmdLine[1]
    EndIf
    If $CmdLine[0] > 1 And $CmdLine[2] <> "." Then
        $h = $CmdLine[2]
    EndIf
    If $CmdLine[0] > 2 And $CmdLine[3] <> "." Then
        $X = $CmdLine[3]
    EndIf
    If $CmdLine[0] > 3 And $CmdLine[4] <> "." Then
        $Y = $CmdLine[4]
    EndIf
EndIf
;
; ----------------------------------
AutoItSetOption("WinTitleMatchMode", -2)
Local $AltBrowser = '"C:\Program Files (x86)\Mozilla Firefox\firefox.exe"'
; Local $AutoExe = @AutoItExe
Local $AutoExe = ""
; Local $AutoExe = '"C:\Program Files (x86)\AutoIt3\AutoIt3_x64.exe"'
Local $IniFile = @ScriptDir & "\WinRun.ini"
Local $LibFile = @ScriptDir & "\WinRun-L.au3"
Local $CrntWin = WinGetTitle("[active]")
Local $I = InputBox("WinRun", _
        "Enter program name, window title, alias or ""ini""", _
        "", "", $w, $h, $X, $Y, 60)
If $I == "" Then
    WinActivate($CrntWin)
    Exit 0
EndIf
Local $KeyValue = IniRead($IniFile, "WinRun", $I, $I)
If $KeyValue Then
    If StringInStr($KeyValue, "[AutoExe] ", 0) > 0 Then
        $KeyValue = StringReplace($KeyValue, "[AutoExe] ", $AutoExe, 0, 0)
    EndIf
    If StringInStr($KeyValue, "[AltBrowser]", 0) > 0 Then
        $KeyValue = StringReplace($KeyValue, "[AltBrowser]", _
            $AltBrowser, 0, 0)
    EndIf
    If StringInStr($KeyValue, "[LibFile]", 0) > 0 Then
        $KeyValue = StringReplace($KeyValue, "[LibFile]", $LibFile, 0, 0)
    EndIf
    If StringInStr($KeyValue, "[IniDir]", 0) > 0 Then
        $KeyValue = StringReplace($KeyValue, "[IniDir]", @ScriptDir, 0, 0)
    EndIf
    $I = $KeyValue
EndIf
If StringUpper($I) == "INI" Then
    ShellExecute($IniFile)
    Exit 1
ElseIf StringInStr($I, ":") > 0 Or StringInStr($I, ".") > 0 Then
    Local $rc = ShellExecuteRaw($I)
    Exit $rc
ElseIf WinExists($I) Then
    WinActivate($I)
    Exit 3
EndIf
; -----------------------------------------------
; Function definitions
Func ShellExecuteRaw($R, $vWorkingDir="", $vVerb="", $vWait="")
#cs
    Format raw string as "command", "params" for ShellExecute[Wait]()
    Variables: $R = raw string; $C = command; $D = delimiter; $P = params
    If input var $vWait is set, func returns
        ShellExecuteWait($C, $P, $vWorkingDir, $vVerb)
    otherwise, it returns
        ShellExecute($C, $P, $vWorkingDir, $vVerb)
#ce
    Local $C = $R, $D = " ", $P = ""
    If StringInStr($R, '"') == 1 Then
        $D = '" '
    EndIf
    If StringInStr($R, $D) > 0 Then
        $C = StringTrimRight( $R, StringLen($R) - StringinStr($R, $D) _
            + 2 - StringLen($D))
        $P = StringTrimLeft( $R, StringInStr($R, $D) )
    EndIf
    Local $ShellFuncName = "ShellExecute"
    If $vWait Then
        $ShellFuncName = "ShellExecuteWait"
    EndIf
    Return Call($ShellFuncName, $C, $P, $vWorkingDir, $vVerb)
EndFunc ; ShellExecuteRaw
; ***********************************************************
; end WinRun.au3
Edited by CarlD
Addition

Share this post


Link to post
Share on other sites
argumentum

you can, while learn to take advantage of AutoIt functions run as you wished from the first post
 

#include <MsgBoxConstants.au3>

AutoItWinSetTitle(@ScriptName & " IS RUNNING")
Local $aWinList = WinList(@ScriptName & " IS RUNNING")
ConsoleWrite("$aWinList[0][0] = " & $aWinList[0][0] & @CRLF)
If $aWinList[0][0] = 1 Then
    HotKeySet("{NumPadAdd}", "ToRun")
    While 1
        Sleep(20)
    WEnd
    Exit 0
EndIf
Func ToRun()
    ShellExecute(@ScriptFullPath)
EndFunc   ;==>ToRun

;all the inline code

MsgBox($MB_TOPMOST, @ScriptName, "something happened at " & @HOUR & ":" & @MIN & ":" & @SEC & "." & @MSEC & @CR & "My PID = " & @AutoItPID, 2)

do disregard this if you feel is no longer needed. 

Share this post


Link to post
Share on other sites
CarlD

you can, while learn to take advantage of AutoIt functions run as you wished from the first post
 

#include <MsgBoxConstants.au3>

AutoItWinSetTitle(@ScriptName & " IS RUNNING")
Local $aWinList = WinList(@ScriptName & " IS RUNNING")
ConsoleWrite("$aWinList[0][0] = " & $aWinList[0][0] & @CRLF)
If $aWinList[0][0] = 1 Then
    HotKeySet("{NumPadAdd}", "ToRun")
    While 1
        Sleep(20)
    WEnd
    Exit 0
EndIf
Func ToRun()
    ShellExecute(@ScriptFullPath)
EndFunc   ;==>ToRun

;all the inline code

MsgBox($MB_TOPMOST, @ScriptName, "something happened at " & @HOUR & ":" & @MIN & ":" & @SEC & "." & @MSEC & @CR & "My PID = " & @AutoItPID, 2)

do disregard this if you feel is no longer needed. 

​Impressive -- and works as advertised. :) It's ever so slightly less responsive than the AHK one-liner, but usable. Thanks, argumentum! :geek:

Edited by CarlD

Share this post


Link to post
Share on other sites
argumentum

well. I've downloaded the code you posted in WinRun.zip and read the ahk code. For what I see the ahk lenguage is very self limiting and the use of GoSub is not the approach used in au3. Anyone familiar with au3 would send rotten tomatoes my way for the way I've written the example but is the way you want it. The slowness is due to the fact that your code needs to load and run the script again, just to run the in-line code, when you can put all that in a function.

You've created a function for the ShellExecuteRaw, so you do have an understanding on how to write one.

Anywayz, have fun learning au3 :)

Edited by argumentum

Share this post


Link to post
Share on other sites
CarlD

OK, I have recast WinRun.au3 so that the heart of the script is in a function, Main(). It now has two hotkeys: NumPadAdd to call up the command input box, and Shift-NumPadAdd to exit the script and clear both hotkeys. The hotkey action is indeed zippier now, virtually the same as the AHK version. :)

As for the GoSubs, they are in WinRun-L.ahk, the small library of subroutines. For AutoIt, I recast the subs as functions (probably could and should do this in AHK, too). See WinRun-L.au3, below.

I do appreciate your guidance and encouragement.

#cs
    **********************************************************

    WinRun.au3 -- AutoIt v3 [CLD rev.6/7/2015]
    Open|Switch_to program, URL, folder, etc., etc.

    Create aliases (command abbreviatons) in WinRun.INI
    Enter "ini" (no quotes) to edit WinRun.INI
    Sample INI entry:
    MyR=[LibFile] MyRoutine ; runs "MyRoutine:" in WinRun-L.au3
    WinRun.txt has additional information

    Run AutoIt subroutines from WinRun-L.au3 library file

    **********************************************************
#ce

#include <MsgBoxConstants.au3>

HotKeySet("{NumPadAdd}", "Main")
HotKeySet("+{NumPadAdd}", "DisableHotkeys")
While 1
    Sleep(20)
WEnd

; -----------------------------------------------
; Function definitions

FUNC Main()
; Input Box dimensions and screen position
; Can set on command line with WinRun.au3 [width] [height] [X] [Y]
Local $w = 330
Local $h = 150
Local $X = 720
Local $Y = 420
; -----------------------------------------------
;
If $CmdLine[0] > 0 Then
    If $CmdLine[1] <> "." Then
        $w = $CmdLine[1]
    EndIf
    If $CmdLine[0] > 1 And $CmdLine[2] <> "." Then
        $h = $CmdLine[2]
    EndIf
    If $CmdLine[0] > 2 And $CmdLine[3] <> "." Then
        $X = $CmdLine[3]
    EndIf
    If $CmdLine[0] > 3 And $CmdLine[4] <> "." Then
        $Y = $CmdLine[4]
    EndIf
EndIf
;
; ----------------------------------

AutoItSetOption("WinTitleMatchMode", -2)

Local $AltBrowser = '"C:\Program Files (x86)\Mozilla Firefox\firefox.exe"'
; Local $AutoExe = @AutoItExe
Local $AutoExe = ""
; Local $AutoExe = '"C:\Program Files (x86)\AutoIt3\AutoIt3_x64.exe"'
Local $IniFile = @ScriptDir & "\WinRun.ini"
Local $LibFile = @ScriptDir & "\WinRun-L.au3"
Local $CrntWin = WinGetTitle("[active]")

Local $I = InputBox("WinRun (Shift-NumPadAdd quits)", _
        "Enter program name, window title, alias or ""ini""", _
        "", "", $w, $h, $X, $Y, 60)

If $I == "" Then
    WinActivate($CrntWin)
    ;Exit 0
EndIf

Local $KeyValue = IniRead($IniFile, "WinRun", $I, $I)
If $KeyValue Then
    If StringInStr($KeyValue, "[AutoExe] ", 0) > 0 Then
        $KeyValue = StringReplace($KeyValue, "[AutoExe] ", $AutoExe, 0, 0)
    EndIf
    If StringInStr($KeyValue, "[AltBrowser]", 0) > 0 Then
        $KeyValue = StringReplace($KeyValue, "[AltBrowser]", _
            $AltBrowser, 0, 0)
    EndIf
    If StringInStr($KeyValue, "[LibFile]", 0) > 0 Then
        $KeyValue = StringReplace($KeyValue, "[LibFile]", $LibFile, 0, 0)
    EndIf
    If StringInStr($KeyValue, "[IniDir]", 0) > 0 Then
        $KeyValue = StringReplace($KeyValue, "[IniDir]", @ScriptDir, 0, 0)
    EndIf
    $I = $KeyValue
EndIf

If StringUpper($I) == "INI" Then
    ShellExecute($IniFile)
    ;Exit 1

ElseIf StringInStr($I, ":") > 0 Or StringInStr($I, ".") > 0 Then
    Local $rc = ShellExecuteRaw($I)
    ;Exit $rc

ElseIf WinExists($I) Then
    WinActivate($I)
    ;Exit 3
EndIf
ENDFUNC ; Main

Func ShellExecuteRaw($R, $vWorkingDir="", $vVerb="", $vWait="")
#cs

    Format raw string as "command", "params" for ShellExecute[Wait]()
    Variables: $R = raw string; $C = command; $D = delimiter; $P = params
    If input var $vWait is set, func returns
        ShellExecuteWait($C, $P, $vWorkingDir, $vVerb)
    otherwise, it returns
        ShellExecute($C, $P, $vWorkingDir, $vVerb)

#ce
    Local $C = $R, $D = " ", $P = ""
    If StringInStr($R, '"') == 1 Then
        $D = '" '
    EndIf
    If StringInStr($R, $D) > 0 Then
        $C = StringTrimRight( $R, StringLen($R) - StringinStr($R, $D) _
            + 2 - StringLen($D))
        $P = StringTrimLeft( $R, StringInStr($R, $D) )
    EndIf
    Local $ShellFuncName = "ShellExecute"
    If $vWait Then
        $ShellFuncName = "ShellExecuteWait"
    EndIf
    Return Call($ShellFuncName, $C, $P, $vWorkingDir, $vVerb)
EndFunc ; ShellExecuteRaw

Func DisableHotKeys()
    HotKeySet("{NumpadAdd}", "")
    HotKeySet("+{NumpadAdd}", "")
    MsgBox(0, "WinRun", "Quitting WinRun...", 2)
    Exit
EndFunc

; ***********************************************************
; end WinRun.au3

Here's WinRun-L.au3:

; AutoIt Library for WinRun.au3 [CLD rev.6/5/2015]

#include <Clipboard.au3>
AutoItSetOption("WinTitleMatchMode", -2)
Global $cur = WinGetTitle("[active]")

; ----------------------------------
; Main
If $CmdLine[0] > 0 Then
    Call($CmdLine[1])
EndIf
Exit 0
; End Main
; -------------------------------

Func Copy()
  _ClipBoard_Empty()
  Send("^c")
  Return
EndFunc

; Close current window
Func Kill()
  WinKill("[active]")
  Return
EndFunc

Func Paste()
  Local $key = "^v"
  Local $win = WinGetTitle("[active]")
  If StringinStr($win, "vDos") > 0 Then
    $key = "#^v"
  EndIf
  Send($key)
  Return
EndFunc

; Maximize current window
Func MaxCur()
  WinSetState($cur, "", @SW_MAXIMIZE)
  Return
EndFunc

; Minimize current window
Func MinCur()
  Local $cur = WinGetTitle("[active]")
  WinSetState($cur, "", @SW_MINIMIZE)
  Return
EndFunc

; Minimize other windows
Func MinOther()
  Local $cur = WinGetTitle("[active]")
  WinSetState("vdos", "", @SW_MINIMIZE)
  WinMinimizeAll()
  WinActivate($cur)
  ; WinSetState($cur, "", @SW_MAXIMIZE)
  Return
EndFunc

; Restore active window
Func Restore()
  WinSetState($cur, "", @SW_RESTORE)
  Return
EndFunc

 

Edited by CarlD
  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×