Giter Site home page Giter Site logo

Feature/Hotkeys about ahk HOT 31 CLOSED

spyoungtech avatar spyoungtech commented on August 24, 2024
Feature/Hotkeys

from ahk.

Comments (31)

dequation avatar dequation commented on August 24, 2024 1

Callbacks would be great. Doing a small application now where I have to import the keyboard-library as well in order to capture when the user presses a key combination and execute some Python-code.

from ahk.

gtusr avatar gtusr commented on August 24, 2024 1

Since we already have the python keyboard project for creating powerful hotkeys from scratch, maybe a useful goal for this project is to incorporate hotkey functionality in a way that makes it as easy as possible to port existing autohotkey hotkeys to this framework.

from ahk.

spyoungtech avatar spyoungtech commented on August 24, 2024 1

@maracko there are some improvements on the way that may help your use case. But let me try to answer your questions:

proper way to close the ahk executable on exit cause it sometimes is left active even after my python script stops?

This library uses finalizer hooks to ensure the AHK process (like those started for hotkeys) is closed. However, as mentioned in the official docs using os._exit will not allow cleanup handlers to run. As such, the hotkey process may be left running.

So, in short, if your python script exits normally (even with an exception), there shouldn't be anything you need to do to ensure the ahk executable terminates.

There are, however, cases where cleanup might not run, such as when a Python fatal internal error is detected, or when os._exit() is called.

In your example, changing os._exit(1) to sys.exit(1) should ensure the AHK process is closed.

there a way to start an event loop so the app doesn't close immediately after execution?

I'm 100% sure what you mean here.

For Hotkeys, the main Python script must continue to run for the hotkey to continue running. If your app consists only of the AHK hotkey, then you can do something like this:

ahk = AHK()
hotkey = ahk.hotkey("#n", "Run Notepad")
hotkey.start() # call .start() to start the AHK process listening to the hotkey
while True: # keep the main thread alive so hotkey will stay running
    try:
        time.sleep(0.5)
    except KeyboardInterrupt:
        hotkey.stop()  # technically you don't have to call stop. 
                       # The process will stop on its own when the script ends
        break

There are a few improvements on the way that may help your situation:

  1. as mentioned earlier Python callbacks for hotkeys are going to implemented in the near future. So something like if ahk.key_state("Control") and ahk.key_state("Shift") and ahk.key_state("1") could reasonably be re-written as a hotkey.

  2. There is a daemon feature coming in #111 that will offer greatly improved performance. Currently, each AHK command runs in its own process. The daemon feature will allow AHK commands to be executed in a single long-running AHK process, which should improve efficiency by an order of magnitude, especially for scripts that call methods in rapid succession.

Lastly, I may add a wait_forever method to hotkeys... but it will likely just be something simple, like the while loop I wrote above.

Hope that answers your question. Let me know if you still have other questions or always feel free to open another issue.

from ahk.

spyoungtech avatar spyoungtech commented on August 24, 2024

As an extended goal, something nice would be methods for remapping keys

from ahk.

spyoungtech avatar spyoungtech commented on August 24, 2024

Implemented with #10 is basic functionality for hotkeys that just setup a running script with the hotkey. Can only execute AHK code, no Python callbacks just yet, but I'd like to figure out if that is possible to do.

from ahk.

Nickiel12 avatar Nickiel12 commented on August 24, 2024

I have a pull request in for Callback functionality in the class Bindable_Hotkey

from ahk.

gtusr avatar gtusr commented on August 24, 2024

Does it support full autohotkey syntax for specifying the keystrokes that activate a hotkey as described here (including the modifier symbols, tilde, ampersand, UP, etc.):

https://www.autohotkey.com/docs/Hotkeys.htm

from ahk.

Nickiel12 avatar Nickiel12 commented on August 24, 2024

Yes

from ahk.

gtusr avatar gtusr commented on August 24, 2024

Another interesting project similar in spirit to this one is:

