diff --git a/docs/index.html b/docs/index.html index 7a081c8..c63299b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -324,7 +324,7 @@

Table of contents

#MaxThreadsBuffer
  • - #MaxThreadsPerHotkey + #MaxThreadsPerHotkey
  • Hotkey @@ -820,7 +820,7 @@

    Table of contents

    #MaxThreadsBuffer
  • - #MaxThreadsPerHotkey + #MaxThreadsPerHotkey
  • #NoTrayIcon @@ -1100,7 +1100,7 @@



    How can a repeating action be stopped without exiting the script?

    To stop an action that is repeating inside a Loop, consider the following example hotkey, which both starts and stops its own repeating action. In other words, pressing the hotkey once will start the Loop. Pressing the same hotkey again will stop it.

    -
    #MaxThreadsPerHotkey 3
    +          
    #MaxThreadsPerHotkey 3
     #z::
     #MaxThreadsPerHotkey 1
     if KeepWinZRunning = y  ; This means an underlying thread is already running the loop below.
    @@ -2840,7 +2840,7 @@ 

    The "Last Found" Window

    Causes some or all hotkeys to buffer rather than ignore keypresses when their #MaxThreadsPerHotkey limit has been reached. - #MaxThreadsPerHotkey + #MaxThreadsPerHotkey Sets the maximum number of simultaneous threads per hotkey. @@ -7502,7 +7502,7 @@

    The "Last Found" Window

    -
    +
    #

    #MaxThreadsPerHotkey


    diff --git a/src/build/parser.cr b/src/build/parser.cr index 4ca8c6d..72ed82c 100644 --- a/src/build/parser.cr +++ b/src/build/parser.cr @@ -106,6 +106,9 @@ module Build raise Exception.new ((e.message || "") + "\n#Include line: #{i}"), e.cause end end + elsif first_word.starts_with?("#maxthreadsperhotkey") + @runner_settings.max_threads_per_hotkey = args.to_u8? || 1_u8 + raise "#MaxThreadsPerHotkey maximum value is 20" if @runner_settings.max_threads_per_hotkey > 20 elsif line.starts_with?("#!") && line_no == 0 # hashbang elsif first_word == "if" split = args.split(/ |\n/, 3, remove_empty: true) @@ -158,7 +161,7 @@ module Build end else # Hotkey @cmds << Cmd::ControlFlow::Label.new line_no, [label.downcase] - @hotkeys << Run::Hotkey.new label, priority: 0, escape_char: @runner_settings.escape_char + @hotkeys << Run::Hotkey.new label, priority: 0, escape_char: @runner_settings.escape_char, max_threads: @runner_settings.max_threads_per_hotkey if ! instant_action.empty? add_line "#{instant_action}", line_no add_line "Return", line_no diff --git a/src/run/display/hotkey.cr b/src/run/display/hotkey.cr index 3b92012..e74d119 100644 --- a/src/run/display/hotkey.cr +++ b/src/run/display/hotkey.cr @@ -9,10 +9,12 @@ module Run getter modifier_variants = [] of UInt32 getter no_grab = false property exempt_from_suspension = false - def initialize(@key_str, *, @priority, escape_char) + getter max_threads : UInt8 + @threads = [] of Thread + def initialize(@key_str, *, @priority, escape_char, @max_threads) init(escape_char) end - def initialize(@cmd, @key_str, *, @priority, escape_char, @active = true) + def initialize(@cmd, @key_str, *, @priority, escape_char, @active = true, @max_threads) init(escape_char) end @@ -50,7 +52,16 @@ module Run end end def trigger(runner) - runner.not_nil!.add_thread @cmd.not_nil!, @priority + @threads.reject! &.done + # TODO: (commands not implemented yet): + # && ! @cmd_is_a?(Cmd::KeyHistory) && ! @cmd_is_a?(Cmd::ListLines) && ! @cmd_is_a?(Cmd::ListVars) && ! @cmd_is_a?(ListHotkeys) + if @threads.size >= @max_threads && ! @cmd.is_a?(Cmd::ControlFlow::ExitApp) && ! @cmd.is_a?(Cmd::Misc::Pause) && ! @cmd.is_a?(Cmd::Gtk::Edit) && ! @cmd.is_a?(Cmd::Misc::Reload) + # TODO: logger warn? what does win ahk do? + STDERR.puts "WARN: Skipping thread for hotkey press '#{key_str}' because #{@threads.size} threads are already running (max_threads==#{@max_threads}" + return + end + thread = runner.not_nil!.add_thread @cmd.not_nil!, @priority + @threads << thread end end end \ No newline at end of file diff --git a/src/run/display/hotkeys.cr b/src/run/display/hotkeys.cr index 4e0bc48..5c65c35 100644 --- a/src/run/display/hotkeys.cr +++ b/src/run/display/hotkeys.cr @@ -46,7 +46,7 @@ module Run active_state = hotkey.active if active_state.nil? else raise RuntimeException.new "Nonexistent Hotkey.\n\nSpecifically: #{hotkey_label}" if ! cmd_label - hotkey = Hotkey.new(cmd.not_nil!, hotkey_label, priority: priority, escape_char: @runner.settings.escape_char) + hotkey = Hotkey.new(cmd.not_nil!, hotkey_label, priority: priority, escape_char: @runner.settings.escape_char, max_threads: @runner.settings.max_threads_per_hotkey) hotkey.exempt_from_suspension = cmd.is_a?(Cmd::Misc::Suspend) @hotkeys << hotkey active_state = true if active_state.nil? diff --git a/src/run/runner.cr b/src/run/runner.cr index ef80318..f490975 100644 --- a/src/run/runner.cr +++ b/src/run/runner.cr @@ -19,6 +19,9 @@ module Run property escape_char = '`' property hotstring_end_chars = ['-', '(', ')', '[', ']', '{', '}', ':', ';', '\'', '"', '/', '\\', ',', '.', '?', '!', '\n', ' ', '\t', '\r'] property single_instance : SingleInstance? + # Can't be altered after parsing but we still need to remember this value somewhere + # for the dynamic creation of hotkeys. + property max_threads_per_hotkey = 1_u8 end # can start a completely fresh and isolated ahk execution instance with its own