Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include more sophisticated regex/exclusion features #161

Open
ghost opened this issue Jun 30, 2018 · 46 comments
Open

Include more sophisticated regex/exclusion features #161

ghost opened this issue Jun 30, 2018 · 46 comments

Comments

@ghost
Copy link

ghost commented Jun 30, 2018

Classification:

Feature

Reproducibility:

Always

Version

AutoKey-Py3 version 0.90.4 / 3.6

Installed via: sudo apt install autokey-gtk

Distro: Ubuntu GNOME 17.10

Summary

When creating shortcuts, you can provide a regular expression to make sure the shortcut only works on applications whose class names match. However, I have had much difficulty coming up with a regular expression that excludes applications based on their class name.

For example, I have shortcuts for copy and paste that send the <ctrl>+c and <ctrl>+v keys, respectively, to any application I'm on. However, I don't want these shortcuts to be enabled for the terminal (URxvt), since it doesn't register those keybindings as copy and paste and it performs a completely irrelevant action upon using those shortcuts.

It would be nice if I could simply provide a regular expression that excludes certain class names or, better yet, have the ability to simply click on a particular window to exclude it, just like how I can use the detect properties feature to include an application window.

Or maybe I can make it so that I can use one shortcut that sends different keys depending on the application I'm currently on. So <alt>+d would send <ctrl>+c to my browser while <alt>+d would send <ctrl>+<alt>+c to my terminal.

What I've Tried

I've tried using the regexes (?!^Terminal$)(^.*$) and ^((?!Terminal).)*$, to no avail. It doesn't seem like any exclusion filters work, from what I've searched on the internet. I don't even know which type of regex autokey uses.

I eventually decided on creating a shortcut that bound <alt>+d to the following script:

 if window.get_active_class() == 'urxvt.URxvt':
        keyboard.send_keys("<ctrl>+<alt>+c")
 else:
        keyboard.send_keys("<ctrl>+c")

I did the same for paste (replacing the c with v) and now copying and pasting works everywhere. However, I feel like for functionality as simple as this, it should be a standard feature and not something the user has to code in.

@josephj11
Copy link
Contributor

First of all, this should work, so it's a valid issue. I have never seen an example of a successful exclusion pattern. This is something a number of users (including me) want.

Problem: The version and version number of AutoKey you are reporting is impossible.