https://github.com/dc740/AutoHotPy

It also uses Python but leverages instead the more powerful lower-level Interception input driver

https://github.com/oblitum/Interception

to handle input from multiple devices and generate keystroke/mouse events for applications that aggressively try to prevent the use of hotkeys.

Wonder if there is a way to incorporate AutoHotPy (which has not seen any updates for a few years now) into the present framework so that the Interception driver can be used for hotkeys when necessary.

This project may be able to provide some guidance:

https://github.com/evilC/AutoHotInterception

from ahk.

Nickiel12 avatar Nickiel12 commented on August 24, 2024

That project also requires the installation of Interception and the whole point of that project is to avoid using AHK.

from ahk.

spyoungtech avatar spyoungtech commented on August 24, 2024

Since we already have the python keyboard project for creating powerful hotkeys from scratch, maybe a useful goal for this project is to incorporate hotkey functionality in a way that makes it as easy as possible to port existing autohotkey hotkeys to this framework.

I agree. Implementing the same functionality of keyboard in this AHK wrapper is low-priority, in my view. If this library will provide Python callbacks to hotkeys, I would like to see it provide some added value, compared to using the keyboard project.

incorporate hotkey functionality in a way that makes it as easy as possible to port existing autohotkey hotkeys to this framework.

Perhaps we can utilize keyboard as in a dependency in some way and provide a uniform interface to creating keyboard-based hotkeys and AHK hotkeys. Is that close to what you had in mind @gtusr ?

The idea might resemble something like the following:

class Hotkey(AHK):
    def __init__(self, hotkey, ahk_script='', callback=None):
        if ahk_script:
            # create autohotkey-based hotkey
        if callback: # a python callable
            # create hotkey using the keyboard module

from ahk.

Nickiel12 avatar Nickiel12 commented on August 24, 2024

Should the hotkeys be blocking as they are in AHK with keyboard.block_key, or maybe make it up to the user with default set to block? When a hotkey is called does the script that might run be blocking? Do you want a hotkey.bind function?

(I know I am asking a lot of questions, but I would like to work on an implementation, and am wondering how it should be implemented)

from ahk.

dequation avatar dequation commented on August 24, 2024

from ahk.

spyoungtech avatar spyoungtech commented on August 24, 2024

@dequation in the current implementation, you can run #Persistent scripts nonblocking. Though, the concurrency is achieved by creating separate processes, not threads.

Hotkeys currently also run in the background and do not block script execution.

from ahk import AHK
ahk = AHK()
my_script = """
#Persistent
; the rest of the script
"""
process = ahk.run_script(my_script, blocking=False) # starts script in separate process and returns immediately

if the blocking argument is set to True, (the default) it will wait for the subprocess to complete. In short, when blocking=True subprocess.run is used. When blocking=False, subprocess.Popen is used.

Was there some other use case you have that is not satisfied currently?

from ahk.

Nickiel12 avatar Nickiel12 commented on August 24, 2024

Does keyboard allow for hotkeys that catch mouse buttons like ahk?

from ahk.

spyoungtech avatar spyoungtech commented on August 24, 2024

There is a counterpart mouse module with similar capabilities. Both projects are mentioned towards the end of the README for this project.

from ahk.

Nickiel12 avatar Nickiel12 commented on August 24, 2024

do you want both in the project?

from ahk.

spyoungtech avatar spyoungtech commented on August 24, 2024

I'm not sure yet if we'll want to use either in the project or not. It's up for discussion at this point.

Personally, I think I want to limit the scope of how the library interacts with Hotkeys to AHK functionality. That is to say, not introduce a new way to create hotkeys utilizing additional libraries other than AHK. At least initially.

In the meantime, if users need Python callbacks for hotkeys, I think that directing users to use keyboard or mouse for that is OK for now.

