phil294 / AHK_X11

AutoHotkey for Linux (X11-based systems)
GNU General Public License v2.0
770 stars 11 forks source link

Support Request #73

Closed ClumsyDerp closed 3 months ago

ClumsyDerp commented 4 months ago

Hey,

I'm sorry having to bother you that way but I wasn't able to find a community I could ask. I've only recently started dabbling in ATH at all, so overall I am somewhat of a newbie but managed to set up my scripts under windows eventually, largely using ATH 2.0 features. I understand that some of the features are not available in AHK_X11 and that it uses old ATH syntax.

So now I am in the progress of translating my existing script but it is lacking some elegancy.

Original Script:

#Requires AutoHotkey v2.0

F12::loop_1(1)

loop_1(flip:=0)
{
    static toggle := 0

    if flip                             ; if flip is true
        toggle := !toggle               ;  switch toggle state: true <-> false
    if !toggle                          ; if toggle is off
        return                          ;  do nothing else

    WinWait "Title"
    WinActivate "Title"
    MouseMove(150,150)

    Send "{F5}"
        Sleep(100)
    Click "Right"
    Sleep (2500)

        ...
    SetTimer(loop_1 -600000)    ; In 10 minutes second, run this function again
}

This script starts a loop, being able to be toggled on and off by F12.

My current translation of said script looks as follows (F12 part only):

F12::
    Loop
    {
        IfWinExist, Title
        {
            WinActivate ; activate window

            Send, {F5} ; press f5
            Sleep, 100
            MouseClick, right, 150, 150
            Sleep, 2000

                       ....

            Sleep, 600000
        }
    }

~~ Ignore this ~~ This however behaves quite wonky.

While F12 does indeed start the script the window fetching seems to not work and the button presses happen randomly on the screen/desktop. Further, pressing F12 over and over again seems to neither stop, nor restart the script but logically that may be biting itself due the use of extended sleeps as I don't know whether the loop is being frozen in place, cancelled or not being toggled at all.

When I remove the hotkey and stick to the loop only the window fetching appears to work just fine, though.

~~ Ignore this ~~

(Having shifted the hotkey to *f12 rather than F12 seems to have fixed the issue)

Now to the subject of elegance: I quite like how the original script is more aching to be "function based" with SetTimer triggering the recall, rather than an infinite loop with long sleeps. Can this functionality be recreated in AHK_X11? While SetTimer does exist, I've no been able to get anything "function esque" to compile due to syntax errors.

Finally, what's the clean AHK_X11 way to properly toggle a script on/off on the press of a button (i.e F12)?

I crawled some of the other issues but I don't really understand what I am seeing, most notably lines aching to these, which I suspect are responsible for what I am struggling with:

*DEL:: Suspend, Toggle

Loop
{
    GetKeyState, 2State, 2, P
    If 2State = U
        break  
   ...
}

(Taken from here https://github.com/phil294/AHK_X11/issues/72)

Thanks in advance and thanks for the project.

EDIT: Encountered two more oddities.

  1. When doing
*f12::
    Loop
    {
        ...
    }

*f11::
    Loop
    {
        ...
    }

it appears both loops will not run simultaneously but whichever loop has been started as the latter will remain active and working. Splitting that construct into two script files seems to work just fine, though.

  1. When running the targeted app twice (i.e two instances of the same program, having an identical title)
Loop
    {
        IfWinExist, Title
        {
            WinActivate ; activate window
                       //do stuff
                }
         }

the window activation seems to always jump between clients, executing on the client that is not currently in focus.

For example: Client A and B are running, both share the same Title.

You focus Client A and start the loop. Client B will become active and has the loop commands executed. Next loop's title lookup will focus Client A and execute the commands there. Client Ping-Pong.

This could be worked around via PIDs I suppose but the behavior still strikes me as odd.

In terms of implementation shouldn't the execution check whether currentActiveWindow == WinTitle and give that a higher priority over "last active window" or "currently inactive window" when there are multiple title matches?

Haven't tested with 3 instances yet, so god knows what will happen then.

phil294 commented 3 months ago

Hey, did you solve these issues or why the closing?

Your code looks pretty good, except I'd be careful with the main loop. The IfWinExist fires with no pause permanently, probably going crazy on your cpu and possibly also prevents other hotkeys from working, so you should add some sleep there.

If you're having trouble understanding which parts of the script have been executed and which not, you can use Echo for custom logging in command line output or put some Tooltips in various positions. At some point there will be a ListLines-like GUI output where one can see the live output of commands executed, but this doesn't exist yet.

Further, pressing F12 over and over again seems to neither stop,

The code you posted contains no stopping logic

Apart from that, indeed there is only one thread per hotkey by default which can be configured with #MaxThreadsPerHotkey iirc

Can this functionality be recreated in AHK_X11?

Yes, SetTimer exists and works exactly as intended, as far as I am aware. You can't (yet) specify a negative number value though, so for one-time usages, a follow-up OFF invocation is necessary or else it keeps on firing forever. For more concrete help you'll need to post actual errors and/or code, please.

I wholeheartedly understand all of this is a bit confusing, as AHK can be quite difficult, but the docs should always be your friend, and also there are great guides on the internet. Unfortunately, many of them make use of function and expression syntax, making things less useful...

Finally, what's the clean AHK_X11 way to properly toggle a script on/off on the press of a button (i.e F12)?

I guess the most proper way would indeed to use a timer.

running = 0
F12::
if running = 0
{
  running = 1
  SetTimer, do_the_thing, 250
} else {
  running = 0
  SetTimer, do_the_thing, OFF
}
return

do_the_thing:
ToolTip, I am a tooltip and I am constantly following your mouse cursor
Return

the next release will even support

a = 0
a := ! a

kind of logic, but unless you've built ahk_x11 from source, this doesn't work yet.

it appears both loops will not run simultaneously but whichever loop has been started as the latter will remain active and working.

that's intended and I think exactly like windows ahk behaves (like everything written here, I hope). There is always only one "pseudo-thread" active at the same time. The way around is to use timers so that each pseudo-thread started by a timer is only shortlived and there are no competitors.

Regarding running multiple scripts... just - don't. That's just scary and unsupported territory and I have no idea how things will behave this way. The main problem in your code is still the missing sleep, I think, as written above.

I'm sorry having to bother you that way but I wasn't able to find a community I could ask

no problem, and indeed there isn't really any community :D you can join the Discord server if you want though, for easier chatting. But issues are always fine too.