xkeysnail
xkeysnail copied to clipboard
Permit keymap conditions to test against wm_name
This allows bindings such as:
define_keymap(lambda wm_class, device_name, wm_name: "Google Docs" in wm_name, {
# Google Docs uses M-slash as an execute-extended-command binding, let's make it more emacsish
K("M-x"): K("M-slash")
})
Notes:
-
Xlib built-in get_wm_name function doesn't support UTF-8 window names, so we use a custom function. Thanks to https://github.com/yoshinari-nomura/xkeysnail/commit/2a74e002a5c43fd757b91fee753d02b38782df36
-
Keymap condition testing still looks at the number of args expected, and additionally passes
wm_name
if the number of args is 3 respectively. It's a bit ugly, but maintains backward compatibility for anyone already using the two argument version. This signature based condition testing was previously only used in the conditional modmap testing, now it is in global keymap testing intransform
, so conditions using device and window name should also work there.
Fixes #122
BTW, I haven't tried using global keymap conditions that use device name - it seems to me that some calls to on_key
don't directly originate from on_event
and wouldn't have a device name assigned since they are synthetic presses. I'm not really familiar with when those would occur, but the situation with this PR is no worse than currently anyway.
I've been using this feature for months. Really useful for me. I hope it could be merged to main line.
Going to see about merging this into my dev branch on my fork. I have completely forgotten about this PR. Thanks @Lenbok!
Just to note I had issues when merging this into my fork, the merge appeared to go ok though. Perhaps it was just my specific config file was too complicated in general or it is not as backwards compatible as it might seem. I am not sure. I will have to explore this more.
One thing that I think would be better though would be to nest it.. so instead of
define_keymap(lambda wm_class, device_name, wm_name: "Google Docs" in wm_name, {
# Google Docs uses M-slash as an execute-extended-command binding, let's make it more emacsish
K("M-x"): K("M-slash")
})
You'd write it like
define_keymap(re.compile("Firefox", re.IGNORECASE),{
# some hotkey sequence that only makes since on a window with this title
define_keymap(lambda wm_name: "Google Docs" in wm_name, {
# Google Docs uses M-slash as an execute-extended-command binding, let's make it more emacsish
K("M-x"): K("M-slash")
}
# some hotkey sequence that only makes since on a window with this title
define_keymap(lambda wm_name: "Preferences" in wm_name, {
K("M-p"): K("M-j")
}
})
At least this was the use case I had mind - and maybe I can write it that way already lol. I have not tried to do so.
I couldn't get the branch to work for me, running window.get_full_text_property
returned the error 'Window' object has no attribute 'get_full_text_property'
which I imagine is either due to library versions of xlib, Cinnamon (Linux Mint) not being supported, or something else. If anyone has the same issue, I got around it by changing line 22 of transform.py
to
from subprocess import run
(...)
wmname = run("xprop -id $(xprop -root _NET_ACTIVE_WINDOW | cut -d ' ' -f 5) WM_NAME",
capture_output=True, shell=True).stdout