(again, personally) I think, the next step towards this library supporting python callbacks for hotkeys is this:

  1. Develop an IPC solution for communication between AHK and Python (this has multiple applications beyond just hotkey callbacks)
  2. Leverage that solution to support python callbacks

Essentially, what #57 may aim to do.

But I'm open to other ideas or contributions.

from ahk.

Nickiel12 avatar Nickiel12 commented on August 24, 2024

I am not experienced enough with ahk to make a websocket solution. But I can make file based data transfer easily enough.

EDIT: I just found this post where this is said
"I have managed to make communication work in one direction: to the autohotkey script (with pywin32's SendMessage() and ahk's OnMessage(). The other direction has proved more difficult."

This might be worth looking into.

Although it looks like he is literally just writing to the same RAM memory location which is really dangerous for an OS. It is a possibility to allocate what would be needed in python, then construct and run an ahk template with the memory address saved.

from ahk.

Nickiel12 avatar Nickiel12 commented on August 24, 2024

Then there is also this file in a rather large github repo

https://github.com/majkinetor/mm-autohotkey/blob/master/IPC/IPC.ahk

It is a header file for ahk and DotNet that send data to a port.
This program just uses SendMessage.

from ahk.

gtusr avatar gtusr commented on August 24, 2024

incorporate hotkey functionality in a way that makes it as easy as possible to port existing autohotkey hotkeys to this framework.

Perhaps we can utilize keyboard as in a dependency in some way and provide a uniform interface to creating keyboard-based hotkeys and AHK hotkeys. Is that close to what you had in mind @gtusr ?

The idea might resemble something like the following:

class Hotkey(AHK):
    def __init__(self, hotkey, ahk_script='', callback=None):
        if ahk_script:
            # create autohotkey-based hotkey
        if callback: # a python callable
            # create hotkey using the keyboard module

This is likely the best approach because it provides the flexibility to create new hotkeys using callbacks while still also allowing us to leverage our prior familiarity with AHK hotkey syntax when appropriate, along with the vast library of useful AHK-based hotkey functions that has been created and distributed through various online forums over the past twenty years.

Just speaking for myself of course, but what I'd like to see most here is a complete representation of AHK hotkey syntax in the first branch (if ahk_script) so that AHK scripts can be ported over as easily as possible. The syntax and semantics of the AHK programming language itself leaves a lot to be desired, and many would no doubt prefer to use python instead. But the specialized syntax for describing keyboard events (and their combinations) may be something worth trying to preserve and even replicate in as faithful a manner as possible.

from ahk.

AdrienHorgnies avatar AdrienHorgnies commented on August 24, 2024

@spyoungtech I'm not sure how I'm supposed to use the Hotkey class. I create and then start the hotkey but it never seems to be usable. Using debug logging, it seems it adds an ExitApp statement which makes the script terminate immediately.

from ahk.

spyoungtech avatar spyoungtech commented on August 24, 2024

@AdrienHorgnies the hotkey class itself will keep the script running until stop is called.

A few things to keep in mind:

  1. If your python script terminates, so will the hotkey; hotkeys do not block.
  2. The hotkey and script arguments use AutoHotkey syntax.
  3. Errors within the script are likely to pass silently

Try running the following script:

import time
from ahk import AHK, Hotkey
ahk = AHK()
notepad_hotkey = Hotkey(engine=ahk, hotkey='#n', script='Run Notepad')
notepad_hotkey.start()
while True:
    time.sleep(10)  # sleep forever to prevent script from ending prematurely

While this script is running if you press Windows Key + n you should see the notepad application open.

from ahk.

AdrienHorgnies avatar AdrienHorgnies commented on August 24, 2024

Indeed, I didn't use the feature as intended. It works.
I was trying Hotkey(engine=ahk, hotkey='e', script='d') but I should have tried Hotkey(engine=ahk, hotkey='e', script='Send, {d}').

from ahk.

spyoungtech avatar spyoungtech commented on August 24, 2024