The old AutoKey went as far as 0.91.x. The new one (which used to be called autokey-py3 - and is now just autokey) started out somewhere around 0.93 and is currently (or about to be) 0.95 - depending on how you install it. If your version is reporting 0.90.4, it is approximately four years old and very out of date. (We don't control what versions of AutoKey are packaged by any distributions.)

Please backup all your macro and phrase definitions then completely uninstall AutoKey.
Next, you will have to install from source. See: Installation Instructions.

Once the new version is up and running, you can restore your phrases and macros from your backup. Don't forget to backup and restore the hidden files as well. There's one for each macro and phrase.

We currently only have PPAs for 16.04 and 18.04 and those probably won't work for you.

The manual install works fine, but sometimes there are issues with getting all the dependencies installed properly. If you get stuck during installation, the place to go for help is on Gitter.

You'll end up with a very much improved version of AutoKey, but it will probably still have your issue.

Fixes (if any) for this issue will only be applied to this new version, so you'll need it anyway.

@luziferius
Copy link
Collaborator

AutoKey uses the regular expressions built into the Python standard library: https://docs.python.org/3/library/re.html
I tried it and it works for me.
I tried using 2 simple scripts (each with one keyboard.send_keys() line), and assigned the same hotkey to both.
I set one window filter to konsole.Konsole, matching my terminals window class, and set the other to ^((?!konsole\.Konsole).)*$, the negation. (This is equivalent to your second tried regular expression.)
Now I get different output depending on the currently active application…

@ghost
Copy link
Author

ghost commented Jul 6, 2018

@josephj11
Thanks for your informative response. It's true that I had an old version of autokey, and I recently figured that out. I have already gone through the process of uninstalling it and installing the newer version.

@luziferius
Thanks for letting me know more about how regular expressions are handled.

@dogweather
Copy link
Contributor

Is it possible that Autokey "swallows up" key triggers for phrases when the window filter excludes the current window?
I'm using the regex to exclude some apps, and the phrase is not entered. But, the original key is also not forwarded on to the app. Or at least that's how it appears.

@luziferius
Copy link
Collaborator

@dogweather Can you please create a new issue for this? That is something else.
It makes tracking easier.

@dogweather
Copy link
Contributor

@luziferius Sure, will do.

@zefei
Copy link

zefei commented Oct 21, 2018

This is an issue I also had. I dug into the code and found these lines to be the cause: https://github.com/autokey/autokey/blob/master/lib/autokey/model.py#L331-L337.

The logic here is that it tries to match the regular expression with either window title or class. This wouldn't work for exclusion because the regular expression must negate both title and class at the same time! Consider this example: we want to exclude window that has title dynamic_title_cannot_be_used and class specific_class, we would like to use re ^((?!specific_class).)*$ to exclude this window, but it does match the title, making it useless.

@luziferius
Copy link
Collaborator

@zefei 💯 Thank you for digging up the location. So @dogweather’s issue is indeed related.
By judging the old test code, WM_CLASS matching was an after-thought and hacked in later. At this location, it breaks.
The code also breaks, if some application uses a window title that by chance is equal to another program’s WM_CLASS content.
This looks like the title/class matching should be fully de-coupled, so that only one property can be matched.

@josephj11
Copy link
Contributor

Uncoupling them would be an improvement anyway - you were already thinking about it. I just hope it's not too much work.

@dogweather
Copy link
Contributor

dogweather commented Nov 7, 2018

Is there any gut feeling about one of those being used more than the other? I.e., is it possible that nobody uses window class, and we can simply stop testing it, or vice-versa?

@josephj11
Copy link
Contributor

You need both. If you want to allow the script to run on any window owned by an application, you look at the class which is relatively invariant, but if you want a particular window from that application, you need to look at the title too - which varies arbitrarily and often does not include the application name.
E.g. Several windows might have a title like "Log In", but one might be a store on the web and another might be a local database. Both of these would also involve other possible windows from the same applications where you were already logged in and would need to take completely different actions (if any).
For now, once a script is running, it can get the title and the class from the AutoKey API , but that approach limits other AutoKey functionality and makes the script code more complicated.

@ghost
Copy link

ghost commented Jan 21, 2019

Any update on this issue?

@kjs3
Copy link
Contributor

kjs3 commented Apr 26, 2019

I've got the following for a phrase and it's still executing in gnome terminal.

"filter": {
  "regex": "^((?!gnome-terminal).)*$", 
  "isRecursive": false
}

This is in AutoKey 0.95.6 and the actual terminal window class is gnome-terminal-server.Gnome-terminal.

The above should not match a string with anything following the regex portion but I tried
^((?!gnome-terminal-server\.Gnome-terminal).)*$ anyway which made no difference.

Am I doing this wrong? This seems to match the konsole.Konsole example above which sounded like it was working.

@josephj11
Copy link
Contributor

josephj11 commented Apr 27, 2019

@kjs3 I'm not that familiar with Python regexes, so I may be wrong.

It appears that you are (correctly) attempting to match the entire window title/class by bracketing your pattern with ^ and $. If that's the case, shouldn't the trailing * be preceded by a . ? Otherwise, it seems to be saying zero or more occurrences of the whole preceding construction.

Also, since AFAIK, AutoKey looks at both the window title and class, getting negative conditions to work is particularly tricky because what works for the title may not work for the class and the reverse - as discussed above.

@kjs3
Copy link
Contributor

kjs3 commented Apr 28, 2019

@josephj11, you're right about the regex. It was working but moving the * in is what I was after to convey anything else like ^((?!gnome-terminal).*)$

Also, window title not being negated was the root issue. Thank you for pointing that out! The fact that I want this phrase not applied in a terminal window where the title changes based on dir/git repo/whatever I setup further complicates things. At least in Ubuntu 19.04, the default title starts with your username and hostname. So that's predictable for my new install. I'll have to figure something out on another Arch install that has pretty fancy titles.

For the moment I have the following regex which is working:

^((?!(gnome-terminal|[USER]@[HOSTNAME]:)).*)$ <- replace with your user/hostname

Ultimately, I think a new option to restrict matching to only the window class would be really helpful.

"filter": {
  "regex": "^((?!gnome-terminal).)*$", 
  "isRecursive": false,
  "matchWindowClassOnly": true // defaults to false
}

☝️ Something like that would be great.

@lpirl
Copy link

lpirl commented Apr 29, 2019

I did struggle with this as well – including @kjs3's example in the Wiki would be neat.

@DoctorSubtilis
Copy link

For me (Kubuntu 18.04, Autokey 0.95) the code of @kjs3 didn't work. I don't find any way to exclude a window (/program) from an autokey's phrase...

@yet-another-account
Copy link

yet-another-account commented Aug 27, 2019

Ubuntu 18.04, Autokey 0.95.4 - @kj3's code didn't work for me either.

@josephj11
Copy link
Contributor

See issue #305 which will help with this if/when it is implemented.

@xpusostomos
Copy link
Contributor

Hi all,

Whilst having working regexp, including negation, would certainly be a step in the right direction, it's hardly user friendly, as the expressions are rather obtuse, even for those handy with regexps.

In AutoHotKey, it's as simple as saying IF !(WinInClass('Terminal) or WinInClass('Emacs'))
or whatever. But surely we can do better than this in the gui. At a bare minimum, a list of regexps with a checkbox for negation. If more ambitious, then an iTunes style interface where you can graphicly construct IF, NOT, AND, OR expressions for what windows you want it in.