Python callbacks for hotkeys are on the way as part of asyncio support #104

from ahk.

maracko avatar maracko commented on August 24, 2024

Hey @spyoungtech I love the library it is exactly what I needed. Is there a way to start an event loop so the app doesn't close immediately after execution? Also it could be used to check the state of keys so hotkeys would have much better functionality. Currently I am doing it with a while loop but it is not very elegant or effecient

hotkey = Hotkey(ahk, "my key combo", "my script")
try:
    while True:
        if ahk.key_state("Control") and ahk.key_state("Shift") and ahk.key_state("1"):
            try:
                print("Stopping timer script!")
                hotkey.stop()
                continue
            except RuntimeError:
                print("Hotkey is not running!!")
except KeyboardInterrupt:
    print("Exiting")
    os._exit(1)

Also what would be the proper way to close the ahk executable on exit cause it sometimes is left active even after my python script stops?

If needed I will open new thread but I feel it is directly related to this one.

Thanks in advance

from ahk.

maracko avatar maracko commented on August 24, 2024

@spyoungtech Thanks for the tips.

I thought I had to use os_exit(1) because a similar module called keyboard launches functions in separate threads so that's the only way to kill the main thread.

The while loop actually works fine after I added micro sleep intervals to it sleep(0.01) before it constantly used 100% of 1 core on CPU. Something like wait_forever would be nice to have.

if ahk.key_state("Control") and ahk.key_state("Shift") and ahk.key_state("1") wasn't really working reliably for some reason, often times it didn't detect properly so now I had to use keyboard module along ahk to detect keypresses which is not ideal but it works.

If you could implement async python callbacks that would be amazing. Keep up the good work!

from ahk.

spyoungtech avatar spyoungtech commented on August 24, 2024

@maracko If you must use os._exit(1), you can try putting hotkey.stop() just beforehand to try to ensure cleanup of the hotkey process.

wasn't really working reliably for some reason

I imagine because there's quite a bit of latency to execute all three keystate checks. On my own system, it takes between 1/5 and 1/3 of a second to do all three checks. Might be slower in other systems/conditions. So, you'd probably have to hold all keys down for a while, which is not ideal.

Things like the daemon mode in #111 would help with that.... but I think the real solution would probably be hotkeys with python callbacks, similar to what keyboard does. So, look forward to that!

from ahk.

aaaaaa2493 avatar aaaaaa2493 commented on August 24, 2024

I did something similar when I found I better to program my quite complex script in Python instead of AHK language. Obviously, I needed hotkeys to run my python functions that utilize my mouse and keyboard.

So, it works like that:

I add hotkeys like that:

hotkeys.on(['Alt', 'w'], start)
hotkeys.on(['Alt', 'e'], pause)
hotkeys.on(['Alt', 's'], open)
hotkeys.on(['Alt', 't'], test)

Here's on function (in my hotkeys module)

hots = []

def on(keys, func):
    global hots
    hots += [(keys, func)]

Here's where everything handled (I'm just checking in a loop using keyboard that these keys are pressed):
I added sleep(1) as a hotfix so that the script won't run 10 times while I'm pressing the keys. It works for me, so I didn't change it to a proper solution. Also, I quit all scripts by Alt+q combination right there.

def waiting():
    while True:
        alt = keyboard.is_pressed('Alt')
        q = keyboard.is_pressed('q')

        if alt and q:
            break

        for hot in hots:
            if all(keyboard.is_pressed(i) for i in hot[0]):
                Thread(target=hot[1], daemon=True).start()
                sleep(1)
                break

        sleep(0.01)

In case someone wanted to do something similar without support from this lib.

from ahk.

spyoungtech avatar spyoungtech commented on August 24, 2024

Python callbacks coming with v1 #185

(available now, if you install from the PR source branch)

from ahk.

spyoungtech avatar spyoungtech commented on August 24, 2024

Hotkeys with Python callbacks now released in v1

from ahk.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.