Is anyone further along in doing this?

@josephj11
Copy link
Contributor

Thomas hasn't commented on this recently. He was gone for the summer and is back now. Since this seems to be a relatively important enhancement, it's likely that he will get to it (but I can't speak for him.) We don't know how hard it is to do yet.

@hakantakiri
Copy link

Any update on this issue? I'm loving using Autokey, but can't come up with a Regex to exclude Auotkey of working in VS Code which class name is code.Code

@xpusostomos
Copy link
Contributor

Hi hakantakiri. I've been working pretty hard on a major revamp of autokey to support Emacs key overloading, and one of the things needed for that is solving this issue. I thought about what small revamp of regex I could do to fix this, and concluded the real way to solve it is the python way, to make the matching a mini script...

if re.match("google-chrome", window.active_class):
window.match = True
if re.match("autokey/autokey.* Google\ Chrome", window.active_title):
window.match = True
As such you would have complete control. I've been testing it on my machine, and it works pretty well, but I'm not quite ready to release it. I don't know if the maintainers here will be on board with it, if not I'll have to fork, because this is a really important enhancement. I've got other enhancements in there that support key combinations ala Emacs as well. You can preview it below, and if you're brave, run it.

https://github.com/xpusostomos/autokey/tree/issue305

@katoquro
Copy link

@hakantakiri
I've found the next workaround to avoid regex using

I use python scripts to exclude VScode and Jetbrains IDEA:

ignore_list = ['jetbrains', 'code.Code']
if any(ignore in window.get_active_class() for ignore in ignore_list):
    keyboard.send_keys("<super>+i") 
else:
    keyboard.send_keys("<ctrl>+i")

@josephj11
Copy link
Contributor

@katoquro That sort of logic works, but the script still gets triggered on windows where it isn't appropriate and that stops other scripts/phrases from being triggered instead. That's why we need the root cause fixed.

@hakantakiri
Copy link

@katoquro Thanks for your workaround, but I noticed it caused some misbehavior for some scripts and phrases I have for other use cases. Finally I found a Regex that properly excludes VS Code without messing with the source code, but it requires certain conditions:

"filter": {
        "regex": "^((?!Code$).)*$",
        "isRecursive": true
}

Notice that isRecursive is set to true otherwise it wont work. Also, all scripts or phrases you want to be excluded must be inside a folder and this filter must be set to that folder's json file: .folder.json.
The last problem I found, but it might be just an issue of mine, is that whenever I open a new VS Code window, the new window doesn't exclude Autokey until I restart it. So what I did is to build another script inside Autokey to reload itself whenever I need it. I mapped it to <ctrl>+F6 for easy access.

The python script I run to kill and restart Autokey is the following:

import os
os.system(''' pgrep autokey-gtk | xargs -I {} kill {} ; autokey-gtk ''')

@xpusostomos
Copy link
Contributor

@hakantakiri

In theory, the isRecursive just allows you to not have to add the same regex to each key combo in the folder

I'm not sure what you mean by new VS Code windows "doesn't exclude autokey". Maybe you mean autokey doesn't activate in a new window? Maybe you'd be better off running my version of the code, because it works fine for that scenario it seems. I've been fixing bugs along the way, and maybe there was one there I fixed. I think my version of the code is stable, but I haven't done a QT update, so as long as you're using GTK, you'd be fine. And I'm planning a menu item to install Emacs keybindings which I haven't done yet.

@hakantakiri
Copy link

@xpusostomos I'll give more context; what I want to achieve is to avoid some Autokey scripts or phrases to work when I'm inside VS Code, this is because they misbehave horrendously because of conflicts with native VS Code keybindings. I thought that maybe a Regex filter could help me EXCLUDE my phrases and scripts to work in VS Code, and in my last response I explain that I somehow achieve that but at the cost of restarting Autokey every time after opening a new VS Code window.

Putting VS Code aside, the thing is that, as shown in this issue and others, there are some users as myself that need a way to exclude AutoKey to work on a given program. The opposite of what filter is meant to do. And is my understanding that they are considering this to be a feature, or at least provide a way to achieve it in the future, hopefully.

@xpusostomos
Copy link
Contributor

@hakantakiri Yes. Attached is a screen shot of the filter window in my version of the code where I exclude Emacs, Intellij, the terminal and VS Code from my emacs keybindings. And yes, it seems to work fine for newly created Code windows. Because its python you've got complete control.
Screenshot_2020-08-31_13-34-50

@josephj11
Copy link
Contributor

#305 is where the code needs some attention. It will probably solve this issue as well. I'm glad see someone else working on our codebase.

Could one or both of you come over to Gitter and explain this "isRecursive" thing to me. I've never seen anyone even mention it before although I wondered what it was.

@katoquro
Copy link

katoquro commented Dec 7, 2020

@xpusostomos Where we can find this fork? It looks OK for my cases (exclusion for some apps). For Idea and VS Code you can use more simple construction than regex like if with window_class.startswith('jetbrains')

@josephj11
Copy link
Contributor

@katoquro This would be in @xpusostomos 's personal repo. We'd love to get this into our develop branch, but our previous lead developer left the project and, currently, I'm the only one with full access and I'm not a Python/AutoKey dev, so I'm only merging trivial/isolated changes. As soon as someone qualified takes over as lead developer, we'll start merging the more substantial changes like this one into develop and working toward getting new releases out the door again.

@xpusostomos
Copy link
Contributor

@katoquro , my repository is here: https://github.com/xpusostomos/autokey As you point out, with this scheme you can use startswith, or regex or whatever you like. @josephj11 Do you want me to be the lead developer?

@josephj11
Copy link
Contributor

@xpusostomos Thanks for the offer!

Propose that on Gitter and see what feedback you get. It's not up to me. I just have the "keys".

When you do, tell us a bit about your qualifications. How much do you know about building releases for us and working with other developers to review and merge PRs? How much time do you have for AutoKey? And anything else you want to share.

There aren't any requirements to be lead developer per se, but I would want to know you plan to stick around for awhile and have the time and interest to do it.

We currently have at least two other developers and I would hope they would be good with you taking the lead. I certainly can't do it.

Totally aside: Can you give me a clue as to how to pronounce your name/handle? I'd also like to know what time zone you're in. It's not that important, but it gives us an idea of when you might be likely to respond to something when a discussion requires some back and forth.

@katoquro
Copy link

@xpusostomos, could you explain a bit more? What the branch contains that feature? I've tried to install this branch

pip3 install --user https://github.com/xpusostomos/autokey/archive/issue305.zip

but it doesn't start

autokey-gtk --verbose                      
Traceback (most recent call last):
  File "/home/katoquro/.local/bin/autokey-gtk", line 11, in <module>
    load_entry_point('autokey==0.95.11', 'console_scripts', 'autokey-gtk')()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 480, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2693, in load_entry_point
    return ep.load()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2324, in load
    return self.resolve()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2330, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/home/katoquro/.local/lib/python3.6/site-packages/autokey/gtkui/__main__.py", line 4, in <module>
    from autokey.gtkapp import Application
  File "/home/katoquro/.local/lib/python3.6/site-packages/autokey/gtkapp.py", line 18, in <module>
    import autokey.model.script
ModuleNotFoundError: No module named 'autokey.model'

@cjh9
Copy link

cjh9 commented Apr 7, 2021

Hi! I also have this problem. It seems that autokey priorities on specitivity with regexes. Is this correct? Or is it perhaps filenames?

I made it to work this way, using "duplicated hotkeys":
I mapped ctrl+u to my command with the regex .*

Then I created another file with regex .*Gnome-terminal$ and mapped ctrl+u to ctrl+u with send_keys. Bit of workaround, and and one extra file per command you want to keep, but it seems to work for me, and terminal is excluded for that command.

Is this an OK approach or do you have any better idea? Although a bit similar to the Python logic above..

@xpusostomos
Copy link
Contributor

xpusostomos commented Apr 7, 2021

@katoquro Sorry the late reply, I only just saw this. I think you'd be best on master branch if you want to try it out

@josephj11
Copy link
Contributor

@xpusostomos AFAIK, no one else has reviewed your code, so it was never pushed into develop. Since it's a major enhancement, I don't think it should go into the main branch until 0.96 is released.
I would really like to get this into develop, but I would like @sebastiansam55 or @BlueDrink9 to review it first.

@xpusostomos
Copy link
Contributor

@josephj11 any idea when 0.96 will be released?

@josephj11
Copy link
Contributor

We have no lead developer(s), so there is no one to create/test/release a new release. Until that changes, we're stuck.
If someone wants to step up and our current developers vouch for them, I'm all for it.

We are making commits to develop, so people could clone that, but I know some of the changes there are incomplete and certainly have not undergone any QA.

Bluedrink9 just requested and received admin access to AutoKey, so he can do everything and is the closest person we have to a lead developer, but he doesn't want to take on that role/responsibility (and that's fine with me. He is a valuable contributor.)

For now, I am the de facto project manager. I will do commits to develop when anyone requests them once they have been reviewed by a developer I trust who says they are safe or if they are isolated and trivial enough that I can determine that myself.

As of now, I trust Bluedrink9 and, to a lesser degree, you and Sam. This is based solely on time and experience with the project. It has nothing to do with personalities, agendas, etc. I like everyone who is a part of this project. I am not a Python dev, so I can't even evaluate your Python programming expertise. What you and Sam have done looks very good to me, but I don't know enough to go beyond that.

@BlueDrink9
Copy link
Collaborator

I'll address a 0.96 release in the Gitter. I'm keen to get one out, but I'd like to create a beta release first from a frozen develop commit (i.e. continue committing to develop, and meanwhile have a new branch based of develop that does not change, that people test as a beta branch.)

@BlueDrink9
Copy link
Collaborator

At a rough guess, I'd say we're maybe 2 months away from a 0.96 release. That is somewhat dependent on how many beta testers we get though

@josephj11
Copy link
Contributor

Best news I've heard in quite awhile! I'll have to get myself setup for using the beta.

@BlueDrink9
Copy link
Collaborator

Very rough guess though haha, because it assumes almost no bugs found in the beta. Creating the release should take less developer energy than fixing bugs, so if bugs do crop up it may take a while to fix them.

@chrisgraham
Copy link

A workaround to support Mac-style copy/paste shortcuts that don't break the terminal is:

  1. do the double regex exclusion for the regular copy&paste phrases you've already set up with both window title and class. For me ^((?!(gnome-terminal|chrisgraham))).* worked.
  2. remap the copy and paste in Gnome Terminal's preferences to alt+c and alt+v
  3. Setup Autokey to map cmd+c and cmd+v to alt+c and alt+v for the Terminal's window class only.

This solves the problem of Autokey "eating up" the keypress even when you have a rule being filtered out by giving it a new positive rule to follow.

@alokbhaisahu
Copy link

@starun96 this worked for me ^(?!.*?Code.*).*$ for excluding vscode and using my abbreviation everywhere else.
This can still be defeated (due to how AutoKey uses this regex acc to #161 (comment)) but the pattern might help you too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests